Terje’s GNU Emacs configuration. It is not very well documented right now, but hopefully I will have time to write down some more details later.
This configuration is making a lot of assumptions as it is built as a package with Nix. This means that all packages are expected to be on the load-path
already and compatibility is only guaranteed with the GNU Emacs version that is part of this package. Currently GNU Emacs 29.0.50.
The rough details:
- themes
- readable-typo-theme and readable-mono-theme
- buffer completion
- corfu,
completion-preview
- minibuffer completion
- vertico
- package configuration
- use-package
- key definitions
- general
- code navigation
- dumb-jump, source-peek, imenu-anywhere
- syntax checker
flymake
- persistent undo
- via
desktop-save-mode
- language server integration
- eglot
;;; early-init.el --- Early Initialization -*- lexical-binding: t; -*-
Time the startup and display the startup time after completed.
(add-hook 'emacs-startup-hook
(lambda ()
(message "Loaded Emacs in %.03fs"
(float-time (time-subtract after-init-time before-init-time)))))
Temporarily reduce garbage collection to gain some performance boost during startup.
(let ((normal-gc-cons-threshold gc-cons-threshold)
(normal-gc-cons-percentage gc-cons-percentage)
(normal-file-name-handler-alist file-name-handler-alist)
(init-gc-cons-threshold most-positive-fixnum)
(init-gc-cons-percentage 0.6))
(setq gc-cons-threshold init-gc-cons-threshold
gc-cons-percentage init-gc-cons-percentage
file-name-handler-alist nil)
(add-hook 'after-init-hook
`(lambda ()
(setq gc-cons-threshold ,normal-gc-cons-threshold
gc-cons-percentage ,normal-gc-cons-percentage
file-name-handler-alist ',normal-file-name-handler-alist))))
Inhibit startup screen and messages. If you are new to Emacs it is recommended to not disable the startup screen as it has great content to get you going.
(setq inhibit-startup-echo-area-message t)
(setq inhibit-startup-screen t)
(setq initial-scratch-message nil)
Performance tweaks. Don’t load default library and use fundamental-mode
to reduce amount
of hooks.
(setq inhibit-default-init t)
(setq initial-major-mode 'fundamental-mode)
Disable package.el
support. Packages are managed via Nix and disabling this gives a slight
performance boost.
(setq package-enable-at-startup nil)
Disable GUI components.
(setq use-dialog-box nil)
(push '(undecorated . t) default-frame-alist)
(push '(menu-bar-lines . 0) default-frame-alist)
(push '(tool-bar-lines . 0) default-frame-alist)
(push '(vertical-scroll-bars) default-frame-alist)
Don’t implicitly resize frames when changing various settings.
(setq frame-inhibit-implied-resize t)
(defvar global-text-scale-adjust-resizes-frames t)
Allow resizing by dragging internal border.
(push '(drag-internal-border . t) default-frame-alist)
Ignore X resources.
(advice-add #'x-apply-session-resources :override #'ignore)
;;; init.el --- Initialization -*- lexical-binding: t; -*-
Provide an easy way to toggle debug mode which will set certain variables to produce more
informative output. It can be set either by providing the environment variable DEBUG
or
start Emacs with --debug-init
.
(eval-and-compile
(when (getenv "DEBUG") (setq init-file-debug t))
(setq debug-on-error (and (not noninteractive) init-file-debug)))
Provide a location where Emacs can store data and cache.
(eval-and-compile
(defvar data-dir
(if (getenv "XDG_DATA_HOME")
(concat (getenv "XDG_DATA_HOME") "/emacs/")
(expand-file-name "~/.local/share/emacs/"))
"Directory for data.")
(defvar cache-dir
(if (getenv "XDG_CACHE_HOME")
(concat (getenv "XDG_CACHE_HOME") "/emacs/")
(expand-file-name "~/.cache/emacs/"))
"Directory for cache.")
(defvar pictures-dir
(or (getenv "XDG_PICTURES_DIR")
(expand-file-name "~/Pictures/"))
"Directory for pictures."))
Put custom definitions in a temporary file so it doesn’t grow over time. This means all customization will disappear upon reboot and instead needs to be managed via the initialization file.
(setq custom-file (expand-file-name "custom.el" temporary-file-directory))
(eval-when-compile
(require 'use-package))
(eval-and-compile
(defun use-package-ensure-ignore (&rest _args) t)
(setq use-package-ensure-function #'use-package-ensure-ignore)
(setq use-package-always-defer t)
(setq use-package-hook-name-suffix nil))
(if init-file-debug
(setq use-package-verbose t
use-package-expand-minimally nil
use-package-compute-statistics t)
(setq use-package-verbose nil
use-package-expand-minimally t))
Enable minor modes by buffer name and contents. It provides the use-package
keyword
:minor
and :magic-minor
where you can specify these rules.
(use-package auto-minor-mode
:ensure t
:init
(eval-when-compile
(require 'auto-minor-mode)))
Help keeping user-emacs-directory
clean.
(use-package no-littering
:ensure t
:demand t
:init
(setq no-littering-etc-directory data-dir)
(setq no-littering-var-directory cache-dir))
No second pass of case-insensitive search over auto-mode-alist
.
(setq auto-mode-case-fold nil)
Give up some bidirectional functionality for slightly faster re-display.
(setq bidi-inhibit-bpa t)
(setq-default bidi-display-reordering 'left-to-right
bidi-paragraph-direction 'left-to-right)
Update UI less frequently
(setq jit-lock-defer-time 0)
Accelerate scrolling with the trade-off of sometimes delayed accurate fontification.
(setq fast-but-imprecise-scrolling t)
Adjust Garbage Collector threshold depending on activity and try to run garbage collection during idle instead.
(use-package gcmh
:ensure t
:hook
(after-init-hook . gcmh-mode)
:init
(setq gcmh-idle-delay 5)
(setq gcmh-high-cons-threshold (* 16 1024 1024)) ; 16MB
(setq gcmh-verbose init-file-debug))
Track how much time is spent in each function and present a view to investigate this data.
(use-package explain-pause-mode
:ensure t
:commands
(explain-pause-mode)
:init
(when init-file-debug
(explain-pause-mode 1)))
Large file support. This can view/edit/search and compare large files.
(use-package vlf :ensure t)
Library for displaying icons. I am trying to use icons where possible.
(use-package all-the-icons
:ensure t
:commands
(all-the-icons-faicon all-the-icons-octicon))
Library providing functions inspired by Common Lisp. In many cases these functions feel more natural to use.
(require 'cl-lib)
(require 'cl-extra)
Library to quickly define backends for flymake
.
(use-package flymake-quickdef :ensure t :commands (flymake-quickdef-backend))
Library to display inline popups; used by source-peek
.
(use-package quick-peek
:ensure t
:commands (quick-peek-show))
Prevent forms from producing output or other noise.
(defmacro quiet! (&rest forms)
"Run FORMS without making any noise."
`(if init-file-debug
(progn ,@forms)
(let ((message-log-max nil))
(with-temp-message (or (current-message) "") ,@forms))))
(defun quiet-function-advice (orig-fn &rest args)
"Advice used to make a function quiet.
Call ORIG-FN with ARGS and suppress the output. Usage:
(advice-add \\='orig-fn :around #\\='quiet-function-advice)"
(quiet! (apply orig-fn args)))
(defun display-ctrl-M-as-newline ()
"Display `^M' as newline."
(interactive)
(setq buffer-display-table (make-display-table))
(aset buffer-display-table ?\^M [?\n]))
Screenshot current frame in .svg
or .png
format.
(defun screenshot (type)
"Save a screenshot of the current frame as an image in TYPE format.
Saves to a temp file and puts the filename in the kill ring."
(let* ((ext (concat "." (symbol-name type)))
(filename (make-temp-file "Emacs-" nil ext))
(data (x-export-frames nil type)))
(with-temp-file filename
(insert data))
(kill-new filename)
(message filename)))
(defun screenshot-svg ()
"Save a screenshot of the current frame as an SVG image.
Saves to a temp file and puts the filename in the kill ring."
(interactive)
(screenshot 'svg))
(defun screenshot-png ()
"Save a screenshot of the current frame as an PNG image.
Saves to a temp file and puts the filename in the kill ring."
(interactive)
(screenshot 'png))
(defun send-buffer-to-ssh ()
"Send the whole buffer to the *ssh* process."
(interactive)
(process-send-region "*ssh*" (point-min) (point-max)))
(defun send-to-ssh ()
"Send selected region or current line to the *ssh* process."
(interactive)
(let ((procbuf "*ssh*"))
(if (use-region-p)
(process-send-region procbuf (region-beginning) (region-end))
(process-send-string procbuf (thing-at-point 'line t)))))
Dedicated window:
(defun toggle-dedicated-window ()
"Toggle selected window as dedicated window."
(interactive)
(set-window-dedicated-p (selected-window)
(not (window-dedicated-p (selected-window)))))
Fringe control:
(defun no-fringes ()
"Remove all fringes."
(interactive)
(set-window-fringes (selected-window) 0 0 nil))
(defun restore-fringes ()
"Restore fringes."
(interactive)
(set-window-fringes (selected-window) 8 8 t))
Persist history.
(use-package savehist
:hook
(after-init-hook . savehist-mode)
:init
(setq savehist-additional-variables
'(kill-ring
search-ring
regexp-search-ring))
(setq savehist-autosave-interval 60)
(setq savehist-save-minibuffer-history t))
(setq-default calendar-week-start-day 1)
Set shell to bash as fish is not compatible with all packages using the shell.
(setq shell-file-name "bash")
Disable bell (both visual and audible).
(setq ring-bell-function #'ignore)
(setq visible-bell nil)
Use y
/ n
instead of yes
/ no.
(setq confirm-kill-emacs #'y-or-n-p)
(fset #'yes-or-no-p #'y-or-n-p)
Hide M-x commands which does not work in the current buffer.
(setq read-extended-command-predicate #'command-completion-default-include-p)
Fix issues with Emacs 29.1 and GnuPG version 2.4.1 or higher.
(use-package epg
:functions epg-wait-for-status
:config
(fset #'epg-wait-for-status #'ignore))
(defvar init-line-spacing 0.25
"Spacing between lines.")
(defvar init-default-font-height 120
"Default font height.")
(defvar init-fixed-pitch-font "Iosevka Curly Slab"
"Font used for fixed-pitch faces.")
(defvar init-variable-pitch-font "Iosevka Aile"
"Font used for variable-pitch faces.")
(defvar init-serif-font "Iosevka Etoile"
"Font used for serif faces.")
(defvar init-unicode-font "Noto Sans Mono"
"Fallback font used for unicode glyphs.")
(defvar init-symbol-fonts '("Noto Emoji" "Symbola")
"Fonts used for symbol/emoji faces.")
Setup symbol fonts.
(dolist (font init-symbol-fonts)
(set-fontset-font t 'symbol font nil 'append))
(setq-default fill-column 110)
Underline line at descent position, not baseline position.
(setq x-underline-at-descent-line t)
Use a bar cursor by default.
(setq-default cursor-type 'bar)
(use-package readable-typo-theme
:ensure t
:demand t
:init
(setq readable-typo-theme-default-font-height init-default-font-height)
(setq readable-typo-theme-line-spacing init-line-spacing)
(setq readable-typo-theme-fixed-pitch-font init-fixed-pitch-font)
(setq readable-typo-theme-fixed-pitch-serif-font init-fixed-pitch-font)
(setq readable-typo-theme-variable-pitch-font init-variable-pitch-font)
(setq readable-typo-theme-serif-font init-serif-font)
:config
(load-theme 'readable-typo t))
(use-package readable-mono-theme
:ensure t
:demand t
:config
(load-theme 'readable-mono t))
(defun toggle-theme-mode ()
"Toggle dark/light `background-mode' and reload all loaded themes."
(interactive)
(customize-set-variable
'frame-background-mode
(if (eq 'light (frame-parameter nil 'background-mode)) 'dark 'light))
(customize-set-variable 'custom-enabled-themes custom-enabled-themes))
(defun reload-themes ()
"Reload all loaded themes."
(interactive)
(customize-set-variable 'custom-enabled-themes custom-enabled-themes))
Attach a face to the echo area in order to style it differently.
(dolist (buffer-name '(" *Echo Area 0*"
" *Echo Area 1*"))
(with-current-buffer (get-buffer-create buffer-name)
(setq-local face-remapping-alist
'((default readable-typo-theme-echo-area)))))
See Frame Layout documentation for details and terminology.
- Add some padding around the whole window (
internal-border-width
) to provide some air.
(cl-pushnew '(internal-border-width . 16) default-frame-alist :test #'equal)
Setup fringes on both sides and display an indicator for buffer boundaries on the right side. Display fringes outside margins to have the padding on the inside.
(setq-default fringes-outside-margins t
left-fringe-width 8
right-fringe-width 8
indicate-buffer-boundaries 'right)
Add margins inside windows to make text feel less crowded. Padding around the frame is
configured via the internal-border-width
in the Frame section.
(setq-default left-margin-width 1
right-margin-width 1)
Add window dividers, mainly to add a border below the mode line.
(use-package frame
:hook
(server-after-make-frame-hook . window-divider-mode)
:init
(setq window-divider-default-places t)
(setq window-divider-default-bottom-width 1)
(setq window-divider-default-right-width 1))
I try to retain functionality from the original mode line as much as possible, but I also want to simplify it slightly and separate into two parts; left side and right side mode line. There is a helper function in order to fill up the space needed to make the mode line appear on the right side. Also the coding system related information will be hidden if using utf-8-unix. I am also not displaying any minor mode lighters.
Define a variable to conveniently access only the major mode part of mode-line-modes
.
(defvar mode-line-major-mode
`(:propertize ("" mode-name)
help-echo "Major mode\n\
mouse-1: Display major mode menu\n\
mouse-2: Show help for major mode\n\
mouse-3: Toggle minor modes"
mouse-face mode-line-highlight
local-map ,mode-line-major-mode-keymap))
Configure the order and components of the mode line.
(setq-default mode-line-format
'("%e" mode-line-front-space
mode-line-misc-info
(vc-mode vc-mode)
" "
mode-line-modified
mode-line-remote
mode-line-buffer-identification
mode-line-position
(:eval
(mode-line-right))
mode-line-end-spaces))
Setup the right aligned mode line and helper functions to display it.
(defvar mode-line-right-format nil
"The mode line to display on the right side.")
(defun mode-line-right ()
"Render the `mode-line-right-format'."
(let ((formatted-line (format-mode-line mode-line-right-format)))
(list
(propertize
" "
'display
`(space :align-to (- right
(+ ,(string-width formatted-line) right-fringe right-margin))))
formatted-line)))
Move default components to the right side of the mode line.
(setq mode-line-right-format
(list '(:eval mode-line-mule-info)
" "
mode-line-major-mode))
Add position information including column and line number but skip the percentage.
(setq mode-line-position-column-line-format '(" L%l:C%C"))
(setq mode-line-percent-position nil)
(column-number-mode 1)
(line-number-mode 1)
To reduce unnecessary information coding system will not be shown by default if the file is UTF-8 with UNIX end-of-line.
- Only display “end of line”-mnemonic when not UNIX end-of-line.
- Only display coding system when not UTF-8.
- Other cases displays either with warning/error face in order to draw attention.
(setq eol-mnemonic-unix ""
eol-mnemonic-dos (propertize "[CR+LF]" 'face 'warning)
eol-mnemonic-mac (propertize "[CR]" 'face 'warning)
eol-mnemonic-undecided (propertize "[?]" 'face 'error))
(let ((coding (nthcdr 2 mode-line-mule-info)))
(setcar coding '(:eval (if (string-equal "U" (format-mode-line "%z"))
""
(propertize "[%z]" 'face 'warning))))
coding)
Display information about the current indentation settings.
(use-package indent-info
:ensure t
:hook
(after-init-hook . global-indent-info-mode)
:init
(setq indent-info-display-change-message-p nil)
(setq indent-info-insert-target 'mode-line-mule-info)
(setq indent-info-space-format "Spaces: %s")
(setq indent-info-tab-format "Tab Size: %s"))
Support hiding the mode line, this can be useful for different modes displaying documents or presentation.
(use-package hide-mode-line
:ensure t
:commands
(hide-mode-line-mode
turn-on-hide-mode-line-mode
turn-off-hide-mode-line-mode))
(defun mode-line-modified-icons ()
"Icon representation of `mode-line-modified'."
(cond (buffer-read-only
(concat (all-the-icons-octicon "lock" :v-adjust -0.05) " "))
((buffer-modified-p)
(concat (all-the-icons-faicon "floppy-o" :v-adjust -0.05) " "))
((and buffer-file-name
(not (file-exists-p buffer-file-name)))
(concat (all-the-icons-octicon "circle-slash" :v-adjust -0.05) " "))))
(setq-default mode-line-modified '((:eval (mode-line-modified-icons))))
(defun mode-line-remote-icons ()
"Icon representation of `mode-line-remote'."
(when (and buffer-file-name
(file-remote-p buffer-file-name))
(concat (all-the-icons-octicon "radio-tower" :v-adjust -0.02) " ")))
(setq-default mode-line-remote '((:eval (mode-line-remote-icons))))
Shorten long Git branch names as well as replace Git prefix with a nice icon.
(defun vc-git-mode-line-shorten (string)
"Shorten `version-control' STRING in mode-line and add icon."
(cond
((string-prefix-p "Git" string)
(concat (all-the-icons-octicon "git-branch" :v-adjust -0.05)
" "
(if (> (length string) 30)
(concat (substring-no-properties string 4 30) "…")
(substring-no-properties string 4))))
(t
string)))
(advice-add 'vc-git-mode-line-string :filter-return #'vc-git-mode-line-shorten)
I am trying to reduce the amount of keybindings, therefore I present a table of default keybindings in case I would forget them.
Keybinding | Alternative |
---|---|
M- | C-[ |
TAB | C-i |
RET | C-m |
Keybinding | Function | Description |
---|---|---|
C-o | open-line | Open line above |
C-j | electric-newline-and-maybe-indent | Add newline and indent if needed |
M-SPC | just-one-space | Ensures just one space |
M-\ | delete-horizontal-space | Delete all space |
M-^ | delete-indentation | Join current line with previous line |
M-z | zap-to-char | Delete until character |
C-S-backspace | kill-whole-line | Kill entire lines, can be used to move several lines at once |
M-/ | dabbrev-expand | Abbreviation completion |
M-tab / C-[ C-i | completion-at-point | More context aware completion |
M-s . | isearch-forward-symbol-at-point | Search for the symbol at point |
C-w | kill-region | Cut |
M-w | kill-ring-save | Copy |
C-y | yank | Paste |
M-y | yank-next | Paste (next item) |
C-x SPC | rectangle-mark-mode | Rectangular selection |
C-x r t | string-rectangle | Insert string in beginning of rectangular selection (C-t in rectangle-mark-mode ) |
C-M-f | forward-sexp | Move forward inside a balanced expression |
C-M-b | backward-sexp | Move backward inside a balanced expression |
C-M-n | forward-list | Move forward across one balanced group of parenthesis |
C-M-p | backward-list | Move backward across one balanced group of parenthesis |
M-m | back-to-indentation | Move to the first non-whitespace character |
M-e | forward-sentence | End of sentence |
M-a | backward-sentence | Start of sentence |
C-M-d | down-list | Move forward down one level of parenthesis |
C-M-u | backward-up-list | Move backward out of one level of parenthesis |
C-u C-x $ | set-selective-display | Hide/show indentation level |
C-x r w <reg> | window-configuration-to-register | Store the window configuration of the selected frame in REGISTER |
C-x r j | jump-to-register | Go to location stored in REGISTER, or restore configuration stored there |
C-x C-M-0 | global-text-scale-adjust | Change font size of all faces |
Keybinding | Function | Description |
---|---|---|
L | gnus-group-list-all-groups | List all groups (works together with prefix to provide level) |
RET | gnus-topic-select-group | List group mails (works together with prefix to see all) |
g | gnus-group-get-new-news | Refresh groups list |
G G | gnus-group-make-nnir-group | Search mails at server side |
# | gnus-group-mark-group | Mark |
M-# | gnus-group-unmark-group | Un-mark |
R | gnus-summary-reply-with-original | Reply w/ quoted text |
r | gnus-summary-reply | Reploy w/o quoted text |
S W | gnus-summary-wide-reply-with-original | Reply all w/ quoted text |
S w | gnus-summary-wide-reply | Reply all w/o quoted text |
m / C-x m | gnus-new-mail | Compose new mail |
S D e | gnus-summary-resend-message-edit | Re-send a mail in Draft folder |
C-c C-a | mml-attach-file | Attach a file |
o | gnus-mime-save-part | Save attachment |
C-c C-f | gnus-summary-mail-forward | Forward mail |
c | gnus-group-catchup-current | Mark mails as read |
Keybinding | Function | Description |
---|---|---|
C-c C-w | org-refile | Move headline under another top level headline |
<S-right> | org-shiftright | Cycle through todo keywords (right) |
<S-left> | org-shiftleft | Cycle through todo keywords (left) |
C-c C-c | org-ctrl-c-ctrl-c | Set tags for an item |
C-c C-t | org-todo | Set tags for an item (via menu) |
C-c C-s | org-schedule | Schedule an item |
C-c C-d | org-deadline | Set a deadline |
C-c C-q | org-set-tags-command | Attach tags to item |
(defvar leader-key "C-,"
"The key used for most custom operations.")
(defvar local-leader-key "C-."
"The key used for major mode operations.")
(defvar toggle-prefix "C-'"
"Key prefix for commands related to toggling.")
(defvar window-prefix "C-x w"
"Key prefix used for commands related to window operations.")
(defvar nav-prefix "M-g"
"Key prefix used for commands related to navigation.")
(defvar search-prefix "M-s"
"Key prefix used for commands related to search.")
(defvar next-prefix "M-]"
"Key prefix used for commands doing a next operation.")
(defvar prev-prefix "M-["
"Key prefix used for commands doing a previous operation.")
Library for defining repeating commands by repeating the last key.
(use-package defrepeater :ensure t :commands (defrepeater))
More convenient key definitions. It provides the use-package
keyword :general
.
(use-package general
:ensure t
:commands
(general-define-key)
:init
(eval-when-compile
(require 'general)))
Display available keybindings in a popup as you press keys.
(use-package which-key
:ensure t
:defer 3
:commands
(which-key-mode
which-key-setup-side-window-bottom
which-key-key-order-alpha)
:init
(setq which-key-sort-order #'which-key-key-order-alpha)
(setq which-key-sort-uppercase-first nil)
(setq which-key-add-column-padding 1)
(setq which-key-min-display-lines 5)
(setq which-key-idle-delay 1)
:config
(which-key-setup-side-window-bottom)
(which-key-mode 1))
(general-define-key
:keymaps 'global
;; Editing
"<Tools>" 'just-one-space
"M-p" 'completion-at-point
"C-M-y" 'duplicate-dwim
"C-z" 'zap-up-to-char
;; Files
"C-x j" 'find-sibling-file
;; Region
"C-x r S" 'sort-lines)
(general-define-key
:keymaps 'global
:prefix nav-prefix
"k" 'eldoc-doc-buffer
"u" 'browse-url)
(general-define-key
:keymaps 'global
:prefix window-prefix
"d" 'toggle-dedicated-window
"m" 'maximize-window
"r" 'window-configuration-to-register
"w" 'window-toggle-side-windows)
(autoload 'smerge-next "smerge-mode")
(general-define-key
:prefix next-prefix
"" '(:ignore t :wk "next...")
"]" '(text-scale-increase :wk "Text size")
"b" '(next-buffer :wk "Buffer")
"c" '(smerge-next :wk "Conflict")
"e" '(next-error :wk "Error"))
(eval-and-compile
(defrepeater #'text-scale-increase)
(defrepeater #'next-buffer)
(defrepeater #'smerge-next)
(defrepeater #'next-error))
(general-define-key
[remap text-scale-increase] 'text-scale-increase-repeat
[remap next-buffer] 'next-buffer-repeat
[remap smerge-next] 'smerge-next-repeat
[remap next-error] 'next-error-repeat)
(autoload 'smerge-prev "smerge-mode")
(general-define-key
:prefix prev-prefix
"" '(:ignore t :wk "previous...")
"[" '(text-scale-decrease :wk "Text size")
"b" '(previous-buffer :wk "Buffer")
"c" '(smerge-prev :wk "Conflict")
"e" '(previous-error :wk "Error"))
(eval-and-compile
(defrepeater #'text-scale-decrease)
(defrepeater #'previous-buffer)
(defrepeater #'smerge-prev)
(defrepeater #'previous-error))
(general-define-key
[remap text-scale-decrease] 'text-scale-decrease
[remap previous-buffer] 'previous-buffer
[remap smerge-prev] 'smerge-prev
[remap previous-error] 'previous-error)
(general-define-key
:prefix toggle-prefix
"*" '(toggle-theme-mode :wk "Light/Dark theme")
"c" '(highlight-changes-mode :wk "Changes")
"d" '(toggle-debug-on-error :wk "Debug on error")
"f" '(hs-minor-mode :wk "Code folding")
"F" '(follow-mode :wk "Follow")
;; Group together as one mode?
"g" '(subword-mode :wk "Sub-word")
"G" '(glasses-mode :wk "Readable camelCase")
"h" '(hl-line-mode :wk "Line highlight")
"l" '(global-display-line-numbers-mode :wk "Line numbers")
"t" '(toggle-truncate-lines :wk "Truncate lines")
"V" '(variable-pitch-mode :wk "Variable-pitch")
"w" '(whitespace-mode :wk "White-space")
"x" '(flymake-mode :wk "Syntax checker"))
(general-define-key
:prefix leader-key
"m" 'gnus
"P" 'list-processes
"s" 'screenshot-svg
"S" 'screenshot-png
"x" 'regexp-builder
"w" 'eww)
Enable indentation and completion with the TAB
key.
(setq tab-always-indent 'complete)
Cycle with the TAB
key if there are only few candidates.
(setq completion-cycle-threshold 3)
Completion preview inline, with quick completion key.
(use-package completion-preview
:hook
(prog-mode-hook . completion-preview-mode)
(text-mode-hook . completion-preview-mode)
(comint-mode-hook . completion-preview-mode)
:general
(:keymaps
'completion-preview-active-mode-map
"C-e" 'completion-preview-insert)
:init
(setq completion-preview-minimum-symbol-length 2)
:config
(cl-pushnew 'org-self-insert-command completion-preview-commands :test #'equal))
Space-separated matching components matching in any order.
(use-package orderless
:ensure t
:init
(setq completion-styles '(substring orderless))
(setq completion-category-defaults nil)
(setq completion-category-overrides '((file (styles partial-completion)))))
Completion Overlay Region FUnction.
(use-package corfu
:ensure t
:commands
(corfu-mode
corfu-indexed-mode
global-corfu-mode)
:preface
(defun corfu-enable-in-minibuffer ()
"Enable Corfu completion in the minibuffer, e.g., `eval-expression'."
(when (where-is-internal #'completion-at-point (list (current-local-map)))
(corfu-mode 1)))
:hook
(minibuffer-setup-hook . corfu-enable-in-minibuffer)
(corfu-mode-hook . corfu-popupinfo-mode)
:general
(:keymaps
'corfu-map
[return] 'nil
"RET" 'nil
"TAB" 'corfu-next
[tab] 'corfu-next
"S-TAB" 'corfu-previous
[backtab] 'corfu-previous
"C-e" 'corfu-complete)
:init
(setq corfu-cycle t)
(setq corfu-preselect 'first)
(global-corfu-mode 1)
(corfu-indexed-mode 1))
Vertical interactive completion UI.
(use-package vertico
:ensure t
:hook
(after-init-hook . vertico-mode)
:commands
(vertico-insert
vertico-exit)
:init
(defun vertico-move-end-of-line-or-insert (arg)
"Move to end of line or insert current candidate.
ARG lines can be used.
When only one candidate exists exit input after insert."
(interactive "p")
(if (eolp)
(progn
(vertico-insert)
(when (= vertico--total 1)
(vertico-exit)))
(move-end-of-line arg)))
:general
(:keymaps
'vertico-map
"C-e" 'vertico-move-end-of-line-or-insert))
(use-package all-the-icons-completion
:ensure t
:hook
(marginalia-mode-hook . all-the-icons-completion-marginalia-setup))
(use-package cape
:ensure t
:commands
(cape-wrap-silent
cape-wrap-purify)
:preface
(defun init-cape-capf ()
(cl-pushnew #'cape-dabbrev completion-at-point-functions :test #'equal)
(cl-pushnew #'cape-elisp-symbol completion-at-point-functions :test #'equal)
(cl-pushnew #'cape-file completion-at-point-functions :test #'equal))
:hook
(prog-mode-hook . init-cape-capf)
:general
([remap dabbrev-expand] 'cape-dabbrev)
(:keymaps
'corfu-map
"C-x C-f" 'cape-file)
(:prefix
"M-P"
"d" 'cape-dabbrev
"h" 'cape-history
"f" 'cape-file
"k" 'cape-keyword
"p" 'completion-at-point
"s" 'cape-elisp-symbol
"a" 'cape-abbrev
"l" 'cape-line
"w" 'cape-dict
"\\" 'cape-tex
"&" 'cape-sgml
"r" 'cape-rfc1345)
:config
(advice-add 'pcomplete-completions-at-point :around #'cape-wrap-silent)
(advice-add 'pcomplete-completions-at-point :around #'cape-wrap-purify))
(use-package consult
:ensure t
:preface
(autoload 'consult-xref "consult-xref")
:general
([remap bookmark-jump] 'consult-bookmark
[remap goto-line] 'consult-goto-line
[remap switch-to-buffer] 'consult-buffer
[remap imenu] 'consult-imenu
[remap yank-pop] 'consult-yank-pop
"C-c k" 'consult-kmacro
"C-c r" 'consult-recent-file)
(:prefix
search-prefix
"g" 'consult-ripgrep
"m" 'consult-mark
"M-m" 'consult-global-mark)
:init
(setq consult-preview-key "M-RET")
(eval-when-compile (require 'xref))
(with-eval-after-load 'xref
(setq xref-show-xrefs-function #'consult-xref)
(setq xref-show-definitions-function #'consult-xref)))
(use-package dabbrev
:init
(setq dabbrev-case-replace nil)
(setq dabbrev-ignored-buffer-regexps '("\\.\\(?:pdf\\|jpe?g\\|png\\)\\'")))
(use-package marginalia
:ensure t
:defer 2
:commands
(marginalia-mode)
:config
(marginalia-mode 1))
(use-package help
:general
(:keymaps
'help-map
"B" 'find-library
"u" 'describe-face
"U" 'list-faces-display
"'" 'describe-char))
(use-package help-at-pt
:init
(setq help-at-pt-timer-delay 0.1)
(setq help-at-pt-display-when-idle '(flymake-diagnostic)))
Generic help system.
(use-package ghelp
:ensure t
:general
(:keymaps
'help-map
"A" 'ghelp-describe-elisp
"f" 'ghelp-describe-function
"k" 'ghelp-describe-key
"v" 'ghelp-describe-variable)
(:prefix
nav-prefix
"h" 'ghelp-describe-at-point))
Better *help*
buffer.
(use-package helpful
:ensure t
:general
(:keymaps
'help-map
"C" 'helpful-command
"M" 'helpful-macro))
Favor horizontal splits.
(setq split-width-threshold nil)
Respect display actions for both automatic and manual window switching.
(setq switch-to-buffer-obey-display-actions t)
Resize pixelwise.
(setq window-resize-pixelwise t)
Hide asynchronous shell command buffers.
(cl-pushnew '("^*Async Shell Command*" . (display-buffer-no-window))
display-buffer-alist
:test #'equal)
Undo/redo between window layouts.
(use-package winner
:hook
(window-setup-hook . winner-mode)
:preface
(defrepeater #'winner-redo)
(defrepeater #'winner-undo)
:general
(:prefix
next-prefix
next-prefix '(winner-redo :wk "Window History"))
(:prefix
prev-prefix
prev-prefix '(winner-undo :wk "Window History"))
([remap winner-redo] 'winner-redo-repeat
[remap winner-undo] 'winner-undo-repeat)
:init
(setq winner-dont-bind-my-keys t))
Transpose window arrangement.
(use-package transpose-frame
:ensure t
:general
(:prefix
window-prefix
"t" 'transpose-frame
"f" 'flip-frame
"F" 'flop-frame))
Manage “popups”.
(use-package popper
:ensure t
:hook
(after-init-hook . popper-mode)
(popper-mode-hook . popper-echo-mode)
:general
(:prefix
window-prefix
"p" 'popper-toggle-type)
("C-`" 'popper-toggle)
("C-M-`" 'popper-cycle)
:init
(setq popper-reference-buffers
'("Output\\*$"
"\\*Messages\\*"
"\\*envrc\\*"
"^\\*eldoc"
compilation-mode
elisp-refs-mode
flymake-diagnostics-buffer-mode
ghelp-page-mode
help-mode)))
Zoom a window to display as a single window temporarily.
(use-package zoom-window
:ensure t
:general
(:prefix window-prefix "z" 'zoom-window-zoom))
Wrap lines according to fill-column
in visual-line-mode
.
(use-package visual-fill-column
:ensure t
:init
(setq visual-fill-column-center-text t))
(use-package virtual-auto-fill
:ensure t
:hook
(markdown-mode-hook . virtual-auto-fill-mode)
(org-mode-hook . virtual-auto-fill-mode)
:general
(:prefix
toggle-prefix
"SPC" '(virtual-auto-fill-mode :wk "Virtual auto fill")))
Convert between tabs and spaces (only tabify initial white-space).
(setq-default tabify-regexp "^\t* [ \t]+")
Wrap at words.
(setq-default word-wrap t)
Save clipboard contents into kill-ring before replacing them.
(setq save-interprogram-paste-before-kill t)
Automatic parenthesis pairing and highlighting.
(electric-pair-mode 1)
(show-paren-mode 1)
(setq show-paren-context-when-offscreen t)
(use-package tempel
:ensure t
:commands
(tempel-expand)
:preface
(defun tempel-setup-capf ()
(setq-local completion-at-point-functions
(cons #'tempel-expand
completion-at-point-functions)))
:hook
(prog-mode-hook . tempel-setup-capf)
(text-mode-hook . tempel-setup-capf)
:general
("M-+" 'tempel-complete)
("M-*" 'tempel-insert))
(use-package cycle-quotes
:ensure t
:preface
(defrepeater #'cycle-quotes)
:general
("C-x C-'" 'cycle-quotes)
([remap cycle-quotes] 'cycle-quotes-repeat))
(use-package dtrt-indent
:ensure t
:hook
(prog-mode-hook . dtrt-indent-mode)
:init
(setq dtrt-indent-ignore-single-chars-flag t)
(setq dtrt-indent-run-after-smie t)
(setq dtrt-indent-verbosity 0)
:config
(cl-pushnew '(default default (standard-indent tab-width)) dtrt-indent-hook-mapping-list :test #'equal)
(cl-pushnew '(groovy-mode default tab-width) dtrt-indent-hook-mapping-list :test #'equal))
Buttonize URLs and e-mail addresses in the current buffer.
(use-package goto-addr
:hook
(text-mode-hook . goto-address-mode)
(prog-mode-hook . goto-address-prog-mode))
Cycle through words, symbols and patterns.
(use-package grugru
:ensure t
:commands
(grugru-default-setup
grugru-define-global
grugru-define-on-major-mode)
:preface
(eval-when-compile
(require 'grugru-default))
(defrepeater #'grugru-backward)
(defrepeater #'grugru-forward)
:general
(:prefix
next-prefix
"r" '(grugru-forward :wk "Rotate text"))
(:prefix
prev-prefix
"r" '(grugru-backward :wk "Rotate text"))
([remap grugru-backward] 'grugru-backward-repeat
[remap grugru-forward] 'grugru-forward-repeat)
:config
(grugru-default-setup)
(grugru-define-global 'symbol '("assert" "refute"))
(grugru-define-global 'symbol '("true" "false"))
(grugru-define-global 'symbol '("yes" "no")))
Structured editing with soft deletion and balanced expressions.
(use-package puni
:ensure t
:commands
(puni-kill-line
puni-kill-active-region
puni-mark-list-around-point)
:preface
(defun puni-kill-ring-save-line (arg)
"Save whole structured line(s) based on ARG or active region."
(interactive "P")
(cl-letf (((symbol-function 'kill-region) #'kill-ring-save))
(puni-kill-line arg)))
(defun puni-whole-line-or-region-kill (arg)
"Kill whole structured line(s) based on ARG or active region."
(interactive "P")
(if (use-region-p)
(puni-kill-active-region)
(let ((kill-whole-line t))
(if (and (looking-at-p "^$") (= (or arg 1) 1))
(kill-line)
(save-excursion
(beginning-of-line)
(puni-kill-line arg))))))
(defun puni-whole-line-or-region-kill-ring-save (arg)
"Save whole structured line(s) based on ARG or active region."
(interactive "P")
(cl-letf (((symbol-function 'kill-region) #'kill-ring-save))
(puni-whole-line-or-region-kill arg)))
(defun puni-kill-list-around-point ()
(interactive)
(puni-mark-list-around-point)
(kill-region nil nil t))
:hook
(after-init-hook . puni-global-mode)
:general
(:prefix
toggle-prefix
toggle-prefix '(puni-mode :wk "Structured editing"))
(:keymaps
'puni-mode-map
[remap transpose-sexps] 'puni-transpose
"M-W" 'puni-kill-ring-save-line
"M-'" 'puni-kill-list-around-point
"M-D" 'puni-splice
"M-R" 'puni-squeeze
"M-S <" 'puni-wrap-angle
"M-S {" 'puni-wrap-curly
"M-S (" 'puni-wrap-round
"M-S [" 'puni-wrap-square
"C-w" 'puni-whole-line-or-region-kill
"M-w" 'puni-whole-line-or-region-kill-ring-save))
Conversion between different variable naming conventions. Toggle between snake/pascal/camel/up/kebab-case or capital underscore.
(use-package string-inflection
:ensure t
:general
("M-_" 'string-inflection-all-cycle))
Visually highlight regular expression searches as you type. Also supports replace.
(use-package visual-regexp
:ensure t
:general
("M-s r" 'vr/query-replace
"M-s R" 'vr/replace))
Display whitespace
(use-package whitespace
:init
(setq whitespace-line-column fill-column)
(setq whitespace-style
'(face tabs tab-mark spaces space-mark trailing lines-tail))
(setq whitespace-display-mappings
'((tab-mark 9 [8250 9])
(newline-mark 10 [172 10])
(space-mark 32 [183] [46]))))
Cut/copy (C-w
/ M-w
) the current line if no region is active.
(use-package whole-line-or-region
:ensure t
:hook
(after-init-hook . whole-line-or-region-global-mode))
Disabled by default. When enabled, only highlight in the selected window.
(use-package hl-line
:init
(setq hl-line-sticky-flag nil)
(setq global-hl-line-sticky-flag nil))
Display page breaks as a horizontal line.
(use-package page-break-lines
:ensure t
:defer 3
:commands
(global-page-break-lines-mode)
:config
(global-page-break-lines-mode 1))
Making invisible text temporarily visible.
(use-package simple
:general
(:prefix
toggle-prefix
"v" '(visible-mode :wk "Visibility")))
(use-package valign
:ensure t
:hook
(markdown-mode-hook . valign-mode)
(org-mode-hook . valign-mode)
:init
(setq valign-fancy-bar t))
Prevent generation of useless lock and backup files.
(setq create-lockfiles nil)
(setq make-backup-files nil)
Don’t require confirmation when opening a new buffer.
(setq confirm-nonexistent-file-or-buffer t)
Remove visual indicators from non-selected windows
(setq highlight-nonselected-windows nil)
(setq-default cursor-in-non-selected-windows nil)
(use-package files
:hook
(after-init-hook . auto-save-visited-mode)
:init
(setq auto-save-no-message t)
(setq save-abbrevs 'silently))
(add-hook 'after-save-hook #'executable-make-buffer-file-executable-if-script-p)
Enable recursive minibuffers.
(setq enable-recursive-minibuffers t)
Do not allow the cursor in the minibuffer prompt.
(setq minibuffer-prompt-properties
'(read-only t cursor-intangible t face minibuffer-prompt))
(add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)
Give some more room to the minbuffer.
(setq max-mini-window-height 0.3)
(setq resize-mini-windows 'grow-only)
Don’t show fringes in the minibuffer.
(defun disable-minibuffer-window-fringes (&rest _)
"Disable the window fringes for minibuffer window."
(set-window-fringes (minibuffer-window) 0 0 nil))
(add-hook 'minibuffer-setup-hook #'disable-minibuffer-window-fringes)
Track minibuffer history
(setq history-delete-duplicates t)
(setq history-length 500)
(use-package embark
:ensure t
:general
(:keymaps
'minibuffer-local-map
"C-." 'embark-act
"C-;" 'embark-dwim))
(use-package embark-consult :ensure t)
Edit minibuffer in a new temporary buffer by pressing =C-c ‘=.
(use-package miniedit
:ensure t
:general
(:keymaps
'minibuffer-local-map
"C-c '" 'miniedit)
:init
(setq miniedit-show-help-p nil))
More procedural scrolling.
(setq auto-window-vscroll nil)
(setq hscroll-margin 5)
(setq hscroll-step 5)
(setq scroll-margin 0)
(setq scroll-preserve-screen-position t)
(setq-default scroll-down-aggressively 0.01)
(setq-default scroll-up-aggressively 0.01)
(use-package pixel-scroll
:hook
(org-mode-hook . pixel-scroll-precision-mode))
Revert buffers when underlying files change.
(use-package autorevert
:hook
(image-mode-hook . auto-revert-mode)
:init
(setq auto-revert-verbose nil))
(use-package eldoc
:hook
(after-init-hook . global-eldoc-mode))
Hide lines in buffer based on a regular expressions.
(use-package hide-lines
:ensure t
:commands
(hide-lines-matching)
:general
(:prefix search-prefix "H" 'hide-lines))
(use-package pairable :ensure t)
Display colors inline.
(use-package rainbow-mode
:ensure t
:minor
"-theme\\.el\\'"
:hook
(help-mode-hook . rainbow-mode))
(use-package readable
:ensure t
:hook
((eww-mode-hook
Info-mode-hook
markdown-mode-hook
nov-mode-hook
org-mode-hook
outline-mode-hook
rst-mode-hook) . readable-mode))
(use-package relative-buffers
:ensure t
:hook
(after-init-hook . global-relative-buffers-mode)
:init
(setq relative-buffers-project-prefix t))
Writeable grep buffer with ability to apply the changes to all the files.
(use-package wgrep-ag
:ensure t
:init
(setq wgrep-auto-save-buffer t))
Allow repeated mark popping. This behavior is similar to Vim’s C-o
. With this
configuration you can press C-u
and continuously C-SPC
to jump to previous entries in the
mark ring.
(setq set-mark-command-repeat-pop t)
(use-package dired
:hook
(dired-mode-hook . auto-revert-mode)
(dired-mode-hook . hl-line-mode)
(dired-mode-hook . dired-hide-details-mode)
:init
(setq dired-listing-switches "-al --group-directories-first")
;; Always copy/delete recursively
(setq dired-recursive-copies 'always)
(setq dired-recursive-deletes 'top))
(use-package wdired
:general
(:keymaps
'dired-mode-map
"C-c '" 'wdired-change-to-wdired-mode))
(use-package find-dired
:general
("C-x D" 'find-dired)
:init
(setq find-ls-option '("-print0 | xargs -0 ls -ld" . "-ld")))
(use-package dired-sidebar
:ensure t
:preface
(defun init-dired-sidebar ()
(setq cursor-type nil)
(stripe-buffer-mode 0))
:hook
(dired-sidebar-mode-hook . hide-mode-line-mode)
(dired-sidebar-mode-hook . hl-line-mode)
(dired-sidebar-mode-hook . variable-pitch-mode)
(dired-sidebar-mode-hook . init-dired-sidebar)
:general
(:prefix
leader-key
"n" 'dired-sidebar-toggle-sidebar))
Display subtrees in dired view.
(use-package dired-subtree
:ensure t
:init
(setq dired-subtree-use-backgrounds nil)
(setq dired-subtree-line-prefix " "))
Striped dired buffers.
(use-package stripe-buffer
:ensure t
:hook
(dired-mode-hook . stripe-buffer-mode))
(use-package all-the-icons-dired
:ensure t
:hook
(dired-mode-hook . all-the-icons-dired-mode))
(use-package dired-git-info
:ensure t
:general
(:keymaps
'dired-mode-map
")" 'dired-git-info-mode))
(use-package replace
(:keymaps
'occur-mode-map
"C-c '" 'occur-edit-mode))
(use-package noccur
:ensure t
:general
(:prefix
search-prefix
"O" 'noccur-project))
Management tool for a library of PDFs.
(use-package bibliothek
:ensure t
:general
(:prefix leader-key "b" 'bibliothek)
:init
(setq bibliothek-path '("~/books" "~/documents/research/papers"))
(setq bibliothek-recursive t))
Keep track of bookmarks
(use-package bookmark
:init
(setq bookmark-save-flag 1))
(use-package ctrlf
:ensure t
:hook
(after-init-hook . ctrlf-mode))
(use-package ctrlxo
:ensure t
:general
("C-x o" 'ctrlxo))
(use-package deadgrep
:ensure t
:general
(:prefix search-prefix "G" 'deadgrep)
(:keymaps
'deadgrep-mode-map
"C-c '" 'deadgrep-edit-mode)
(:keymaps
'deadgrep-edit-mode-map
"C-c C-c" 'deadgrep-mode))
(use-package find-file
:init
(setq-default ff-quiet-mode t)
(put 'ff-search-directories
'safe-local-variable
(lambda (x) (cl-every #'stringp x))))
Find files via rg --files
.
(use-package find-file-rg
:ensure t
:general
("C-c f" 'find-file-rg))
Move point through buffer-undo-list positions.
(use-package goto-chg
:ensure t
:general
(:prefix
next-prefix
"l" '(goto-last-change :wk "Change"))
(:prefix
prev-prefix
"l" '(goto-last-change-reverse :wk "Change")))
Hint mode for links.
(use-package link-hint
:ensure t
:general
(:prefix nav-prefix
"l" 'link-hint-open-link
"L" 'link-hint-copy-link))
Keep track of recently opened files.
(use-package recentf
:defer 1
:init
(setq recentf-exclude
(list "/tmp/" ; Temp-files
"/dev/shm" ; Potential secrets
"/ssh:" ; Files over SSH
"/nix/store" ; Files in Nix store
"/TAGS$" ; Tag files
"^/\\.git/.+$" ; Git contents
"\\.?ido\\.last$"
"\\.revive$"
"^/var/folders/.+$"
(concat "^" cache-dir ".+$")
(concat "^" data-dir ".+$")))
(setq recentf-filename-handlers '(abbreviate-file-name))
(setq recentf-max-menu-items 0)
(setq recentf-max-saved-items 300)
(setq recentf-auto-cleanup 'never)
:config
(quiet! (recentf-mode 1)))
Keep track of last point place to resume editing in the same file.
(use-package saveplace
:defer 2
:config
(save-place-mode 1))
Retrieve project list via ghq.
(use-package project
:preface
(defun project-read-project-list-from-ghq ()
"Initialize `project--list' using contents of command ghq output."
(interactive)
(with-temp-buffer
(call-process "ghq" nil t nil "list" "--full-path")
(goto-char (point-min))
(while (not (eobp))
(cl-pushnew
(list (buffer-substring-no-properties (line-beginning-position) (line-end-position)))
project--list
:test #'equal)
(forward-line 1))))
:init
(advice-add 'project--read-project-list :after #'project-read-project-list-from-ghq))
Reduce scroll margin.
(defun prog-scroll-margin-setup ()
"Setup `scroll-margin' for `prog-mode'."
(setq-local scroll-margin 3))
(add-hook 'prog-mode-hook #'prog-scroll-margin-setup)
Kill compilation process before stating another and save all buffers on compile
.
(use-package compile
:functions
(compilation-find-buffer)
:preface
(defun compile-on-save-start ()
(let ((compile-buffer (compilation-find-buffer)))
(unless (get-buffer-process compile-buffer)
(let ((display-buffer-alist '(("^*compilation*" . (display-buffer-no-window)))))
(recompile)))))
(define-minor-mode compile-on-save-mode
"Minor mode to automatically call `recompile' whenever the
current buffer is saved. When there is ongoing compilation,
nothing happens."
:lighter " CoS"
(if compile-on-save-mode
(progn (make-local-variable 'after-save-hook)
(add-hook 'after-save-hook 'compile-on-save-start nil t))
(kill-local-variable 'after-save-hook)))
(defun compile-finish-handle-buffer-display (buffer outstr)
"Display failed compilation buffer or burry finished ones."
(let ((compilation-window (get-buffer-window buffer)))
(cond
;; If compilation failed and compilation buffer is not visible,
((and (not (string-match "finished" outstr))
(not compilation-window))
;; display that buffer.
(display-buffer "*compilation*"))
;; If compilation succeeded and compilation buffer is visible,
((and (string-match "finished" outstr)
compilation-window)
;; bury that buffer.
(with-selected-window compilation-window
(bury-buffer))))))
:general
(:keymaps
'global
:prefix
local-leader-key
"a" 'compile-on-save-mode
"c" 'recompile
"C" 'compile)
:init
(setq compilation-always-kill t)
(setq compilation-ask-about-save nil)
(setq compilation-scroll-output t)
(cl-pushnew #'compile-finish-handle-buffer-display compilation-finish-functions :test #'equal)
(put 'compile-command 'safe-local-variable 'stringp))
(make-variable-buffer-local 'compile-command)
(use-package compile-multi
:ensure t
:general
(:keymaps
'global
:prefix
local-leader-key
local-leader-key 'compile-multi)
:preface
(autoload 'package-lint-current-buffer "package-lint")
:config
(cl-pushnew `(emacs-lisp-mode
("emacs:bytecompile" . ,#'emacs-lisp-byte-compile)
("emacs:package-lint" . ,#'package-lint-current-buffer)
("emacs:checkdoc" . ,#'checkdoc))
compile-multi-config
:test #'equal))
(use-package consult-compile-multi
:ensure t
:after compile-multi
:demand t
:commands
(consult-compile-multi-mode)
:config
(consult-compile-multi-mode))
(use-package ansi-color
:hook
(compilation-filter-hook . ansi-color-compilation-filter))
(use-package docker
:ensure t
:general
(:prefix
leader-key
"d" 'docker
"c" 'docker-compose)
:init
(setq docker-command "podman"))
Support for Docker related files.
(use-package dockerfile-ts-mode
:mode
"Dockerfile\\'"
"\\.dockerfile\\'")
(use-package docker-compose-mode :ensure t)
(use-package kubernetes :ensure t)
(use-package cov
:ensure t
:commands
(cov-mode)
:preface
(defun cov-mode-toggle ()
"Turn on `cov-mode'."
(interactive)
(require 'cov)
(if (bound-and-true-p cov-mode)
(cov-mode 0)
(unless cov-lcov-file-name
(setq cov-lcov-file-name (expand-file-name "lcov.info" (project-root (project-current)))))
(cov-mode 1)))
:general
(:prefix
local-leader-key
"v" 'cov-mode-toggle)
:init
(setq cov-coverage-mode t))
Lookup documentation via DevDocs.
(use-package devdocs
:ensure t
:general
(:prefix nav-prefix "K" 'devdocs-lookup))
(use-package separedit
:ensure t
:general
(:keymaps
'prog-mode-map
"C-c '" 'separedit)
:init
(setq separedit-preserve-string-indentation t))
Code folding.
(use-package hideshow
:preface
(defun hs-fold-overlay-ellipsis (ov)
(when (eq 'code (overlay-get ov 'hs))
(overlay-put
ov 'display (propertize " … " 'face 'font-lock-comment-face))))
:hook
(prog-mode-hook . hs-minor-mode)
:general
(:prefix
(concat leader-key " " "z")
"" '(:ignore t :wk "hide")
"c" 'hs-hide-block
"o" 'hs-show-block
"C" 'hs-hide-all
"O" 'hs-show-all
"l" 'hs-hide-level
"z" 'hs-toggle-hiding
"<tab>" 'hs-toggle-hiding)
:init
(setq hs-hide-comments-when-hiding-all nil)
(setq hs-allow-nesting t)
(setq hs-set-up-overlay #'hs-fold-overlay-ellipsis))
Reformat buffer without moving point.
(use-package apheleia
:ensure t
:hook
(prog-mode-hook . apheleia-mode)
:general
(:keymaps
'prog-mode-map
:prefix local-leader-key
"f" 'apheleia-format-buffer)
:config
(dolist (formatter '((eslint . (npx "eslint_d" "--fix-to-stdout" "--stdin" "--stdin-filename" file))
(nix . ("nix" "fmt" "--" "-"))
(rufo . ("rufo" "--simple-exit"))))
(cl-pushnew formatter apheleia-formatters :test #'equal)))
Jump to definition is really useful and I prefer doing so without TAGS which is pretty
much the default for most modes. I am using the excellent package dumb-jump
to jump via
grep tools e.g. (grep
, rx
, ag
)
Don’t ask about keeping current list of tags tables.
(use-package etags
:init
(setq tags-add-tables nil))
(use-package xref
:commands
(xref-show-definitions-completing-read)
:general
(:prefix
nav-prefix
"o" 'xref-find-definitions-other-window)
:config
(remove-hook 'xref-backend-functions #'etags--xref-backend))
(use-package dumb-jump
:ensure t
:hook
(xref-backend-functions . dumb-jump-xref-activate)
:init
(setq dumb-jump-default-project user-emacs-directory)
(setq dumb-jump-selector 'completing-read))
(use-package comint
:general
(:keymaps
'comint-mode-map
"C-c C-k" 'term-char-mode)
:init
(setq comint-use-prompt-regexp t))
(use-package repl-toggle
:ensure t
:preface
(defun clojure-repl ()
"Open a Clojure REPL."
(interactive)
(pop-to-buffer (cider-current-repl nil 'ensure)))
(defun lua-repl ()
"Open a Lua REPL."
(interactive)
(pop-to-buffer (process-buffer (lua-get-create-process))))
:general
(:keymaps
'prog-mode-map
:prefix local-leader-key
"r" 'rtog/toggle-repl)
:init
(setq rtog/goto-buffer-fun 'pop-to-buffer)
(setq rtog/mode-repl-alist
'((emacs-lisp-mode . ielm)
(clojure-mode . clojure-repl)
(elm-mode . elm-repl-load)
(lua-mode . lua-repl)
(racket-mode . racket-repl))))
(autoload 'comint-read-input-ring "comint")
(autoload 'comint-write-input-ring "comint")
(defun +comint-history-write-on-exit (process event)
"Write `comint' history on exit.
Receives PROCESS and EVENT."
(comint-write-input-ring)
(let ((buf (process-buffer process)))
(when (buffer-live-p buf)
(with-current-buffer buf
(insert (format "\nProcess %s %s" process event))))))
(defun +comint-history-enable ()
"Enable `comint' history."
(let ((process (get-buffer-process (current-buffer))))
(when process
(setq comint-input-ring-file-name
(expand-file-name
(format "comint-%s-history" (process-name process))
cache-dir))
(comint-read-input-ring)
(set-process-sentinel process #'+comint-history-write-on-exit))))
Silence next/previous error, by default it produces a message every time.
(advice-add 'next-error :around #'quiet-function-advice)
(advice-add 'previous-error :around #'quiet-function-advice)
Connect flymake to next-error-function
and add some navigation bindings. Disable the
legacy diagnostic functions as some of them have bugs and cause instability (mainly the
Haskell one).
(use-package flymake
:preface
(defun flymake-setup-next-error-function ()
(setq next-error-function 'flymake-next-error-compat))
(defun flymake-next-error-compat (&optional n _)
(flymake-goto-next-error n))
(defun flymake-diagnostics-next-error ()
(interactive)
(forward-line)
(when (eobp) (forward-line -1))
(flymake-show-diagnostic (point)))
(defun flymake-diagnostics-prev-error ()
(interactive)
(forward-line -1)
(flymake-show-diagnostic (point)))
:hook
(flymake-mode-hook . flymake-setup-next-error-function)
:general
(:keymaps
'flymake-mode-map
:prefix
local-leader-key
"!" 'flymake-show-buffer-diagnostics)
(:keymaps
'flymake-mode-map
:prefix next-prefix
"E" 'flymake-goto-next-error)
(:keymaps
'flymake-mode-map
:prefix prev-prefix
"E" 'flymake-goto-prev-error)
(:keymaps
'flymake-diagnostics-buffer-mode-map
"n" 'flymake-diagnostics-next-error
"p" 'flymake-diagnostics-prev-error
"j" 'flymake-diagnostics-next-error
"k" 'flymake-diagnostics-prev-error
"TAB" 'flymake-show-diagnostic))
(use-package flymake-proc
:config
(setq flymake-proc-ignored-file-name-regexps '("\\.l?hs\\'"))
(remove-hook 'flymake-diagnostic-functions 'flymake-proc-legacy-flymake))
(setq vc-follow-symlinks t)
(setq vc-make-backup-files nil)
Open link to files in the web UI connected to a repository.
(use-package browse-at-remote
:ensure t
:general
("C-x v SPC" 'browse-at-remote-kill))
(use-package diff
:preface
(defrepeater #'diff-hunk-next)
(defrepeater #'diff-hunk-prev)
:general
(:keymaps
'diff-mode-map
:prefix next-prefix
"d" '(diff-hunk-next :wk "Diff Hunk"))
(:keymaps
'diff-mode-map
:prefix prev-prefix
"d" '(diff-hunk-prev :wk "Diff Hunk"))
([remap diff-hunk-next] 'diff-hunk-next-repeat
[remap diff-hunk-prev] 'diff-hunk-prev-repeat)
:init
(setq diff-font-lock-prettify t))
- Split horizontally
- Use existing frame instead of creating a new one
- Add a third resolution option, copy both A and B to C
(use-package ediff
:preface
(autoload 'ediff-copy-diff "ediff-util")
(autoload 'ediff-get-region-contents "ediff-util")
(autoload 'ediff-setup-windows-plain "ediff-wind")
(defun ediff-copy-both-to-C ()
"Copy change from both A and B to C."
(interactive)
(ediff-copy-diff
ediff-current-difference nil 'C nil
(concat
(ediff-get-region-contents ediff-current-difference 'A ediff-control-buffer)
(ediff-get-region-contents ediff-current-difference 'B ediff-control-buffer))))
(defun init-ediff-keys ()
"Setup keybindings for `ediff-mode'."
(general-define-key
:keymaps 'ediff-mode-map
"d" '(ediff-copy-both-to-C :wk "Copy both to C")
"j" '(ediff-next-difference :wk "Next difference")
"k" '(ediff-previous-difference :wk "Previous difference")))
:hook
(ediff-quit-hook . winner-undo)
(ediff-keymap-setup-hook . init-ediff-keys)
:init
(setq ediff-diff-options "-w")
(setq ediff-merge-split-window-function #'split-window-horizontally)
(setq ediff-split-window-function #'split-window-horizontally)
(setq ediff-window-setup-function #'ediff-setup-windows-plain))
Diff indicators in fringe
(use-package diff-hl
:ensure t
:defer 2
:commands
(global-diff-hl-mode)
:preface
(autoload 'diff-hl-flydiff-mode "diff-hl-flydiff" nil t)
(autoload 'diff-hl-dired-mode "diff-hl-dired" nil t)
(defrepeater #'diff-hl-next-hunk)
(defrepeater #'diff-hl-previous-hunk)
:hook
(dired-mode-hook . diff-hl-dired-mode)
(magit-post-refresh-hook . diff-hl-magit-post-refresh)
:general
(:keymaps
'diff-hl-mode-map
:prefix next-prefix
"d" '(diff-hl-next-hunk :wk "Diff Hunk"))
(:keymaps
'diff-hl-mode-map
:prefix prev-prefix
"d" '(diff-hl-previous-hunk :wk "Diff Hunk"))
([remap diff-hl-next-hunk] 'diff-hl-next-hunk-repeat
[remap diff-hl-previous-hunk] 'diff-hl-previous-hunk-repeat)
:init
(setq diff-hl-ask-before-revert-hunk nil)
(setq diff-hl-update-async t)
:config
(global-diff-hl-mode 1)
(diff-hl-flydiff-mode 1))
Enhanced git related views and commands.
(use-package magit
:ensure t
:defer 2
:preface
(autoload 'magit-show-commit "magit-diff" nil t)
(eval-when-compile
(require 'vc-msg-git))
(defun +git-commit-set-fill-column ()
"Set `fill-column' for git commit."
(setq fill-column 72))
(defvar magit-process-create-pull-request-regexp
"remote: Create pull request for.*\nremote: +\\(?1:[^ ]+\\)[^\n]*"
"Regular expression detecting PR.")
(defun magit-process-ask-create-pull-request (_process string)
"Detect pull request STRING and ask to create PR."
(when (string-match magit-process-create-pull-request-regexp string)
(let ((url (match-string 1 string))
(inhibit-message t))
(if (y-or-n-p "Create PR? ")
(browse-url (url-encode-url url))))))
:hook
(git-commit-mode-hook . +git-commit-set-fill-column)
:general
(:keymaps
'dired-mode-map
"C-x g" 'magit)
:init
(setq magit-log-buffer-file-locked t)
(setq magit-refs-show-commit-count 'all)
(setq magit-save-repository-buffers 'dontask)
(setq magit-process-prompt-functions #'magit-process-ask-create-pull-request)
:config
;; Unset pager as it is not supported properly inside emacs.
(setenv "GIT_PAGER" ""))
Popup commit message for current line
(use-package vc-msg
:ensure t
:general
("C-x v p" 'vc-msg-show))
Project-specific environment variables via direnv
.
(use-package envrc
:ensure t
:if (executable-find "direnv")
:defer 1
:commands
(envrc-global-mode)
:general
(:keymaps
'envrc-mode-map
"C-c e" 'envrc-command-map)
:config
(envrc-global-mode 1))
Generic Language Server Protocol integration via eglot
.
(use-package eglot
:defer 3
:general
(:keymaps
'eglot-mode-map
:prefix local-leader-key
local-leader-key 'eglot-code-actions
"e" '(:ignore t :wk "eglot")
"ea" 'eglot-code-actions
"ef" 'eglot-format
"er" 'eglot-rename
"eq" 'eglot-reconnect
"eQ" 'eglot-shutdown)
:init
(setq eglot-autoshutdown t)
(setq eglot-confirm-server-edits nil)
(setq eglot-sync-connect nil)
:config
(cl-pushnew '((elixir-mode elixir-ts-mode heex-ts-mode) . ("elixir-ls"))
eglot-server-programs
:test #'equal)
(cl-pushnew '((java-mode java-ts-mode) . ("jdt-language-server" "-data" ".jdtls-cache"))
eglot-server-programs
:test #'equal))
Highlight TODO inside comments and strings.
(use-package hl-todo
:ensure t
:preface
(defrepeater #'hl-todo-next)
(defrepeater #'hl-todo-previous)
:hook
(prog-mode-hook . hl-todo-mode)
:general
(:prefix next-prefix "t" '(hl-todo-next :wk "Todo"))
(:prefix prev-prefix "t" '(hl-todo-previous :wk "Todo"))
([remap hl-todo-next] 'hl-todo-next-repeat
[remap hl-todo-previous] 'hl-todo-previous-repeat))
Highlight symbol at point on idle.
(use-package idle-highlight-mode
:ensure t
:hook
(prog-mode-hook . idle-highlight-mode)
:init
(setq idle-highlight-exclude-point t))
Jump to document locations in current buffer
(use-package imenu-anywhere
:ensure t
:general
(:prefix
search-prefix
"i" 'imenu
"I" 'imenu-anywhere))
Easily add document locations via regular expressions.
(use-package imenu-extra
:ensure t
:functions (imenu-extra-auto-setup))
Document locations in a sidebar.
(use-package imenu-list
:ensure t
:general
(:prefix
leader-key
"i" 'imenu-list-smart-toggle))
Peek definition (Display the function source inline).
(use-package source-peek
:ensure t
:general
(:prefix
nav-prefix
"SPC" 'source-peek))
Delete trailing white-space before save, but only for edited lines.
(use-package ws-butler
:ensure t
:commands
(ws-butler-mode)
:init
(setq ws-butler-convert-leading-tabs-or-spaces t))
Visually separate delimiter pairs.
(use-package rainbow-delimiters
:ensure t
:hook
((clojure-mode-hook
emacs-lisp-mode-hook
ielm-mode-hook
lisp-mode-hook
racket-mode-hook) . rainbow-delimiters-mode)
:init
(setq rainbow-delimiters-max-face-count 3))
Highlight source code identifiers based on their name.
(use-package color-identifiers-mode :ensure t)
(use-package ligature
:ensure t
:commands
(ligature-set-ligatures)
:hook
(prog-mode-hook . ligature-mode)
:config
(ligature-set-ligatures
'prog-mode
'("-<<" "-<" "-<-" "<--" "<---" "<<-" "<-" "->" "->>" "-->" "--->" "->-" ">-" ">>-" "<->" "<-->" "<--->" "<---->" "<!--"
"=<<" "=<" "=<=" "<==" "<===" "<<=" "<=" "=>" "=>>" "==>" "===>" "=>=" ">=" ">>=" "<=>" "<==>" "<===>" "<====>" "<!---"
"<------" "------>" "<=====>" "<~~" "<~" "~>" "~~>" "::" ":::" "\\/" "/\\" "==" "!=" "/=" "~=" "<>" "===" "!==" "=/=" "=!="
":=" ":-" ":+" "<*" "<*>" "*>" "<|" "<|>" "|>" "<." "<.>" ".>" "+:" "-:" "=:" "<******>" "(*" "*)" "++" "+++" "|-" "-|"
"&&" "||")))
(use-package prog-mode
:init
(setq prettify-symbols-unprettify-at-point t))
(add-hook 'emacs-lisp-mode-hook #'flymake-mode)
(add-hook 'emacs-lisp-mode-hook #'outline-minor-mode)
(general-define-key
:keymaps 'emacs-lisp-mode-map
:prefix local-leader-key
"c" 'emacs-lisp-byte-compile
"C" 'emacs-lisp-byte-compile-and-load
"l" `(,(lambda () (interactive) (load-file (buffer-file-name))) :wk "Load file")
"L" 'eval-buffer
"t" 'ert)
(custom-set-variables
'(ad-redefinition-action 'accept)
'(apropos-do-all t)
'(enable-local-eval 'maybe)
'(enable-local-variables :safe))
Specific safe local code can be specified via:
safe-local-variable-values
safe-local-eval-forms
safe-local-eval-function
Persist ielm history.
(defvar +ielm-comint-input-ring nil)
(with-eval-after-load 'savehist
(cl-pushnew '+ielm-comint-input-ring savehist-additional-variables :test #'equal))
(defun +ielm-set-comint-input-ring ()
"Restore `ielm' history."
(setq-local comint-input-ring-size 200)
(add-hook 'kill-buffer-hook #'+ielm-save-comint-input-ring nil t)
(when +ielm-comint-input-ring
(setq comint-input-ring +ielm-comint-input-ring)))
(defun +ielm-save-comint-input-ring ()
"Save `ielm' history."
(setq +ielm-comint-input-ring comint-input-ring))
(add-hook 'ielm-mode-hook #'+ielm-set-comint-input-ring)
Auto-compile Elisp files.
(use-package auto-compile
:ensure t
:hook
(emacs-lisp-mode-hook . auto-compile-on-load-mode)
(emacs-lisp-mode-hook . auto-compile-on-save-mode)
:init
(setq auto-compile-display-buffer nil)
(setq auto-compile-use-mode-line nil))
Evaluation results in overlay.
(use-package eros
:ensure t
:hook
(emacs-lisp-mode-hook . eros-mode))
(use-package highlight-quoted
:ensure t
:hook
(emacs-lisp-mode-hook . highlight-quoted-mode))
(use-package package-lint-flymake
:ensure t
:commands (package-lint-flymake-setup)
:preface
(autoload 'package-lint--provided-feature "package-lint")
(defun package-lint-flymake-setup-when-package ()
"Enable `package-lint-flymake' when buffer seems to be a package."
(when (package-lint--provided-feature)
(package-lint-flymake-setup)))
:hook
(emacs-lisp-mode-hook . package-lint-flymake-setup-when-package))
Discover functions.
(use-package suggest
:ensure t
:commands (suggest)
:preface
(defun +suggest-popup ()
"Open suggest as a popup."
(interactive)
(let* ((window (selected-window))
(dedicated-flag (window-dedicated-p window)))
(set-window-dedicated-p window t)
(suggest)
(set-window-dedicated-p window dedicated-flag)))
:general
(:keymaps
'emacs-lisp-mode-map
:prefix local-leader-key
"s" '+suggest-popup))
Improve readability of escape characters in regular expressions.
(use-package easy-escape
:ensure t
:hook
(emacs-lisp-mode-hook . easy-escape-minor-mode))
(use-package erc
:init
(setq erc-hide-list '("JOIN" "PART" "QUIT"))
(setq erc-prompt-for-password nil))
(use-package org
:defer 5
:preface
(autoload 'org-get-outline-path "org-refile" nil t)
:hook
(org-mode-hook . auto-fill-mode)
:general
("C-C a" 'org-agenda)
(:keymaps
'org-mode-map
"C-'" 'nil
"C-," 'nil)
:init
(setq org-agenda-files
'("~/org/Personal.org" "~/org/Work.org"))
(setq org-insert-heading-respect-content t)
(setq org-log-done 'time)
(setq org-modules nil)
(setq org-special-ctrl-a/e t)
(setq org-confirm-babel-evaluate nil)
(setq org-edit-src-content-indentation 0)
(setq org-src-preserve-indentation nil)
(setq org-src-tab-acts-natively t)
(setq org-src-window-setup 'current-window)
(setq org-startup-truncated nil)
(setq org-auto-align-tags nil)
(setq org-tags-column 0)
(setq org-tag-alist
'(("@work" . ?w)
("@home" . ?h)
("laptop" . ?l))))
(use-package ob-plantuml
:init
(setq org-plantuml-exec-mode 'plantuml))
Unmaintained add-ons for org-mode, in this configuration org-eldoc
is used.
(use-package org-contrib :ensure t)
Paste links from clipboard and automatically fetch title.
(use-package org-cliplink
:ensure t
:general
(:keymaps
'org-mode-map
:prefix local-leader-key
"l" 'org-cliplink))
Eldoc support, showing path to current section.
(use-package org-eldoc
:after eldoc
:preface
(defun +org-eldoc-get-breadcrumb-no-properties (string)
"Remove properties from STRING."
(when string (substring-no-properties string)))
:hook
(org-mode-hook . org-eldoc-load)
:config
(advice-add 'org-eldoc-get-breadcrumb :filter-return #'+org-eldoc-get-breadcrumb-no-properties))
(use-package org-limit-image-size
:ensure t
:after org
:commands
(org-limit-image-size-activate
org-limit-image-size-deactivate)
:init
(org-limit-image-size-activate)
(setq org-limit-image-size '(0.48 . 0.8)))
Annotate documents with org-mode
.
(use-package org-noter :ensure t)
Preview org-file in an eww
buffer.
(use-package org-preview-html :ensure t)
Presentation mode.
(use-package org-tree-slide
:ensure t
:hook
(org-tree-slide-play-hook . turn-on-hide-mode-line-mode)
(org-tree-slide-stop-hook . turn-off-hide-mode-line-mode)
(org-tree-slide-play-hook . no-fringes)
(org-tree-slide-stop-hook . restore-fringes)
:general
(:keymaps
'org-tree-slide-mode-map
"<right>" 'org-tree-slide-move-next-tree
"<left>" 'org-tree-slide-move-previous-tree)
(:keymaps
'org-mode-map
:prefix local-leader-key
"p" 'org-tree-slide-mode)
:init
(setq org-tree-slide-header nil)
(setq org-tree-slide-slide-in-effect nil))
(use-package ob-http :ensure t)
This sections makes org-mode
look more beautiful and appealing.
(use-package org
:hook
(org-babel-after-execute-hook . org-redisplay-inline-images)
:init
(setq org-fold-catch-invisible-edits 'show-and-error)
(setq org-fontify-quote-and-verse-blocks t)
(setq org-hide-emphasis-markers t)
(setq org-pretty-entities t)
(setq org-src-fontify-natively t)
(setq org-startup-with-inline-images t))
(use-package org-modern
:ensure t
:hook
(org-mode-hook . org-modern-mode)
:init
(setq org-modern-hide-stars t)
(setq org-modern-table nil))
Allow more newlines (1 to 4) for emphasized text, useful when filling long text.
(use-package org
:preface
(autoload 'org-set-emph-re "org")
:config
(setcar (nthcdr 4 org-emphasis-regexp-components) 4)
(org-set-emph-re 'org-emphasis-regexp-components org-emphasis-regexp-components))
(use-package org
:init
(setq org-ellipsis " ┅ ")
(setq org-fontify-whole-heading-line t)
(setq org-fontify-todo-headline t)
(setq org-fontify-done-headline t))
(use-package ox-epub :ensure t)
(use-package ox-html
:init
(setq org-html-postamble nil)
(setq org-html-validation-link nil))
Disable link colors.
(use-package ox-latex
:init
(setq org-latex-hyperref-template
(mapconcat
'identity
'("\\hypersetup{"
"pdfauthor={%a},"
"pdftitle={%t},"
"pdfkeywords={%k},"
"pdfsubject={%d},"
"pdfcreator={%c},"
"pdflang={%L},"
"pdfborder=0 0 0}")
"\n")))
Add links in footnotes.
(autoload 'org-export-derived-backend-p "ox")
(defvar org-export-latex-add-link-footnotes t
"If non-nil links will be added as footnotes if exported to latex.")
(defun org-export-latex-link-footnote (text backend _info)
"Create a footnote for each link to retain this information for print.
If there is a URL and the export BACKEND is latex, then extract
URL into footnote from TEXT."
(when (and org-export-latex-add-link-footnotes
(org-export-derived-backend-p backend 'latex)
(string-match "\\\\href{\\(.*\\)}{\\(.*\\)}" text))
(when (cl-some (lambda (type)
(string-prefix-p type (match-string 1 text)))
'("http" "https" "ftp" "mailto" "doi"))
(format "%s \\footnote{\\url{%s}} " text (match-string 1 text)))))
(with-eval-after-load 'ox
(cl-pushnew #'org-export-latex-link-footnote org-export-filter-link-functions :test #'equal))
Display outlines in text like files or use it in conjunction with other major modes via outline-minor-mode
.
Add faces to outline-minor-mode
in order to make the headings stand out.
(use-package outline-minor-faces
:ensure t
:after outline
:hook
(outline-minor-mode-hook . outline-minor-faces-mode))
(use-package clojure-mode
:ensure t
:mode
"\\.\\(clj\\|dtm\\|edn\\)\\'"
"\\(?:build\\|profile\\)\\.boot\\'"
("\\.cljc\\'" . clojurec-mode)
("\\.cljs\\'" . clojurescript-mode))
(use-package cider
:ensure t
:commands
(cider-current-repl)
:hook
(cider-mode-hook . cider-auto-test-mode)
:general
(:keymaps
'cider-mode-map
:prefix local-leader-key
"c" 'cider-refresh
"t a" 'cider-test-run-project-tests
"t n" 'cider-test-run-ns-tests
"t t" 'cider-test-run-test)
:init
(setq cider-prompt-for-symbol nil)
(setq cider-repl-display-help-banner nil)
(setq cider-repl-history-file (concat data-dir "cider-history")))
(use-package cobol-mode
:ensure t
:mode "\\.\\(cob\\|cbl\\|cpy\\)\\'")
(use-package crystal-mode
:ensure t
:mode "\\(?:\\.cr\\)\\'"
:general
(:keymaps
'crystal-mode-map
:prefix local-leader-key
"t a" 'crystal-spec-all
"t f" 'crystal-spec-buffer
"t t" 'crystal-spec-line))
(use-package inf-crystal
:ensure t
:hook
(crystal-mode-hook . inf-crystal-minor-mode)
:general
(:keymaps
'crystal-mode-map
:prefix local-leader-key
"r" 'inf-crystal))
(use-package csv-mode
:ensure t
:mode
"\\.[Cc][Ss][Vv]\\'"
("\\.tsv\\'" . tsv-mode)
:init
(setq csv-separators '("," "\t" ";")))
(use-package d2-mode
:ensure t
:mode "\\.d2\\'"
:commands
(d2-compile-buffer)
:preface
(defun d2-mode-set-compile-command ()
"Configure compile command for d2-mode."
(set (make-local-variable 'compile-command)
(mapconcat #'shell-quote-argument (append (list d2-location buffer-file-name) d2-flags)
" ")))
:hook
(d2-mode-hook . d2-mode-set-compile-command)
(d2-mode-hook . compile-on-save-mode)
:init
(setq d2-flags '("--layout" "elk" "--sketch" "--theme" "1"))
:config
(with-eval-after-load 'compile-multi
(cl-pushnew `(d2-mode ("d2:generate" . ,#'d2-compile-buffer))
compile-multi-config
:test #'equal)))
(use-package es-mode
:ensure t
:mode "\\.es\\'")
(use-package elixir-ts-mode
:mode
"\\.elixir\\'"
"\\.ex\\'"
"\\.exs\\'"
:hook
(elixir-ts-mode-hook . eglot-ensure)
:init
(cl-pushnew '("lib/\\([^/]+\\)\\.ex\\'" "test/\\1_test.exs") find-sibling-rules :test #'equal)
(cl-pushnew '("test/\\([^/]+\\)_test\\.exs\\'" "lib/\\1.ex") find-sibling-rules :test #'equal))
(cl-pushnew '(elixir-mode . elixir-ts-mode) major-mode-remap-alist :test #'equal)
(use-package elm-mode
:ensure t
:mode "\\.elm\\'"
:general
(:keymaps
'elm-mode-map
:prefix local-leader-key
"t" 'elm-test-project)
:init
(setq elm-format-on-save t)
(setq elm-package-json "elm.json")
(setq elm-tags-exclude-elm-stuff nil)
(setq elm-tags-on-save t))
(use-package nov
:ensure t
:mode
("\\.epub\\'" . nov-mode)
:preface
(defun init-nov-delayed-render ()
(run-with-idle-timer 0.2 nil 'nov-render-document))
:hook
(nov-mode-hook . init-nov-delayed-render)
(nov-mode-hook . no-fringes)
:init
(setq nov-save-place-file (concat data-dir "nov-places")))
(use-package erlang
:ensure t
:mode
("\\.\\(e\\|h\\|x\\|y\\)rl$" . erlang-mode)
("\\.escript" . erlang-mode)
("\\.app\\.src$" . erlang-mode)
("/ebin/.+\\.app" . erlang-mode)
:preface
(defun init-erlang-eunit ()
"Setup EUnit support for `erlang-mode'."
(require 'erlang-eunit))
(defun init-erlang-flymake ()
"Setup `flymake' support for `erlang-mode'."
(require 'erlang-flymake)
(flymake-mode 1))
:hook
(erlang-mode-hook . init-erlang-eunit)
(erlang-mode-hook . init-erlang-flymake)
:general
(:keymaps
'erlang-mode-map
:prefix nav-prefix
"k" 'erlang-man-function)
(:keymaps
'erlang-mode-map
:prefix local-leader-key
"r" 'erlang-shell-display
"t t" 'erlang-eunit-compile-and-run-current-test
"t m" 'erlang-eunit-compile-and-run-module-tests)
:init
(cl-pushnew '("src/\\([^/]+\\)\\.erl\\'" "test/\\1_tests.erl") find-sibling-rules :test #'equal)
(cl-pushnew '("test/\\([^/]+\\)_tests\\.erl\\'" "src/\\1.erl") find-sibling-rules :test #'equal))
(use-package git-modes
:ensure t
:mode
("/\\.dockerignore\\'" . gitignore-mode))
(use-package go-ts-mode
:mode
"\\.go\\'"
("go\\.mod\\'" . go-mod-ts-mode)
:hook
(go-ts-mode-hook . eglot-ensure)
:config
(cl-pushnew '(go-mode . go-ts-mode) major-mode-remap-alist :test #'equal)
(with-eval-after-load 'apheleia
(cl-pushnew '(go-ts-mode . goimports) apheleia-mode-alist :test #'equal))
(cl-pushnew '("\\([^/]+\\)\\.go\\'" "\\1_test.go") find-sibling-rules :test #'equal)
(cl-pushnew '("\\([^/]+\\)_test\\.go\\'" "\\1.go") find-sibling-rules :test #'equal))
(use-package gotest
:ensure t
:general
(:keymaps
'go-ts-mode-map
:prefix local-leader-key
"l" 'go-run
"t a" 'go-test-current-project
"t f" 'go-test-current-file
"t t" 'go-test-current-test))
(use-package gorepl-mode
:ensure t
:hook
(go-ts-mode-hook . gorepl-mode)
:init
(with-eval-after-load 'repl-toggle
(cl-pushnew '(go-ts-mode . gorepl-run) rtog/mode-repl-alist :test #'equal)))
(use-package groovy-mode
:ensure t
:mode
"\\.g\\(?:ant\\|roovy\\|radle\\)\\'"
"Jenkinsfile")
(use-package fish-mode
:ensure t
:mode
"\\.fish\\'"
"/fish_funced\\..*\\'")
(use-package haskell-mode
:ensure t
:preface
(eval-when-compile
(require 'haskell-commands))
:mode
"\\.[gh]s\\'"
"\\.hsig\\'"
"\\.hsc\\'"
("\\.cabal\\'\\|/cabal\\.project\\|/\\.cabal/config\\'" . haskell-cabal-mode)
("\\.l[gh]s\\'" . haskell-literate-mode)
:hook
(haskell-mode-hook . interactive-haskell-mode)
(haskell-mode-hook . eglot-ensure)
:general
(:keymaps
'interactive-haskell-mode-map
"M-." 'nil)
(:keymaps
'haskell-mode-map
:prefix local-leader-key
"r" 'haskell-interactive-switch
"R" 'haskell-session-change-target)
:init
(setq haskell-font-lock-symbols t)
(setq haskell-process-auto-import-loaded-modules t)
(setq haskell-process-log t)
(setq haskell-process-show-debug-tips nil)
(setq haskell-process-use-presentation-mode t)
(setq haskell-stylish-on-save t)
(setq haskell-mode-stylish-haskell-path "brittany")
;; Allow configuring project local cabal repl commands.
(put 'haskell-process-args-cabal-repl
'safe-local-variable
(lambda (x) (cl-every #'stringp x))))
Persist REPL history.
(use-package haskell-mode
:preface
(defvar +haskell-interactive-global-history nil)
(defun +haskell-interactive-save-history ()
"Save `haskell-interactive-mode' history."
(setq +haskell-interactive-global-history haskell-interactive-mode-history))
(defun +haskell-interactive-load-history ()
"Restore `haskell-interactive-mode' history."
(add-hook 'kill-buffer-hook #'+haskell-interactive-save-history nil t)
(when +haskell-interactive-global-history
(setq haskell-interactive-mode-history +haskell-interactive-global-history)))
:defines (haskell-interactive-mode-history)
:hook
(haskell-interactive-mode-hook . +haskell-interactive-load-history)
:config
(cl-pushnew '+haskell-interactive-global-history savehist-additional-variables :test #'equal))
(use-package java-ts-mode
:hook
(java-ts-mode-hook . eglot-ensure))
(cl-pushnew '(java-mode . java-ts-mode) major-mode-remap-alist :test #'equal)
(use-package gradle-mode
:ensure t
:hook
((java-mode-hook java-ts-mode-hook kotlin-mode-hook) . gradle-mode)
:general
(:keymaps
'gradle-mode-map
:prefix local-leader-key
"t t" 'gradle-test)
:init
(setq gradle-executable-path "gradle"))
(use-package javadoc-lookup
:ensure t
:general
(:keymaps
'java-ts-mode-map
:prefix nav-prefix
"k" 'javadoc-lookup))
(use-package js
:mode
("\\.js[mx]?\\'" . js-ts-mode)
("\\.har\\'" . js-ts-mode)
:hook
(js-ts-mode-hook . eglot-ensure)
:init
(cl-pushnew '("\\([^/]+\\)\\.js\\'" "\\1.spec.js") find-sibling-rules :test #'equal)
(cl-pushnew '("\\([^/]+\\).spec\\.js\\'" "\\1.js") find-sibling-rules :test #'equal))
(cl-pushnew '(js-mode . js-ts-mode) major-mode-remap-alist :test #'equal)
(use-package flymake-eslint
:ensure t
:init
(put 'flymake-eslint-executable-name 'safe-local-variable #'(lambda (x) (member x '("eslint" "eslint_d"))))
(put 'flymake-eslint-executable-args 'safe-local-variable 'stringp))
Test framework execution.
(use-package jest
:ensure t
:general
(:keymaps
'js-ts-mode-map
:prefix local-leader-key
"t a" 'jest
"t f" 'jest-file
"t t" 'jest-popup)
:init
(setq jest-executable "jest"))
REPL for nodejs.
(use-package nodejs-repl
:ensure t
:commands (nodejs-repl)
:init
(with-eval-after-load 'repl-toggle
(cl-pushnew '(js-ts-mode . nodejs-repl) rtog/mode-repl-alist :test #'equal)))
(use-package json-ts-mode
:mode
"\\(?:\\(?:\\.json\\|\\.jsonld\\|\\.babelrc\\|\\.bowerrc\\|composer\\.lock\\)\\'\\)")
(cl-pushnew '(json-mode . json-ts-mode) major-mode-remap-alist :test #'equal)
(use-package json-navigator
:ensure t
:general
(:keymaps
'json-ts-mode-map
:prefix local-leader-key
"n" 'json-navigator-navigate-region))
(use-package kotlin-mode :ensure t)
(use-package inf-lisp
:init
(setq inferior-lisp-program "sbcl"))
(use-package sly
:ensure t
:general
(:keymaps
'sly-mode-map
:prefix nav-prefix
"k" 'sly-describe-symbol)
(:keymaps
'sly-mode-map
:prefix local-leader-key
"o" 'sly))
(use-package sly-quicklisp :ensure t)
(use-package lua-mode
:ensure t
:mode "\\.lua\\'"
:commands
(lua-get-create-process)
:general
(:keymaps
'lua-mode-map
:prefix nav-prefix
"k" 'lua-search-documentation)
:init
(setq lua-documentation-function 'eww))
(use-package markdown-mode
:ensure t
:mode
"\\.markdown\\'"
"\\.md\\'"
:hook
(markdown-mode-hook . markdown-display-inline-images)
:general
(:keymaps
'markdown-mode-map
:prefix local-leader-key
"i" 'markdown-toggle-inline-images
"v" 'markdown-toggle-markup-hiding)
:init
(setq markdown-enable-wiki-links t)
(setq markdown-fontify-code-blocks-natively t)
(setq markdown-header-scaling t)
(setq markdown-hide-markup t)
(setq markdown-italic-underscore t)
(setq markdown-blockquote-display-char '("┃" ">"))
(setq markdown-list-item-bullets '("⏺" "▪"))
(setq markdown-make-gfm-checkboxes-buttons t)
(setq markdown-max-image-size '(1024 . 1024)))
Editing regions in separate buffers.
(use-package edit-indirect :ensure t)
Generate Table of Contents.
(use-package markdown-toc :ensure t)
Use variable-pitch font but still make sure everything aligns.
(font-lock-add-keywords
'markdown-mode
'(("^[[:space:]-*+>]+" 0 'fixed-pitch append))
'append)
Pretty check-boxes
(font-lock-add-keywords
'markdown-mode
'(("^ *[-*+] \\[\\([Xx]\\)\\] "
(0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "✕"))))))
(use-package mermaid-mode
:ensure t
:mode "\\.\\(mmd|mermaid\\)\\'"
:commands
(mermaid-compile-buffer)
:preface
(defun mermaid-mode-set-compile-command ()
"Configure compile command for mermaid-mode."
(set (make-local-variable 'compile-command)
(concat (mapconcat #'shell-quote-argument
(list
mermaid-mmdc-location
"-i" buffer-file-name
"-o" (concat (file-name-sans-extension buffer-file-name) mermaid-output-format)) " ")
" "
mermaid-flags)))
:hook
(mermaid-mode-hook . mermaid-mode-set-compile-command)
(mermaid-mode-hook . compile-on-save-mode)
:init
(setq mermaid-flags "--backgroundColor transparent")
:config
(with-eval-after-load 'compile-multi
(cl-pushnew `(mermaid-mode ("mermaid:generate" . ,#'mermaid-compile-buffer))
compile-multi-config
:test #'equal)))
(use-package message
:init
(setq message-expand-name-standard-ui t))
(use-package nginx-mode
:ensure t
:mode
"/nginx/.+\\.conf\\'"
"nginx\\.conf\\'")
(use-package nix-mode
:ensure t
:mode "\\.nix\\'"
:hook
(nix-mode-hook . eglot-ensure)
:general
(:prefix leader-key
"f" 'nix-flake)
:init
(with-eval-after-load 'apheleia
(cl-pushnew '(nix-mode . nix) apheleia-mode-alist :test #'equal))
(with-eval-after-load 'grugru
(grugru-define-on-major-mode 'nix-mode 'symbol '("true" "false")))
(with-eval-after-load 'repl-toggle
(cl-pushnew '(nix-mode . nix-repl) rtog/mode-repl-alist :test #'equal)))
(use-package nix-update
:ensure t
:general
(:keymaps
'nix-mode-map
:prefix local-leader-key
"u" 'nix-update-fetch))
(use-package nxml-mode
:mode "\\.plist\\'"
:init
(setq nxml-slash-auto-complete-flag t))
(use-package caml :ensure t)
(use-package tuareg
:ensure t
:general
(:keymaps
'tuareg-mode-map
"C-x C-e" 'tuareg-eval-phrase)
(:keymaps
'tuareg-mode-map
:prefix local-leader-key
"r" 'run-ocaml))
(use-package pdf-tools
:ensure t
:mode ("\\.pdf\\'" . pdf-view-mode))
(use-package plantuml-mode
:ensure t
:mode "\\.\\(plantuml\\|pum\\|plu\\)\\'"
:init
(setq plantuml-default-exec-mode 'executable))
(use-package protobuf-mode
:ensure t
:mode "\\.proto\\'")
(use-package python
:hook
(python-ts-mode-hook . eglot-ensure)
(python-ts-mode-hook . indent-bars-mode)
:general
(:keymaps
'python-ts-mode-map
:prefix local-leader-key
"r" 'run-python)
:init
(cl-pushnew '("\\([^/]+\\)\\.py\\'" "\\1_test.py") find-sibling-rules :test #'equal)
(cl-pushnew '("\\([^/]+\\)_test\\.py\\'" "\\1.py") find-sibling-rules :test #'equal)
:config
(put 'python-shell-interpreter 'safe-local-variable #'(lambda (x) (member x '("python" "ipython")))))
(cl-pushnew '(python-mode . python-ts-mode) major-mode-remap-alist :test #'equal)
(use-package pydoc
:ensure t
:general
(:keymaps
'python-ts-mode-map
:prefix nav-prefix
"k" 'pydoc-at-point))
(use-package python-test
:ensure t
:general
(:keymaps
'python-ts-mode-map
:prefix local-leader-key
"t a" 'python-test-project
"t f" 'python-test-file
"t t" 'python-test-function)
:init
(setq python-test-backend 'pytest)
:config
(setq python-test-project-root-files
(append '("README.md") python-test-project-root-files)))
(use-package racket-mode
:ensure t
:mode "\\.rkt[dl]?\\'"
:general
(:keymaps
'racket-mode-map
:prefix nav-prefix
"k" 'racket-doc)
(:keymaps
'racket-mode-map
:prefix local-leader-key
"t" 'racket-test))
(use-package flymake-racket
:ensure t
:hook
(racket-mode-hook . flymake-racket-add-hook))
(use-package rego-mode :ensure t)
(use-package rst
:preface
(defvar rst-adornment-regexp nil
"Regular expression to match adornments.")
:hook
(rst-mode-hook . auto-fill-mode)
:config
(setq rst-adornment-regexp
(concat "^[" rst-adornment-chars "]\\{3,\\}$")))
Use variable-pitch font but still make sure everything aligns.
(font-lock-add-keywords
'rst-mode
'(("^[[:space:]-*+]+\\(\\[.\\]\\)?" 0 'fixed-pitch append))
'append)
Hide heading adornments.
(defun +rst-hide-heading-adornment ()
"Hide heading adornment for `rst-mode'."
(interactive)
(hide-lines-matching rst-adornment-regexp))
(add-hook 'rst-mode-hook #'+rst-hide-heading-adornment)
Pretty check-boxes as well as bullet lists.
(font-lock-add-keywords
'rst-mode
'(("^ *\\([-*+]\\) "
(0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "⏺"))))
("^ *[-*+] \\[\\([Xx]\\)\\] "
(0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "✕"))))))
(use-package ruby-ts-mode
:mode
"\\.\\(rbw?\\|ru\\|rake\\|thor\\|jbuilder\\|rabl\\|gemspec\\|podspec\\)\\'"
"\\(Gem\\|Rake\\|Cap\\|Thor\\|Puppet\\|Berks\\|Brew\\|Vagrant\\|Guard\\|Pod\\)file"
:hook
(ruby-ts-mode-hook . eglot-ensure)
:init
(setq ruby-align-chained-calls t)
(with-eval-after-load 'apheleia
(cl-pushnew '(ruby-ts-mode . rufo) apheleia-mode-alist :test #'equal))
(cl-pushnew '("\\([^/]+\\)\\.rb\\'" "\\1_test.rb") find-sibling-rules :test #'equal)
(cl-pushnew '("\\([^/]+\\)_test\\.rb\\'" "\\1.rb") find-sibling-rules :test #'equal)
:config
(with-eval-after-load 'hideshow
(cl-pushnew `(ruby-ts-mode
,(rx (or "def" "class" "module" "do" "{" "[")) ; Block start
,(rx (or "}" "]" "end")) ; Block end
,(rx bol
(or (+ (zero-or-more blank) "#") "=begin")) ; Comment start
ruby-forward-sexp nil)
hs-special-modes-alist
:test #'equal)))
(use-package inf-ruby
:ensure t
:hook
(ruby-ts-mode-hook . inf-ruby-minor-mode)
;; Auto breakpoint
(compilation-filter . inf-ruby-auto-enter)
:general
(:keymaps
'ruby-ts-mode-map
:prefix local-leader-key
"r" 'inf-ruby)
:init
(setq inf-ruby-default-implementation "pry"))
(use-package minitest
:ensure t
:hook
(ruby-ts-mode-hook . minitest-enable-appropriate-mode)
:general
(:keymaps
'minitest-mode-map
:prefix local-leader-key
"t a" 'minitest-verify-all
"t f" 'minitest-verify
"t t" 'minitest-verify-single)
:init
(put 'minitest-use-bundler 'safe-local-variable 'booleanp))
(use-package rake
:ensure t
:init
(setq rake-completion-system 'default)
(setq rake-cache-file (expand-file-name "rake.cache" cache-dir)))
(use-package rspec-mode
:ensure t
:hook
(ruby-ts-mode-hook . rspec-enable-appropriate-mode)
:general
(:keymaps
'rspec-mode-map
:prefix local-leader-key
"t a" 'rspec-verify-all
"t f" 'rspec-verify
"t t" 'rspec-verify-single)
:init
(setq rspec-use-relative-path t)
(setq rspec-use-opts-file-when-available nil)
(setq rspec-command-options "--format progress"))
(use-package ruby-refactor
:ensure t
:hook
(ruby-ts-mode-hook . ruby-refactor-mode))
(use-package yard-mode
:ensure t
:hook
(ruby-ts-mode-hook . yard-mode))
(use-package yari
:ensure t
:general
(:keymaps
'ruby-ts-mode-map
:prefix nav-prefix
"k" 'yari)
(:keymaps
'help-command-map
"R" 'yari))
(use-package rustic
:ensure t
:mode
("\\.rs\\'" . rustic-mode)
:hook
(rustic-mode-hook . eglot-ensure)
:general
(:keymaps
'rustic-mode-map
:prefix local-leader-key
"t" 'rustic-cargo-test)
:init
(setq rustic-lsp-client 'eglot)
(with-eval-after-load 'org
(cl-pushnew '("rust" . rustic) org-src-lang-modes :test #'equal))
:config
(require 'eglot))
(use-package scala-mode
:ensure t
:mode "\\.\\(scala\\|sbt\\)\\'"
:preface
(defun init-scala-prettify-symbols ()
(setq prettify-symbols-alist scala-prettify-symbols-alist)
(prettify-symbols-mode 1))
:hook
(scala-mode-hook . init-scala-prettify-symbols)
:init
(setq scala-indent:align-parameters t))
(use-package sbt-mode :ensure t)
(use-package sh-script
:hook
(sh-mode-hook . flymake-mode)
:general
(:keymaps
'sh-mode-map
:prefix nav-prefix
"k" 'man)
:init
;; Use regular indentation for line-continuation
(setq sh-indent-after-continuation 'always)
(cl-pushnew '("\\([^/]+\\)\\.sh\\'" "\\1.bats") find-sibling-rules :test #'equal)
(cl-pushnew '("\\([^/]+\\)\\.bats\\'" "\\1.sh") find-sibling-rules :test #'equal)
(with-eval-after-load 'apheleia
(cl-pushnew '(sh-mode . shfmt) apheleia-mode-alist :test #'equal)))
(use-package sql
:init
(setq sql-mysql-options '("--protocol=tcp" "--prompt=" "--disable-pager")))
(use-package terraform-mode
:ensure t
:mode "\\.tf$")
(use-package typescript-ts-mode
:mode "\\.ts$"
:hook
(typescript-ts-mode-hook . eglot-ensure)
:init
(with-eval-after-load 'repl-toggle
(cl-pushnew '(typescript-ts-mode . run-ts) rtog/mode-repl-alist :test #'equal))
(cl-pushnew '("\\([^/]+\\)\\.ts\\'" "\\1.test.ts") find-sibling-rules :test #'equal)
(cl-pushnew '("\\([^/]+\\).test\\.ts\\'" "\\1.ts") find-sibling-rules :test #'equal))
TypeScript REPL.
(use-package ts-comint
:ensure t
:init
(setq ts-comint-program-command "ts-node"))
Test framework execution.
(use-package jest
:ensure t
:general
(:keymaps
'typescript-ts-mode-map
:prefix local-leader-key
"t a" 'jest
"t f" 'jest-file
"t t" 'jest-popup)
:init
(setq jest-executable "jest"))
Display current path for HTML/XML/CSS.
(use-package cakecrumbs
:ensure t
:defer 3
:commands
(cakecrumbs-auto-setup)
:config
(cakecrumbs-auto-setup))
(use-package web-mode
:ensure t
:mode "\\.\\(phtml\\|php\\|[agj]sp\\|as[cp]x\\|erb\\|djhtml\\|html?\\|hbs\\|ejs\\|jade\\|swig\\|tmpl\\)\\'"
:init
(setq web-mode-enable-html-entities-fontification t)
;; Highlight enclosing tags of the element under cursor
(setq web-mode-enable-current-element-highlight t)
;; No extra indentation for blocks.
(setq web-mode-script-padding 0)
(setq web-mode-style-padding 0))
(use-package yaml-mode
:ensure t
:mode "\\.\\(e?ya?\\|ra\\)ml\\'"
:hook (yaml-mode-hook . indent-bars-mode))
Store contacts.
(use-package bbdb :ensure t)
Import contacts from Gmail vCard data.
(use-package gmail2bbdb
:ensure t
:init
(setq gmail2bbdb-bbdb-file bbdb-file)
(setq gmail2bbdb-exclude-people-without-name t))
Dim out the surrounding text except the current focused paragraph or expression.
(use-package focus :ensure t)
(use-package indent-bars
:ensure t
:init
(setq indent-bars-width-frac 0.2))
(use-package pomm
:ensure t
:commands (pomm pomm-third-time)
:general
(:prefix leader-key "p" 'pomm-third-time))
Support for restoring previous session on Emacs restart. This adds a few tweaks that makes it really useful.
- Support for persistent undo history via
buffer-undo-list
. - Ignore saving of
gz
files as it seems not to properly load those. - Restore no buffers to begin with to avoid slow starts with huge sessions.
(use-package desktop
:demand t
:init
(setq desktop-files-not-to-save "\\(\\`/[^/:]*:\\|(ftp)\\|\\.gz\\'\\)")
(setq desktop-restore-eager 0)
(setq desktop-save (daemonp))
(setq desktop-load-locked-desktop (daemonp))
:config
(dolist (var '(buffer-undo-list))
(cl-pushnew var desktop-locals-to-save :test #'equal))
(desktop-save-mode 1))
(use-package spray
:ensure t
:general
(:prefix
toggle-prefix
"s" '(spray-mode :wk "Speed reading"))
:init
(setq spray-height 500)
(setq spray-margin-left 2)
:config
(setq spray-unsupported-minor-modes
(append '(beacon-mode centered-window-mode visual-fill-column-mode)
spray-unsupported-minor-modes)))
(use-package jinx
:ensure t
:hook
(prog-mode-hook . jinx-mode)
(text-mode-hook . jinx-mode)
:general
([remap ispell-word] 'jinx-correct)
(:prefix next-prefix "s" '(jinx-next :wk "Misspelling"))
(:prefix prev-prefix "s" '(jinx-previous :wk "Misspelling")))
Automatic language detection that updates the spell checker.
(use-package guess-language
:ensure t
:commands
(guess-language-mode))
Avoid color when possible.
(setenv "NO_COLOR" "1")
(use-package eshell
:preface
(eval-when-compile
(require 'em-hist)
(require 'em-term))
(defvar eshell-visual-commands)
(defun init-eshell-define-keys ()
(general-define-key
:keymaps 'eshell-mode-map
"RET" '+eshell-expand-abbrev-and-send-input
"<tab>" 'completion-at-point))
(defun init-eshell-set-visual-commands ()
(setq eshell-visual-commands
(append
'("fish" "ghcid" "jshell" "most" "ssh" "tail" "tsun" "watch")
eshell-visual-commands)))
:hook
(eshell-mode-hook . abbrev-mode)
(eshell-mode-hook . init-eshell-define-keys)
(eshell-mode-hook . init-eshell-set-visual-commands)
:general
("C-!" 'eshell)
(:prefix leader-key "t" 'eshell)
:init
(setq eshell-buffer-maximum-lines 20000)
(setq eshell-history-size 1000)
(setq eshell-hist-ignoredups t)
(setq eshell-error-if-no-glob t)
(setq eshell-destroy-buffer-when-process-dies t)
(autoload 'eshell-smart-initialize "em-smart"))
Fish-like abbreviations that expand on space or enter.
(use-package eshell
:preface
(autoload 'eshell-parse-arguments "esh-arg")
(autoload 'eshell-send-input "esh-mode")
(defun +eshell-expand-abbrev-and-send-input ()
"Expand abbreviation and send input to `eshell'."
(interactive)
(expand-abbrev)
(call-interactively #'eshell-send-input))
(defun +eshell-abbrev-expand-p ()
"Return t if abbreviation should be expanded.
Expansion should happen when abbreviation is at the beginning of
the line or after an eshell operator."
(let* ((end (point-marker))
(begin (save-excursion (beginning-of-line) (point)))
(args (catch 'eshell-incomplete (eshell-parse-arguments begin end))))
(or (= 1 (length args))
(let ((last-two-args (last args 2)))
(and (consp (car last-two-args))
(eq (caar last-two-args)
'eshell-operator))))))
:init
(define-abbrev-table 'eshell-mode-abbrev-table
'(("base64" "base64 -w0")
("e" "find-file-other-window")
("E" "dired")
("gco" "git checkout")
("gd" "magit-diff-unstaged")
("gds" "magit-diff-staged")
("gs" "magit-status")
("time" "time -p")
("tree" "tree -a")
("week" "date '+%V'"))
:enable-function #'+eshell-abbrev-expand-p))
Command execution status indicator in the fringe.
(use-package eshell-fringe-status
:ensure t
:hook
(eshell-mode-hook . eshell-fringe-status-mode))
Populate auto-completions from fish.
(use-package fish-completion
:ensure t
:hook
(eshell-mode-hook . fish-completion-mode))
Fast terminal emulator utilizing libvterm
.
(use-package vterm
:ensure t
:general
(:prefix leader-key "T" 'vterm)
:init
(setq vterm-max-scrollback 100000)
(setq vterm-shell "fish"))
(use-package vterm-toggle
:ensure t
:general
("C-M-!" 'vterm-toggle)
(:keymaps
'vterm-mode-map
"C-<return>" 'vterm-toggle-insert-cd))
Increase undo limit.
(setq undo-limit 1000000)
(setq undo-strong-limit (* 2 undo-limit))
Visual undo history navigation.
(use-package vundo
:ensure t
:general
(:prefix leader-key "u" 'vundo))
Packages that I am currently testing or evaluating.
(use-package adaptive-wrap :ensure t)
(use-package annotate :ensure t)
(use-package attrap :ensure t)
(use-package awscli-capf :ensure t)
(use-package comment-or-uncomment-sexp :ensure t)
(use-package consult-git-log-grep
:ensure t
:after magit
:init
(setq consult-git-log-grep-open-function #'magit-show-commit))
(use-package consult-jump-project
:ensure t)
(use-package dape :ensure t)
(use-package eglot-x :ensure t)
(use-package elfeed :ensure t)
(use-package ellama
:ensure t
:init
(setq ellama-auto-scroll t))
(use-package elsa :disabled t)
(use-package epithet :ensure t)
(use-package freeze-it :ensure t)
(use-package kind-icon
:ensure t
:after corfu
:commands
(kind-icon-margin-formatter)
:init
(cl-pushnew #'kind-icon-margin-formatter corfu-margin-formatters :test #'equal))
(use-package messages-are-flowing :ensure t)
(use-package native-complete :ensure t)
(use-package org-fragtog :ensure t)
(use-package org-roam :ensure t)
(use-package paimon
:ensure t
:commands paimon)
(use-package shrface :ensure t)
(use-package terraform-doc :ensure t)
(require 'private nil t)
- comint
- ielm (via comint and savehist)
- haskell-interactive (via savehist)
- Also
vc-dir
and thevc-git-stash
(can stash individual files) - Diff merge-base
C-x v M D
,C-x v M L
vc-log-search
Create xref-quick-peek
(inspired by xref-posframe or source-peek)
Create macros via checking C-h l
(view-lossage
) then it can be used together with edit-last-kbd-macro
.
- One theme to set big headers and such things
- One theme to highlight errors
- One theme for the mode-line