;;; keybindings.el --- My Evil preferences -*- lexical-binding: t -*- ;; Author: William Carroll ;;; Commentary: ;; This module hosts my Evil preferences ;; ;; Wish List: ;; - restore support for concise (n ) instead of `general-mmap' ;; - restore support for `general-unbind' ;;; Code: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Dependencies ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (require 'general) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Packages ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; This may be contraversial, but I never use the prefix key, and I'd prefer to ;; have to bound to the readline function that deletes the entire line. (general-unbind "C-u") (use-package evil :init ;; Should remove the warning messages on init. (setq evil-want-integration t) ;; TODO: Troubleshoot why this binding causes the following warning: ;; "Warning (evil-collection): `evil-want-keybinding' was set to nil but not ;; before loading evil." (setq evil-want-keybinding nil) (general-evil-setup) :config ;; Ensure that evil's command mode behaves with readline bindings. (general-define-key :keymaps 'evil-ex-completion-map "C-a" #'move-beginning-of-line "C-e" #'move-end-of-line "C-k" #'kill-line "C-u" #'evil-delete-whole-line "C-v" #'evil-paste-after "C-d" #'delete-char "C-f" #'forward-char "M-b" #'backward-word "M-f" #'forward-word "M-d" #'kill-word "M-DEL" #'backward-kill-word "C-b" #'backward-char) ;; TODO: Ensure all of my custom keybindings end up in a single map that is ;; easy to enable or disable. (general-mmap :keymaps 'override "RET" #'evil-goto-line "H" #'evil-first-non-blank "L" #'evil-end-of-line "_" #'ranger "-" #'dired-jump "sl" #'wpc/evil-window-vsplit-right "sh" #'evil-window-vsplit "sk" #'evil-window-split "sj" #'wpc/evil-window-split-down) (general-nmap :keymaps 'override "gd" #'xref-find-definitions ;; Wrapping `xref-find-references' in the `let' binding to prevent xref from ;; prompting. There are other ways to handle this variable, such as setting ;; it globally with `setq' or buffer-locally with `setq-local'. For now, I ;; prefer setting it with `let', which should bind it in the dynamic scope ;; for the duration of the `xref-find-references' function call. "gx" (lambda () (interactive) (let ((xref-prompt-for-identifier nil)) (call-interactively #'xref-find-references)))) (general-unbind 'motion "M-." "C-p") (general-unbind 'normal "s" "M-." "C-p" "C-n") (general-unbind 'insert "C-v" "C-d" "C-a" "C-e" "C-n" "C-p" "C-k") (setq evil-symbol-word-search t) (evil-mode 1)) ;; TODO: Write `evil-collection' KBDs for `refine'. ;; evil keybindings (use-package evil-collection :after (evil) :config (evil-collection-init)) ;; `evil-collection' does not support `magit', and the preferred way to get evil ;; kbds for magit is with `evil-magit'. (use-package evil-magit) ;; TODO: Consider moving this to another module. (general-define-key :prefix "" :states '(normal) "i" #'counsel-semantic-or-imenu "I" #'ibuffer "hk" #'helpful-callable "hf" #'helpful-function "hm" #'helpful-macro "hc" #'helpful-command "hk" #'helpful-key "hv" #'helpful-variable "hp" #'helpful-at-point "s" #'flyspell-mode "S" #'sort-lines "a" #'wpc-terminal/toggle "=" #'align "p" #'flycheck-previous-error "f" #'wpc/find-file "n" #'flycheck-next-error "N" #'smerge-next "W" #'balance-windows "gs" #'magit-status "E" #'refine "es" #'wpc/create-snippet ;; TODO: Replace with `macros/ilambda' when that is working again. "ev" (lambda () (interactive) (wpc/find-file-split "~/.config/nvim/init.vim")) "ee" (lambda () (interactive) (wpc/find-file-split "~/.emacs.d/init.el")) "ez" (lambda () (interactive) (wpc/find-file-split "~/.zshrc")) "ea" (lambda () (interactive) (wpc/find-file-split "~/aliases.zsh")) "ef" (lambda () (interactive) (wpc/find-file-split "~/functions.zsh")) "el" (lambda () (interactive) (wpc/find-file-split "~/variables.zsh")) "ex" (lambda () (interactive) (wpc/find-file-split "~/.Xresources")) "em" (lambda () (interactive) (wpc/find-file-split "~/.tmux.conf")) "l" #'locate "L" #'list-packages "B" #'magit-blame "w" #'save-buffer "r" #'wpc/evil-replace-under-point "R" #'deadgrep) ;; create comments easily (use-package evil-commentary :after (evil) :config (evil-commentary-mode)) ;; evil surround (use-package evil-surround :after (evil) :config (global-evil-surround-mode 1)) ;; I expect in insert mode: ;; C-a: beginning-of-line ;; C-e: end-of-line ;; C-b: backwards-char ;; C-f: forwards-char ;; TODO: Move these KBD constants to kbd.el. (defconst wpc/up-kbds '("C-p" "C-k" "" "") "The keybindings that I expect to work for moving upwards in lists.") (defconst wpc/down-kbds '("C-n" "C-j" "" "") "The keybindings that I expect to work for moving downwards in lists.") (defconst wpc/left-kbds '("C-b" "") "The keybindings that I expect to move leftwards in insert-like modes.") (defconst wpc/right-kbds '("C-f" "") "The keybindings that I expect to move rightwards in insert-like modes.") (defun wpc/ensure-kbds (_ignore) "Try to ensure that my keybindings retain priority over other minor modes." (unless (eq (caar minor-mode-map-alist) 'wpc/kbds-minor-mode) (let ((mykbds (assq 'wpc/kbds-minor-mode minor-mode-map-alist))) (assq-delete-all 'wpc/kbds-minor-mode minor-mode-map-alist) (add-to-list 'minor-mode-map-alist mykbds)))) ;; Custom minor mode that ensures that my kbds are available no matter which ;; major or minor modes are active. (add-hook 'after-load-functions #'wpc/ensure-kbds) ;; TODO: Prefer using general and 'override maps to implement this. (defvar wpc/kbds (let ((map (make-sparse-keymap))) (bind-keys :map map ("M-q" . delete-window) ("" . toggle-frame-fullscreen) ("M-h" . windmove-left) ("M-l" . windmove-right) ("M-k" . windmove-up) ("M-j" . windmove-down) ("M-q" . delete-window)) map) "William Carroll's keybindings that should have the highest precedence.") ;; Support pasting in M-:. (general-define-key :keymaps 'read-expression-map "C-v" #'clipboard-yank "C-S-v" #'clipboard-yank) (define-minor-mode wpc/kbds-minor-mode "A minor mode so that my key settings override annoying major modes." :init-value t :lighter " wpc/kbds" :keymap wpc/kbds) ;; allow jk to escape (use-package key-chord :after (evil) :config (key-chord-mode 1) (key-chord-define evil-insert-state-map "jk" 'evil-normal-state)) ;; Ensure the Evil search results get centered vertically. ;; TODO: Consider packaging this up for others. (progn (defadvice isearch-update (before advice-for-isearch-update activate) (evil-scroll-line-to-center (line-number-at-pos))) (defadvice evil-search-next (after advice-for-evil-search-next activate) (evil-scroll-line-to-center (line-number-at-pos))) (defadvice evil-search-previous (after advice-for-evil-search-previous activate) (evil-scroll-line-to-center (line-number-at-pos)))) (provide 'wpc-keybindings) ;;; wpc-keybindings.el ends here