Disclaimer about editing the configuration.
;;;; init. el -*- lexical-binding: t -*-
;;;;
;;;; This is a generated file. DO NOT EDIT IT.
;;;; Edit `emacs.org' and use `org-babel-tangle'
;;;; The default hotkey is C-c C-v tRelax the GC treshold.
(setq init/old-gc-treshold gc-cons-threshold
gc-cons-threshold most-positive-fixnum)- Require the functions to handle packages
- Add repos to make available all packages
(require 'package)
(setq package-enable-at-startup nil)
(let ((archives '(("melpa" . "http://melpa.org/packages/")
("gnu" . "http://elpa.gnu.org/packages/")
("nongnu" . "http://elpa.nongnu.org/nongnu/"))))
(dolist (archive archives)
(add-to-list 'package-archives archive)))
(package-initialize)If not installed yet, then install use-package.
This is useful when migrating to a new computer.
(unless (package-installed-p 'use-package)
(package-refresh-contents)
(package-install 'use-package))Require it only for expansion time. Bind-key will be used in package configs.
(eval-when-compile
(require 'use-package))
(require 'bind-key)Mostly lifted from the better defaults package unless otherwise stated.
Disable menu, toolbar and scrollbars.
(menu-bar-mode -1)
(when (fboundp 'tool-bar-mode)
(tool-bar-mode -1))
(when (fboundp 'scroll-bar-mode)
(scroll-bar-mode -1))
(when (fboundp 'horizontal-scroll-bar-mode)
(horizontal-scroll-bar-mode -1))Don’t use the bell, thank you.
(setq visible-bell nil
ring-bell-function 'ignore)Play nice with system clipboard.
(setq save-interprogram-paste-before-kill t
mouse-yank-at-point t
x-select-request-type 'text/plain\;charset=utf-8)Show matching parens
(show-paren-mode 1)Don’t create new frame for ediff
(setq ediff-window-setup-function 'ediff-setup-windows-plain)Change yes/no prompts to y/n prompts
(defalias 'yes-or-no-p 'y-or-n-p)Enable narrowing
(put 'narrow-to-region 'disabled nil)Add to emacs search path.
(add-to-list 'load-path "~/lib/emacs/")Start an edit server for each instance and set up the editor environment variable
(setq server-name
(format "server-%d" (emacs-pid)))
(server-start)
(setenv "EDITOR"
(format "emacsclient -s %s" server-name))Use ace-window for window navigation instead of other-window.
(use-package ace-window
:ensure t
:bind (("C-x o" . ace-window)))Use avy to move around. Use M-g as a leader which already has
goto-line and goto-char.
(use-package avy
:ensure t
:bind (;; Word jumping
("M-g w" . avy-goto-word-1)
("M-g M-b" . avy-goto-word-1-above)
("M-g M-f" . avy-goto-word-1-below)
;; Line jumping
("M-g l" . avy-goto-line)))Use ivy/swiper/counsel for completion
Use ivy for autocompletion of symbols. Use the minibuffer for autocompletion.
(use-package counsel
:ensure t
:commands (ivy-completing-read ivy-completion-in-region)
:bind (
<<bindings>>
)
:init
(setq completing-read-function 'ivy-completing-read
;; next line deletes
;; '(ivy-completion-in-region . ivy-display-function-overlay)
;; which would do autocompletion at point
ivy-display-functions-alist '((t . nil))
completion-in-region-function 'ivy-completion-in-region))Replace isearch with swiper
("C-s" . swiper)Use the counsel version of M-x
("M-x" . counsel-M-x)Use counsel for file and buffer search
("C-x C-f" . counsel-find-file)
("C-x b" . ivy-switch-buffer)Use counsel for help functionality
("C-h f" . counsel-describe-function)
("C-h v" . counsel-describe-variable)Use counsel for entering unicode glyphs
("C-c u" . counsel-unicode-char)Use counsel-git-grep instead of project-find-regexp
("C-x p g" . counsel-git-grep)Use ivy-hydra for different actions with C-o
(use-package ivy-hydra
:ensure t
:commands hydra-ivy/body)Indent with spaces.
(setq-default indent-tabs-mode nil)Require newline at end of file.
(setq require-final-newline t)Delete trailing whitespace before saving.
(add-hook 'before-save-hook #'delete-trailing-whitespace)Don’t create lock files. I never needed it and it drives the nodejs file watcher crazy.
(setq create-lockfiles nil)Most of the time it is the easter european input for Hungarian / Polish.
Other ones still can be chosen with a universal argument (C-u).
(setq default-input-method "latin-2-alt-postfix")Use the WGrep package to be able to edit multiple files at once. A tipical case is editing Ivy occur buffers.
(use-package wgrep
:ensure t
:commands wgrep-change-to-wgrep-mode)Use ripgrep for grep-find command.
;;;; TODO: instead of doing this it might be more optimal to do an
;;;; advice aroung `grep-find'.
(require 'grep)
(grep-apply-setting
'grep-find-command
(let ((starting-cursor-offset 27)
(command "rg -n -H --no-heading -e '' $(git rev-parse --show-toplevel || pwd)"))
`(,command . ,starting-cursor-offset)))TODO:
- [ ] Calculate the offset.
- [ ] Check for availability of the
rgexecutable.
Use the counsel version of jq to see results live.
(use-package counsel-jq
:ensure t
:commands counsel-jq
:config
(setq counsel-jq-json-buffer-mode 'json-ts-mode))Possibly use multiple cursors for editing.
(use-package multiple-cursors
:ensure t
:bind (("C-c m a" . mc/mark-all-dwim) ;; All
("C-c m b" . mc/edit-beginnings-of-lines) ;; Beginning
("C-c m e" . mc/edit-ends-of-lines) ;; End
("C-c m m" . mc/mark-more-like-this-extended) ;; More
("C-c m n" . mc/insert-numbers) ;; Numbers
))Functions for writing undelinings symbols for section headings in text files.
Code lifted from emacs wiki originally by user KragenJavierSitaker.
(defun my/underline-line-with (char)
(save-excursion
(let ((length (- (line-end-position) (line-beginning-position))))
(end-of-line)
(insert "\n")
(insert (make-string length char)))))
(defun my/underline-with-dash ()
(interactive)
(my/underline-line-with ?-))
(defun my/underline-with-equal ()
(interactive)
(my/underline-line-with ?=))
(defun my/underline-with-degree ()
(interactive)
(my/underline-line-with ?°))
(bind-keys
:prefix "C-c _"
:prefix-map my/underline-prefix-map
("-" . my/underline-with-dash)
("=" . my/underline-with-equal)
("o" . my/underline-with-degree))Show sizes in a human-readable way.
(setq dired-listing-switches "-alh")Enable changing the buffer to the visited file by pressing a.
(put 'dired-find-alternate-file 'disabled nil)Move files to trash on deletion
(setq delete-by-moving-to-trash t)Install trashed to manage the contents of the trash from emacs.
(use-package trashed
:ensure t
:commands trashed)Bind C-x C-d to dired instead of list-directory.
(bind-key (kbd "C-x C-d") #'dired)Enable multi-panel file operations by turning on “Do what I mean” mode.
(setq dired-dwim-target t)Make ssh the default connection method.
(setq tramp-default-method "ssh")Snippets taken from https://www.emacswiki.org/emacs/BackupDirectory
Define a dir where emacs can put all the backups
(eval-when-compile
(require 'cl-lib))
(let ((backup-dir "~/.backups/"))
<<set-up-backups>>
<<set-up-autosave>>
<<clean-up-backups>>)- Backup by copying
- Don’t backup TRAMP files
- keep 6 of the newest versions
- keep 2 of the oldest versions
(setq backup-by-copying t
backup-directory-alist `((,tramp-file-name-regexp . nil)
("." . ,backup-dir))
delete-old-versions t
kept-new-versions 6
kept-old-versions 2
version-control t)Clean any backup that is older than a week
(message "Deleting old backup files...")
(let ((week (* 60 60 24 7))
(current (float-time (current-time))))
(cl-dolist (file (directory-files backup-dir t))
(when (and (backup-file-name-p file)
(> (- current (float-time (cl-fifth (file-attributes file))))
week))
(message "%s" file)
(delete-file file))))Save the auto-saves there too.
(setq auto-save-file-name-transforms
`((".*" ,backup-dir t)))
(setq auto-save-list-file-prefix
backup-dir)Use EMMS for listening to music
(use-package emms
:ensure t
:commands (emms-add-dired emms-start emms-streams emms-play-url)
:config
(progn
(emms-all)
(setq emms-player-list '(emms-player-mpv)
emms-info-functions '(emms-info-native))))Use htmlize to add syntax highlighting to org exported code blocks.
Load it when htmlize-region is used as this is the function
which is called org’s HTML export.
(use-package htmlize
:ensure t
:commands htmlize-region)Use org contrib packages. Load the groff exporter
(use-package org-contrib
:ensure t
:config
(require 'ox-groff)
:after org)Make the markdown export use the backtick syntax for exporting code blocks. The deault one exports only with indentation.
Using the backtick syntax makes it possible to syntax highlight code blocks properly.
Create a function to export with the backtick rule.
(defun my/md-backtick-src-block (src-block contents info)
"Print code blocks with the backtick syntax so they can be
highlighted appropriately. The CONTENTS parameter is empty."
(format (concat "```%s\n"
"%s"
"```\n")
(org-element-property :language src-block)
(org-remove-indentation
(org-export-format-code-default src-block info))))Register the new export mode which uses our function. Derive it
from the default markdown mode md.
(use-package org
:ensure nil
:defer t
:init
(autoload #'org-export-define-derived-backend "ox")
:config
(progn
(require 'ox-md)
(require 'org-tempo)
(org-export-define-derived-backend
'md-backtick 'md
:translate-alist '((src-block . my/md-backtick-src-block)))))Create an interactive function so we can use our new export
functionality from the M-x menu or from a key binding.
(defun org-export-md-backtick-to-buffer ()
"Export the current org mode buffer as Markdown with code
blocks exported with the backtick syntax."
(interactive)
(org-export-to-buffer 'md-backtick "*MD Bactick Export*"))Install magit and set C-c g to magit-status and C-c b to magit-blame.
(use-package magit
:ensure t
:bind (("C-c g" . magit-status)
("C-c b" . magit-blame)))Needed for lsp-java to not get “Wrong type argument”
(setq-default c-basic-offset 4)Install haskell-mode
(use-package haskell-mode
:ensure t
:mode "\\.hs\\'")Use tuareg mode for OCaml files.
(use-package tuareg
:ensure t
:mode ("\\.ml[li]?\\'" . tuareg-mode)
:mode ("\\.mly\\'" . tuareg-menhir-mode))Use utop for having a toplevel. Bind Meta+Tab to completion to be
consistent with other modes.
(use-package utop
:ensure t
:bind (:map utop-mode-map
("C-M-i" . utop-complete)))Add F# mode.
(use-package fsharp-mode
:ensure t
:mode "\\.fs\\'"
:config
(setq lsp-fsharp-use-dotnet-tool-for-fsac nil
lsp-fsharp-external-autocomplete t))C# mode is part of emacs starting with version 29 so only add them on earlier versions.
(when (< emacs-major-version 29)
(use-package csharp-mode :ensure t))Add rescript mode for editing rescript files.
(use-package rescript-mode
:ensure t
:mode "\\.res\\'")Use sbt for building.
(use-package sbt-mode
:ensure t
:commands sbt-start sbt-hydra
:config
(setq sbt:program-options '("-Dsbt.supershell=false")))Add scala-mode and set up using the sbt hydra.
(use-package scala-mode
:ensure t
:interpreter ("scala" . scala-mode)
:bind (:map scala-mode-map
("C-c C-c" . sbt-hydra)))Add erlang mode for erlang and erlang header files
(use-package erlang
:ensure t
:mode ("\\.[eh]rl\\'" . erlang-mode))Will need paredit for all lisps.
(use-package paredit
:ensure t
:mode ((rx "dune" (? "-project") eos) . paredit-mode)
:commands enable-paredit-mode
:init
(let ((lisp-mode-hooks '(emacs-lisp-mode-hook
lisp-mode-hook
clojure-mode-hook
cider-repl-mode-hook
;; racket-mode-hook
scheme-mode-hook
slime-repl-mode-hook
;; This stopped working
;; eval-expression-minibuffer-setup-hook
lisp-interaction-mode)))
(dolist (mode-hook lisp-mode-hooks)
(add-hook mode-hook 'paredit-mode))))Add smart parens mode for minibuffer evaluation
(add-hook 'eval-expression-minibuffer-setup-hook 'smartparens-mode)Reazon (a miniKanren for Emacs lisp) for logic programming.
(use-package reazon
:ensure t
;; will always require it before use
:defer t)Set up slime for interactive editing.
(use-package slime
:ensure t
:commands inferior-slime-mode
:init
(setq inferior-lisp-program "sbcl"
slime-contribs '(slime-fancy))
:config
(add-hook 'inferior-lisp-mode-hook
#'(lambda () (inferior-slime-mode t))))Install clojure mode for editing clojure and boot files
(use-package clojure-mode
:ensure t
:commands (clojure-mode clojurescript-mode)
:config
(let ((associations '(("\\.\\(clj\\|boot\\)\\'" . clojure-mode)
("\\.cljs\\'" . clojurescript-mode))))
(dolist (association associations)
(add-to-list 'auto-mode-alist association))))Install cider for interactive development.
(use-package cider
:commands cider-jack-in
:ensure t)Use smartparens
(use-package smartparens
:ensure t
:commands smartparens-mode
:init
(add-hook 'c-mode-common-hook #'smartparens-mode))Use yasnippet for c-like langs.
If the tables are not loaded then load them.
(defvar *snippet-tables-loaded-p*
nil
"`nil' if the yas tables have not been loaded yet.")
(defun load-snippets ()
"Load yas minor mode. If the snippet tables have not yet been
loaded then load them."
(unless *snippet-tables-loaded-p*
(yas-reload-all)
(setq *snippet-tables-loaded-p* t))
(yas-minor-mode-on))Add the package and hook.
lsp mode needs yas for autocomletion of functions.
(use-package yasnippet-snippets
:ensure t
:commands yas-reload-all
:hook ((c-mode-common . load-snippets)
(lsp-mode . yas-minor-mode-on)))Add more snippets for Java.
(use-package java-snippets
:ensure t
:after yasnippet-snippets)Use the lsp package for Java
(use-package lsp-java
:ensure t
:after lsp)Use a tab stop of 2.
(setq js-indent-level 2)Use typescript mode
(use-package typescript-mode
:ensure t
:config
(setf (alist-get 'tsx-ts-mode lsp--formatting-indent-alist) 'typescript-ts-mode-indent-offset)
:mode "\\.tsx?\\'")Use emmet mode for HTML, JSX, and TSX files.
(use-package emmet-mode
:hook ((tsx-ts-mode . emmet-mode)
(js-jsx-mode . emmet-mode)
(js-ts-mode . emmet-mode)
(html-ts-mode . emmet-mode))
:ensure t
:config
(add-to-list 'emmet-jsx-major-modes 'tsx-ts-mode)
(setq emmet-move-cursor-between-quotes t))Add rust mode. Binding clippy to C-c C-c.
(use-package rust-mode
:ensure t
:bind (:map rust-mode-map
("C-c C-c" . rust-run-clippy)))Install terraform mode and documentation retrieval
(use-package terraform-mode
:ensure t
:mode "\\.tf\\'")
(use-package terraform-doc
:ensure t
:after terraform-mode
:bind (:map terraform-mode-map
("C-c h" . terraform-doc)))Install kubernetes mode and documentation retrieval
(use-package k8s-mode
:ensure t
:commands k8s-mode)
(use-package kubedoc
:ensure t
:after k8s-mode
:bind (:map k8s-mode-map
("C-c h" . kubedoc)))Install magit-like porcelain for kubernetes
(use-package kubernetes
:ensure t
:commands (kubernetes-overview)
:bind (("C-c k" . kubernetes-overview))
:config
(setq kubernetes-poll-frequency 3600
kubernetes-redraw-frequency 3600))Set up language server protocol with
C-c C-las the leading key- no breadcrump at the top of the buffer
- no flymake
(use-package lsp-mode
:ensure t
:commands lsp
:init (setq
lsp-keymap-prefix "C-c C-l"
lsp-headerline-breadcrumb-enable nil
lsp-diagnostics-provider :none))If the version supports it then use tree-sitter. When the combobulate git repo is present on the system then load it.
(when (>= emacs-major-version 29)
(use-package treesit
:config
;; Optional, but recommended. Tree-sitter enabled major modes are
;; distinct from their ordinary counterparts.
;;
;; You can remap major modes with `major-mode-remap-alist'.
;; TODO: Note that this does *not* extend to hooks!
;; Make sure you migrate them also
(dolist (mapping '((python-mode . python-ts-mode)
(css-mode . css-ts-mode)
;; TODO differentiate TSX and and plain Typescript
(typescript-mode . tsx-ts-mode)
(js-mode . js-ts-mode)
(css-mode . css-ts-mode)
(java-mode . java-ts-mode)
(csharp-mode . csharp-ts-mode)
(yaml-mode . yaml-ts-mode)))
(add-to-list 'major-mode-remap-alist mapping))
(when (file-exists-p "~/lib/emacs/combobulate")
(use-package combobulate
:custom
;; You can customize Combobulate's key prefix here.
;; Note that you may have to restart Emacs for this to take effect!
(combobulate-key-prefix "C-c o")
(combobulate-cursor-tool 'multiple-cursors)
;; Optional, but recommended.
;;
;; You can manually enable Combobulate with `M-x
;; combobulate-mode'.
:hook ((python-ts-mode . combobulate-mode)
(js-ts-mode . combobulate-mode)
(css-ts-mode . combobulate-mode)
(yaml-ts-mode . combobulate-mode)
(typescript-ts-mode . combobulate-mode)
(tsx-ts-mode . combobulate-mode))
:load-path ("~/lib/emacs/combobulate")))))If vterm is available then amend it to use a prefix argument to read buffer name
(when (fboundp 'vterm)
(define-advice vterm (:around (old-fn prefix) "buffer-name")
(interactive "P\n")
(if (null prefix) (funcall old-fn)
(let ((buf-name (read-string "Buffer name: " nil nil "*vterm*" 'inherit-input)))
(funcall old-fn buf-name)))))Use nix mode for editing nix configuration files:
(use-package nix-mode
:ensure t
:mode "\\.nix\\'")Use the demo-it package to do presentations from emacs.
(use-package demo-it
:ensure t
:defer t)It needs the org-tree-slide for presenting org files.
(use-package org-tree-slide
:ensure t
:after org)Add ledger mode
(use-package ledger-mode
:ensure t
:mode "\\.ledger\\'")Use the ISO format (year/month/day) for the diary.
(require 'calendar)
(calendar-set-date-style 'iso)
(setq diary-date-insertion-form '((format "%4s-%02d-%02d" year (read month) (read day))))Set up C-c c as a key binding for the calendar.
(bind-key (kbd "C-c c") #'calendar)Since my diary is symlinked to a version controlled file we get a prompt. Let’s auto-answer that
(put 'my/answer-prompt 'lisp-indent-function 1)
(defmacro my/answer-prompt (answer body)
(let ((g-answer (gensym 'answer)))
`(let ((,g-answer (cl-case ,answer
((y yes) t)
((n no) nil))))
(defalias 'yes-or-no-p #'(lambda (_prompt) ,g-answer))
(prog1 ,body
(defalias 'yes-or-no-p #'y-or-n-p)))))
Set the starting buffer for frames to the calendar.
(setq initial-buffer-choice
#'(lambda ()
(my/answer-prompt 'yes
(let ((buf (get-buffer "*Calendar*")))
(if buf buf (progn
(calendar)
(diary-mark-entries 'redraw)
(get-buffer "*Calendar*")))))))Use my at program from my utility repository if available.
(when (executable-find "at")
(defun my/at (time action)
"Perform `action' at a give time point.
`action' is a command understandable by the `exec' system call.
`time' is anything understandable by the `date(1)' command.
Returns the buffer representing the background process."
(let* ((command (car (string-split action " ")))
(buffer (format "*cron-%s-%s*" command time))
(script (format "at %s -- %s" time action)))
(async-shell-command script buffer))))Add REST client mode
(use-package restclient
:ensure t
:commands restclient-mode)Bind artist-mode to C-c a.
(bind-key (kbd "C-c a") #'artist-mode global-map)Use the rx macro sytnax.
(setq reb-re-syntax 'rx)Enable markdown mode for markdown files. Use multimarkdown if available.
(use-package markdown-mode
:ensure t
:mode "\\.md\\'"
:config
(when (executable-find "multimarkdown")
(setq markdown-command "multimarkdown")))Enable YAML mode.
(use-package yaml-mode
:ensure t
:mode "\\.ya?ml\\'")Use plantUML to draw diagrams.
- Use the local execuatable
- Emit ascii art
- Indent with two spaces
(use-package plantuml-mode
:ensure t
:commands plantuml-mode
:init
(setq plantuml-default-exec-mode 'executable
plantuml-executable-path "plantuml"
plantuml-output-type "txt"
plantuml-indent-level 2))Use the misterioso theme on older versions
and the modus-operandi themes on newer versions.
(let ((theme (cond
((< emacs-major-version 28) 'misterioso)
((< emacs-major-version 30) 'modus-operandi)
(t 'modus-operandi-tinted))))
(load-theme theme t)
(enable-theme theme))Use the Victor mono fonts.
(add-to-list 'default-frame-alist '(font . "Victor Mono Medium-12"))Use ligatures. Needs to be enabled globally so don’t defer.
(use-package ligature
:ensure t
:config
;; Enable traditional ligature support in eww-mode, if the
;; `variable-pitch' face supports it
(ligature-set-ligatures 'eww-mode '("ff" "fi" "ffi"))
;; Use XML-related ligatures in HTML mode
(ligature-set-ligatures 'html-mode '("<!--" "-->" "</" "/>"))
;; Enable all Cascadia Code ligatures in programming modes
(ligature-set-ligatures 'prog-mode
'("</" "</>" "/>" "~-" "-~" "~@"
"<~" "<~>" "<~~" "~>" "~~" "~~>"
">=" "<=" "<!--" "##" "###" "####"
"|-" "-|" "|->" "<-|" ">-|" "|-<"
"|=" "|=>" ">-" "<-" "<--" "-->" "->" "-<"
">->" ">>-" "<<-" "<->" "->>" "-<<" "<-<"
"==>" "=>" "=/=" "!==" "!=" "<=="
">>=" "=>>" ">=>" "<=>" "<=<" "=<=" "=>=" "<<=" "=<<"
".-" ".=" "=:=" "=!=" "==" "===" "::" ":=" ":>" ":<" ">:"
"<|" "<|>" "|>" "<>"
"<$" "<$>" "$>" "<+" "<+>" "+>"
"?=" "/=" "/==" "__" "&&" "++" "+++"))
;; Enables ligature checks globally in all buffers. You can also do it
;; per mode with `ligature-mode'.
(global-ligature-mode t))Reset GC treshold
(setq gc-cons-threshold init/old-gc-treshold)