8

I'm trying to redefine the keys used to navigate the history when inside several commands accepting regexps and offering C-p / C-n history navigation. I'd like to use other keys, in addition to C-p / C-n. For example when using occur or replace-regexp, C-p and C-n can be used to go to previous and next elements.

I've tried several things but can't make it work. I think I'm missing the "big picture" here.

Which mode-map do I need to modify, when and how? Everything I tried failed.

P.S: Note that I've got my own minor mode with all my keymaps as adviced here.

Drew
  • 29,895
  • 7
  • 74
  • 104
Cedric Martin
  • 5,945
  • 4
  • 34
  • 66

2 Answers2

7

I'm assuming you just needed minibuffer-local-map. Subsequent definitions using keys previously assigned to that key map will trump the prior definitions. To disable a prior key assignment, then just create a new definition and set the last portion to nil instead of 'function-name.

(define-key minibuffer-local-map (kbd "<f6>") 'help-for-help)

Here is an excerpt from Emacs Trunk .../lisp/bindings.el:

(let ((map minibuffer-local-map))
  (define-key map "\en"   'next-history-element)
  (define-key map [next]  'next-history-element)
  (define-key map [down]  'next-history-element)
  (define-key map [XF86Forward] 'next-history-element)
  (define-key map "\ep"   'previous-history-element)
  (define-key map [prior] 'previous-history-element)
  (define-key map [up]    'previous-history-element)
  (define-key map [XF86Back] 'previous-history-element)
  (define-key map "\es"   'next-matching-history-element)
  (define-key map "\er"   'previous-matching-history-element)
  ;; Override the global binding (which calls indent-relative via
  ;; indent-for-tab-command).  The alignment that indent-relative tries to
  ;; do doesn't make much sense here since the prompt messes it up.
  (define-key map "\t"    'self-insert-command)
  (define-key map [C-tab] 'file-cache-minibuffer-complete))
lawlist
  • 13,099
  • 3
  • 49
  • 158
  • using your *define-key* I can indeed assign to *previous-history-element* so that's a good start but... I still can't redefine a key which I'm using in my own minor keys mode: even if I try to set it to *nil* first. – Cedric Martin Nov 04 '13 at 13:37
  • If your own minor mode is the one that needs to be modified, then here is an example based on whatever name you may have assigned to your own key map:  `(add-hook 'minibuffer-setup-hook (lambda () (define-key cedric-martin-mode-map (kbd "") nil) (define-key cedric-martin-mode-map (kbd "") 'help-for-help) ))`      `(add-hook 'minibuffer-exit-hook (lambda () (define-key cedric-martin-mode-map (kbd "") 'help-for-help) (define-key cedric-martin-mode-map (kbd "") nil) ))` – lawlist Nov 04 '13 at 13:58
  • You could also modify your own minor mode to include conditions with the key assignment depending upon whether focus is in the minibuffer by using something like this: `(cond ((minibufferp) [insert key definition] ) (t [insert key definition] ))`. If you do that, then you wouldn't need to use setup and exit hooks. – lawlist Nov 04 '13 at 15:17
  • thanks a lot for all the help, I'm slowly beginning to "get" it : ) – Cedric Martin Nov 04 '13 at 16:53
  • Great! I got it to work thanks to your comment, but there's still something which I don't understand: why does my own *cedric-martin-mode-map* minor mode somehow "clash" or supercede the minibuffer mode? It seems a bit "weird" to be somehow forced to use hooks everytime there's a conflicting keymapping no!? Anyway, it's working and that's great : ) – Cedric Martin Nov 04 '13 at 17:02
  • In general, I prefer to make my keymap assignments based on the major mode that I am in, or global assignments if I want it to work everywhere. One option would be to disable your minor mode with the setup hook and enable it with the exit hook, and then there is no conflict. Another option would be to use the `minibufferp` condition in your minor mode key map definitions, and then there is no conflict. – lawlist Nov 04 '13 at 17:13
  • Minor mode keymaps take precedence over major mode keymaps, which means they take precedence over the minibuffer keymaps. – Drew Nov 04 '13 at 19:33
6

To add to what @lawlist said (which was to bind the key in minibuffer-local-map):

There are multiple minibuffer keymaps, depending on what is being read in the minibuffer, and how. And which of those keymaps you might want to use can depend on which Emacs version you are using.

In addition, there is also the keymap for interaction with buffer *Completions*: completion-list-mode-map.

For completion in the minibuffer, the main keymap is minibuffer-local-completion-map.

Here is a list of the minibuffer keymaps. Some of these might not be available (used) in your Emacs version.

  • minibuffer-local-map
  • minibuffer-local-ns-map
  • minibuffer-local-isearch-map
  • minibuffer-local-completion-map
  • minibuffer-local-must-match-map
  • minibuffer-local-filename-completion-map
  • minibuffer-local-filename-must-match-map
  • minibuffer-local-must-match-filename-map

In addition, you can use minibuffer-with-setup-hook (or minibuffer-setup-hook directly) to add key bindings on the fly, for the duration of a single minibuffer reading.

I will add this info, since it can be really helpful when you are manipulating minibuffer keymaps: You can use C-h M-k (command describe-keymap), from library help-fns+.el, to see all of the bindings of a given minibuffer keymap in human-readable form.

Drew
  • 29,895
  • 7
  • 74
  • 104
  • +1 to both of you. I always try to use close to the latest version of Emacs. I compiled 24.3.50.1 a few days/weeks ago. I'll install the helper functions you suggested and then I'll try to modify these mappings. – Cedric Martin Nov 04 '13 at 16:53
  • Since you are using a recent development snapshot, you can generally ignore the `*-filename-*` maps. If you are using completion then you can ignore the first two maps listed. If you are not using Isearch then you can ignore the `*-isearch-*` map. – Drew Nov 04 '13 at 19:31