09 Jul 2023

general.el and two ways to define keybindings

When I abandoned spacemacs I really wanted to duplicate its keybindings using SPC as leader key and per-mode bindings available by pressing ,. I found a nice setup using general.el in Tianshu Wang's Emacs config. I made only minor modification and ended up with the following setup.

(use-package general
  :after (evil evil-easymotion)
  :config
  (general-evil-setup)
  (general-auto-unbind-keys)

  (general-define-key
   :states '(normal insert motion visual emacs)
   :keymaps 'override
   :prefix-map 'tyrant-map
   :prefix "SPC"
   :non-normal-prefix "M-SPC")
  (general-create-definer mes/tyrant-def :keymaps 'tyrant-map)
  (mes/tyrant-def "" nil)

  (general-create-definer mes/despot-def
    :states '(normal insert motion visual emacs)
    :keymaps 'override
    :major-modes t
    :prefix ","
    :non-normal-prefix "M-,")
  (mes/despot-def "" nil)

  (general-def universal-argument-map
    "SPC u" 'universal-argument-more))

One slightly surprising thing I found out is that two different ways to define keybindings can be used, one seems to work on both top and mode level, the other only on mode level.

Top-level keybindings (SPC)

At the top-level, i.e. when using mes/tyrant-def, I need to use a cons based configuration. This is part of my top-level keybindings:

(mes/tyrant-def
  "SPC" '("M-x" . execute-extended-command)
  "TAB" '("latest buffer" . mode-line-other-buffer)
  "!" 'shell-command
  "/" '("search" . consult-ripgrep)
  "u" 'universal-argument

  "b" (cons "bufs" (make-sparse-keymap))
  "bb" '("switch" . consult-buffer)
  "bc" '("close" . kill-this-buffer)
  "be" '("erase" . erase-buffer)
  "bs" '("scratch" . scratch-buffer)

  ;; ....
  )

When it's done this way which-key picks up the descriptive strings.

It did take me a while to figure out that this config style was necessary. Again Tianshu Wang's Emacs config was what led me right.

Mode-level keybindings (,)

At the mode-level, i.e. using mes/despot-def, I've found that I can, almost always, define keybindings following the documentation of general.el. Here's the keybindings I have for nix-mode:

(mes/despot-def nix-mode-map
  "=" '(:ignore t :wk "format")
  "=b" '(nix-format-buffer :wk "buffer"))

Just the other day I found that AUCTeX must be doing something with it's keymaps and I have to use the cons-based configuration style for its keymaps.

Tags: emacs general.el
Comment here.