Skip to content

Commit 15fd063

Browse files
authored
Repeat when execute in normal state (#1467)
* Handle `execute-kbd-macro`'s nil value for `this-command` * Handle repeating of execute-normal commands earlier in insert
1 parent 0ad1941 commit 15fd063

File tree

3 files changed

+39
-11
lines changed

3 files changed

+39
-11
lines changed

evil-commands.el

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4639,11 +4639,23 @@ if the previous state was Emacs state."
46394639
"Vim has special behaviour for executing in normal state at eol.
46404640
This var stores the eol position, so it can be restored when necessary.")
46414641

4642+
(defun evil--restore-repeat-hooks ()
4643+
"No insert-state repeat info is recorded after executing in normal state.
4644+
Restore the disabled repeat hooks on insert-state exit."
4645+
(evil-repeat-stop)
4646+
(add-hook 'pre-command-hook 'evil-repeat-pre-hook)
4647+
(add-hook 'post-command-hook 'evil-repeat-post-hook)
4648+
(remove-hook 'evil-insert-state-exit-hook 'evil--restore-repeat-hooks))
4649+
4650+
(defvar evil--execute-normal-return-state nil
4651+
"The state to return to after executing in normal state.")
4652+
46424653
(defun evil-execute-in-normal-state ()
46434654
"Execute the next command in Normal state."
46444655
(interactive)
46454656
(evil-delay '(not (memq this-command
4646-
'(evil-execute-in-normal-state
4657+
'(nil
4658+
evil-execute-in-normal-state
46474659
evil-replace-state
46484660
evil-use-register
46494661
digit-argument
@@ -4661,12 +4673,17 @@ This var stores the eol position, so it can be restored when necessary.")
46614673
(forward-char))
46624674
(unless (eq 'replace evil-state)
46634675
(evil-change-state ',evil-state))
4676+
(when (eq 'insert evil-state)
4677+
(remove-hook 'pre-command-hook 'evil-repeat-pre-hook)
4678+
(remove-hook 'post-command-hook 'evil-repeat-post-hook)
4679+
(add-hook 'evil-insert-state-exit-hook 'evil--restore-repeat-hooks))
46644680
(setq evil-move-cursor-back ',evil-move-cursor-back
46654681
evil-move-beyond-eol ',evil-move-beyond-eol)))
46664682
'post-command-hook)
4667-
(setq evil-insert-count nil)
4668-
(setq evil--execute-normal-eol-pos (when (eolp) (point)))
4669-
(setq evil-move-cursor-back nil)
4683+
(setq evil-insert-count nil
4684+
evil--execute-normal-return-state evil-state
4685+
evil--execute-normal-eol-pos (when (eolp) (point))
4686+
evil-move-cursor-back nil)
46704687
(evil-normal-state)
46714688
(setq evil-move-beyond-eol t)
46724689
(evil-echo "Switched to Normal state for the next command ..."))

evil-repeat.el

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@
5050
;; \___/
5151
;;
5252
;; The recording of a repeat is started in one of two cases: Either a
53-
;; command is about being executed (in pre-command-hook) or normal
53+
;; command is about to be executed (in pre-command-hook) or normal
5454
;; state is exited. The recording is stopped whenever a command has
55-
;; being completed and evil is in normal state afterwards. Therefore,
55+
;; been completed and evil is in normal state afterwards. Therefore,
5656
;; a non-inserting command in normal-state is recorded as a single
5757
;; repeat unit. In contrast, if the command leaves normal state and
5858
;; starts insert-state, all commands that are executed until
@@ -63,7 +63,7 @@
6363
;;
6464
;; Not all commands are recorded. There are several commands that are
6565
;; completely ignored and other commands that even abort the currently
66-
;; active recording, e.g., commands that change the current buffer.
66+
;; active recording, e.g., commands that switch buffer.
6767
;;
6868
;; During recording the repeat information is appended to the variable
6969
;; `evil-repeat-info', which is cleared when the recording
@@ -399,8 +399,8 @@ If CHANGE is specified, it is added to `evil-repeat-changes'."
399399

400400
(defun evil-repeat-insert-at-point (flag)
401401
"Repeation recording function for commands that insert text in region.
402-
This records text insertion when a command inserts some text in a
403-
buffer between (point) and (mark)."
402+
For example `mouse-yank-primary'. This records text insertion when a command
403+
inserts some text in a buffer between (point) and (mark)."
404404
(cond
405405
((eq flag 'pre)
406406
(add-hook 'after-change-functions #'evil-repeat-insert-at-point-hook nil t))
@@ -580,7 +580,9 @@ If SAVE-POINT is non-nil, do not move point."
580580
(evil-execute-repeat-info-with-count
581581
count (ring-ref evil-repeat-ring 0))
582582
(setq evil-last-find evil-last-find-temp)))
583-
(evil-normal-state)))))
583+
(if (eq 'evil-execute-in-normal-state last-command)
584+
(evil-change-state evil--execute-normal-return-state)
585+
(evil-normal-state))))))
584586

585587
;; TODO: the same issue concering disabled undos as for `evil-paste-pop'
586588
(evil-define-command evil-repeat-pop (count &optional save-point)

evil-tests.el

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,16 @@ with `M-x evil-tests-run'"))
347347
(evil-test-buffer
348348
"[]"
349349
("2i" "abcdef" "\C-o~" "g" [escape])
350-
"abcdeF[g]"))))
350+
"abcdeF[g]"))
351+
(ert-info ("Can execute evil-repeat in normal state")
352+
(evil-test-buffer
353+
;; Although this is the same in vim, text inserted after the temporary
354+
;; normal command is not recorded for repetition, which is a subtle
355+
;; (but arguably more useful) difference
356+
:state insert
357+
"ab[]cfg"
358+
("\C-o~de\C-o.")
359+
"abCdeF[]g"))))
351360

352361
(defun evil-test-suppress-keymap (state)
353362
"Verify that `self-insert-command' is suppressed in STATE"

0 commit comments

Comments
 (0)