exit Emacs evil operator mode with "jk" keychord - emacs

I want to exit evil-mode's operator pending state when I press "jk" in quick succession.
For example, If I press d, and then jk, nothing should be deleted and Emacs should be in normal mode.
I tried using key-chord.el to exit the operator mode like so, but it didn't work.
(key-chord-define evil-operator-state-map "jk" 'evil-force-normal-state)
A similar question was how to exit isearch with "jk": key chords in isearch. I think the solution might require a similar approach.

This is a little hacky as it relies on <down> being bound to the same as j, but it's the best I can do with my current evil-knowledge. It should work properly in all cases, including repeats.
(define-key evil-operator-state-map "j" 'evil-operator-state-j)
(evil-define-command evil-operator-state-j () (save-excursion
(let ((evt (read-event "Press k to exit operator state" nil 0.5)))
(if (and (integerp evt) (char-equal evt ?k))
(keyboard-quit)
;; assume <down> is bound to the same as j:
(let* ((operator-string (substring (this-command-keys) 0 -1)) ; get the keys used to invoke the operator
(new-macro (kbd (concat operator-string " <down>")))) ; add " <down>" to the end instead of "j"
(evil-force-normal-state)
(execute-kbd-macro new-macro)
(when (not (null evt))
(push evt unread-command-events))))))) ; process any other key pressed within 0.5 seconds
If you find a bug or have any questions about how it works, just ask. :)

Related

key chords in isearch

I really love key-chord.el. It's become an integral part of my workflow, but sometimes I wish I could have them in the minibuffer (for things like evil-search). Specifically, I'd like jj to exit out of evil-search and move down a line. Is this possible?
I know I can hack together a command that acts as both a prefix and a command (see this SO question), so I could bind j to a self inserting command, and jj to my special command. How would I be able to break the event loop after a specified idle time? I do type jj once in a blue moon, and I'd still like the flexibility of a timeout.
Is there any other way which I am unaware of to achieve what I want?
EDIT:
Origionally, this question was about the minibuffer in general. key-chord.el seems to work fine with minibuffer-local-map. It does not, however, work with isearch-mode-map. Binding a command to a single regular key like j does work in isearch. This is what I'm trying to solve.
I have found a solution which manually reproduces the behaviour of key-chord.el.
(defun isearch-exit-chord-worker (&optional arg)
(interactive "p")
(execute-kbd-macro (kbd "<backspace> <return>")))
(defun isearch-exit-chord (arg)
(interactive "p")
(isearch-printing-char)
(unless (fboundp 'smartrep-read-event-loop)
(require 'smartrep))
(run-at-time 0.3 nil 'keyboard-quit)
(condition-case e
(smartrep-read-event-loop
'(("j" . isearch-exit-chord-worker)
("k" . isearch-exit-chord-worker)))
(quit nil)))
;; example bindings
(define-key isearch-mode-map "j" 'isearch-exit-chord)
(define-key isearch-mode-map "k" 'isearch-exit-chord)
This approach actually has several advantages over key-chord.el.
It does not use an input method, so you can use a different input method in conjunction with this.
The first character is shown immediately, and retracted if it is incorrect, while key-chord.el only shows it after a delay.
I have found this to be useful:
(defun isearch-enable-key-chord ()
(key-chord-mode 1)
(key-chord-define isearch-mode-map "jj" 'isearch-cancel))
(add-hook 'isearch-mode-hook 'isearch-enable-key-chord)

how to emulate a specific key press in Emacs Lisp

Context: I want to make a minor mode where pressing f twice fast results in whatever the pressing of ( should do at that time. This doesn't always mean just insertion of (. For example, in buffers where paredit mode or autopair mode is enabled, pressing of ( usually results in insertion of (). In a paredit mode buffer, that sometimes results in wrapping the selected text: for example, if I select a b and press (, that should result in replacing the selection with (a b).
For detection of f being pressed twice, I just need to take the logic in the short code in http://www.emacswiki.org/emacs/electric-dot-and-dash.el
So the only missing piece is a Lisp code snippet that tells Emacs "Trigger pressing of ( now!"
The first thing that came to my mind was that the snippet should do
find the command bound to the key (
and then call call-interactively on that command.
but that breaks down if the auto pairing package (autopair or paredit or other similar package) binds ( to a command that has a logic that looks up what key was used to call the command, or if the package simply relies on post-self-insert-hook or post-command-hook instead of binding (.
update
I've looked up Key Chord documentation and it turns out what I am trying to do with answers to this question has a simpler solution:
(require 'key-chord)
(key-chord-mode 1)
(defvar my-easy-open-paren-mode-map
(let ((map (make-sparse-keymap)))
(key-chord-define map ",." (kbd "("))
map))
(define-minor-mode my-easy-open-paren-mode
"In this mode, pressing . and , together is another way of pressing the open paren.")
(defvar my-easy-semicolon-mode-map
(let ((map (make-sparse-keymap)))
(key-chord-define map ";;" (kbd "C-e ;"))
map))
(define-minor-mode my-easy-semicolon-mode
"In this mode, pressing semicolon twice fast is another way of pressing C-e and semicolon.")
(add-hook 'prog-mode-hook 'my-easy-open-paren-mode)
(add-hook 'c-mode-common-hook 'my-easy-semicolon-mode)
Triggering key press may still be useful in other contexts though.
You might appreciate the Key Chord library for binding functions to a double key-press. (I wouldn't recommend using f if you'll be writing in English, mind you; but YMMV.)
post-self-insert-hook would still run if the binding was self-insert-command. post-command-hook will run in any case, but if you're worried about it seeing an incorrect function and/or input event, you can manipulate those...
After looking up the binding, your function can set this-command to the function you're about to call-interactively, and last-command-event to the required key. e.g.:
(defun my-fake-paren ()
(interactive)
(let ((command (key-binding "(")))
(setq last-command-event ?\()
(setq this-command command)
(call-interactively command)))
I use Key Chord for this sort of thing, although the page you link appears to do the same thing. The trick is getting the call to call-interactively to work correctly. I wrapped it in a let that reset the variable last-command-event, such that call-interactively thinks it was a "(". This works for me in paredit and fundamental modes.
(require 'key-chord)
(key-chord-mode 1)
(defun my-paren-call ()
(interactive)
(let ((last-command-event ?\())
(call-interactively (key-binding "("))))
(key-chord-define-global "ff" 'my-paren-call)

Emacs caps lock minor mode?

Is there a command in Emacs to turn on what might be described as "caps lock minor mode"? I'm looking to do something like M-x toggle-caps-mode, then every letter I type in the buffer is a capital letter until I do M-x toggle-caps-mode again.
Note: I'm NOT looking for directions on how to swap caps and control. In reality this is because I have already done that. I am generally quite happy with it, but occasionally I'm editing code where there are a bunch of constants that are in all caps, and it gets to be a strain holding down the shift key. I'm aware of the various upcase conversion functions; I'd rather not have to type the word, select it, then run upcase-region.
If it matters, I'm using Aquamacs 2.2 w/ Emacs 23.3.1.
You don't need to type the word then select it. If you want to upcase the last word, press M-b M-u or ESC b u. Ok, you'll need to press b several times if it's a word_with_underscores.
If you really want a caps lock minor mode, try John Paul Wallington's lockcaps.el.
You can try something like this:
(define-minor-mode caps-lock-mode
"caps-lock mode"
;; The initial value.
nil
;; The indicator for the mode line.
" CAPS-LOCK"
;; The minor mode bindings.
'(("a" . (lambda () (interactive) (insert-char ?A 1)))
("b" . (lambda () (interactive) (insert-char ?B 1)))
;;etc
("A" . (lambda () (interactive) (insert-char ?a 1)))
("B" . (lambda () (interactive) (insert-char ?b 1)))
;;etc
))

Emacs: How to yank the last yanked text regardless of subsequent kills?

I often find myself repeatedly yanking something after doing some kills and it becomes a process like:
C-y
C-y M-y
C-y M-y M-y
C-y M-y M-y M-y
Each time I kill some text it pushes the first kill back in the kill ring so that I need to cycle through all the kills to return to text I want to yank. What I want to do is repeatedly yank the same text while killing text in-between yanks. Is this possible?
Don't use the kill ring; put the text into a register instead. C-x r s a to store the region's text into (say) register "a"; then C-x r i a to insert it elsewhere.
This is a strange hack, but may help.
The first time you use M-y you normally get an error (no previous yank). So the idea is that this first time you get the last yank instead of the last kill.
For storing that last yank I use the 'Y' register in this example.
These 2 functions would wrap around yank and yank-pop. You expect bugs, I expect suggestions.
(defun jp/yank (&optional arg)
"Yank and save text to register Y"
(interactive)
(set-register ?Y (current-kill 0 t))
(yank arg))
(defun jp/yank-pop (&optional arg)
"If yank-pop fails, then insert register Y"
(interactive)
(condition-case nil
(yank-pop arg)
(error (insert (get-register ?Y)))))
(global-set-key (kbd "M-y") (quote jp/yank-pop))
(global-set-key (kbd "C-y") (quote jp/yank))
You could use M-x delete-region instead to kill the text, possibly binding it to a key if you want to use it a lot.
If you want to repeatedly yank the same text, use the secondary selection instead of the region or killed text.
What's missing from vanilla Emacs is a key binding to yank the secondary selection. I use C-M-y for that (see library second-sel.el).
To get direct access to any kills in the kill ring, use M-y with Browse Kill Ring or with Icicles.
In both cases, M-y at top level gives you access to all entries in the kill ring.
And if you use library second-sel.el then, in addition to the kill ring, you have access to a ring of your past secondary selections.
And if you use library second-sel.el and Icicles then M-y yanks an entry from the the ring you last yanked from (kill ring or secondary-selection ring).
And if you use library browse-kill-ring+.el then the kill-ring browser gives you access to an alternative ring also (which, by default, is the ring of secondary selections if you use library second-sel.el).
I'll try to use delete-region more, but I know the kill commands better. A trick that requires no programming or advance planning is to use M-w after a particularly annoying string of M-y. This puts a more accessible copy of the final yank into the kill ring.
A Better Yank-Pop Implementation
This defines a better yank-pop implementation which tries to fix the increasing yank-pop problem.
It only overrides the function "current-kill". Due to the modular design of yank, yank-pop, and the kill ring variables and functions in Emacs, it turns out that overriding "current-kill" is all that is necessary to get the behavior we want.
The desired behavior is that (1) killing something still puts it at the front of the kill ring, but now (2) yanking or yank-popping something also puts it at the front of the kill ring (3) we preserve the ability of yank-pop to give the appearance of moving through the kill ring by incrementing a global variable and using this to replace the last yank-pop'ped item back where it was. This also means that (4) items which are transitionally yanked (i.e. items placed by yank or yank-pop commands, where the next command is a yank-pop) ultimately get to stay where they are in the kill ring.
;; Example:
;; (setq kill-ring '("a" "b" "c" "d" "e"))
;;
;; keystroke kill ring contents value of kill-ring-yank-index
;; C-y ("a" "b" "c" "d" "e") 0
;; M-y ("b" "a" "c" "d" "e") 1
;; M-y ("c" "a" "b" "d" "e") 2
;; M-y ("d" "a" "b" "c" "e") 3
;; C-y ("d" "a" "b" "c" "e") 0
;; M-y ("a" "d" "b" "c" "e") 1
;; M-d ("x" "a" "d" "b" "c" "e")
;; etc.
the code:
;; ----------------------------------------------------------------
;; helper functions
(defun list-insert-before (l n x)
(if (<= n 0) (cons x l)
(cons (car l) (list-insert-before (cdr l) (- n 1) x))))
(defun list-prepend-nth (l n)
(if (<= n 0) l
(let* ((lx (list-prepend-nth (cdr l) (- n 1))))
(cons (car lx) (cons (car l) (cdr lx))))))
(defun list-insert-car-at (l n)
(list-insert-before (cdr l) n (car l)))
;; ----------------------------------------------------------------
;; overriding current-kill
(defvar kill-ring-yank-index 0
"Index into kill-ring of last yank-pop. The item yank-popped
will be at the head of the kill ring, but if the next command
is also yank-pop, it will be returned here first before this
variable is incremented.")
(defun current-kill (n)
"Replaces standard 'current-kill' function. This version tries
to fix the increasing yank-pop problem.
TODO:
- respect second argument of original function
- deal with 'interprogram-{cut,paste}-function'
"
(if (eq 0 n) ;; looks like we're doing a yank; reset
;; kill-ring-yank-index to 0 to indicate that the
;; current head of the list is useful to the user
(progn (setq kill-ring-yank-index 0)
(car kill-ring))
;; otherwise put the head of kill-ring back where we had
;; previously found it, and fetch the next element
(setq kill-ring
(list-insert-car-at kill-ring kill-ring-yank-index))
(setq kill-ring-yank-index (+ kill-ring-yank-index n))
(when (>= kill-ring-yank-index (- (length kill-ring) 1))
(setq kill-ring-yank-index (- (length kill-ring) 1))
(message "Reached end of kill-ring"))
(when (< kill-ring-yank-index 0)
(setq kill-ring-yank-index 0)
(message "Reached beginning of kill-ring"))
(setq kill-ring (list-prepend-nth kill-ring kill-ring-yank-index))
(car kill-ring)))
;; ----------------------------------------------------------------
;; new key binding
;; Here's an auxiliary function and key binding that makes it easy to
;; go back and forth in the kill-ring while we're yank-popping
(defun yank-pop-back () "" (interactive "*")
(yank-pop -1))
(global-set-key "\C-\M-y" 'yank-pop-back)
I am trying to hack along the line of using a minor mode. Let's call this delete-mode. Once you get into delete mode, kill commands (kill-line, kill-paragraph, kill-word, ...) will change their behavior so that the kill-region part of their commands will be replaced by delete-region, and new material will not be added to the kill ring. While in this mode, the kill ring will stay constant. When you switch back out of this mode, the behaviour returns to normal.
The following is an incomplete code attempting to implement what I wrote above. It works correctly in switching to delete mode, but it has problem switching back (turning the minor mode off). Any help fixing this would be appreciated.
(defvar delete-mode nil)
(defun delete-mode ()
"delete minor-mode"
(interactive)
(setq delete-mode (not delete-mode))
(if delete-mode
(defalias 'kill-region 'delete-region)
(defalias 'kill-region 'original-kill-region)
)
)
(if (not (assq 'delete-mode minor-mode-alist))
(setq minor-mode-alist
(cons '(delete-mode "Delete mode on") minor-mode-alist)
)
(defalias 'original-kill-region 'kill-region)
)
I use
M-x browse-kill-ring
with keybinding 'M-y'. There is also helm support.
https://www.emacswiki.org/emacs/BrowseKillRing
offers more solutions.

Emacs Modes: "Command attempted to use minibuffer while in minibuffer"

Scenario:
I start to type M-x to type a command
I switch to another emacs window/buffer because I realise I'm executing the command in the wrong window
I start to type M-x again to execute the command in the correct window
Result: I get the dreaded "Command attempted to use minibuffer while in minibuffer"
This happens to me multiple times a day while using emacs, and not just in this scenario. This behaviour is highly user-hostile (ref. Modes and Pseudo-modes in The Humane Interface by Jef Raskin)
Is there a way to customize emacs behaviour so that instead of giving this error, it just cancels the first minibuffer and replaces it with a new one?
You can set the variable enable-recursive-minibuffers, which will prevent that error message from coming up. But it just enables multiple calls to the minibuffer - it doesn't redirect the current minibuffer's command to the new buffer. You can give this a try, but I think it'll be more confusing because the original action is still pending...
M-x is bound to 'execute-extended-command, and re-hosting (changing the original buffer) for that command is kind of like programming with continuation. i.e. you call a subroutine from location X, but instead of returning to X when done, you return to Y. I personally think it'd open up more confusion than it'd solve. But I understand the frustration (and know others who have the same frustration).
Indeed this emacs "feature" is aggressive and annoying.
I found this to be the right answer to the problem .Most likely you lost focus of the minibuffer because you switched windows with the mouse and NOT a minibuffer command. So whenever you lose focus using the mouse, the minibuffer will be cleared. Check this post. It works for me and it's way better than recursive minibuffers which will cause a headache
http://trey-jackson.blogspot.com/2010/04/emacs-tip-36-abort-minibuffer-when.html
I'm not sure if there is such a customization, but the way I avoid this is hitting ctrl-g to cancel the command I was in the middle of writing in the minibuffer.
Since my first answer doesn't directly give you what you want, I thought I'd come up with a real solution. This is what I have:
(defvar my-execute-extended-command-source-buffer nil
"var holding the buffer to which the extended-execute-command should apply")
(defvar in-my-execute-extended-command nil
"internal use - indicates whether we're in a 'recursive edit' of sorts")
(defun my-execute-extended-command (command)
"home-grown version of execute-extended-command that supports re-hosting the buffer"
(interactive (list (if in-my-execute-extended-command
nil
(let ((in-my-execute-extended-command t))
(setq my-execute-extended-command-source-buffer (current-buffer))
(completing-read "My-x " obarray 'commandp t nil 'extended-command-history nil nil)))))
(if in-my-execute-extended-command
(progn (setq my-execute-extended-command-source-buffer (current-buffer))
(select-window (minibuffer-window)))
(switch-to-buffer my-execute-extended-command-source-buffer)
(call-interactively (symbol-function (intern command)))))
I've tested it this way. I bound it to a key (F10 in my case b/c I didn't want to lose M-x). Then, with two windows open, each showing a different buffer (say A and B):
From window showing buffer A: F10 isearch-for
Switch from minibuffer to window showing A: C-x o
Switch from window showing A to that showing B: C-x o
"re-host" the command from buffer B: F10
Now back in the minibuffer, finish the command ward RET
When I started typing a search term, the search applied to buffer B.
This only replaces the M-x functionality, not the commands invoked from M-x. Also, this version does not support the prefix argument.
Hopefully this is what you want.
Here you go:
;; automatically cancel the minibuffer when you switch to it, to avoid
;; "attempted to use minibuffer" error.
;; cy was here
(provide 'cancel-minibuffer)
(defun cancel-minibuffer-first (sub-read &rest args)
(let ((active (active-minibuffer-window)))
(if active
(progn
;; we have to trampoline, since we're IN the minibuffer right now.
(apply 'run-at-time 0 nil sub-read args)
(abort-recursive-edit))
(apply sub-read args))))
(advice-add 'read-from-minibuffer :around #'cancel-minibuffer-first)
Can anyone improve on the following?
I've given up and just want to set \C-w to cancel any previous minibuffer before opening a new one (like doing \C-g\C-w)
So far thanks to Trey I've got:
(defun cancel-completing-read ()
(if (> (minibuffer-depth) 0) (exit-minibuffer))
(completing-read "My-x " obarray 'commandp t nil 'extended-command-history nil nil))
(defun cancel-and-execute-command (command)
(interactive (list (cancel-completing-read)))
(call-interactively (symbol-function (intern command))))
(global-set-key "\M-x" 'cancel-and-execute-command)
What command should I use in the place of exit-minibuffer above?
I've tried
keyboard-escape-quit
exit-minibuffer
keyboard-quit