Emacs: How to bind key only in regular buffers and not in the minibuffer? - emacs

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.

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.

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.

Related

emacs key binding command affects another

Previously I used C-SPC to activate/deactivate mark, now I use expand-region package and set key binding to C-# like this:
(global-set-key (kbd "C-#") 'er/expand-region)
But this affected the C-SPC keybinding also, so it is also bound to expand-region.
What I need is C-# bind to expand-region and C-SPC to bind to old activate/deactivate mark.
Suggest you refer to:
set-mark-command not working emacs with C-SPC
and
https://www.gnu.org/software/emacs/manual/html_node/emacs/Setting-Mark.html
Quoting from the latter:
"Footnotes [1] There is no C-<SPC> character in ASCII; usually, typing C-<SPC> on a text terminal gives the character C-#. This key is also bound to set-mark-command, so unless you are unlucky enough to have a text terminal that behaves differently, you might as well think of C-# as C-<SPC>."
I think you'll find that they are not separate keys; C-SPC sends a code that's the same as C-#. I think that means you'll have to find somewhere else to bind one of the functions, (even if you have to override expand-region)
Apologies for a second answer... I think the first was wrong because I have now been able to make separate definitions for C-SPC and C-#, as described below.
This works to define C-# and C-SPC separately:
(global-set-key [?\C-#] 'beginning-of-line)
(global-set-key (kbd "C-SPC") 'end-of-line)
To give credit, I derived the answer from here: Rebind C-space in Emacs
after googling "emacs control space"
(Regarding your question, "what key should I bind this expand-region to?", I ordinarily use C-h C-k and type some key I don't think I use. Then look at the function that that key is bound to by default. If it seems useful to me, I try another key and keep looking. If I feel like I will never use the default definition, I redefine it for my own purposes.)

Modifying Emacs isearch key bindings to yank

I want to be able to use M-v hotkey in the emacs search mode to paste text. I know I can add the binding to the isearch-mode-map but when I try to bind yank as a method, it yanks the text in the current buffer, not the search input. How can I find which command is invoked when C-y is pressed in the search mode?
Use isearch-yank-kill instead of yank. Try (lookup-key isearch-mode-map (kbd "C-y")). I use minibuffer-inactive-mode-map, minibuffer-local-map, minibuffer-local-completion-map. You can get exhaustive list of maps by C-hv-mapTAB. Function (current-local-map) can help. See also http://www.gnu.org/software/emacs/manual/html_node/elisp/Controlling-Active-Maps.html
Upd.: Name of current local keymap, definition of function keymap-symbol, see https://stackoverflow.com/a/14490054/1937596
If you use
(setq enable-recursive-minibuffers t)
you can, while in minibuffer, call (eval-expression) by hotkey and execute (current-local-map) or (keymap-symbol (current-local-map))
Typing C-sC-hkC-y will tell you:
C-y runs the command isearch-yank-kill.
More generally, type C-hk whilst isearching, followed by the key sequence you want to know about. Analogous to C-hk when you're not searching, of course.
Typing C-hb whilst isearching displays all of the isearch bindings, which is likewise analogous to the output for C-hb when you're not searching.
The other isearch help bindings are C-hm to show you the mode help, and C-hC-h which gives you a menu to all of the above.

redefined keys doesn't work correctly

I've redefined key bindings for some basic movement functions in my init.el file:
(global-set-key "\C-j" 'backward-char)
(global-set-key "\C-k" 'next-line)
(global-set-key "\C-l" 'forward-char)
(keyboard-translate ?\C-i ?\H-i)
(global-set-key [?\H-i] 'previous-line)
(global-set-key "\M-j" 'backward-word)
(global-set-key "\M-l" 'forward-word)
And in general (text editing) it perfectly works, but in some modes it executes multiple commands, e.g. in Buffer mode when I press C-k aside from moving the cursor down Emacs marks the listed buffer for deletion. Also, when I call helm-prelude with C-c p h and press one of these key bindings Emacs either doesn't react at all or, in case of C-k, clears the search bar. I thought that the purpose of global-set-key was to bind commands to specific keys everywhere, am I wrong?
Local (e.g., major-mode) keymap bindings trump global keymap (global-map) bindings. And minor-mode keymap bindings trump both of these.
There is a hierarchy of several keymap types that determines which maps take precedence. See the Elisp manual, node Controlling Active Maps (and nearby nodes about keymaps). The full hierarchy is a bit complicated, but most of the time what you need to be aware of is what I stated in the preceding paragraph.
Yes, the global keymap is only used when there is no binding for the key being pressed in a local keymap. For example, the buffer menu mode uses Buffer-menu-mode-map, where C-k is bound to Buffer-menu-delete.
You may have better luck using keyboard-translate to translate these keys to the "normal" Emacs bindings for those commands, i.e. C-p, C-n etc.

Emacs, probing arbitrary keymap

key-binding probes keys in the currently active keymaps. For those keymaps, such as minibuffer ones, or isearch-mode-map which are restrictive and become inactive as soon as the user presses a key outside of a limited set of defined keys, I am not able to invoke key-binding without deactivating those keymaps.
How do I:
Determine which keymaps come into effect after invoking certain commands (for example, isearch-mode-map is set as the overriding-local-map by isearch-forward-regexp) in a way that does not involve analyzing source code. Is there a hook that I can use to track/log the state of a variable?
Probe keys in those keymaps. For example, to what is RET bound in isearch-mode-map?
My closest solution has been to bind this function:
(defun probe_keybinding ()
(interactive)
(message (prin1-to-string (key-binding (read-key-sequence-vector "Enter key to probe"))))
)
to an uncommon key like 'S-f9' and invoke it when the keymaps in which I am interested are active (eg in the middle of a find-file in the minibuffer or a eval-expression). This does not always work, for example, isearch-forward-regexp exits as soon as a non-recognized key is entered.
There's no easy way to determine which keymaps will come into use in response to particular commands. Any function can call (use-local-map ...) whenever it likes, so the only way to be sure is to read the source code.
Having said that, the Emacs code does follow conventions that make it possible to find the answer in many cases. If foo-mode has a keymap, then the keymap will usually be named foo-mode-map. You can see a list of variables with names ending in -map by running M-x apropos RET -map$ RET.
You can look up a key in a keymap with the function lookup-key. See "Functions for Key Lookup" in the Emacs Lisp manual. So to find out what RET is bound to in isearch-mode-map, evaluate:
(lookup-key isearch-mode-map (kbd "RET"))
===> isearch-exit
Another element of the answer is to look at individual keymaps. Unfortunately, if you just do C-h v isearch-mode-map (or any other keymap variable) you will see a Lisp expression that is not very readable.
Instead, you can use describe-keymap, from library help-fns+.el. It is bound to C-h M-k, and it shows you all of the (non-menu) keys bound in a keymap, in a human-readable way. More description here.

writing lisp emacs key binding and cannot specify the <delete> character

For some reason I got the default M-del key binding for backward-kill-word mapped to a scan for matching brackets and resetting is not working, so I am trying to set the global key binding in lisp. So I wrote in ~/.emacs.d/init.el the lisp commands:
(global-set-key (kbd "M-h") 'backward-kill-word)
(global-set-key (kbd "M-<\delete>") ‘backward-kill-word)
I tried them with C-x C-e and they both give the 'backward-kill-word output but only the first key-binding works "M-h", the other is ignored and M-del still trying the strange scanning action. The delete key works in emacs elsewhere, so it seems like "delete" is not being mapped to the physical key in lisp (and the backslash is there to show in this text only as the word was being commented out). Any idea what keyword to use or special character?
Best.
(I looked for libraries that may have overrided this command but I cannot find them)
On some systems, the delete key is defined as an alias to C-d. This is done through function-key-map on GNU Emacs <23 and local-function-key-map on GNU Emacs 23. (I've observed this behavior on Debian and Ubuntu 10.04 under X.) The purpose of such translations is to isolate people who code modes from the terminal intricacies: a mode that wants to shadow the delete command only needs to rebind C-d and not wonder if it should rebind delete (is that a delete left or delete right?) or deletechar or something else.
If there is a global or local binding for delete, it shadows this translation to C-d. However, if you press ESC delete, if there is no global or local binding for ESC delete, the second key is translated to C-d. This translation has precedence over the interpretation of ESC delete as M-delete. So ESC delete becomes equivalent to C-M-d.
This is arguably a bug in Emacs: the effect of ESC delete should be the same as M-delete, and there is no reason why ESC delete would run down-list which has nothing to do with deletion.
There are several possible fixes; I don't know which is best. One that should work with any version of Emacs is
(global-set-key [?\e delete] 'backward-kill-word)
The really nice thing about kbd is that what you type there is the same string that Emacs displays. So, try the following
C-h k M-<\delete> (to use your syntax)
or
M-x describe-key M-<\delete>
Emacs (for me) responds with:
M-DEL (translated from <M-delete>)
runs the command backward-kill-word,
which is an interactive compiled Lisp
function in `simple.el'.
It is bound to , M-DEL.
(backward-kill-word arg)
....
Which you can see shows that the representation for the key you want is M-DEL or M-delete.
Which is a long way of getting to the point that what you want is
(global-set-key (kbd "M-delete") 'backward-kill-word)
Of course, if you have something in your .emacs that overrides it, the above won't help. You'll need to find that included library and stop using it (or customize its behavior).
You might want to call global-set-key interactively to see how it interprets meta-delete. Also try local-set-key to ensure the strange binding is not mode-specific.
After not being able to find the library holding the conflict I found this webpage
http://www.cs.cmu.edu/cgi-bin/info2www?%28emacs%29Rebinding
Changing Key Bindings Interactively...
`M-x global-set-key KEY CMD '
Define KEY globally to run CMD....
Normally, C-z' is bound to the function
suspend-emacs' (when not using the X Window System), but you can
change C-z' to invoke an interactive subshell within Emacs, by binding
it toshell' as follows:
M-x global-set-key <RET> C-z shell <RET>
`global-set-key' reads the command name after the key. After you
press the key, a message like this appears so that you can confirm that
you are binding the key you want:
Set key C-z to command:...
And now the standard default is returned to by doing
M-x global-set-key M-del ...
backward-kill-word
But this is transient and must be done on each reload, any way to make this permanent?
Putting a command into the init.el is not overriding the other effect