Emacs, probing arbitrary keymap - emacs

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.

Related

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

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.

org mode - how to disable some keybindings?

I started using Emacs (currently for org mode only). I don't use priorities in my TODOs, hence I'd like to disable S-UP and S-DOWN key bindings (which loop through the priorities). How can I do this?
#lawlist gave you the recipe in his comment. Here's how to find this out for yourself.
See if there is a keymap variable for the mode in question - typically there is one. In this case, try C-h v org-mode-map. If you find no such variable, fish around a little, using the apropos commands - for example, M-x apropos-variable org-mode.
Bind the key(s) in question to nil in that keymap:
(define-key org-mode-map (kbd "S-<up>") nil)
C-h m gives you info about the current mode. Sometimes it lists the important key bindings for the mode. And C-h b (anywhere) lists lots of key bindings for the current context.
If you want to see all of the key bindings that belong to a given keymap variable (in human-readable form), then load library help-fns+.el and then use C-h M-k followed by the keymap variable name (e.g. org-mode-map). See Help+.

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.

Cannot get to bind Enter to 'newline-and-indent in Emacs !!! Very annoying

Cannot get to bind Enter to newline-and-indent in Emacs !!! Very annoying.
I already tried everything on the following thread by changing 'mode' to ruby and still nothing:
How do I make Emacs auto-indent my C code?
I know that the problem is the RETURN key, since if I bind to something else, works fine.
I tried [enter], (kbd "enter"), (read-kbd-macro "enter"), (kbd "RET")
Follow-up 1.
This is what I get from C-hkRET
RET runs the command newline, which is an interactive compiled Lisp
function.
It is bound to RET.
(newline &optional ARG)
Insert a newline, and move to left margin of the new line if it's blank.
If use-hard-newlines' is non-nil, the newline is marked with the
text-propertyhard'.
With ARG, insert that many newlines.
Call auto-fill-function' if the current column number is greater
than the value offill-column' and ARG is nil.
I dont know what to make of it or how to figure out if it's a global
or local binding that gets in the way. trying to remap C-j
also doesnt work.
As a previous comment says, use C-h k (describe-key) to see what the key is bound to at the point when it's not doing what you want. The (kbd "foo") syntax will be correct for whichever foo describe-key refers to it as.
Chances are that you are simply not defining that key in the appropriate keymap.
Note that major and minor mode keymaps take precedence over the global keymap, so you shouldn't necessarily be surprised if a global binding is overridden.
edit:
Myself, I have a hook function for common behaviours for all the programming modes I use, and it includes the sort of remapping you're after. The relevant part looks like this:
(defun my-coding-config ()
(local-set-key (kbd "RET") (key-binding (kbd "M-j")))
(local-set-key (kbd "<S-return>") 'newline)
)
(mapc
(lambda (language-mode-hook)
(add-hook language-mode-hook 'my-coding-config))
'(cperl-mode-hook
css-mode-hook
emacs-lisp-mode-hook
;; etc...
))
See Daimrod's answer for the explanation of why I'm re-binding RET to the current binding of M-j -- although I'm using comment-indent-new-line (or similar) instead of newline-and-indent (or similar), which does what I want in both comments and non-comments.
In Emacs 24, programming modes seem to derive from prog-mode, so you could probably (un-tested) reduce that list to prog-mode-hook plus any exceptions for third-party modes which don't yet do that.
As said earlier, use C-hkC-j because
C-j is the standard key to do newline-and-indent.
If you open a new file, activate ruby-mode and try the previous
command you will see why it doesn't work. Because ruby-mode doesn't
have newline-and-indent but rather
reindent-then-newline-and-indent. Yes that's stupid but you can either ask
to the maintener to change it, or accept it.
However I suggest you to use C-j to do it because
ruby-mode is not the only mode to do so, like paredit-mode which
uses paredit-newline.

Semi-modal editing / auto prefixing keys

Most emacs modes include some sort of prefix to activate their features. For example, when using GUD "next" is "C-c C-n". Of these modes, many provide special buffers where one can use a single key to activate some functionality (just 'n' or 'p' to read next/previous mail in GNUS for example).
Not all modes provide such a buffer, however, and repeatedly typing the prefix can be tiresome. Is there a well-known bit of elisp that will allow for ad-hoc specification of prefix keys to be perpended to all input for some time? (Until hitting ESC or some other sanctioned key, for example)
I agree with Joe Casadonte's answer that the way to go is to define your own minor (or major) mode.
That being said, your question is interesting.
Here's a solution that prompts you for a key sequence and it takes the prefix keystrokes and promotes that keymap to the top level.
e.g. Assume the following keymap:
M-g ESC Prefix Command
M-g g goto-line
M-g n next-error
M-g p previous-error
When you run M-x semi-modal-minor-mode, it will prompt you for some keystrokes. If you enter M-g n, then the following keybindings are set:
ESC Prefix Command (same as M-g ESC)
g goto-line
n next-error
p previous-error
So now n doesn't self-insert, but jumps to the next error. See the code below.
Note: when this minor mode is enabled, <f12> is bound to a command which disables the minor mode. This is because the keybindings might very well disable your Emacs (for instance, what if there was a new keybinding for M-x).
Edited to add these thoughts: the minor mode variable was originally made buffer local, but that doesn't work unless you also make the minor-mode-alist variable buffer local (duh). But, you also (probably) don't want these bindings in the minibuffer... So, I'm not going to test it b/c it really depends on what you want, but I've added a comment to the code reflecting this thought.
Without further ado:
(defvar semi-modal-minor-mode-keymap (make-sparse-keymap)
"keymap holding the prefix key's keymapping, not really used")
(defvar semi-modal-minor-mode-disable-key (kbd "<f12>")
"key to disable the minor mode")
(defun semi-modal-minor-mode-disable ()
"disable the minor mode"
(interactive)
(semi-modal-minor-mode 0))
(define-minor-mode semi-modal-minor-mode
"local minor mode that prompts for a prefix key and promotes that keymap to the toplevel
e.g. If there are bindings like the following:
M-g ESC Prefix Command
M-g g goto-line
M-g n next-error
M-g p previous-error
And you enter 'M-g n' when prompted,
then the minor mode keymap has the bindings
g -> goto-line
n -> next-error
p -> previous-error
ESC -> Prefix Command (same as M-g ESC)
The variable semi-modal-minor-mode-disable-key is bound to disable the minor mode map.
This is provided because often the mappings make the keyboard unusable.
Use at your own risk."
nil " Semi" semi-modal-minor-mode-keymap
(make-local-variable 'semi-modal-minor-mode)
(make-local-variable 'minor-mode-map-alist)
(let ((pair-holding-keymap-to-modify (assq 'semi-modal-minor-mode minor-mode-map-alist)))
(setcdr pair-holding-keymap-to-modify (make-sparse-keymap))
(if semi-modal-minor-mode
(let (key
keymap)
;; all but last (b/c we want a prefix
(setq key (substring (read-key-sequence "Enter a full key combination, the prefix will be used: ") 0 -1))
(if (and (not (equal "" key))
(not (equal (kbd "C-g") key))
(let ((semi-modal-minor-mode nil))
(keymapp (setq keymap (key-binding key)))))
(progn
(setcdr pair-holding-keymap-to-modify (copy-keymap keymap))
(when semi-modal-minor-mode-disable-key
(define-key (cdr pair-holding-keymap-to-modify)
semi-modal-minor-mode-disable-key 'semi-modal-minor-mode-disable)))
(semi-modal-minor-mode 0))))))
The mode-specific (modal?) part of key-bindings in Emacs is realized by the various local maps that overshadow the universal global-map. Most major and minor modes define their own local maps; for example, there is a gud-mode-map. Key bindings in a local keymap will be activated only when the current-buffer is in the respective mode. You can customize a mode specific keymap through the mode's hook. For example, you may put this snippet into your ~/.emacs
(add-hook 'gud-mode-hook
(lambda ()
(local-set-key (kbd "C-n")
(lookup-key (current-local-map) (kbd "C-c C-n")))))
More details about keymaps can be found in Elisp reference manual.
The basic issue here is that there is no current keymap per-se. There's the global keymap which is overridden by the major mode's keymap which in turn is overridden by one or more minor mode keymaps (and they can step on each other in some defined way, I'm sure). Defining a new major mode will still leave the minor mode keys functional, and defining a new minor mode will only affect whatever keys you define in the minor mode's keymap.
For example, you could define a minor mode that will do what you want as long as the minor mode is active. You define a new minor mode my-gud-mode which will have its own keymap. You would then have to define all of your key mappings for it (e.g. n, p, etc) and you would also have to define all of the keys that you didn't want to work to be bound to the function ignore. That's the real pain of this, remapping all of the other keys. The minor mode is easy to switch on and off, though; that's the advantage.
Defining a new major mode would be easier at first blush, as it will let you override more of the "current keymap" in one shot. It should note the current major mode in a buffer-local variable so it can be restored later when the temporary major mode is turned off. But you'll still have other minor modes intruding into your keymap, so it won't be "pure".
What I do in this situation is define an easier prefix! For stuff I use all of the time, all day every day, I give them a function key all on their own (e.g. I have F1 set aside as my jabber-mode key). For less immediately useful things, I have two other function keys set aside, F3 and F12 (I'm sure there was some reason I picked them long ago, but I no longer remember why). F3 defines keys that are always available, regardless of major mode. F12 defines keys that are major-mode-dependent. Some examples:
I have set up F3-m- as a prefix to switch major modes (e.g. F3-m-p switches to cperl-mode) and F3-M- as a prefix for minor modes (e.g. F3-M-v toggles view-mode). These are always available, so you could do something like bind F3-g- to be your gud prefix, and type F3-g-p for previous and so on.
My F12 key is mode-dependent. So, in dired mode F12-e will call dired-nt-open-in-excel on the current file, and in emacs-lisp-mode F12-e will call elint-current-buffer. Somehow I never get them confused.
If you need help in defining keymaps like this, let me know.
Viper mode allows you to map commands to keys or key sequences while in the visual mode (entered using the "esc" key). Go back to insert mode with "i".
Have a look at viper-in-more-modes.elIt uses viper-modify-major-mode.
I also like to use the viper-vi-global-user-map: a snippet from my .emacs file.