Emacs: unbind all keys of some-mode-map - emacs

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.

Related

Define key in prefix keymap for a particular mode

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.

File-specific key-binding in emacs

Is it possible to define file specific key-bindings in emacs?
I suppose it would be possible to create a minor mode and have it loaded when the particular file is open but for only one key-binding that seems overkill.
If you combine the code to local-set-key and Buffer-locally overriding minor-mode key bindings in Emacs then you could end up with something like this:
(defun my-buffer-local-set-key (key command)
(interactive "KSet key buffer-locally: \nCSet key %s buffer-locally to command: ")
(let ((oldmap (current-local-map))
(newmap (make-sparse-keymap)))
(when oldmap
(set-keymap-parent newmap oldmap))
(define-key newmap key command)
(use-local-map newmap)))
and then, as per Barmar's answer:
;; Local Variables:
;; eval: (my-buffer-local-set-key (kbd "C-c C-c") 'foo)
;; End:
Note that minor mode maps take precedence over the local map.
Use eval: in the File Local Variables section:
;;; Local Variables:
;;; eval: (local-set-key ...)
It smells like you are doing things wrong --- that's my guess. If you have a particular file buffer for which a given key binding is appropriate, then define a mode especially for it and bind the key in that mode's keymap. Let the mode inherit from any other mode you like.
For example:
(define-derived-mode my-file-mode org-mode "My file mode")
(define-key 'my-file-mode-map (kbd "SPC") #'org-toggle-checkbox)
You don't really describe anything about your context: how do you access this file (C-x C-f something else)?, why only this file -- what is special about it? what is the key used for? So it is hard to give you any helpful advice.
If you really want to have some key act differently for this particular file, then maybe define a command that visits the file (however you want to visit it) and then creates an overlay over all of its text, and uses the overlay property keymap to add your binding everywhere. This of course sounds pretty silly, but as it stands now, so does your question.
Emacs works with buffers. Buffers are in modes. A file has little meaning in this context. Once the file is visited, its buffer is what you want to work with.
That's why #Barmar tried to answer in terms of a buffer and its mode. You apparently don't want this to be for a given mode, unless, I guess, the mode is specific to that one file. In that case, define a mode that applies (only) to that file.
Clarify your question and perhaps we will be able to help you more.
(Sounds like this might be an XY problem.)
Setting up a minor mode and loading it automatically when opening the specific file is actually simpler than I thought.
The mode file is something along these lines:
(define-minor-mode magic-mode
"Provide functions to do magic."
:lighter " !!!"
:keymap (let ((map (make-sparse-keymap)))
(define-key map (kbd "M-z") 'xyzzy)
map)
)
(defun xyzzy()
"Use at your own risk"
(message "Nothing happens.")
)
(provide 'magic-mode)
It has to be put somewhere the .emacs will look into and the following line is to be added to the .emacs:
(require magic-mode)
Finally, the followingblock should be added at the end of the file that should use the specific commands:
;; Local Variables:
;; eval: (magic-mode)
;; End:

emacs unbound key bindings

How do I clear a binding or edit a binding an emacs package provide?
For instance I had keybindings M-c to capitalize a word.
After I install some 3rd party emacs package, it is changed to calc-dispatch.
I'd like to use M-c as capitalize as before, and set calc-dispatch to something else.
How can I do this in general?
The keybind maps are loaded by order. The keybind map which loaded later will have higher priority. This is why the local key map will override the global keymap, because the global key map is loaded before the local key map(the mode key map). Something is wrong here. Look phils's comment.
What I solve this problem is add a hook to that specify mode to disable that key bind and rebind it to other key in that key map.
First, you need to find the key-map name which defines the M-c bind to calc-dispatch.
It is usually the combination of mode name and mode-map.
For example, the name of python mode key map is py-mode-map.
Second, remove the M-c bind in that mode and rebind to other key using hook.
For example, in python mode, I want to remove the bind C-j (py-newline-and-indent). And rebind it to C-i. Because globally I bind C-j to linum-ace-jump. This is the similar case with yours.
(add-hook 'python-mode-hook
#'(lambda ()
(define-key py-mode-map "\C-j" nil)
(define-key py-mode-map "\C-i" 'py-newline-and-indent)))
What you ask for is:
(global-set-key (kbd "M-c") 'capitalize-word)
This is in general the way to set words globally.
Maybe if you want to substite the two, you can try this:
(substitute-key-definition
'capitalize-word 'calc-dispatch (current-global-map))
(define-key KEYMAPNAME (kbd "KEYCOMBO") 'FUNCNAME)
Is for specific mode. For example: (define-key emacs-lisp-mode (kbd "M-c) 'capitalize-word).
(global-set-key (kbd "M-c") nil)
Is to generally unbind a key (globally).
You can easily find more on this by just googling.

Assign multiple Emacs keybindings to a single command?

I'm giving ErgoEmacs mode a try to see if I can use Emacs more comfortably. Some of its keybindings are fairly intuitive, but in many cases I don't want to outright replace the defaults.
For example, in the context of ErgoEmacs' navigation shortcut structure, M-h makes sense as a replacement for C-a--but I want to be able to use both, not just M-h. I tried simply duplicating the commands:
;; Move to beginning/ending of line
(defconst ergoemacs-move-beginning-of-line-key (kbd "C-a")) ; original
(defconst ergoemacs-move-end-of-line-key (kbd "C-e")) ; original
(defconst ergoemacs-move-beginning-of-line-key (kbd "M-h")) ; ergoemacs
(defconst ergoemacs-move-end-of-line-key (kbd "M-H")) ; ergoemacs
But Emacs simply overwrites the first keybinding with the second. What's the best way to address this?
To re-post reply from ergo-emacs mailing list:
Xah Lee said:
that's very easy.
in the
ergoemacs-mode.el file, there's this
line (load "ergoemacs-unbind") just
comment it out. That should be all
you need to do. However, note that
ErgoEmacs keybinding defines those
common shortcuts such as Open, Close,
New, Save... with keys Ctrl+o,
Ctrl+w, Ctrl+n, Ctrl+s etc. About 7 of
them or so. So, i think some of these
will hit on emacs traditional
bindings with Ctrl. if you are new to
ErgoEmacs and trying to explore it,
you might just try starting with few
keys. this page might have some
useful info:
http://code.google.com/p/ergoemacs/wiki/adoption
thanks for checking out ErgoEmacs!
Xah ∑ http://xahlee.org/
As it turns out, ErgoEmacs uses two files to define the keybinding. One is the main ergoemacs-mode.el file, and the other is the specific keyboard layout you select (e.g. ergoemacs-layout-us.el). The latter document creates a constant, which the former uses to create the keybinding. So while I thought I was duplicating the keybinding, I was actually changing the constant which was subsequently used for that purpose.
Solution:
In ergomacs-mode.el:
;; Move to beginning/ending of line
(define-key ergoemacs-keymap ergoemacs-move-beginning-of-line-key 'move-beginning-of-line)
(define-key ergoemacs-keymap ergoemacs-move-end-of-line-key 'move-end-of-line)
(define-key ergoemacs-keymap ergoemacs-move-beginning-of-line-key2 'move-beginning-of-line) ; new
(define-key ergoemacs-keymap ergoemacs-move-end-of-line-key2 'move-end-of-line) ; new
In ergoemacs-layout-us.el:
;; Move to beginning/ending of line
(defconst ergoemacs-move-beginning-of-line-key (kbd "M-h"))
(defconst ergoemacs-move-end-of-line-key (kbd "M-H"))
(defconst ergoemacs-move-beginning-of-line-key2 (kbd "C-a")) ; new
(defconst ergoemacs-move-end-of-line-key2 (kbd "C-e")) ; new
Huh? Is having one and only one way for every function some golden principle of ErgoEmacs? Because normal keybinding works exactly the opposite way: you name one key at a time and specify what it should do. If a mode defines a global variable to mean "the key that end-of-line is bound to", then of course there can be only one value, but with the normal binding commands you can bind the same function to as many combinations as you like. In fact, every keybinding I have ever seen used looked either like this
(global-set-key [(meta space)] 'just-one-space)
or like this
(add-hook 'c-mode-hook 'my-c-mode-hook)
(defun my-c-mode-hook ()
(define-key c-mode-map [(control c) b] 'c-insert-block))
if it's only for a specific mode.

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.