1

I like binding M-n to make-frame, so I have the following in my init file:

(bind-key* "M-n" 'make-frame)

The * form of bind-key allows me to override other minor-mode M-n bindings. But when I'm using the minibuffer (e.g. find-file), I'd rather M-n retained it's original behavior and ran next-history-element.

I'm currently using a workaround, but I'm hoping there's a better solution.

(defun ivan-unbind-make-frame () (bind-key* "M-n" nil))
(defun ivan-rebind-make-frame () (bind-key* "M-n" 'make-frame))

(add-to-list 'minibuffer-setup-hook #'ivan-unbind-make-frame)
(add-to-list 'minibuffer-exit-hook  #'ivan-rebind-make-frame)

Another approach I considered was to create a keymap of the minibuffer bindings I want to take precedence over bind-key* bindings and put it in an entry at the front of emulation-mode-map-alists.

(defvar overriding-minibuffer-map
  (let ((map (make-sparse-keymap)))
    (define-key map (kbd "M-n") #'next-history-element)
    map))

(defvar minibuffer-active-p nil)

(add-to-list 'emulation-mode-map-alists
             `((minibuffer-active-p . ,overriding-minibuffer-map)))

(defun minibuffer-active-on  () (setq minibuffer-active-p t))
(defun minibuffer-active-off () (setq minibuffer-active-p nil))

(add-to-list 'minibuffer-setup-hook #'minibuffer-active-on)
(add-to-list 'minibuffer-exit-hook  #'minibuffer-active-off)

This is more complicated and still doesn't free me from using minibuffer setup/exit hooks (unless there's an existing variable that reflects whether the minibuffer is active, but I couldn't find one). It also makes the assumption that M-n runs next-history-element in all minibuffer use-cases, and I'm not sure that's true.

Is there a better way to handle this, or should I stick with my current solution?

1 Answer 1

4

You can use the PREDICATE argument of bind-key*

(bind-key* KEY-NAME COMMAND &optional PREDICATE)

Similar to ‘bind-key’, but overrides any mode-specific bindings.

(bind-key KEY-NAME COMMAND &optional KEYMAP PREDICATE)
[...]

If PREDICATE is non-nil, it is a form evaluated to determine when
a key should be bound. It must return non-nil in such cases.[...]

Therefore (bind-key* "M-n" 'make-frame (not (minibufferp))) should do what you want.

The predicate parameter is a wrapper around Emacs' filtered keybindings (see (elisp) Extended Menu Items, Define context-aware keys in Emacs, Elisp: Conditionally change keybinding).

1
  • Wow, that's perfect (I should've rtfd :D) -- thanks. I'm actually using bind-keys* (plural), so I ended up with: (bind-keys* :filter (not (minibufferp)) ("M-n" . make-frame)).
    – ivan
    Apr 16, 2017 at 20:55

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.