From 2d5f962378428ef6f97f2284ca95aa977c86a256 Mon Sep 17 00:00:00 2001 From: William G Hatch Date: Mon, 26 Jun 2017 16:01:27 -0600 Subject: [PATCH 1/2] Advise read-key as well as read-key-sequence --- evil-repeat.el | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/evil-repeat.el b/evil-repeat.el index 73cd2da30..a33d0e961 100644 --- a/evil-repeat.el +++ b/evil-repeat.el @@ -636,7 +636,7 @@ If COUNT is negative, this is a more recent kill." (not evil-repeat-move-cursor))) (evil-repeat-pop (- count) save-point)) -(defadvice read-key-sequence (before evil activate) +(defun evil--read-key-sequence-advice () "Record `this-command-keys' before it is reset." (when (and (evil-repeat-recording-p) evil-recording-current-command) @@ -644,6 +644,11 @@ If COUNT is negative, this is a more recent kill." (if (functionp repeat-type) (funcall repeat-type 'post))))) +(defadvice read-key-sequence (before evil activate) + (evil--read-key-sequence-advice)) +(defadvice read-key-sequence-vector (before evil activate) + (evil--read-key-sequence-advice)) + (provide 'evil-repeat) ;;; evil-repeat.el ends here From d332a3b1b9e2d4c3e27e5d39cf788c588bd6338b Mon Sep 17 00:00:00 2001 From: Axel Forsman Date: Mon, 20 Feb 2023 12:25:58 +0100 Subject: [PATCH 2/2] Remove evil-last-read-digraph-char hack With the Evil repeat system now aware of read-key, there is no need for the digraph repeat workaround introduced by commit dba2fa9907cf096f5e615df2e8b0381b643d47ee. --- evil-commands.el | 2 +- evil-common.el | 65 +++++++++++++++++++++----------------------- evil-repeat.el | 71 ++++++++++++++++++++---------------------------- evil-vars.el | 3 -- 4 files changed, 61 insertions(+), 80 deletions(-) diff --git a/evil-commands.el b/evil-commands.el index e8cdb2ebd..d44d3ab7e 100644 --- a/evil-commands.el +++ b/evil-commands.el @@ -3767,7 +3767,7 @@ resp. after executing the command." ;; tag, which bypasses the source of `this-command-keys', we'd be able ;; to capture the key(s) in the post-command of the operator as usual. ;; Fortunately however, `last-input-event' can see the key (by default, `return') - (unless (append (this-command-keys) nil) + (when (= (length (this-command-keys)) 0) (evil-repeat-record (vector last-input-event)))) (t (evil-repeat-motion flag)))) diff --git a/evil-common.el b/evil-common.el index 7f9c0984a..989becfdd 100644 --- a/evil-common.el +++ b/evil-common.el @@ -580,13 +580,9 @@ Translates it according to the input method." (setq char (aref cmd 0) cmd (key-binding cmd))) (cond - ((eq cmd 'self-insert-command) - char) - (cmd - (setq evil-last-read-digraph-char nil) - (call-interactively cmd)) - (t - (user-error "No replacement character typed")))) + ((eq cmd 'self-insert-command) char) + (cmd (call-interactively cmd)) + (t (user-error "No replacement character typed")))) (quit (when (fboundp 'evil-repeat-abort) (evil-repeat-abort)) @@ -601,41 +597,42 @@ as a command. Its main use is in the `evil-read-key-map'." (read-quoted-char)) (defun evil-read-digraph-char-with-overlay (overlay) - "Read two chars, displaying the first in OVERLAY, replacing `?'. + "Read two chars, displaying the first in OVERLAY, replacing \"?\". Return the digraph from `evil-digraph', else return second char." (interactive) - (let (char1 char2 string) - (unwind-protect - (progn - (overlay-put overlay 'invisible t) - ;; create overlay prompt - (setq string (propertize "?" - 'face 'minibuffer-prompt - 'cursor 1)) - (overlay-put overlay 'after-string string) - (setq char1 (read-key)) - (setq string (propertize (string char1) - 'face 'minibuffer-prompt - 'cursor 1)) - (overlay-put overlay 'after-string string) - (setq char2 (read-key))) - (delete-overlay overlay)) - (or (evil-digraph (list char1 char2)) - ;; use the last character if undefined - char2))) + (unwind-protect + (let ((read-key-empty-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map read-key-empty-map) + ;; Disable read-key-sequence unbound fallbacks, e.g. downcasing + (define-key map [t] 'dummy) + map)) + char1 char2) + ;; create overlay prompt + (overlay-put overlay 'invisible t) + (overlay-put overlay 'after-string + #("?" 0 1 (face minibuffer-prompt cursor 1))) + (setq char1 (read-key)) + (overlay-put overlay 'after-string + (propertize (char-to-string char1) + 'face 'minibuffer-prompt + 'cursor 1)) + (setq char2 (read-key)) + + (or (evil-digraph (list char1 char2)) + ;; use the last character if undefined + char2)) + (delete-overlay overlay))) (defun evil-read-digraph-char (&optional hide-chars) "Read two keys from keyboard forming a digraph. This function creates an overlay at (point), hiding the next HIDE-CHARS characters. HIDE-CHARS defaults to 1." (interactive) - (let* ((overlay (make-overlay (point) - (min (point-max) - (+ (or hide-chars 1) - (point))))) - (char (evil-read-digraph-char-with-overlay overlay))) - (setq evil-last-read-digraph-char char) - char)) + (let ((overlay (make-overlay + (point) (min (+ (point) (or hide-chars 1)) + (point-max))))) + (evil-read-digraph-char-with-overlay overlay))) (defun evil-read-motion (&optional motion count type modifier) "Read a MOTION, motion COUNT and motion TYPE from the keyboard. diff --git a/evil-repeat.el b/evil-repeat.el index a33d0e961..89cf044cc 100644 --- a/evil-repeat.el +++ b/evil-repeat.el @@ -74,9 +74,9 @@ ;; `\[evil-repeat-pop]' (`evil-repeat-pop'). ;; ;; Repeat information can be stored in almost arbitrary form. How the -;; repeat information for each single command is recored is determined -;; by the :repeat property of the command. This property has the -;; following interpretation: +;; repeat information for each single command is recorded is +;; determined by the :repeat property of the command. This property +;; has the following interpretation: ;; ;; t record commands by storing the key-sequence that invoked it ;; nil ignore this command completely @@ -85,13 +85,13 @@ ;; insert state, otherwise it is ignored. ;; abort stop recording of repeat information immediately ;; change record commands by storing buffer changes -;; SYMBOL if SYMBOL is contained as key in `evil-repeat-types' -;; call the corresponding (function-)value, otherwise -;; call the function associated with SYMBOL. In both -;; cases the function should take exactly one argument -;; which is either 'pre or 'post depending on whether -;; the function is called before or after the execution -;; of the command. +;; SYMBOL if SYMBOL is contained as key in `evil-repeat-types' call +;; the corresponding (function-)value, otherwise call the +;; function associated with SYMBOL. In both cases the +;; function should take exactly one argument which is either +;; `pre', `pre-read-key-sequence' or `post' specifying on +;; whether the function is called before or after the +;; execution of the command. ;; ;; Therefore, using a certain SYMBOL one can write specific repeation ;; functions for each command. @@ -107,13 +107,6 @@ ;; `evil-record-repeat' to append further repeat-information of the ;; form described above to `evil-repeat-info'. See the implementation ;; of `evil-repeat-keystrokes' and `evil-repeat-changes' for examples. -;; Those functions are called in different situations before and after -;; the execution of a command. Each function should take one argument -;; which can be either 'pre, 'post, 'pre-operator or 'post-operator -;; specifying when the repeat function has been called. If the command -;; is a usual command the function is called with 'pre before the -;; command is executed and with 'post after the command has been -;; executed. ;; ;; The repeat information is executed with `evil-execute-repeat-info', ;; which passes key-sequence elements to `execute-kbd-macro' and @@ -125,10 +118,10 @@ ;; prepending the count as a string to the vector of the remaining ;; key-sequence. -(require 'evil-states) - ;;; Code: +(require 'evil-states) + (declare-function evil-visual-state-p "evil-visual") (declare-function evil-visual-range "evil-visual") (declare-function evil-visual-char "evil-visual") @@ -323,15 +316,13 @@ invoked the current command" (defun evil-this-command-keys (&optional post-cmd) "Version of `this-command-keys' with finer control over prefix args." - (let ((arg (if post-cmd current-prefix-arg prefix-arg))) - (vconcat - (when (and (numberp arg) - ;; Only add prefix if no repeat info recorded yet - (null evil-repeat-info)) - (string-to-vector (number-to-string arg))) - (or (when evil-last-read-digraph-char - (vector evil-last-read-digraph-char)) - (this-single-command-keys))))) + (vconcat + (let ((arg (if post-cmd current-prefix-arg prefix-arg))) + (and (numberp arg) + ;; Only add prefix if no repeat info recorded yet + (null evil-repeat-info) + (number-to-string arg))) + (this-single-command-keys))) (defun evil-repeat-keystrokes (flag) "Repeation recording function for commands that are repeated by keystrokes." @@ -341,11 +332,10 @@ invoked the current command" (evil-repeat-record `(set evil-this-register ,evil-this-register))) (setq evil-repeat-keys (evil-this-command-keys))) - ((eq flag 'post) + ((memq flag '(post pre-read-key-sequence)) (evil-repeat-record (if (zerop (length (evil-this-command-keys t))) evil-repeat-keys (evil-this-command-keys t))) - (setq evil-last-read-digraph-char nil) ;; erase commands keys to prevent double recording (evil-clear-command-keys)))) @@ -436,14 +426,13 @@ Return a single array." (cur (setcdr cur-last (cons rep nil)) (setq cur-last (cdr cur-last))) - (t - (setq cur (cons rep nil)) - (setq cur-last cur)))) + (t (setq cur (cons rep nil) + cur-last cur)))) (t (when cur (setcdr result-last (cons (apply #'vconcat cur) nil)) - (setq result-last (cdr result-last)) - (setq cur nil)) + (setq result-last (cdr result-last) + cur nil)) (setcdr result-last (cons rep nil)) (setq result-last (cdr result-last))))) (when cur @@ -523,8 +512,7 @@ where point should be placed after all changes." (< (nth 2 rep) ?9)) (setcar (nthcdr 2 rep) (1+ (nth 2 rep)))) (apply (car rep) (cdr rep))) - (t - (error "Unexpected repeat-info: %S" rep)))))) + (t (error "Unexpected repeat-info: %S" rep)))))) ;; TODO: currently we prepend the replacing count before the ;; key-sequence that calls the command. Can we use direct @@ -553,8 +541,7 @@ and only if COUNT is non-nil." (setq done t))) (evil-execute-repeat-info repeat-info))) ;; repeat with original count - (t - (evil-execute-repeat-info repeat-info))))) + (t (evil-execute-repeat-info repeat-info))))) ;; Keep the compiler happy - this is a buffer local var (defvar evil--execute-normal-return-state) @@ -637,12 +624,12 @@ If COUNT is negative, this is a more recent kill." (evil-repeat-pop (- count) save-point)) (defun evil--read-key-sequence-advice () - "Record `this-command-keys' before it is reset." + "Record `this-command-keys' before it is overwritten." (when (and (evil-repeat-recording-p) evil-recording-current-command) (let ((repeat-type (evil-repeat-type this-command t))) - (if (functionp repeat-type) - (funcall repeat-type 'post))))) + (when (functionp repeat-type) + (funcall repeat-type 'pre-read-key-sequence))))) (defadvice read-key-sequence (before evil activate) (evil--read-key-sequence-advice)) diff --git a/evil-vars.el b/evil-vars.el index b5869834f..2b833d115 100644 --- a/evil-vars.el +++ b/evil-vars.el @@ -1559,9 +1559,6 @@ This keymap can be used to bind some commands during the execution of `evil-read-key' which is usually used to read a character argument for some commands, e.g. `evil-replace'.") -(defvar evil-last-read-digraph-char nil - "The last digraph character read. Used for repeats.") - ;; TODO: customize size of ring (defvar evil-repeat-ring (make-ring 10) "A ring of repeat-informations to repeat the last command.")