Files
dotemacs/lisp/init-bindings.el
2022-01-09 21:19:46 +01:00

460 lines
16 KiB
EmacsLisp

;;; init-bindings.el --- sets up basic Emacs bindings -*- lexical-binding: t; -*-
;;; Commentary:
;;; Code:
(defvar user/global-keymap nil
"Global keymap.")
(defvar user/global-reverse-keymap nil
"Global reverse keymap, mapping bindings back to functions.")
(defvar ctl-l-map (make-keymap)
"Default keymap for \\<ctl-l-map> commands.")
;; Set up prefixes for command groups.
(defcustom user/view-prefix (kbd "C-x v")
"Keyboard prefix to use for view commands."
:type 'key-sequence
:group 'user)
(defcustom user/help-prefix (kbd "C-c h")
"Keyboard prefix to use for help commands."
:type 'key-sequence
:group 'user)
(defcustom user/documentation-prefix (kbd "C-c d")
"Keyboard prefix to use for documentation commands."
:type 'key-sequence
:group 'user)
(defcustom user/code-prefix (kbd "C-c c")
"Keyboard prefix to use for code manipulation commands."
:type 'key-sequence
:group 'user)
(defcustom user/code-eval-prefix (kbd "C-c c e")
"Keyboard prefix to use for code evaluation commands."
:type 'key-sequence
:group 'user)
(defcustom user/vcs-prefix (kbd "C-c v")
"Keyboard prefix to use for version control commands."
:type 'key-sequence
:group 'user)
(defcustom user/utilities-prefix (kbd "C-c u")
"Keyboard prefix to use for utility commands."
:type 'key-sequence
:group 'user)
(defcustom user/apps-prefix (kbd "C-c a")
"Keyboard prefix to use for application commands."
:type 'key-sequence
:group 'user)
(defconst user/prefix-list (list "C-x" "C-c" "C-l")
"List of the registered prefix keys.")
(defun user/make-key (keys)
"Convert KEYS into the internal Emacs key representation."
(kbd (if (listp keys)
(mapconcat 'identity (mapcar 'eval keys) " ")
keys)))
(defun user/get-key (group operation)
"Get the key from GROUP to bind for OPERATION."
(let ((key (cdr (assq operation (cdr (assq group user/global-keymap))))))
(if key
(user/make-key key)
(error (format "Group %s does not contain key for %s!"
(symbol-name group) (symbol-name operation))))))
(defun user/get-key-function (group operation)
"Get the function bound to GROUP OPERATION."
(car (cdr (assq operation
(cdr (assq group user/global-reverse-keymap))))))
(defun user/bind-key-global (group key function)
"Bind GROUP KEY to FUNCTION globally."
(let ((rev-group (assq group user/global-reverse-keymap)))
(setq user/global-reverse-keymap
(append `((,group . ,(append `((,key ,function)) (cdr rev-group))))
(delq (assoc group user/global-reverse-keymap)
user/global-reverse-keymap))))
(global-set-key (user/get-key group key) function))
(defun user/bind-key-local (group key function)
"Bind GROUP KEY to FUNCTION in the current keymap."
(local-set-key (user/get-key group key) function))
(defun user/merge-keymap-groups (overlay base)
"Merge OVERLAY keymap with BASE group."
(let ((group-name (car base))
(overlay-keys (cdr overlay))
(base-keys (cdr base)))
`((,group-name . ,(append overlay-keys base-keys)))))
(defun user/global-keymap-overlay (overlay)
"Load keymap OVERLAY."
(dolist (ovl-group overlay)
(let ((ovl-gname (car ovl-group))
(ovl-keys (cdr ovl-group)))
(dolist (ovl-op (cdr ovl-group))
(let ((ovl-oname (car ovl-op))
(ovl-key (cdr ovl-op)))
;; TODO: Check that ovl-oname exists.
(global-set-key (user/make-key ovl-key)
(user/get-key-function ovl-gname ovl-oname))))
(let ((orig-group (assq ovl-gname user/global-keymap))
(keymap-without-group (assq-delete-all ovl-gname user/global-keymap)))
(setq user/global-keymap
(append (user/merge-keymap-groups ovl-group orig-group)
keymap-without-group)))))
t)
(defun user--global-keymap-config ()
"Initialize the global keymap."
(setq
user/global-keymap
'(;;; (Basic keys) ;;;
(:basic . ((:open-file . "C-x C-f")
(:open-file-context . "C-x f")
(:open-file-tramp . "C-x t")
(:view-file . "C-x C-v")
(:open-buffer . "C-x b")
(:open-buffer-context . "C-x M-b")
(:save . "C-x C-s")
(:save-as . "C-x M-s")
(:close . "C-x k")
(:quit . "C-x C-c")
(:server-edit . "C-x #")
(:undo . "C-_")
(:redo . "M-_")
(:forward-line . "C-n")
(:backward-line . "C-p")
(:forward-word . "M-f")
(:backward-word . "M-b")
(:forward-expr . "C-M-f")
(:backward-expr . "C-M-b")
(:del-char-left . "C-h")
(:del-char-right . "C-d")
(:search-forward . "C-s")
(:search-backward . "C-r")
(:search-files . ("C-l M-f"))
(:swoop . "C-l C-s")
(:swoop-multi . "C-l C-M-s")
(:selection-start . "C-SPC")
(:selection-expand . "M-=")
(:selection-next . "M-.")
(:selection-prev . "M-,")
(:selection-all . "C-c M-.")
(:selection-edit-lines . "C-c M-e")
(:select-paragraph . "M-h")
(:select-function . "C-M-h")
(:select-inside . "M-+")
(:widen . (user/view-prefix "n w"))
(:narrow-to-page . (user/view-prefix "n p"))
(:narrow-to-region . (user/view-prefix "n r"))
(:narrow-to-function . (user/view-prefix "n f"))
(:copy . "C-x C-w")
(:cut . "C-x C-k")
(:copy-expr . "C-M-w")
(:cut-expr . "C-M-k")
(:paste . "C-y")
(:alternate-paste . "C-M-y")
(:cycle-paste . "M-y")
(:cut-word-left . "C-w")
(:cut-word-right . "M-w")
(:zoom . (user/view-prefix "z"))))
;;; (Emacs) ;;;
(:emacs . ((:describe-bindings . (user/help-prefix "b"))
(:describe-coding . (user/help-prefix "C"))
(:describe-char . (user/help-prefix "c"))
(:describe-face . (user/help-prefix "F"))
(:describe-all-faces . (user/help-prefix "M-f"))
(:describe-function . (user/help-prefix "f"))
(:describe-macro . (user/help-prefix "M-m"))
(:describe-command . (user/help-prefix "i"))
(:describe-key . (user/help-prefix "k"))
(:describe-key-extensive . (user/help-prefix "K"))
(:describe-variable . (user/help-prefix "v"))
(:search-variable-value . (user/help-prefix "V"))
(:describe-language . (user/help-prefix "L"))
(:describe-mode . (user/help-prefix "m"))
(:describe-symbol . (user/help-prefix "s"))
(:describe-syntax . (user/help-prefix "S"))
(:find-library . (user/help-prefix "l"))
(:find-package . (user/help-prefix "p"))
(:manual . (user/help-prefix "M"))
(:elisp-search . (user/help-prefix "e"))
(:tutorial . (user/help-prefix "t"))
(:where-is . (user/help-prefix "w"))
(:redraw . "C-l C-l")
(:recenter . "C-l l")
(:fullscreen . "C-c <C-return>")
(:text-scale-reset . "C-0")
(:text-scale-increase . "C-+")
(:text-scale-decrease . "C--")
(:grow-vertical . "C-c C-p")
(:shrink-vertical . "C-c C-n")
(:grow-horizontal . "C-c C-f")
(:shrink-horizontal . "C-c C-b")
(:flop-frame . "C-c C-t")
(:flip-frame . "C-c M-t")
(:rotate-frame-forward . "C-c C-r")
(:rotate-frame-backward . "C-c M-r")
(:profiler-start . (user/utilities-prefix "p p"))
(:profiler-stop . (user/utilities-prefix "p P"))
(:profiler-report . (user/utilities-prefix "p r"))))
;;; (Documentation) ;;;
(:doc . ((:apropos . (user/documentation-prefix "SPC"))
(:manual . (user/documentation-prefix "m"))
(:describe . (user/documentation-prefix "d"))
(:describe-function . (user/documentation-prefix "f"))
(:describe-variable . (user/documentation-prefix "v"))
(:dictionary . (user/documentation-prefix "D"))
(:reference . (user/documentation-prefix "r"))))
;;; (Navigation) ;;;
(:nav . ((:context . ("C-l SPC"))
(:goto-line . ("C-l g"))
(:go-forward . ("C-l f"))
(:go-back . ("C-l b"))
(:scroll-up . "M-n")
(:scroll-down . "M-p")
(:context-cycle . ("C-l C-c"))
(:context-forward . ("C-l C-f"))
(:context-backward . ("C-l C-b"))
(:context-up . ("C-l C-p"))
(:context-down . ("C-l C-n"))
(:next . ("C-l n"))
(:follow-symbol . ("C-l j"))
(:find-symbol . ("C-l s"))
(:jump-spec-impl . ("C-l i"))
(:references . ("C-l r"))
(:find-references . ("C-l M-r"))
(:find-virtuals . ("C-l v"))
(:switch-spec-impl . ("C-l h"))
(:functions/toc . ("C-l t"))
(:file-dependencies . ("C-l d"))
(:history . ("C-l h"))
(:find-todos . ("C-l M-t"))
(:open . (user/utilities-prefix "o"))))
;;; (Programming) ;;;
(:code . ((:compile . (user/code-prefix "c"))
(:clean . (user/code-prefix "M-c"))
(:run . (user/code-prefix "r"))
(:test . (user/code-prefix "t"))
(:compilation-result . (user/view-prefix "c"))
(:repl . (user/code-prefix "M-r"))
(:bookmark-prefix . "C-c b")
(:bookmark-toggle . "C-c b v")
(:bookmark-next . "C-c b n")
(:bookmark-prev . "C-c b p")
(:comment . "M-;")
(:document . (user/code-prefix "="))
(:join-line . ((if (display-graphic-p) "C-x C-6" "C-x C-^")))
(:align . ((if (display-graphic-p) "C-x C-5" "C-x C-]")))
(:fill-paragraph . ((if (display-graphic-p) "C-x C-4" "C-x C-\\")))
(:tidy . ("C-x ="))
(:whitespace-auto-cleanup . (user/code-prefix "w"))
(:itemize . (user/code-prefix "b"))
(:enumerate . (user/code-prefix "e"))
(:complete . "TAB")
(:try-complete . "TAB")
(:auto-complete . "C-TAB")
(:unwrap-expr . "C-M-d")
(:context-promote . (user/code-prefix "P"))
(:context-demote . (user/code-prefix "N"))
(:refactor-rename . (user/code-prefix "M-r"))
(:refactor-extract . (user/code-prefix "M-x"))
(:insert-dependency . (user/code-eval-prefix "M-d"))
(:generate-test . (user/code-prefix "M-t"))
(:library-list . (user/code-prefix "l"))
(:disassemble . (user/code-prefix "D"))
(:warnings/errors . (user/code-prefix "E"))
(:spellcheck-word . (user/code-prefix "s"))
(:spellcheck-add-word . (user/code-prefix "S"))
;; (:thesaurus-lookup . (user/code-prefix "t"))
(:update-index . (user/code-prefix "i"))
(:eval-expression . ("C-x C-e"))
(:eval-buffer . (user/code-eval-prefix "b"))
(:eval-function . (user/code-eval-prefix "f"))
(:eval-selection . (user/code-eval-prefix "s"))
(:macro-expand . (user/code-eval-prefix "m"))
(:virtual . (user/code-prefix "v"))))
;;; (Debugging) ;;;
(:debug . ((:start . (user/code-prefix "d"))
(:break . (user/code-prefix "b"))
(:trace . (user/code-prefix "T"))
(:break-temporary . (user/code-prefix "t"))
(:watch . (user/code-prefix "w"))
(:run . (user/code-prefix "r"))
(:continue . (user/code-prefix "c"))
(:continue-stack . (user/code-prefix "f"))
(:continue-until . (user/code-prefix "u"))
(:step . (user/code-prefix "s"))
(:step-instruction . (user/code-prefix "i"))
(:next . (user/code-prefix "n"))
(:stack-up . (user/code-prefix "p"))
(:stack-down . (user/code-prefix "n"))
(:show-value . (user/code-prefix "p"))))
;;; (Version Control) ;;;
(:vcs . ((:clone . (user/vcs-prefix "c"))
(:status . (user/vcs-prefix "s"))
(:history . (user/vcs-prefix "h"))
(:version . (user/vcs-prefix "v"))
(:describe . (user/vcs-prefix "d"))
(:gutter . (user/vcs-prefix "g"))
(:review . (user/vcs-prefix "r"))
(:add-buffer . (user/vcs-prefix "a"))
(:next-action . (user/vcs-prefix "SPC"))
(:mergetool . (user/vcs-prefix "m"))
(:search . (user/vcs-prefix "M-s"))
(:find-file . ("C-c p"))
(:time-machine . (user/vcs-prefix "t"))))
;;; (Utilities) ;;;
(:util . ((:annotate-buffer . (user/utilities-prefix "a"))
(:draw . (user/utilities-prefix "g"))
(:diff . (user/utilities-prefix "d"))
(:dumb-diff . (user/utilities-prefix "M-d"))
(:ace-jump-mode . ("C-l a"))
(:ecb-toggle . (user/utilities-prefix "e"))
(:google . (user/utilities-prefix "s"))
(:google-at-point . (user/documentation-prefix "s RET"))
(:google-selection . (user/documentation-prefix "s SPC"))
(:stack-overflow-search . (user/documentation-prefix "s"))
(:notifications . (user/utilities-prefix "n"))
(:perspective . ("C-x x s"))
(:presentation . (user/utilities-prefix "P"))
(:popwin-close . (user/view-prefix "0"))
(:popwin-buffer . (user/view-prefix "p"))
(:popwin-messages . (user/view-prefix "m"))
(:undo-tree . (user/utilities-prefix "u"))
(:wc-mode . (user/utilities-prefix "w"))
(:docker . (user/utilities-prefix "d"))))
;;; (Applications) ;;;
(:apps . ((:packages . (user/apps-prefix "M-p"))
(:shell . (user/apps-prefix "s"))
(:processes . (user/apps-prefix "p"))
(:daemons . (user/apps-prefix "M-d"))
(:services . (user/apps-prefix "P"))
(:agenda . (user/apps-prefix "a"))
(:notes . (user/apps-prefix "n"))
(:todo . (user/apps-prefix "t"))
(:capture-task . (user/apps-prefix "M-t"))
(:information-db . (user/apps-prefix "D"))
(:browse . (user/apps-prefix "b"))
(:browse-external . (user/apps-prefix "B"))
(:feed-reader . (user/apps-prefix "f"))
(:stack-exchange . (user/apps-prefix "x"))
(:weather . (user/apps-prefix "w"))
(:cheat-sh . (user/apps-prefix "C"))
(:email . (user/apps-prefix "e"))
(:irc . (user/apps-prefix "i"))
(:instant-messenger . (user/apps-prefix "I"))
(:ipython-notebook . (user/apps-prefix "N"))
(:music . (user/apps-prefix "m"))
(:elnode . (user/apps-prefix "E"))
(:calculator . (user/apps-prefix "c"))
(:convert-unit . (user/apps-prefix "M-c"))
(:statistics . (user/apps-prefix "R"))
(:sage . (user/apps-prefix "S")))))))
(defun user--bindings-config ()
"Initialize key bindings."
(global-unset-key (kbd "C-l"))
(define-prefix-command 'ctl-l-map)
(global-set-key (kbd "C-l") 'ctl-l-map)
;; Initialize global keymap.
(user--global-keymap-config)
;;; (Bindings) ;;;
;; Alias C-x C-m to M-x which is a bit awkward to reach.
(global-set-key (kbd "C-x C-m") 'execute-extended-command)
(global-set-key (kbd "C-x m") 'execute-extended-command)
;; Toggle comments
(global-set-key (kbd "C-x -") 'comment-or-uncomment-region))
(user--bindings-config)
(provide 'init-bindings)
;;; init-bindings.el ends here