For today, I have an extremely specific Emacs Lisp tip – this is definitely not something you would use every day, but when you need it, it’s there.
Assume that you are writing a mode (call it cool-mode
), which should support some general Emacs command (call it do-something
) – only the workings of this mode are so specific that this command should be basically written from scratch instead of using Emacs’ own do-something
. You could (of course) advise do-something
, but it seems cleaner to define cool-do-something
instead. How do you bind it to the same keys it is normally bound to in Emacs? For bonus points, the user might have its Emacs customized (with global-set-key
, for example) to bind do-something
to a key of their choice.
It turns out that (surprise!) Emacs has support for exactly this use case. The function substitute-key-definition
, called with four arguments, olddef
, newdef
, keymap
and oldmap
, finds all the keys in oldmap
which are bound to olddef
and binds these precise keys in keymap
to newdef
. So the only thing you need to say (after defining your mode’s keymap) is something like
(substitute-key-definition 'do-something 'cool-do-something cool-mode-map global-map)
Clever, isn’t it? And if that code is called after the user’s customizations, every key customized by the user (in global-map
, of course) to call do-something
will call cool-do-something
in cool-mode
. Great!
One caveat: the fourth parameter to the substitute-key-definition
function is optional, but if it’s absent, the meaning of the command is different (though still related). Head on to the manual to learn what it does then (although it’s not hard to guess, really).
And, if you happen to be wondering why I needed this, here’s why: I was writing a mode which I wanted to have undo capabilities, but it was so atypical (basically it involved changing the current buffer to read-only and using some custom commands to edit the contents of another buffer, however strange it may sound!) that the usual undo
command was useless there.
And, if you happen to be wondering what strange mode I was coding… Well, I will talk about it very soon on this blog, but if you really want to know now, there is a certain book about Elisp you might want to check out. (Note that as of today, this particular command isn’t yet used there – it is a part of a section-in-progress.)