GNU Emacs, use-package, and key binding for mode specific keymaps

September 11, 2023

Over on the Fediverse, I said:

Current status: ELisp. So much ELisp. In so many little defuns.

Also, it has been '0' days since I had to use ':demand t' with use-package in order to get keymaps working. I think I should just assume any per-mode keymaps need ':demand t' for mysterious reasons I would probably understand if I knew enough and read the use-package documentation (such as it is) carefully enough.

Many GNU Emacs modes, such as MH-E, define mode specific keyboard mappings (keymaps), instead of putting their special keyboard commands into the global keymap that's normally used in every file (okay, buffer). This is especially common in Emacs modes that are basically implementing an application inside Emacs, like MH-E and magit, but they also appear for other things like lsp-mode and backward-forward. Often you may want to modify those mode-specific keymaps, like mh-folder-mode-map, backward-forward-mode-map, company-active-map, and lsp-ui-mode-map.

These days I try to do all of my management of Emacs configuration with use-package, which has become sufficiently popular that it's officially part of GNU Emacs now (justifying my decision to focus on it). Use-package has features for defining key bindings in mode-specific keymaps, for example:

(use-package mh-folder
  :bind (:map mh-folder-mode-map
           ("S-SPC" . mh-previous-page)
           ("s" . mh-alt-show))
  )

However, as far as I can tell, this example does not work as is. Instead, you must force use-package to load the mh-folder package immediately, with the ':demand' keyword. Before I do this, use-package reports no errors but my key bindings are mysteriously missing; once I do this, everything works.

(I would like to avoid loading large packages until I actually use them, but I suppose that in practice Emacs startup time hardly matters in these days of fairly fast machines. On the other hand, several MH-E packages take over a tenth of a second each to load. Sadly, I'm not sure use-package provides any good way for a non-expert to work out why it's immediately loading something, and the slow MH-E packages have innocuous looking use-package declarations and load even without mh-folder enabled.)

As covered in How and when use-package loads packages, use-package sometimes already loads packages immediately and sometimes doesn't. I'm not sure exactly when use-package decides that it must load a package immediately and when it can be deferred (it's not quite as simple as only having keywords from Deferring package loading). With appropriate use-package settings you can look at your *Messages* buffer after starting Emacs to see what was loaded already (at this point I may leave 'use-package-verbose' set to debug). However, it is not as simple as everything that uses ':bind' to bind keys requires forced immediate loading, because the following works:

(use-package magit
  :config
  (global-magit-file-mode)
  :bind
  ("C-x g" . magit-status)
  )

(I have tried some of the ways of expanding what use-package is doing that were mentioned here, but without enlightenment.)

(This is the kind of entry I write for my future self, and to gather various links in one place. Hopefully I will remember this the next time I'm beating my head against problems where a key binding is mysteriously missing.)

Written on 11 September 2023.
« The roots of an obscure Bourne shell error message
My (new) simple system to open URLs on my desktop from remote Linux machines »

Page tools: View Source, Add Comment.
Search:
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Mon Sep 11 23:35:33 2023
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.