3

I have written a fancy function, which I would like to bind to TAB. The functionality is only meaningful in any non-read-only text buffer. Currently, I bind it either like that:

(global-set-key (kbd "<tab>") 'my-indent-region)

or

(define-key global-map (kbd "<tab>") 'my-indent-region)

The problem with this binding is that now tab-completion does no longer work in the minibuffer, which is an essential feature (e.g. for buffer/file names, or M-x).

Is it possible to bind TAB only for regular modes? I know that I can use define-key some-major-mode-map, but since I want it in all modes except for the minibuffer, this would be annoying to maintain. Thus, I'm probably looking for something like a define-key any-mode-except-minibuffer ....

If such a functionality does not exist: Is there a workaround to get the tab-completion working in the minibuffer again? Maybe I can re-set the original minibuffer tab binding after changing the global binding? I couldn't figure out though which function I actually have to bind to make it work.

bluenote10
  • 23,414
  • 14
  • 122
  • 178

2 Answers2

3

After some more research I found a workaround/solution to the problem in this answer.

Apparently, my problem was that I was binding to (kbd "<tab>"). If I understand it correctly, my problem was in fact not that I overwrote the actual keymap of the minibuffer -- I guess they are correctly loaded when entering the minibuffer minor modes. However, there seems to be a precedence of a binding to (kbd "<tab>") over a binding to just "\t". According to the above answer, the minibuffer bindings just use "\t", so binding to (kbd "<tab>") shadows them. I'm now using the following binding instead:

(global-set-key "\t" 'my-indent-region)

Now everything seems to be working fine.

Community
  • 1
  • 1
bluenote10
  • 23,414
  • 14
  • 122
  • 178
1

Do you see this behavior when you start Emacs without your init file (emacs -Q)? I doubt it. If not, then recursively bisect your init file to find out what is causing the problem.

The minibuffer uses its own keymaps, which are local and which therefore take precedence over global keymap bindings.

However, any minor-mode keymaps take precedence over local keymaps. So if, for example, you have a (global) minor mode turned on that binds <tab> then that will override any binding for that key in the minibuffer keymaps.

Another thing you can do is simply bind whatever command you want to <tab> in the minibuffer keymaps. But again, you should not need to do that, if you want the usual <tab> behavior for the minibuffer.

[Another possible confusion: Some things, such as Isearch, which you might think use the minibuffer do not use it. Isearch uses its own keymap, isearch-mode-map.]


UPDATE after your comment:

Assigning a key in the global map, as you have done, should not affect what that key does in the minibuffer, provided it has a different binding in the minibuffer keymaps. TAB is typically bound in all of the minibuffer completion keymaps (but not in the non-completion minibuffer keymaps).

See the Elisp manual, nodes Completion Commands and Text from Minibuffer for information about the minibuffer keymaps.

To see what the current bindings are for a keymap that is associated with a variable (such as minibuffer-local-completion-map), load library help-fns+.el and use C-h M-k followed by the keymap variable's name. (See Help+ for more information about the library.)

If you do not want TAB to use your global command binding in the non-completion minibuffer maps (minibuffer-local-map, minibuffer-local-ns-map), then just bind it in those maps to whatever command you like. But for the completion maps you should not need to do anything - TAB should already be bound there.


Did you try emacs -Q, to see if something in your init file is interfering? If not, do that first.

Drew
  • 29,895
  • 7
  • 74
  • 104
  • Hm, maybe my question was not clear enough. I _do_ know exactly what "is causing the problem": My new global tab binding to the fancy `my-indent-region` function. If I remove it, the "problem" is gone, but so is my desired binding. To clarify: My goal is to bind TAB to `my-indent-function' _except_ for when I'm typing in the minibuffer. Your paragraph "Another things you can do..." is probably what I'm looking for, but I don't know what/how I have to bind to get the default behavior. – bluenote10 Apr 06 '15 at 18:01
  • See my edit. Your question was clear. Perhaps my answer was not clear enough? ;-) – Drew Apr 06 '15 at 18:32