Emacs Lisp - Should you unset keys before setting them? - emacs

If I'm going to redefine a key, should I call (global-unset-key (kbd "key-combo")), or does using the function global-set-key automatically call that for me?

There is absolutely no need to unset the key before setting it.
This is similar to variable setting in any programming language: you do not need to do foo = NULL before foo = x. This comparison is closer than one might think because (global-unset-key k) is the same as (global-set-key k nil).

Like sds saied, global-unset-key actually calls global-set-key:
(defun global-unset-key (key)
"Remove global binding of KEY.
KEY is a string or vector representing a sequence of keystrokes."
(interactive "kUnset key globally: ")
(global-set-key key nil))
so there is no real difference between set and unset key actually.

Related

New Doom Emacs user - trying to set global-set-key

I've installed neotree in Doom Emacs. I would like to bind function key 8 ([f8]) using global-set-key. i've put
(global-set-key [f8] 'neotree-toggle)
in init.el, config.el, and custome.el. When I press f8, emacs says " is undefined".
if i type in ":neotree-toggle", it works.
Can you help?
In emacs-lisp (elisp), keys can be represented in different ways, vector or string. The usual way to represent them is to use the macro kbd (for keybinding of course) that transforms a simple string like "C-h f" to the key representing CTRL+h f.
If you want to learn more about that you can read the emacs manual about keys here, or this blog post that is pretty good here.
Finally, if you look at the description of the function global-set-key with C-h f RET global-set-key :
global-set-key is an interactive compiled Lisp function in ‘subr.el’.
(global-set-key KEY COMMAND)
Probably introduced at or before Emacs version 1.4.
Give KEY a global binding as COMMAND.
COMMAND is the command definition to use; usually it is
a symbol naming an interactively-callable function.
KEY is a key sequence; noninteractively, it is a string or vector
of characters or event types, and non-ASCII characters with codes
above 127 (such as ISO Latin-1) can be included if you use a vector.
Note that if KEY has a local binding in the current buffer,
that local binding will continue to shadow any global binding
that you make with this function.
You have to give it a key than a command, so in your case, it'll be something like :
(global-set-key (kbd "<f8>") 'neotree-toggle)
See how special keys are dealt with with kbd here.
I had a few minutes, and since I'm already using doom I did a little experimentation. This should work for you:
(global-set-key (kbd "<f8>") #'neotree)

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.

Emacs: Use a function key (F19) as meta

I’m on a Mac and would like to use the function key F19 as meta.
(There’s a good reason, although it's a bit of a hack: My built (the otherwise excellent port by Yamamoto Mitsuharu) doesn’t support using only the left alt key as meta while preserving the native behavior (inserting special characters) of the right alt key.. So I remapped the left alt key to an unused key - F19 - on the system level with PCKeyboardHack (xmodmap is sorely missed) and would like to tell Emacs to use that as meta.)
So, how do I: use a function key (F19 in my case) as meta key in Emacs?
(I’m fairly new to Emacs and, after some googling, tried out something like
(define-key global-map [f19] \M)
but that, of course, doesn’t do the trick (Symbol’s value as variable is void: M)
Well, with
(setq x-alt-keysym symbol)
you can tell emacs what key is to be understood as meta, but afaik it only accepts 'meta, 'alt, 'super and 'hyper as symbol. Maybe try it with f19.
An alternative option that will work but which will require adaption to a new way of working would be to use F19 as a prefix key (like you use C-h or F1 to invoke help commands):
(define-prefix-command 'f19-map)
(global-set-key (kbd "<f19>") 'f19-map)
(global-set-key (kbd "<f19> x") 'execute-extended-command)
(global-set-key (kbd "<f19> u") 'upcase-word)
...
Writing the configuration shouldn't be too hard. Just press C-h b to get all existing keybindings and edit the help buffer. Get rid of all lines that don't start with M-, then use rectangles to replace all occurrences of ^M- by (global-set-key (kbd ", and so on.
Yet another option would be to bind the key to Esc instead of F19, as long as that's supported by your system, and use the esc prefix instead of the f19 prefix. That way you don't have to change the emacs configuration at all.

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?

Emacs: function that writes down an elisp code that adds a keybinding specified by the user

How can I make an interactive function that interactively read a key from the user (like when you press C-h k) and then writes some line like this:
(global-set-key (kbd "C-x C-s") 'hello)
where the "C-x C-s" part is replaced appropriately with the read key.
Some beginning users have problem making keybindings and in fact I get confused about it too, so I thought let's just automate it.
This seems to work:
(defun insert-key (key)
(interactive (list (read-key-sequence "Key: ")))
(insert "(global-set-key (kbd \"" (key-description key) "\") 'hello)\n"))
Huh? Maybe I'm misunderstanding the question, but if not, this is the answer: global-set-key is a command. And it does just what is requested (IIUC): It reads a key sequence (type, click, etc.), and then it reads the command to bind the key sequence to.