Define key in prefix keymap for a particular mode - emacs

I have all my keybindings in a separate minor mode - firstly, to be sure that keybindings that I consider mandatory wouldn't be overridden by some major mode; and secondly, to be able to disable all of them in one command in case I need too.
Up until now I have been extending prefix keys like so:
(define-key my-minor-mode-map (kbd "M-g f") 'my-goto-file-func)
But then I realized that there is such thing as prefix keymap, and for M-g key it is goto-map. So I'd rather extend this keymap instead of hardcoding the prefix key, so it would be like:
(define-key goto-map (kbd "f") 'my-goto-file-func)
But in this case my minor mode has nothing to do with it, so I lose all my advantages of using it.
One way would be to determine which key is bound to that particular prefix keymap and then use that key in the bindings. But it has a drawback - prefix key wouldn't be remapped for my minor mode if I remap it after loading my minor mode.
So are there any better ways to do that?

Extending keys the way you did is perfectly fine because it keeps complexity to a minimum. So while it is certainly possible to modify a keymap in your minor mode, it is not necessarily better.
In order to use a modified keymap in your minor mode without overriding the original one, simply set the original as your parent, e.g.
(defvar my-goto-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map goto-map)
map))
You can then use a modified version in your minor mode:
(define-key my-goto-map "f" 'find-file)
(define-key my-mode-map (kbd "M-g") my-goto-map)
But the original goto-map is still alive and kicking, and modifying it will reflect in your my-goto-map:
(define-key goto-map "i" 'info)
See "Inheritance and Keymaps" in the elisp manual.

Note that olab b's answer is totally fine, and I gonna accept his answer and use it by myself, but there is one issue with it:
The original goto-map is untouched. Imagine hypothetical situation where some library provides a command which uses goto-map in some way - for example, to provide some fancy interface for commands in it or binds to it inside its own keymap - that is something that helm could do if they were crazy enough. Since all my keys would go to the my-goto-map, they wouldn't be reflected in those extensions.
So here is a weird solution for a made-up problem, just for funzies:
First, note that keymap in elisp can be one of two things:
variable containing list whos first element is symbol 'keymap (and it is usually how keymaps are used in emacs)
symbol whos function cell is set to the keymap variable (and I never saw that anybody used it like that)
So first we are going to define a variable for our keymap:
(defvar my-goto-map (make-sparse-keymap))
Next, write its value to the function cell as well:
(fset 'my-goto-map my-goto-map)
Note that we can't replace goto-map since everything that was already bound to it wouldn't catch the replacement. And manipulating with keybindinds one by one isn't fun. So here is a proper insert:
(setcdr goto-map (cons (make-composed-keymap 'my-goto-map (cons (car goto-map) (cdr goto-map))) nil))
(Of course we could just append my-goto-map to goto-map, but in that case the relation between my-goto-map and original goto-map would be "neighbors" and not "parent-child"; and "neighboring" does not allow for undefining keybindings)
Note that goto-map now depends on the symbol my-goto-map so we can do whatever we want with that symbol without loosing our keymap. So we can easily disable all custom keybindings like so:
(fset 'my-goto-map nil)
And the variable cell of my-goto-map is untouched, so we can easily restore keybindings:
(fset 'my-goto-map my-goto-map)
The main drawback comes from the fact that emacs does not allow "buffer-local functions", only "buffer-local variables". And here we need a local function :( So we can't just make that activation of prefix map in the hook of the minor mode - cause that modification would be reflected globally.
But at least all the original prefix keys for that keymap (which is one and only M-g IIRC) would automatically use all the custom keybindings, so no need to hardcode M-g as a prefix key in the my-goto-map.

Related

Emacs: unbind all keys of some-mode-map

I know, that I can unbind keys using unbind-key. In this case I have to know the key I want to unbind. But I don't know the key. I just want to unbind all keys of some-mode-map. I don't want override them, I just want to unbind them and then to define my own keys in the some-mode-map. I know that I could iterate some-mode-map and apply unbind-key, but may be there is a more straightforward solution? And I don't know how to iterate a keymap.
Update
Tried (as was suggested by phils in comments) this way and it didn't work:
(use-package neotree
:config
(setq neotree-mode-map (make-sparse-keymap))
(define-key neotree-mode-map (kbd "RET") 'neotree-enter)
)
(use-package evil
:init
(setq evil-overriding-maps '((neotree-mode-map)))
)
neotree-mode-map remains not cleaned. And depending on package configuration order, evil bindings gets overridden. It doesn't unless I redefine neotree-mode-map. I know I could obtain desired result with evil-define-key, but I want to keep package specific settings in its own configuration file. If I employ evil-define-key, neotree key binding definitions will be in setup-evil.el and not in setup-neotree.el
Update 2
Answer works, as does (setq neotree-mode-map (make-sparse-keymap)).
But it appears that neotree-mode-map has parent map, and that's why some key bindings "come back" after "cleaning".
Another thing I figured out is, that evil put into overriding maps some extra information.
(keymap
...
(override-state . all)
...
)
And that's why I should clear map before evilconfiguration.
You can gut all the bindings in a keymap with the following:
(setf (cdr <keymap>) nil)
I think in practice it rarely does really what you want, because there'll be some bindings you didn't realize were useful (e.g. those corresponding to menubar entries), but you get what you asked for.
As for iterating a keymap, you can use map-keymap for that.

How to define keymap for minor mode correctly

I'd like to define custom mode for improvements that suits to any program mode. And I need to define key-bindings for all this modes. I choose to use define-minor-mode with :keymap to declare key bindings with minimum effort.
I'd like to bind comment-or-uncomment-region to "C-;" The kbd macro gave me [67108923] magic number for this key sequence.
I've wrote sample that doesn't work
(define-minor-mode
my-mode
nil nil
:keymap '(
( [67108923] . comment-or-uncomment-region )
)
)
I've registered mode, toggled it on, but pressing С-; produces notifications that the key sequence is not defined
After that I've wrote in the scratch buffer and evaluate simple global-set-key that performed in expected way.
(global-set-key [67108923] 'comment-or-uncomment-region )
Now pressing C-; produces expected comment-or-oncomment-region behavior.
I've tried to debug the issue with searching to function info via C-h f. It produces strange output, comment-or-oncomment-region is bound twice to different key sequences:
It is bound to C - ;, C-;
First one appears and disappears with the minor mode toggling, other emerge from global-set-key invocation.
How can it be, if I've used the same key definition for both maps? What details I have missed?
Don't use the magic number. IOW use [?\C-\;], so it can be understood by humans.
And I agree with Drew:
(defvar my-mode-map
(let ((map (make-sparse-keymap)))
(define-key map [?\C-\;] 'comment-or-uncomment-region)
map))
(define-minor-mode my-mode
"blabla"
nil nil nil
<add code, if any>)
Oh, and one more thing: why would you prefer C-; over the standard M-; binding?
Just create a keymap normally, using make-sparse-keymap, and name it my-mode-map --- you're done. No need for :keymap arg to define-minor-mode.
Or use the keymap you create using make-sparse-keymap as the value of :keymap, if you like. (But no need to, since it is named as the minor mode expects: my-mode-map.)
But why not just use a global binding, via global-set-key? Why do you even need this to be a minor-mode binding?

How to create keybindings for a custom minor mode in Emacs

Question:
How do I create custom keybindings for minor modes? Something like this.
Here is what I have so far. I'm trying to get just one custom keybinding to work:
(define-minor-mode num-mode
"Toggle the Num pad keys.
With no argument, this command toggles the mode.
Non-null prefix argument turns on the mode.
Null prefix argument turns off the mode.
When Num mode is enabled, the num pad inserts the
keys you see on the pad. This may over ried existing
definitions, and is probably only usefule if you aref
running Emacs through a terminal."
;; The initial value.
nil
;; The indicator for the mode line.
" NumPad"
;; The minor mode bindings.
;; This doesn't work right now!!!!
'(((kbd "<kp-1>") . "a"))
:global 1
)
When I hit "1" on the num pad after calling my custom minor mode, "num-mode" and verifying it is on in the mini buffer, I get the error <kp-1> is undefined. What I want to happen is a is printed out where the pointer is when I hit <kp-1>. (just a test)
Context:
So, I usually use my num pad to move between buffers (the arrow keys move me the appropriate directions). This is set globally. I want to create a minor mode that I can call when I want to use my num-pad to simply enter numbers.
By default, the keys on my num-pad are undefined. I use <kp-0> to <kp-9> to define the keybindings for the numpad keys.
I can create a minor mode that I can call, but I can't attach any keybindings. This is true for all keybindings, including one not defined anywhere else.
Thanks for any help!
Short Answer
Problem line:
'(((kbd "<kp-1>") . "a"))
Solution (force the evaluation of the macro):
;; Single quote changed to back-quote and added a comma
`((,(kbd "<kp-1>") . "a"))
Long Answer
The define-minor-mode macro allows you to create minor modes relatively easily (as far as Emacs) goes.
First I'll show how it's done, then I'll explain how it works:
In general form:
(define-minor-mode NAME-mode
"DOCUMENTATION"
INIT-VALUE
"LIGHTER"
;; keymap
'(
(KEY-SEQUENCE . DEFINITION)
(KEY-SEQUENCE . DEFINITION)
... ETC ...
)
;; other options
:KEYWORD-ARG VALUE
:KEYWORD-ARG VALUE
... ETC ...
)
Specific example with forced evaluation of macros in the alist:
;; Custom Minor Mode
(define-minor-mode custom-mode
"Doc description, yada yada yada."
;; The initial value - Set to 1 to enable by default
nil
;; The indicator for the mode line.
" CustomMode"
;; The minor mode keymap
`(
(,(kbd "C-c C-a") . some-command)
(,(kbd "C-c C-b") . other-command)
("\C-c\C-c" . "This works too")
)
;; Make mode global rather than buffer local
:global 1
)
An alternative way, if you wish to use a variable for the keymap is to define the keymap variable and the keymap before the minor mode declaration something like this:
(defvar custom-mode-keymap (make-keymap) "num-mode keymap.")
(define-key custom-mode-keymap (kbd "C-c C-a") 'some-command)
And then, in your minor mode definition, simple list the variable name for your keymap, instead of the alist
(define-key custom-mode-keymap (kbd "C-c C-b") 'other-command)
;; Num pad enable
(define-minor-mode custom-mode
...
;; The minor mode bindings.
custom-mode-keymap
How it all works
From top to bottom, right after define-minor-mode we define a command name to toggle the minor mode. custom-mode in this case (M-x custom-mode to toggle the mode). This also defines a variable of the same name.
Right after the command name, we list the documentation string for the minor mode in quotes. This can pretty much be as long as you want.
Next we have several choices. The simplest choice is to simply list three things and then any additional options. The three things have to be listed in the order below. These three things are:
The initilization value for the minor mode variable. nil will have the mode off by default. Something other than nil will have it on by default.
The lighter. The lighter is simply what is display in the mode line at the bottom when your minor mode is on. This should be short, and it'll often help, in terms of formatting, to start it with a space.
The keymap. The keymap can either be defined as a variable or an alist (association list). Since using an alist is simpler and shorter, that's what I used in the example. The alist should be in the form (key-sequence . definition).
If you define the keymap as an alist, there's a few things to watch out for, especially if you're used to defining global keybindings. First, command names are not quoted. Second, if you want to use a macro, you have to force it to evaluate (and on SO). This is done with a combination of the back-quote (not single quote) and comma. You can see how this is done in the example with the kbd macro. I also included a keystroke definition if you don't use the kbd macro. If you simply quote a string in your keymap, that'll print out when the defined key combination is pressed (just like for defining global key bindings).
The keymap will not work with kbd macros if you do not force the evaluation of the kbd macros with a combination of the back quote and comma. Like this:
`((,(kbd "C-c C-a") . some-command))
Finally, you can add additional options using keyword-args of the form :blah. In the example I used :global. We could have defined the entire mode with keyword-args, but it's shorter to just list the init value, lighter, and keymap in the right order.
You need to have code like this in your minor mode definition:
(defvar your-mode-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map parent-mode-shared-map)
(define-key map "\C-c\C-a" 'some-defun)
(define-key map "\C-c\C-b" 'some-other-sexp)
map)
(use-local-map your-mode-map)
You could have a look at the many modes available in EmacsWiki for reference.
Have a look at this (just for information about keybindings):
http://www.gnu.org/software/emacs/manual/html_node/emacs/Key-Bindings.html#Key-Bindings
http://www.gnu.org/software/emacs/manual/html_node/emacs/Local-Keymaps.html#Local-Keymaps
From Link:
Well written major modes will run hook at the end. So, you can use a hook to define your keybinding. Minor modes usually do not have hooks. In that case, you can call “(require ‹minor mode feature symbol›)” first, then define your keybinding.
Also you might have a look at:
http://www.cs.utah.edu/dept/old/texinfo/emacs19/emacs_35.html#SEC347
Maybe the accepted answer here also helps you.

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.

Globally override key binding in Emacs

How can I set a key binding that globally overrides and takes precedence over all other bindings for that key? I want to override all major/minor mode maps and make sure my binding is always in effect.
This of course doesn't work:
(global-set-key "\C-i" 'some-function)
It works in text-mode, but when I use lisp-mode, C-i is rebound to lisp-indent-line.
I can go through and override this binding in lisp-mode and in every other mode individually, but there must be an easier way. Every time I install a new mode for a new file type, I'd have to go back and check to make sure that all of my key bindings aren't being overridden by the new mode.
I want to do this because I want to emulate bindings I've already learned and ingrained from other editors.
I use a minor mode for all my "override" key bindings:
(defvar my-keys-minor-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-i") 'some-function)
map)
"my-keys-minor-mode keymap.")
(define-minor-mode my-keys-minor-mode
"A minor mode so that my key settings override annoying major modes."
:init-value t
:lighter " my-keys")
(my-keys-minor-mode 1)
This has the added benefit of being able to turn off all my modifications in one fell swoop (just disable the minor mode) in case someone else is driving the keyboard or if I need to see what a default key binding does.
Note that you may need to turn this off in the minibuffer:
(defun my-minibuffer-setup-hook ()
(my-keys-minor-mode 0))
(add-hook 'minibuffer-setup-hook 'my-minibuffer-setup-hook)
As an addition to scottfrazer's answer, I've written the following so that my keybindings retain precedence, even if subsequently-loaded libraries bring in new keymaps of their own.
Because keymaps can be generated at compile time, load seemed like the best place to do this.
(add-hook 'after-load-functions 'my-keys-have-priority)
(defun my-keys-have-priority (_file)
"Try to ensure that my keybindings retain priority over other minor modes.
Called via the `after-load-functions' special hook."
(unless (eq (caar minor-mode-map-alist) 'my-keys-minor-mode)
(let ((mykeys (assq 'my-keys-minor-mode minor-mode-map-alist)))
(assq-delete-all 'my-keys-minor-mode minor-mode-map-alist)
(add-to-list 'minor-mode-map-alist mykeys))))
Install use-package, eval and you're done:
(require 'bind-key)
(bind-key* "C-i" 'some-function)
I found this question while searching for "emacs undefine org mode keybindings", because I wanted to unbind the existing C-c C-b behavior to allow my global map to bury-buffer to work in an org buffer.
This ended up being the simplest solution for me:
(add-hook 'org-mode-hook
(lambda ()
(local-unset-key (kbd "C-c C-b"))))
Although scottfrazer's answer is exactly what you asked for, I will mention for posterity another solution.
From The Emacs Manual:
"Don't define C-c letter as a key in Lisp programs. Sequences consisting of C-c and a letter (either upper or lower case) are reserved for users; they are the only sequences reserved for users, so do not block them."
If you bind your personal global bindings to C-c plus a letter, then you "should" be safe. However, this is merely a convention, and any mode is still able to override your bindings.
If you want to "always use the keybinds in the map, unless I explicitly override them for a specific mode-map", and assuming you are using scottfrazier's approach, you want:
(defun locally-override (key cmd)
(unless (local-variable-p 'my-keys-minor-mode-map)
(set (make-variable-buffer-local 'my-keys-minor-mode-map)
(make-sparse-keymap))
(set-keymap-parent my-keys-minor-mode-map
(default-value 'my-keys-minor-mode-map)))
(define-key my-keys-minor-mode-map key cmd))
So
(locally-override "\C-i" nil)
should remove the "\C-i" binding from the minor mode in the current buffer only. Warning: this is completely untested, but seems like the right approach. The point of setting the parent rather than just coping the global value of my-keys-minor-mode-map is so any later changes to the global value are automatically reflected in the local value.
I don't think you can. That is roughly equivalent to saying that you want to define a global variable that cannot be hidden by local variable declarations in functions. Scope just doesn't work that way.
However, there might be a way to write an elisp function to go through the mode list and reassign it in every single one for you.
Unless you really want to do this yourself, you should check around and see if anyone else already has done it.
There is a package for Emacs which gives your windows-like keybindings. You should be able to find it through google.