aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAxel Forsman <axel@axelf.se>2025-01-04 17:34:57 +0100
committerAxel Forsman <axel@axelf.se>2025-01-20 20:52:29 +0100
commitc07438d3cb4ca49c9f2acc5636f8fab8a2a08c0e (patch)
tree1de13207b82c6484afd0d8af9492217e6e98eeed
parent9adbebddcdd495b53748559fae7750bbcf9eec6b (diff)
Remove evil--ex-expression
As after-change-functions such as evil--ex-update are not guaranteed to run, this commit ensures evil-ex re-parses the final Ex command string instead of relying on evil--ex-expression. This makes the workaround in commit 6afd86bbc740f3008e91881f990bf346b31d3f0b (Fix for evil-ex-teardown, 2025-01-03) to not overwrite a shortcut in evil--ex-expression no longer necessary. Closes #1949
-rw-r--r--evil-ex.el54
1 files changed, 26 insertions, 28 deletions
diff --git a/evil-ex.el b/evil-ex.el
index f021892..94edd6e 100644
--- a/evil-ex.el
+++ b/evil-ex.el
@@ -310,15 +310,15 @@ The following symbols have reserved meanings within a grammar:
(defvar evil-ex-reverse-range nil
"Whether the current Ex range was entered reversed.")
-(defvar evil--ex-expression nil
- "The Ex evaluation tree.")
-
(defvar evil--ex-cmd nil
"The current Ex command string.")
(defvar evil--ex-argument-handler nil
"The argument handler for the current Ex command.")
+(defvar evil--ex-shortcut-command nil
+ "Interactive command to use instead of an Ex command.")
+
(define-error 'evil-ex-error "Ex syntax error")
(defun evil-ex-p ()
@@ -353,7 +353,7 @@ the initial input is the visual region '<,'> or `<,`>. The variable
(let ((buffer (current-buffer))
(previous-command (when evil-want-empty-ex-last-command
(car evil-ex-history)))
- s evil--ex-expression evil--ex-cmd evil--ex-argument-handler)
+ s evil--ex-cmd evil--ex-argument-handler evil--ex-shortcut-command)
(minibuffer-with-setup-hook
(lambda ()
(setq-local evil-ex-original-buffer buffer)
@@ -366,17 +366,17 @@ the initial input is the visual region '<,'> or `<,`>. The variable
(or initial-input
(and previous-command (propertize previous-command 'face 'shadow)))
evil-ex-completion-map nil 'evil-ex-history)))
- (if evil--ex-expression
- (eval evil--ex-expression t)
+ (if evil--ex-shortcut-command
+ (call-interactively evil--ex-shortcut-command)
(when (string= s "") (setq s previous-command))
- (unless (= (length s) 0) (evil-ex-execute s)))))
+ (unless (string= s "") (evil-ex-execute s)))))
(defun evil-ex-execute (string)
"Execute STRING as an Ex command."
(eval (or (evil-ex-parse string) (signal 'evil-ex-error string)) t))
-(defun evil-ex-parse (string &optional syntax entrypoint)
- "Parse STRING as an Ex expression and return an evaluation tree.
+(defun evil-ex-parse (&optional string syntax entrypoint)
+ "Parse STRING as an Ex expression and return its evaluation tree.
If STRING is nil, parse the text after point instead. If SYNTAX is
non-nil, return a syntax tree instead. ENTRYPOINT is the start
symbol, which defaults to `expression'."
@@ -416,7 +416,7 @@ actions during Ex state."
"Return non-nil if the string COMMAND has a \"!\" suffix."
(and (> (length command) 1) (eq (aref command (1- (length command))) ?!)))
-(defun evil--ex-update (&optional beg _end _len string)
+(defun evil--ex-update (&optional beg _end _old-len)
"Update Ex variables when the minibuffer changes.
This function is usually called from `after-change-functions'
hook. If BEG is non-nil (which is the case when called from
@@ -425,22 +425,22 @@ in case of incomplete or unknown commands."
(when (and beg (eq this-command #'self-insert-command))
(let ((cmd (lookup-key evil-ex-shortcut-map (minibuffer-contents-no-properties))))
(when (commandp cmd)
- (setq evil--ex-expression `(call-interactively #',cmd))
+ (setq evil--ex-shortcut-command cmd)
(exit-minibuffer))))
- (setq evil--ex-expression (save-excursion (goto-char (minibuffer-prompt-end))
- (evil-ex-parse string))
- evil--ex-cmd nil)
- (when (eq (car evil--ex-expression) #'evil-ex-call-command)
- (let (current-prefix-arg func handler evil-ex-range evil-ex-bang evil-ex-argument)
+ (setq evil--ex-cmd nil)
+ (let ((expr (save-excursion (goto-char (minibuffer-prompt-end))
+ (evil-ex-parse)))
+ func handler current-prefix-arg evil-ex-range evil-ex-bang evil-ex-argument)
+ (when (eq (car expr) #'evil-ex-call-command)
(with-current-buffer evil-ex-original-buffer
- (let* ((range (eval (nth 1 evil--ex-expression) t))
+ (let* ((range (eval (nth 1 expr) t))
(count (when (integerp range) range)))
(setq current-prefix-arg count
evil-ex-range (if count (evil-ex-range count count) range)
- evil--ex-cmd (eval (nth 2 evil--ex-expression) t)
+ evil--ex-cmd (eval (nth 2 expr) t)
evil-ex-bang (evil--ex-bang-p evil--ex-cmd)
- evil-ex-argument (eval (nth 3 evil--ex-expression) t))))
+ evil-ex-argument (eval (nth 3 expr) t))))
(cond
((not beg))
;; Test the current command when called from `after-change-functions'
@@ -451,8 +451,7 @@ in case of incomplete or unknown commands."
(if (eq handler evil--ex-argument-handler)
(let ((runner (evil-ex-argument-handler-runner handler)))
(when runner (funcall runner 'update evil-ex-argument)))
- (let ((runner (evil-ex-argument-handler-runner
- evil--ex-argument-handler)))
+ (let ((runner (evil-ex-argument-handler-runner evil--ex-argument-handler)))
(when runner (funcall runner 'stop)))
(setq evil--ex-argument-handler handler)
(let ((runner (evil-ex-argument-handler-runner handler)))
@@ -465,9 +464,6 @@ in case of incomplete or unknown commands."
(defun evil-ex-teardown ()
"Deinitialize Ex minibuffer.
Clean up everything set up by `evil-ex-setup'."
- (when (eq this-command #'exit-minibuffer)
- ;; Call ex--update one last time, in case after-change-functions are combined
- (evil--ex-update))
(let ((runner (evil-ex-argument-handler-runner evil--ex-argument-handler)))
(when runner (funcall runner 'stop))))
@@ -747,6 +743,8 @@ This function interprets special file names like # and %."
(unless (zerop (length evil-ex-argument))
(evil-ex-replace-special-filenames evil-ex-argument)))
+(define-error 'evil-ex-no-previous-cmd "No previous command line")
+
(defun evil-ex-repeat (&optional count)
"Repeat the last Ex command."
(interactive "P")
@@ -756,10 +754,10 @@ This function interprets special file names like # and %."
(cl-loop
with evil-ex-original-buffer = (current-buffer)
for last-cmd in evil-ex-history do
- (evil--ex-update nil nil nil last-cmd)
- (let ((expr (or evil--ex-expression (signal 'evil-ex-error last-cmd))))
- (unless (eq (evil-ex-binding evil--ex-cmd) #'evil-ex-repeat)
- (cl-return (eval expr t))))))
+ (condition-case nil
+ (cl-return (let (evil-ex-history) (evil-ex-execute last-cmd)))
+ (evil-ex-no-previous-cmd))
+ finally (signal 'evil-ex-no-previous-cmd nil)))
(defun evil-ex-call-command (range command argument)
"Execute the given command COMMAND."