3

Let's say I want to customize a keybind for a mode that hasn't been loaded yet like so:

(define-key eshell-mode-map (kbd "C-M-i") 'eshell-previous-input)

But the problem is if I haven't yet loaded eshell I get this error:
Debugger entered--Lisp error: (void-variable eshell-mode-map)

How would I make the keymap visible without opting for the mode-hook eshell-mode-hook?
Are there multiple ways of achieving this?
If so, what is the standard way of doing so (loading files to make variables/functions/keymaps visible)?

Also, what would the implications be if I decided to load the file manually as opposed to using a mode-hook?

2 Answers 2

3

You don't :) At least, not for this use-case.

Instead you defer your configuration until such time as the library in question has been loaded:

(with-eval-after-load "esh-mode"
  (define-key eshell-mode-map (kbd "C-M-i") 'eshell-previous-input))

Note that C-hv eshell-mode-map provided me with the "esh-mode" library name.


If you did want to "make all variables and functions of a mode visible without activating the mode" then you would require the library. e.g.:

(require 'eshell)

Also, what would the implications be if I decided to load the file manually as opposed to using a mode-hook?

If you load the file, then you incur the cost of doing so. If that's happening at init time, then you've slowed down your start-up time slightly. If it's possible that you won't even use eshell in a given session, then this probably isn't what you want to do. (Or if you invariably run emacs as a server which starts when your system boots, then maybe you do want to pre-load things to make it that much more responsive later on, should you happen use that feature -- your call.)

If you use a mode hook then you are once again deferring the evaluation -- but rather than evaluating the code once, you are (re)evaluating it every time any buffer enters that mode. In this particular use-case we only need it to happen once, so with-eval-after-load is more appropriate.

1
  • 4
    You gave what is generally the right answer (i.e., would be correct for most modes), but eshell does things the hard way. :) For some reason, eshell actually creates its keymap in the eshell-mode command and sets it with setq-local. (Search for ;; FIXME: What the hell!? in esh-mode.el.) This means that to redefine eshell-mode-map keys you need to do it everytime the mode is activated, in eshell-mode-hook, for example.
    – Omar
    Sep 19, 2018 at 12:39
5

@phils gave you what is almost always the correct answer, that is, it is the right answer for most major and minor modes; but in the case of eshell you need to do something else:

(add-hook 'eshell-mode-hook
  (lambda ()
    (define-key eshell-mode-map (kbd "C-M-i") 'eshell-previous-input)))

The reason is that, unlike most modes, eshell creates its keymap very late, in fact, it does it every time you activate the mode. In the file esh-mode.el, inside the (define-derived-mode eshell-mode ...) definition, you'll find:

;; FIXME: What the hell!?
(setq-local eshell-mode-map (make-sparse-keymap))
(use-local-map eshell-mode-map)
1
  • 1
    That's certainly unusual. It goes to show that there are always special cases! Good answer. I would just recommend using a named function instead of a lambda for the hook, to make it easier to modify and inspect.
    – phils
    Sep 19, 2018 at 13:49

Your Answer

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

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