commit 1e1a842eb8cddc6a14942ba9277e7a7e5577eeb7
parent ddb568185ff905df4a8a72d853b470517b22037c
Author: Alex Balgavy <alex@balgavy.eu>
Date: Tue, 3 May 2022 18:54:12 +0200
emacs: added a way to keep track of custom keybindings
Diffstat:
M | emacs/config.org | | | 145 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------ |
1 file changed, 113 insertions(+), 32 deletions(-)
diff --git a/emacs/config.org b/emacs/config.org
@@ -1,3 +1,73 @@
+* Keep track of custom key bindings
+I want an easy way to see which global key bindings I have.
+Some packages provide things like this, but I want it to be simple and always available, so I'll roll my own.
+These functions allow a way to store personal global key bindings and view them as a list.
+
+I'll use a hash table to map a key (in ~kbd~ format, the inverse of this is ~key-description~) to its function (and its previous function):
+
+#+begin_src emacs-lisp
+ (setq za/personal-keybinds (make-hash-table :test 'equal))
+#+end_src
+
+A function to bind keys:
+
+#+begin_src emacs-lisp
+ (defun za/global-set-key (keys fun)
+ "Bind KEYS to FUN. This will be saved to the za/personal-keybinds hash table."
+ (let* (;; Store the previous function KEYS were bound to
+ (lookup-result (lookup-key (current-global-map) keys))
+ (previous-fun (cond ((not lookup-result) nil)
+ ((numberp lookup-result) nil)
+ ((equal lookup-result fun) nil)
+ (t lookup-result)))
+ ;; Try to see if it already has a custom binding
+ (existing-entry (gethash keys za/personal-keybinds)))
+
+ ;; If KEYS already have a custom binding, fail, unless we're just repeating the same binding
+ (if (and existing-entry
+ (not (equal (car existing-entry) fun)))
+ (user-error (format "Keys are already bound to %s" (car existing-entry))))
+
+ (puthash keys (list fun previous-fun) za/personal-keybinds)
+ (global-set-key keys fun)))
+#+end_src
+
+And one to remove bindings:
+
+#+begin_src emacs-lisp
+ (defun za/global-unset-key (keys)
+ "Remove a custom key binding from za/personal-keybinds and unbind the keys."
+ (remhash keys za/personal-keybinds)
+ (global-unset-key keys))
+#+end_src
+
+Then a way to retrieve keybindings:
+
+#+begin_src emacs-lisp
+ (defun za/get-personal-keybinds ()
+ "Return the contents of za/personal-keybinds as a string."
+ (let (result
+ (format-entry (lambda (k v)
+ (let ((get-func (lambda (e) (nth 0 e)))
+ (get-prev-func (lambda (e) (nth 1 e))))
+ (push
+ (concat (format "%s\t\t%s" (key-description k) (funcall get-func v))
+ (if (funcall get-prev-func v)
+ (format "\t\t(previously %s)" (funcall get-prev-func v))))
+ result)))))
+ (maphash format-entry za/personal-keybinds)
+ (mapconcat 'identity (sort result 'string<) "\n")))
+#+end_src
+(za/global-unset-key (kbd "C-x C-s"))
+And a way to display all of the keybindings:
+
+#+begin_src emacs-lisp
+ (defun za/list-personal-keybinds ()
+ (interactive)
+ (with-output-to-temp-buffer "*Personal Keybindings*"
+ (princ (za/get-personal-keybinds))))
+#+end_src
+
* Emacs file locations
** Auto-Save files
By default, auto-save files ("#file#") are placed in the same directory as the file itself.
@@ -32,7 +102,6 @@ The second one actually loads them.
(setq custom-file (expand-file-name (concat user-emacs-directory "custom.el")))
(load custom-file)
#+end_src
-
* Theme
Icons required for some parts of the doom theme:
@@ -338,12 +407,12 @@ Convenience functions to make opening the main file faster:
Bind keys to those functions:
#+begin_src emacs-lisp
- (global-set-key (kbd "C-c g i") 'gtd-inbox)
- (global-set-key (kbd "C-c g g") 'gtd)
- (global-set-key (kbd "C-c g a") 'gtd-archive)
- (global-set-key (kbd "C-c g s") 'gtd-someday)
- (global-set-key (kbd "C-c g r") 'gtd-reference)
- (global-set-key (kbd "C-c g t") 'gtd-tickler)
+ (za/global-set-key (kbd "C-c g i") #'gtd-inbox)
+ (za/global-set-key (kbd "C-c g g") #'gtd)
+ (za/global-set-key (kbd "C-c g a") #'gtd-archive)
+ (za/global-set-key (kbd "C-c g s") #'gtd-someday)
+ (za/global-set-key (kbd "C-c g r") #'gtd-reference)
+ (za/global-set-key (kbd "C-c g t") #'gtd-tickler)
#+end_src
**** Refiling & archiving
Where I want to be able to move subtrees (doesn't include inbox because I never refile to that, and the archive has its own keybining):
@@ -804,7 +873,7 @@ I'll bind a key to start a vterm or switch to the running vterm:
(if (get-buffer vterm-buffer-name)
(switch-to-buffer vterm-buffer-name)
(vterm)))
- (global-set-key (kbd "C-c t") 'switch-to-vterm)
+ (za/global-set-key (kbd "C-c t") 'switch-to-vterm)
#+end_src
** sr-speedbar
@@ -823,13 +892,17 @@ If it's not bound, or if it's false, first open the speedbar.
Then, select it.
#+begin_src emacs-lisp
- (global-set-key (kbd "C-c F") (lambda () (interactive)
- (if (or (not (boundp 'sr-speedbar-exist-p))
- (not (sr-speedbar-exist-p)))
- (sr-speedbar-open))
- (sr-speedbar-select-window)))
+ (defun za/jump-to-speedbar-or-open ()
+ "Open a speedbar or jump to it if already open."
+ (interactive)
+ (if (or (not (boundp 'sr-speedbar-exist-p))
+ (not (sr-speedbar-exist-p)))
+ (sr-speedbar-open))
+ (sr-speedbar-select-window))
+#+end_src
+#+begin_src emacs-lisp
+ (za/global-set-key (kbd "C-c F") 'za/jump-to-speedbar-or-open)
#+end_src
-
** expand-region
Expand the selected region semantically.
@@ -1177,7 +1250,7 @@ use in order for displaying the list, and then options for those functions (each
And a way to toggle those side windows:
#+begin_src emacs-lisp
- (global-set-key (kbd "C-c w") (lambda () (interactive) (window-toggle-side-windows)))
+ (za/global-set-key (kbd "C-c w") #'window-toggle-side-windows)
#+end_src
* Editor
** Overwrite selection on typing
@@ -1279,7 +1352,7 @@ A function to toggle wrapping:
And a keybinding to toggle wrapping:
#+begin_src emacs-lisp
- (global-set-key (kbd "C-c q w") #'za/toggle-wrap)
+ (za/global-set-key (kbd "C-c q w") #'za/toggle-wrap)
#+end_src
I want to wrap text at window boundary for some modes:
@@ -1344,13 +1417,13 @@ Even though I won't be sending the email from there, I like the syntax highlight
It's more useful for me to be able to delete up to a character instead of to and including a character:
#+begin_src emacs-lisp
- (global-set-key (kbd "M-z") 'zap-up-to-char)
+ (za/global-set-key (kbd "M-z") 'zap-up-to-char)
#+end_src
** Expansion/completion
Use hippie expand instead of dabbrev-expand:
#+begin_src emacs-lisp
- (global-set-key (kbd "M-/") 'hippie-expand)
+ (za/global-set-key (kbd "M-/") 'hippie-expand)
#+end_src
** Prefer newer file loading
@@ -1411,19 +1484,19 @@ Enable semantic mode for major modes:
Change M-f to stop at the start of the word:
#+begin_src emacs-lisp
- (global-set-key (kbd "M-f") 'forward-to-word)
+ (za/global-set-key (kbd "M-f") 'forward-to-word)
#+end_src
Bind C-M-S-F to the old functionality of M-f (stop at end of word)
#+begin_src emacs-lisp
- (global-set-key (kbd "C-M-S-F") 'forward-word)
+ (za/global-set-key (kbd "C-M-S-F") 'forward-word)
#+end_src
** Rectangle insert string
#+begin_src emacs-lisp
- (global-set-key (kbd "C-x r I") 'string-insert-rectangle)
- (global-set-key (kbd "C-x r R") 'replace-rectangle)
+ (za/global-set-key (kbd "C-x r I") 'string-insert-rectangle)
+ (za/global-set-key (kbd "C-x r R") 'replace-rectangle)
#+end_src
** End sentences with one space
Emacs uses the rather old-fashioned convention of treating a period followed by double spaces as end of sentence. However, it is more common these days to end sentences with a period followed by a single space.
@@ -1499,30 +1572,38 @@ I want to have these enabled so I don't get a prompt whenever I try to use a dis
#+end_src
** Easily edit my config
Bind a keyboard shortcut to open my config.
-The "(interactive)" means that it can be called from a keybinding or from M-x (though since it's a lambda, it can't be called from M-x).
+The "(interactive)" means that it can be called from a keybinding or from M-x.
+
+#+begin_src emacs-lisp
+ (defun za/edit-config-org ()
+ "Edit my config.org file"
+ (interactive)
+ (find-file (expand-file-name "config.org" user-emacs-directory)))
+#+end_src
#+begin_src emacs-lisp
- (global-set-key (kbd "C-c E") (lambda () (interactive) (find-file (expand-file-name "config.org" user-emacs-directory))))
+ (za/global-set-key (kbd "C-c E") 'za/edit-config-org)
#+end_src
+(describe-key (kbd "C-c E"))
** Fast access to view-mode (pager)
I want to bind view-mode to a key for easy access:
#+begin_src emacs-lisp
- (global-set-key (kbd "C-c r") 'view-mode)
+ (za/global-set-key (kbd "C-c q r") 'view-mode)
#+end_src
** Kill this buffer
I like to be able to kill a buffer instantly:
#+begin_src emacs-lisp
- (global-set-key (kbd "s-<backspace>") 'kill-current-buffer)
+ (za/global-set-key (kbd "s-<backspace>") 'kill-current-buffer)
#+end_src
** Toggle fullscreen
I'll use the keybinding that's standard on macOS:
#+begin_src emacs-lisp
- (global-set-key (kbd "C-s-f") #'toggle-frame-fullscreen)
+ (za/global-set-key (kbd "C-s-f") #'toggle-frame-fullscreen)
#+end_src
** Enable recursive minibuffers
@@ -1535,13 +1616,13 @@ I'll use the keybinding that's standard on macOS:
When I write lisp, sometimes I want to switch two sexps (e.g. ~(one) (two)~ → ~(two) (one)~), so a key binding is nice for that:
#+begin_src emacs-lisp
- (global-set-key (kbd "C-S-t") #'transpose-sexps)
+ (za/global-set-key (kbd "C-S-t") #'transpose-sexps)
#+end_src
Also, to raise a sexp (e.g. ~(one (two))~ → ~(two)~):
#+begin_src emacs-lisp
- (global-set-key (kbd "C-S-u") #'raise-sexp)
+ (za/global-set-key (kbd "C-S-u") #'raise-sexp)
#+end_src
** Dedicated windows
@@ -1559,7 +1640,7 @@ So I create a keybinding to toggle dedicated on a window:
(set-window-dedicated-p (selected-window) t)
(message "Window marked as dedicated"))))
- (global-set-key (kbd "C-x 9") #'za/toggle-window-dedicated-p)
+ (za/global-set-key (kbd "C-x 9") #'za/toggle-window-dedicated-p)
#+end_src
@@ -1581,7 +1662,7 @@ Then, if I'm in an emacsclient, I want to bind C-x C-c to that function (if not,
#+begin_src emacs-lisp
;; If not running in emacsclient, use the default bindings
(if (daemonp)
- (global-set-key (kbd "C-x C-c") #'za/emacsclient-c-x-c-c))
+ (za/global-set-key (kbd "C-x C-c") #'za/emacsclient-c-x-c-c))
#+end_src
Furthermore, I want to set the theme correctly whenever I connect with 'emacsclient':
@@ -1615,7 +1696,7 @@ Define the main screen sections:
Global keybindings:
#+begin_src emacs-lisp
- (global-set-key (kbd "C-c m") #'notmuch)
+ (za/global-set-key (kbd "C-c m") #'notmuch)
#+end_src
Show newest mail first: