12

I started coding a minor mode to provide some keybindings. My initial attempt had a typo:

(define-minor-mode borked-mode
  "A mode defined with a broken key binding"
  nil nil
  '(([b] . 'previous-line)))

I had intended to use the b key, and immediately realized that I should have used "b" instead of [b]. So I redefined the minor mode:

(define-minor-mode borked-mode
  "A mode defined with a broken key binding"
  nil nil
  '(("b" . 'previous-line)))

However, this didn't work. This set me off on a wild goose chase through all the various ways of binding keys (i.e., (kbd ...), [ ... ], etc). Finally I realized that simply re-evaluating the (define-minor-mode ...) form was not changing anything, I was stuck with the original, broken key map. I then tried changing the keymap directly via (define-key borked-mode-map ...) and still couldn't get the corrected keymap loaded. Finally I restarted Emacs, and my minor mode was correctly loaded.

My question is: how do you update a minor mode definition as you develop it? Is there any way to flush a broken definition, or do you have to restart emacs to clear away broken bits?

11

The first time you evaluate your define-minor-mode it defines a variable borked-mode-map with the key bindings you specified. Once that symbol has been defined, however, re-evaluating your define-minor-mode won't change it.

You could delete the various borked-mode-xxx symbols using unintern and then re-evaluate your code. Try:

(unintern 'borked-mode-map)

You might be interested in expanding the define-minor-mode macro to see what it is actually doing. Put point at the end and call M-x pp-macroexpand-last-sexp. This will open a new buffer showing the expanded macro. There you'll see the defvar calls used to set up your mode variables. If you read the help for defvar you'll see that the initial value is only used if the symbol being defined is void -- once it exists, subsequent defvar calls won't change its value.

11

I think the best answer I can give you is to stay away from the "inline keybindings feature" of define-minor-mode. Use

(defvar borked-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map [b] 'previous-line)
    ...
    map))

(define-minor-mode borked-mode
  "A mode defined with a broken key binding"
  :global nil
  ...)

Instead. Then you can use C-M-x to re-evaluate those definitions.

  • 1
    defvar won't evaluate it's value again after C-M-x :) You'd need defparameter or a separate setf. – wvxvw Aug 27 '15 at 18:03
  • As @wvxvw points out, this does not actually address the issue. Your example code is doing the same that the define-minor-mode macro does: calling defvar to define the map. Evaluating that defvar a second time has no effect. – glucas Aug 27 '15 at 19:51
  • 5
    @wvxvw If you use C-M-x (eval-defun) to reevaluate the defvar then the variable is updated. This is a special case in eval-defun; if you call eval-buffer or eval-region then the existing value isn't changed. – Gilles 'SO- stop being evil' Aug 27 '15 at 22:45
  • Ah -- that seems like the key point. – glucas Aug 28 '15 at 3:00
  • @Gilles the more you learn... I had no idea eval-defun is any different in this respect. Good to know though. – wvxvw Aug 28 '15 at 8:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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