15

Assume that I have downloaded a major mode called magical-mode, and it has its own magical keymap called magical-mode-map. This mode also provides a hook magical-mode-hook which is run each time magical-mode becomes the major mode of a buffer. Now I want to modify my init file to add a few custom key bindings to use in that mode.

It seems that there are (at least) two ways to set up custom key bindings for magical-mode. The one that I see most commonly is this:

(defun my-magical-keys ()
  (local-set-key (kbd "C-i") 'previous-line)
  (local-set-key (kbd "C-k") 'next-line)
  (local-set-key (kbd "C-j") 'backward-char)
  (local-set-key (kbd "C-l") 'forward-char))
(add-hook 'magical-mode-hook 'my-magical-keys)

But it is also possible to do it this way:

(define-key magical-mode-map (kbd "C-i") 'previous-line)
(define-key magical-mode-map (kbd "C-k") 'next-line)
(define-key magical-mode-map (kbd "C-j") 'backward-char)
(define-key magical-mode-map (kbd "C-l") 'forward-char)

The second method actually seems cleaner to me. Are there any advantages to doing it one way over the other?

3
  • I use the same keys for the basic movement commands. Be warned: this is an uphill battle and you might want to learn a little bit more about key bindings before you start doing this.
    – tarsius
    Commented Oct 10, 2014 at 0:58
  • @tarsius An uphill battle indeed. I have gone down that path before, but now I am back to good ol' C-n and C-p. The example is just dummy code. I wanted to come up with some very simple example modes and example bindings, precisely so that the bindings themselves would not distract from the actual purpose of the question.
    – nispio
    Commented Oct 10, 2014 at 13:49
  • the second way doesn't actually work without either add-hook or require. See here
    – xdavidliu
    Commented May 22, 2022 at 17:54

4 Answers 4

17

The second approach is preferable as it modifies the mode's keymap just once.

If you do it using the mode's hook then that will be called every time that mode is enabled in some buffer. Doing so again usually won't actually have an effect because the keys are just again bound to what they are already bound to. Major mode keymaps are "local" to the major mode not the individual buffers which use that mode, so if you change a binding in one of these buffers using local-set-key then that affects all buffers with the same major mode.

local-set-key is primarily intended to be used as a command. Once you have determined that you would like to make some change persistent, use define-key with the mode keymap as the first argument.

If you use a hook to modify the keymap over and over again then that could conflict with the intended use of local-set-key. Say you used M-x local-set-key RET C-i fancy-previous-line RET because you want to tryout that variant of previous-line. If you now open a new buffer which uses the same major mode, then the hook would run again and override your temporary binding, in all buffers using that major mode, including the buffer in which you did previously use local-set-key.

2
  • I like this answer but what if the mode is autoloaded?
    – remvee
    Commented Oct 10, 2014 at 15:30
  • 2
    You can delay loading any code until after some library has been loaded: (eval-after-load 'magical '(progn (define-key magical-mode-map ...) ...)).
    – tarsius
    Commented Oct 10, 2014 at 15:34
4

Using (define-key my-magical-mode-map …) is the normal way.

When you use a hook and local-set-key, the keys are added each time you enter My Magical mode in some buffer. This is weird because local-set-key affects all buffers that are in the same mode (more generally, all buffers using the same keymap). So if you've made any changes to the keymap, they will be overridden each time you enter My Magical mode in a buffer.

The second method may also be confusing if you customize the keymap in different places. The hooks are executed in the reverse order from the order they're added in, and until the first time they are executed, you won't see any trace of your customizations.

2
  • but if you just say define-key like you did, it doesn't actually work; you would still need a mode hook or require at beginning or else it will complain that my-magical-mode-map has symbol not found
    – xdavidliu
    Commented May 22, 2022 at 17:55
  • @xdavidliu No, you wouldn't put that in a mode hook: there's no point in running it each time you open a file in that mode. You'd typically put it in an eval-after-load form or similar. Commented May 22, 2022 at 18:26
2

You are apparently not asking about defining a major-mode keymap but about user code to add or change a few keybindings in an existing major-mode keymap. You say "custom", which suggests this, but we might as well make it clear.

To be sure, what you say you see most commonly for this is not what is used generally to define a major-mode keymap. It is not what you find in the Emacs source code, for instance. And it is not what is recommended in the Elisp manual (node Major Mode Conventions).

Just wanted to get that out of the way, to be clear for others: you generally do not want to use the mode hook to define the major-mode map.


To your question about user key customizations -

In any case it is not local-set-key that you should use in a mode hook. Just use define-key with the major-mode keymap, exactly as in your first example. @tarsius has already explained this well.

Other than that, the answer is: it makes little difference, in general, whether you bind the keys (using define-key with the mode map) once and for all or you use the hook to bind them each time you enter the mode.

But it can make a difference if bindings in the map change - for example, by your loading some other code that changes them. In that case, putting bindings on the major-mode hook ensures that when the mode is entered the bindings will be established. That is, it ensures that they will be made, but it does not ensure that nothing else changes them afterward (e.g. another function on the same hook, invoked afterward). Remember that you have little control over what gets run on a hook and when - unless, of course you are sure that only your own code messes with it.

That is the only difference in effect, that I can think of. For you to decide when you consider that difference to be an advantage of one or the other approach. FWIW, looking at my own code, I don't think I ever bind keys on a mode hook.

1
  • Thanks. I have modified the question to hopefully clarify the fact that I am not creating a major mode, simply adding my own key bindings to and existing major mode.
    – nispio
    Commented Oct 10, 2014 at 13:55
0

Your naming is little confusing (I think you should remove my in your second part of the question).

Anyway assuming my-magical-keys is a user customizing function of magical-mode, I see one obvious advantage. It is easy to remove (by remove-hook) hook in a single go.

The second advantage is what functions are meant for. I mean they are reusable. you can hook them to other modes.

Edit:

As @tarsius has pointed out, removing hook won't restore original behavior and turning the function into a minor mode may be better.

6
  • I am customizing a hypothetical major mode called my-magical-mode. However, if the use of the my- prefix is confusing I can certainly edit the question.
    – nispio
    Commented Oct 10, 2014 at 0:39
  • Yes, that would be better, usually (atleast as I see in the wild) my- is added for user functions.
    – kindahero
    Commented Oct 10, 2014 at 0:42
  • 1
    Agreed. I just applied the my- so that nobody would think that I was asking how to configure a real mode called magical-mode (if it exists).
    – nispio
    Commented Oct 10, 2014 at 0:45
  • 1
    No, removing the hook won't restore the old bindings. At least not until Emacs is restarted, and then I don't see having to comment out only one line instead of four as such a big improvement.
    – tarsius
    Commented Oct 10, 2014 at 0:52
  • 2
    As for the second advantage you mention: here it would be preferable to create a minor mode which could then be enabled for various major modes and/or only some of the buffers using a particular major mode.
    – tarsius
    Commented Oct 10, 2014 at 0:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.