Emacs Evil-mode key rebinding - emacs

How do I rebind
1 as 4 and 4 as 6 without 1 becoming 6?

Your question isn't clear at all. What do you want to achieve ?
If you want to insert "4" when you press 1:
(global-set-key (kbd "1") (lambda () (interactive) (insert "4")))
(global-set-key (kbd "4") (lambda () (interactive) (insert "6")))

Related

Is is possible to bind a key plus a variable in Emacs?

I have buffers named *terminal<1>*, *terminal<2>*, *terminal<3>*, etc. Is there a way to bind a key combination that will take an argument for the number? That is, I want to bind C-c 1 to switch to *terminal<1>* and C-c 2 to switch to *terminal<2>*, and so on. If I can't do this directly, is it possible to do metaprogramming in Elisp that will define all the functions for me?
In this suggestion, the interactive switch-to-terminal will take either a prefix argument C-u 2 for example, or prompt the user.
The macro then makes setting up the key bindings a little easier.
Finally I bind C-c 1 to C-c 4 to switch to *terminal<1>* to *terminal<4>*.
(defun switch-to-terminal (buf-num)
(interactive "NNumber of buffer to visist: ")
(let* ((buf-name (format "*terminal<%d>*" buf-num))
(buf (get-buffer buf-name)))
(unless buf
(error "No buffer %s" buf-name))
(switch-to-buffer buf)))
(defmacro bind-switch-to-terminal (num)
`(global-set-key
,(kbd (format "C-c %d" num))
(lambda ()
(interactive)
(switch-to-terminal ,num))))
(bind-switch-to-terminal 1)
(bind-switch-to-terminal 2)
(bind-switch-to-terminal 3)
(bind-switch-to-terminal 4)
This change uses the same switch-to-terminal function, but replaces bind-switch-to-terminal with a function. The lexical-let* allows for the creation of a closure to create unique terminal switching functions, the dotimes loop then binds for C-c 1 to C-c 9.
(defun bind-switch-to-terminal (num)
(lexical-let* ((buf-num num)
(switch-func
(lambda ()
(interactive)
(switch-to-terminal buf-num))))
(global-set-key
(kbd (format "C-c %d" buf-num))
switch-func)))
(dotimes (num 9)
(bind-switch-to-terminal (1+ num)))
You can bind keys as usual:
(global-set-key (kbd "C-c 1") (lambda ()
(interactive)
(switch-to-buffer "*terminal<1>*")))
To create all the shortcuts from 1 to 9 we would use macros.
edit: This buggy version may put you on tracks. I give up :(
(defmacro gototerminal (count)
`(global-set-key (kbd ,(concat "C-c " (number-to-string count)))
;; with the comma I want to evaluate what is inside concat
(lambda () (interactive)
(switch-to-buffer (concat "*terminal<" ,count ">*"))))
)
(progn (setq count 1)
(while (< count 10)
(gototerminal count)
(setq count (1+ count))
))
ps: an elisp debugger is edebug. Set it with C-u C-M-x
I would write a function that calls interactive with an n argument which indicates that the function reads a number from the mini buffer:
(defun test (x)
(interactive "nNumber of buffer to visit: ")
(message (concat "received number: " (number-to-string x))))
Binding this to a key will let you enter a number in the mini buffer.
Another way is to use a numerical argument:
(defun test (x)
(interactive "P")
(message (concat "received number: " (number-to-string x))))
Say you bind this function to C-c c, you can then pass it the number 2 as an argument by pressing C-u 2 C-c c.
If you avoid the usage of an existing prefix key like C-c you can trigger a command with one keypress e.g. F9.
This command can have a single key as input.
Example:
(defun test (k)
(interactive "K")
(message "Pressed key: %d" (- (aref k 0) ?0)))
(local-set-key [f9] 'test)

Elisp: call keymap from code?

Here's a minimal snippet to get things going:
(define-prefix-command 'foo)
(define-key foo "a" 'bar)
(define-key foo "b" 'baz)
(global-set-key (kbd "C-M-r") 'foo)
Now I can "call" the foo keymap when I press C-M-r.
But I wonder how I can do this from code, e.g. something like:
(funcall (lambda-from-keymap 'foo))
After this call, I expect the focus to be in the minibuffer, expecting either
a, or b or C-h to be entered.
Is something like this possible?
You can use read-key-sequence and lookup-key to implement this:
(defun call-keymap (map &optional prompt)
"Read a key sequence and call the command it's bound to in MAP."
;; Note: MAP must be a symbol so we can trick `describe-bindings' into giving
;; us a nice help text.
(let* ((overriding-local-map `(keymap (,map . ,map)))
(help-form `(describe-bindings ,(vector map)))
(key (read-key-sequence prompt))
(cmd (lookup-key map key t)))
(if (functionp cmd) (call-interactively cmd)
(user-error "%s is undefined" key))))
If you hit C-h read-key-sequence still waits for you to complete the sequence. I think you could simulate Emacs' normal behaviour by looping with read-key instead, it's a bit more involved though.
Use it like this:
(defun bar () (interactive) (message "you called bar"))
(defun baz () (interactive) (message "you called baz"))
(define-prefix-command 'foo)
(define-key foo "a" 'bar)
(define-key foo "b" 'baz)
(global-set-key (kbd "C-M-r") 'foo)
(defun call-foo ()
(interactive)
;; Note: pass the symbol form of the keymap so we can give nice help
(call-keymap 'foo "enter a foo command: "))
(global-set-key (kbd "C-c f") 'call-foo)
If the keymap is bound to a key sequence, you can invoke it by emulating the exact key sequence by setting unread-command-events:
(setq unread-command-events
(mapcar (lambda (e) `(t . ,e))
(listify-key-sequence (kbd "C-M-r"))
You need to have foo interactive. I did so using:
(global-set-key (kbd "C-M-r") (lambda () (interactive) ( foo)))
This should fix your problem.

Passing a function to a parameter in elisp

I added the following code to my .emacs file.
(defun delete-right-window ()
(interactive)
(windmove-right)
(delete-window))
(defun delete-left-window ()
(interactive)
(windmove-left)
(delete-window))
(defun delete-below-window ()
(interactive)
(windmove-down)
(delete-window))
(defun delete-above-window ()
(interactive)
(windmove-up)
(delete-window))
(global-set-key (kbd "C-s-<right>") 'delete-right-window)
(global-set-key (kbd "C-s-<left>") 'delete-left-window)
(global-set-key (kbd "C-s-<down>") 'delete-below-window)
(global-set-key (kbd "C-s-<up>") 'delete-above-window)
As you can see, most of the codes are repetitive.
I read How do I pass a function as a parameter to in elisp? and tried to refactor the code to passing windmove-* function as follow:
(defun delete-other-window (callback)
(interactive)
(funcall callback)
(delete-window))
...
(defun delete-right ()
(delete-other-window 'windmove-right))
And I bound keystroke like this:
(global-set-key (kbd "C-s-<right>") 'delete-right)
But when I hit C-s-<right> it doesn't work, only display Wrong type argument: commandp, delete-right in the mini buffer.
What am I missing or what should I do to work the code correctly?
Here's a fix:
(defun delete-after (fn)
`(lambda () (interactive)
(,fn)
(delete-window)))
(global-set-key (kbd "C-s-<right>") (delete-after 'windmove-right))
(global-set-key (kbd "C-s-<left>") (delete-after 'windmove-left))
(global-set-key (kbd "C-s-<down>") (delete-after 'windmove-down))
(global-set-key (kbd "C-s-<up>") (delete-after 'windmove-up))
To make a function into a command, you need to add the special form interactive to it:
(defun delete-right ()
(interactive)
(delete-other-window 'windmove-right))
The problem with your code is that it's the function bind to the key that should be interactive. Not one of the function it call:
(defun delete-other-window (callback)
(funcall callback)
(delete-window))
(defun delete-right ()
(interactive)
(delete-other-window 'windmove-right))
You could also use a macro:
(defmacro defun-delete-other-window (direction)
`(defun ,(intern (concat "delete-" direction)) ()
(interactive)
(,(intern (concat "windmove-" direction)))
(delete-window)))
(defun-delete-other-window "right")

One-Key Macros in Emacs

I am trying to use One-Key Macros (as was written here)
(defun toggle-kbd-macro-recording-on ()
"One-key keyboard macros: turn recording on."
(interactive)
(define-key
global-map
(events-to-keys (this-command-keys) t)
'toggle-kbd-macro-recording-off)
(start-kbd-macro nil))
(defun toggle-kbd-macro-recording-off ()
"One-key keyboard macros: turn recording off."
(interactive)
(define-key
global-map
(events-to-keys (this-command-keys) t)
'toggle-kbd-macro-recording-on)
(end-kbd-macro))
(global-set-key '[(f1)] 'call-last-kbd-macro)
(global-set-key '[(shift f1)] 'toggle-kbd-macro-recording-on)
But when I press Shift-F1 I get error:
define-key: Symbol's function
definition is void: events-to-keys
How can I fix it?
The events-to-keys function seems to be something obsolete. From what I can tell, it should work by just writing:
(defun toggle-kbd-macro-recording-on ()
"One-key keyboard macros: turn recording on."
(interactive)
(define-key
global-map
(this-command-keys)
'toggle-kbd-macro-recording-off)
(start-kbd-macro nil))
(defun toggle-kbd-macro-recording-off ()
"One-key keyboard macros: turn recording off."
(interactive)
(define-key
global-map
(this-command-keys)
'toggle-kbd-macro-recording-on)
(end-kbd-macro))
(global-set-key '[(f1)] 'call-last-kbd-macro)
(global-set-key '[(shift f1)] 'toggle-kbd-macro-recording-on)

How to I remap the Emacs command M-d into the macro M-b, M-d?

I would like the "delete to end of word" command to delete the word, regardless of cursor position.
(defun my-kill-word ()
(interactive)
(backward-word)
(kill-word 1))
(global-set-key (kbd "M-d") 'my-kill-word)
A better code could be:
(defun my-kill-word ()
(interactive)
(unless (looking-at "\\<")
(backward-word))
(kill-word 1))
(global-set-key (kbd "M-d") 'my-kill-word)
So we move backward only if we are not at the beginning of the word
yet.