Emacs Lisp: defvar-keymap hints for which-key
| emacsEmacs has far too many keyboard shortcuts for me to remember, so I use which-key to show me a menu if I pause for too long and which-key-posframe to put it somewhere close to my cursor.
(use-package which-key :init (which-key-mode 1))
(use-package which-key-posframe :init (which-key-posframe-mode 1))
I've used which-key-replacement-alist to rewrite the function names and re-sort the order to make them a little easier to scan, but that doesn't cover the case where you've defined an anonymous function ((lambda ...)) for those quick one-off commands. It just displays "function".
Pedro A. Aranda GutiƩrrez wanted to share this tip about defining hints by using cons. Here's his example:
(defun insert-surround (opening &optional closing)
"Insert OPENING and CLOSING and place the cursor before CLOSING.
Default CLOSING is \"}\"."
(insert opening)
(save-excursion
(insert (or closing "}"))))
(defvar-keymap tex-format-map
:doc "My keymap for text formatting"
"-" (cons "under" (lambda() (interactive) (insert-surround
"\\underline{")))
"b" (cons "bold" (lambda() (interactive) (insert-surround "\\textbf{")))
"e" (cons "emph" (lambda() (interactive) (insert-surround "\\emph{")))
"i" (cons "ital" (lambda() (interactive) (insert-surround "\\textit{")))
"m" (cons "math" (lambda() (interactive) (insert-surround "$" "$")))
"s" (cons "sans" (lambda() (interactive) (insert-surround "\\textsf{")))
"t" (cons "tty" (lambda() (interactive) (insert-surround "\\texttt{")))
"v" (cons "Verb" (lambda() (interactive) (insert-surround "\\Verb{")))
"S" (cons "small" (lambda() (interactive) (insert-surround "\\small{"))))
(fset 'tex-format-map tex-format-map)
Let's try it out:
(with-eval-after-load 'tex-mode
(keymap-set tex-mode-map "C-c t" 'tex-format-map))
This works for named functions as well. Here's how I've updated my config:
(defvar-keymap my-french-map
"l" (cons "🔍 lookup" #'my-french-lexique-complete-word)
"w" (cons "📚 wordref" #'my-french-wordreference-lookup)
"c" (cons "✏️ conj" #'my-french-conjugate)
"f" (cons "🇫🇷 fr" #'my-french-consult-en-fr)
"s" (cons "🗨️ say" #'my-french-say-word-at-point)
"t" (cons "🇬🇧 en" #'my-french-translate-dwim))
(fset 'my-french-map my-french-map)
(with-eval-after-load 'org
(keymap-set org-mode-map "C-," 'my-french-map)
(keymap-set org-mode-map "C-c u" 'my-french-map))
In case you're adding to an existing keymap, you can use keymap-set with cons.
(keymap-set my-french-map "S" (cons "sentence" #'my-french-say-sentence-at-point))
This is also different from the :hints that show up in the minibuffer when you have a repeating map. Those are defined like this:
(defvar-keymap my-french-map
:repeat (:hints ((my-french-lexique-complete-word . "lookup")
(my-french-consult-en-fr . "fr")
(my-french-translate-dwim . "en")
(my-french-say-word-at-point . "say")))
"l" (cons "🔍 lookup" #'my-french-lexique-complete-word)
"w" (cons "📚 wordref" #'my-french-wordreference-lookup)
"c" (cons "✏️ conj" #'my-french-conjugate)
"f" (cons "🇫🇷 fr" #'my-french-consult-en-fr)
"s" (cons "🗨️ say" #'my-french-say-word-at-point)
"t" (cons "🇬🇧 en" #'my-french-translate-dwim))
and those appear in the minibuffer like this:
Menus in Emacs are also keymaps, but the labels work differently. These ones are defined with easymenu.
(with-eval-after-load 'org
(define-key-after
org-mode-map
[menu-bar french-menu]
(cons "French"
(easy-menu-create-menu
"French"
'(["🕮Grammalecte" my-flycheck-grammalecte-setup t]
["✓Gptel" my-lang-gptel-flycheck-setup t]
["🎤Subed-record" my-french-prepare-subed-record t])))
'org))
Using your own hints is like leaving little breadcrumbs for yourself.
Thanks to Pedro for the tip!