26 Jul 2023

Making keymaps prettier with general.el

After my previous post on defining keymaps using general.el I revisited some of my setup in order to make some package keymaps prettier when displayed by which-key. The keymaps defined by packages are typically don't contain any description of the bindings, so which-key ends up displaying the name of the function bound to the key. It's not always easy to remember what a function does based just on its name, and sometimes the names are so long that which-key cuts the name short and all you see is a bunch of keybindings for seemingly the same function.

The only remedy I've found is to re-define the keybindings decorating them with descriptions that (hopefully) are easier to understand than the function name. (At least, this way I only have myself to blame if it's a bad description.)

One such keymap that I use somewhat frequently, and where the function names often confuse me is evil-mc-key-map from evil-mc. The keymap is bound at g . in evil's normal and visual modes, and it also contains a few bindings using control (C-) and meta (M-) which I think would be better placed under sub-keymaps.

I decided to group the "make and go" functions under g . m and the "skip and go" function under g . s. The rest I'm just giving descriptions. general.el makes it easy both to overwrite already existing bindings, but adding descriptions, and to add new ones, all in one call to general-def:

(general-def evil-mc-key-map
  :states '(normal visual)
  "g.A" '("make end sel" . evil-mc-make-cursor-in-visual-selection-end)
  "g.I" '("make beg sel" . evil-mc-make-cursor-in-visual-selection-beg)
  "g.a" '("make all" . evil-mc-make-all-cursors)
  "g.q" '("undo all" . evil-mc-undo-all-cursors)
  "g.u" '("undo last" . evil-mc-undo-last-added-cursor)
  "g. RET" '("make here" . evil-mc-make-cursor-here)
  "g.p" '("pause" . evil-mc-pause-cursors)
  "g.r" '("resume" . evil-mc-resume-cursors)

  "g.m" '(:ignore t :wk "make & go")
  "g.m$" '("to last cur" . evil-mc-make-and-goto-last-cursor)
  "g.m0" '("to first cur" . evil-mc-make-and-goto-first-cursor)
  "g.mC" '("to prev cur" . evil-mc-make-and-goto-prev-cursor)
  "g.mc" '("to next cur" . evil-mc-make-and-goto-next-cursor)
  "g.mh" '("to prev match" . evil-mc-make-and-goto-prev-match)
  "g.mj" '("to next line" . evil-mc-make-cursor-move-next-line)
  "g.mk" '("to prev line" . evil-mc-make-cursor-move-prev-line)
  "g.ml" '("to next match" . evil-mc-make-and-goto-next-match)

  "g.s" '(:ignore t :wk "skip & go")
  "g.sC" '("to prev cur" . evil-mc-skip-and-goto-prev-cursor)
  "g.sc" '("to next cur" . evil-mc-skip-and-goto-next-cursor)
  "g.sh" '("to prev match" . evil-mc-skip-and-goto-prev-match)
  "g.sl" '("to next match" . evil-mc-skip-and-goto-next-match))

Finally I want to remove the bindings that weren't overwritten. general.el makes that easy too with general-undbind:

(general-unbind '(normal visual) evil-mc-key-map
  "g.$" "g.0"
  "g. C-n" "g. C-S-n"
  "g. C-u" "g. C-S-u"
  "g. C-p" "g. C-r"
  "g. M-N" "g. M-n"
  "g.N" "g.O" "g.n" "g.o")

Yes, this is a bit of work, and so far I've only done this for a few keymaps (those containing bindings I use frequently and/or find difficult to remember). So far I've found it worth the cost.

Tags: emacs general.el
Comment here.