diff options
| author | Axel Forsman <axel@axelf.se> | 2025-01-04 17:34:57 +0100 |
|---|---|---|
| committer | Axel Forsman <axel@axelf.se> | 2025-01-20 20:52:29 +0100 |
| commit | c07438d3cb4ca49c9f2acc5636f8fab8a2a08c0e (patch) | |
| tree | 1de13207b82c6484afd0d8af9492217e6e98eeed | |
| parent | 9adbebddcdd495b53748559fae7750bbcf9eec6b (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.el | 54 |
1 files changed, 26 insertions, 28 deletions
@@ -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." |
