[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/evil f84d3453b3: Read Ex commands from buffer
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/evil f84d3453b3: Read Ex commands from buffer |
Date: |
Mon, 17 Jul 2023 16:01:39 -0400 (EDT) |
branch: elpa/evil
commit f84d3453b312bd8ec0a1c092d075bbc3d91e157b
Author: Axel Forsman <axelsfor@gmail.com>
Commit: Axel Forsman <axelsfor@gmail.com>
Read Ex commands from buffer
When lexing a string with string-match and its START argument, there
is no way to anchor matches to the START position. Instead, one must
either allocate substrings - as done prior to commit
56b43b6f7e014e905f85df1c542c67f46ea99566 - or use looking-at etc.,
instead. This commit opts for the latter.
The Ex completion-at-point functions are also rewritten in order to
avoid having to add ex-index text properties to the command string,
since evil--ex-syntactic-context could be extended to provide that
information just as easily.
---
evil-command-window.el | 7 +
evil-commands.el | 33 +-
evil-common.el | 27 +-
evil-core.el | 4 +-
evil-ex.el | 830 +++++++++++++++++++++----------------------------
evil-maps.el | 11 +-
evil-tests.el | 98 +++---
evil-vars.el | 33 +-
8 files changed, 450 insertions(+), 593 deletions(-)
diff --git a/evil-command-window.el b/evil-command-window.el
index 21299a2dc0..23ac189477 100644
--- a/evil-command-window.el
+++ b/evil-command-window.el
@@ -124,6 +124,13 @@ function to execute."
(let ((evil-ex-current-buffer evil-command-window-current-buffer))
(evil-ex-execute result))))
+(defun evil-ex-command-window-execute (config result)
+ (select-window (active-minibuffer-window) t)
+ (set-window-configuration config)
+ (delete-minibuffer-contents)
+ (insert result)
+ (exit-minibuffer))
+
(defun evil-command-window-search-forward ()
"Open a command line window for forward searches."
(interactive)
diff --git a/evil-commands.el b/evil-commands.el
index fb8263ba90..f8b9cd12ee 100644
--- a/evil-commands.el
+++ b/evil-commands.el
@@ -3560,14 +3560,13 @@ the previous shell command is executed instead."
(if (or current-prefix-arg (evil-visual-state-p))
current-prefix-arg
(goto-char (min beg end))
- (setq current-prefix-arg (count-lines beg end))))
+ (count-lines beg end)))
(evil-ex-initial-input "!"))
(call-interactively #'evil-ex))
- (when command
- (setq command (evil-ex-replace-special-filenames command)))
(if (zerop (length command))
(when previous (setq command evil-previous-shell-command))
- (setq evil-previous-shell-command command))
+ (setq command (evil-ex-replace-special-filenames command)
+ evil-previous-shell-command command))
(cond
((zerop (length command))
(user-error "No%s shell command" (if previous " previous" "")))
@@ -3577,10 +3576,9 @@ the previous shell command is executed instead."
(let ((output-buffer (generate-new-buffer " *temp*"))
(error-buffer (generate-new-buffer " *temp*")))
(unwind-protect
- (if (zerop (shell-command-on-region beg end
- command
- output-buffer nil
- error-buffer))
+ (if (zerop (shell-command-on-region
+ beg end command
+ output-buffer nil error-buffer))
(progn
(delete-region beg end)
(insert-buffer-substring output-buffer)
@@ -3794,7 +3792,7 @@ Signal an error if the file does not exist."
"A valid evil state."
:ex-arg state
(list (when (and (evil-ex-p) evil-ex-argument)
- (intern evil-ex-argument))))
+ (intern-soft evil-ex-argument))))
;; TODO: should we merge this command with `evil-set-initial-state'?
(evil-define-command evil-ex-set-initial-state (state)
@@ -4304,25 +4302,20 @@ range. The given argument is passed straight to
(evil-with-single-undo
(let (markers evil-ex-current-buffer prefix-arg current-prefix-arg)
(goto-char beg)
- (while
- (and (< (point) end)
- (progn
- (push (move-marker (make-marker) (line-beginning-position))
- markers)
- (and (= (forward-line) 0) (bolp)))))
+ (beginning-of-line)
+ (while (when (< (point) end)
+ (push (point-marker) markers)
+ (and (= (forward-line) 0) (bolp))))
(setq markers (nreverse markers))
(deactivate-mark)
(evil-force-normal-state)
;; replace ^[ by escape
(setq commands
(vconcat
- (mapcar #'(lambda (ch) (if (equal ch ?) 'escape ch))
- (append commands nil))))
+ (mapcar (lambda (ch) (if (eq ch ?) 'escape ch)) commands)))
(dolist (marker markers)
(goto-char marker)
- (condition-case nil
- (execute-kbd-macro commands)
- (error nil))
+ (ignore-errors (execute-kbd-macro commands))
(evil-force-normal-state)
(set-marker marker nil)))))
diff --git a/evil-common.el b/evil-common.el
index 7e6b568c24..51d55b03bb 100644
--- a/evil-common.el
+++ b/evil-common.el
@@ -811,14 +811,13 @@ Inhibits echo area messages, mode line updates and cursor
changes."
,@body))
(defun evil-count-lines (beg end)
- "Return absolute line-number-difference betweeen `beg` and `end`.
-This should give the same results no matter where on the line `beg`
-and `end` are."
+ "Return absolute line-number-difference betweeen BEG and END.
+This should give the same results no matter where on the line BEG
+and END are."
(if (= beg end)
0
- (let* ((last (max beg end))
- (end-at-bol (save-excursion (goto-char last)
- (bolp))))
+ (let ((end-at-bol (save-excursion (goto-char (max beg end))
+ (bolp))))
(if end-at-bol
(count-lines beg end)
(1- (count-lines beg end))))))
@@ -978,14 +977,13 @@ argument. Movement is constrained to the current field."
"Return the position of LINE.
If COLUMN is specified, return its position on the line.
A negative number means the end of the line."
- (declare-function evil-goto-line "evil-commands")
(save-excursion
- (evil-goto-line line)
- (if (numberp column)
- (if (< column 0)
- (beginning-of-line 2)
- (move-to-column column))
- (beginning-of-line))
+ (goto-char (point-min))
+ (forward-line (1- line))
+ (when (numberp column)
+ (if (< column 0)
+ (forward-line)
+ (move-to-column column)))
(point)))
(defun evil-column (&optional pos)
@@ -2007,8 +2005,7 @@ The following special registers are supported.
(t search-ring)))
(user-error "No previous regular expression")))
((eq register ?:)
- (or (car-safe evil-ex-history)
- (user-error "No previous command line")))
+ (or (car evil-ex-history) (user-error "No previous command
line")))
((eq register ?.)
evil-last-insertion)
((eq register ?-)
diff --git a/evil-core.el b/evil-core.el
index fabb050223..533d94f6f5 100644
--- a/evil-core.el
+++ b/evil-core.el
@@ -848,7 +848,7 @@ does not already exist."
(let ((map (make-sparse-keymap)))
(evil-set-keymap-prompt
map (format "Minor-mode keymap for %s in %s"
- (symbol-name mode)
+ mode
(or (evil-state-property state :name)
(format "%s state" state))))
(if state-entry
@@ -973,7 +973,7 @@ mode, in which case `evil-define-minor-mode-key' is used."
(declare (indent defun))
(cond ((member keymap '('global 'local))
`(evil-define-key* ,state ,keymap ,key ,def ,@bindings))
- ((and (consp keymap) (eq (car keymap) 'quote))
+ ((eq (car-safe keymap) 'quote)
`(evil-define-minor-mode-key ,state ,keymap ,key ,def ,@bindings))
(t
`(evil-delay ',(if (symbolp keymap)
diff --git a/evil-ex.el b/evil-ex.el
index 7b42930551..fa3aada0e2 100644
--- a/evil-ex.el
+++ b/evil-ex.el
@@ -33,7 +33,7 @@
;; to an interactive function. It is also possible to define key
;; sequences which execute a command immediately when entered:
;; such shortcuts go in `evil-ex-map'.
-;;
+
;; To provide buffer and filename completion, as well as interactive
;; feedback, Ex defines the concept of an argument handler, specified
;; with `evil-ex-define-argument-type'. In the case of the
@@ -71,34 +71,27 @@
#'(let ((l1 $1))
(save-excursion
(and l1 (string= $2 ";") (goto-line l1))
- (evil-ex-range (or l1 (evil-ex-current-line)) $3))))
+ (evil-ex-range l1 $3))))
(line #'evil-ex-range)
("`" marker-name ",`" marker-name
#'(evil-ex-char-marker-range $2 $4)))
(line
- (base (\? offset) search (\? offset)
- #'(let ((tmp (evil-ex-line $1 $2)))
- (save-excursion
- (goto-line tmp)
- (evil-ex-line $3 $4))))
- ((\? base) offset search (\? offset)
+ ((\? base) (\? offset) search (\? offset)
#'(let ((tmp (evil-ex-line $1 $2)))
(save-excursion
(goto-line tmp)
(evil-ex-line $3 $4))))
(base (\? offset) #'evil-ex-line)
- ((\? base) offset #'evil-ex-line))
+ (nil offset #'evil-ex-line))
(base
number
- marker
+ ("'" marker-name #'(evil-ex-marker $2))
search
("\\^" #'(evil-ex-first-line))
("\\$" #'(evil-ex-last-line))
("\\." #'(evil-ex-current-line)))
(offset
(+ signed-number #'+))
- (marker
- ("'" marker-name #'(evil-ex-marker $2)))
;; TODO - handle offset & ;next-pattern search elements
(search
forward
@@ -107,9 +100,9 @@
prev
subst)
(forward
- ("/" "\\(?:[\\].\\|[^/]\\)+" "/\\|$" #'(evil-ex-re-fwd $2)))
+ ("/" "\\(?:\\\\.\\|[^/]\\)+" "/\\|$" #'(evil-ex-re-fwd $2)))
(backward
- ("\\?" "\\(?:[\\].\\|[^?]\\)+" "\\?\\|$" #'(evil-ex-re-bwd $2)))
+ ("?" "\\(?:\\\\.\\|[^?]\\)+" "?\\|$" #'(evil-ex-re-bwd $2)))
(marker-name
"[]\\[-a-zA-Z_<>'}{)(]")
(next
@@ -121,11 +114,11 @@
(signed-number
(sign (\? number) #'evil-ex-signed-number))
(sign
- "\\+\\|-" #'intern)
+ "[+-]" #'intern)
(number
"[0-9]+" #'string-to-number)
(sexp
- "(.*)" #'(car-safe (read-from-string $0))))
+ "(.*)?" #'(car (read-from-string $0))))
"Grammar for Ex.
An association list of syntactic symbols and their definitions.
The first entry is the start symbol. A symbol's definition may
@@ -143,18 +136,15 @@ Given e.g. $4, return 4."
(defmacro evil-parser (grammar &rest entrypoints)
"Construct a parser for GRAMMAR with ENTRYPOINTS.
-The result is a function taking the arguments STRING, SYMBOL and
-SYNTAX, that parses STRING. SYMBOL should be one of ENTRYPOINTS.
+The result is a function taking the arguments SYMBOL and SYNTAX, that
+parses the text after point. SYMBOL should be one of ENTRYPOINTS.
-If the parse succeeds, the return value is a cons cell
-\(RESULT . END), where RESULT is a parse tree and END is the start of
-the remainder of STRING. Otherwise, the return value is nil.
+If parsing succeeds, point is moved to the end of the parsed text and
+a 1-tuple (RESULT) is returned. Otherwise, the return value is nil.
GRAMMAR is an association list of symbols and their definitions.
A definition is a list of production rules, which are tried in
-succession.
-
-A production rule can be one of the following:
+succession. A production rule can be one of the following:
nil matches the empty string.
A regular expression matches a substring.
@@ -203,33 +193,24 @@ The following symbols have reserved meanings within a
grammar:
`\\?', `*', `+', `&', `!', `function', `alt', `seq' and nil."
(cl-labels
;; Return code for parsing PRODUCTION.
- ;; Assumes the variable POS stores the current offset into
- ;; STRING.
((compile
(production)
(pcase production
- ((or 'nil "") '(cons (when syntax "") pos)) ; Epsilon
+ ('nil '(list (when syntax (point)))) ; Epsilon
((and (pred stringp) regexp) ; Token
- `(when
- ;; Ignore leading whitespace
- (let ((start (string-match-p "[^ \f\t\n\r\v]\\|\\'" string
pos)))
- (equal (string-match ,regexp string start) start))
- (cons (if syntax (substring string pos (match-end 0))
- (match-string 0 string))
- (match-end 0))))
+ `(when (progn
+ (skip-chars-forward " \t\n\r") ; Ignore leading
whitespace
+ (looking-at ,regexp))
+ (goto-char (match-end 0))
+ (list (if syntax (point) (match-string 0)))))
((and (pred symbolp) symbol) ; Symbol
- `(let ((pair (,symbol string pos syntax)))
- (and syntax pair
- (setcar
- pair
- (let ((result (car pair)))
- (cons ',symbol
- (if (listp result) result (list result))))))
- pair))
+ `(let ((result (,symbol syntax)))
+ (and syntax result (push ',symbol (car result)))
+ result))
(`(function ,fun) ; Function
- `(let ((pair (funcall #',fun string pos)))
- (and pair syntax (setcar pair (substring string pos (cdr
pair))))
- pair))
+ `(let ((result (funcall #',fun)))
+ (and syntax result (setcar result (point)))
+ result))
;; Positive lookahead
(`(& . ,rule) `(when ,(compile rule) ,(compile nil)))
;; Negative lookahead
@@ -244,44 +225,40 @@ The following symbols have reserved meanings within a
grammar:
(let ((func (unless (eq symbol 'alt) #'list)))
(pcase (when (> (length rules) 1) (car (last rules)))
(`(function ,x) (setq func x
- rules (butlast (copy-sequence rules)))))
- `(let ((pair
+ rules (butlast rules))))
+ `(let ((cell
,(pcase symbol
('+ ; One or more
(when (cdr rules) (error "Too many `+' rules"))
- `(let ((pos pos) result)
- (while (let ((x ,(compile (car rules))))
- (when x
- (push (car x) result)
- (< (setq pos (cdr x)) (length
string)))))
- (when result (cons (nreverse result) pos))))
+ `(cl-loop for x = ,(compile (car rules))
+ while x collect (car x) into result until
(eobp)
+ finally return (when result (list
result))))
('alt `(or ,@(mapcar #'compile rules)))
('seq
(cl-loop
for rule in rules collect
- `(let ((x ,(compile rule)))
- (when x
- (setq pos (cdr x))
- ,(if (memq (car-safe rule) '(& !)) t
- `(push (car x) result))))
+ (macroexp-let2 nil x (compile rule)
+ (if (memq (car-safe rule) '(& !)) x
+ `(when ,x (push (car ,x) result))))
into items finally return
- `(let ((pos pos) result)
- (and ,@items (cons (nreverse result) pos))))))))
+ `(let ((pos (point)) result)
+ (if (and ,@items) (list (nreverse result))
+ (goto-char pos)
+ nil)))))))
;; Semantic action
- ,(when func
- `(when (and pair (not syntax))
- (let ((result (car pair)))
- (ignore result) ; Suppress unused var warning
- (setcar
- pair
- ,(pcase func
- ;; Dollar expression
- ((or (pred evil-parser--dexp) (pred listp))
- (dval func))
- ((pred symbolp)
- `(,(if (eq symbol 'alt) 'list 'cons) #',func
result))
- (_ (error "Invalid semantic action `%S'"
func)))))))
- pair)))))
+ (when (and ',func cell (not syntax))
+ (setcar
+ cell
+ (let ((result (car cell)))
+ (ignore result) ; Suppress unused var warning
+ ,(pcase func
+ ;; Dollar expression
+ ((or (pred evil-parser--dexp) (pred listp))
+ (dval func))
+ ((pred symbolp)
+ `(,(if (eq symbol 'alt) #'list #'cons) #',func
result))
+ (_ (error "Invalid semantic action `%S'" func))))))
+ cell)))))
;; Substitute all dollar-sign symbols in X.
;; Each dollar-sign symbol is replaced with the corresponding
;; element in RESULT, so that $1 becomes the first element, etc.
@@ -290,46 +267,58 @@ The following symbols have reserved meanings within a
grammar:
(x)
(if (listp x) (cons #'list (mapcar #'dval x))
(let ((num (evil-parser--dexp x)))
- (cond ((null num) `(quote ,x))
+ (cond ((null num) `',x)
((eq num 0) 'result)
(t `(nth (1- ,num) result)))))))
- `(lambda (string symbol &optional syntax)
+ `(lambda (symbol &optional syntax)
(cl-labels
- (,@(cl-loop
- for (symbol . def) in (eval grammar t) collect
- `(,symbol (string pos syntax) ,(compile `(alt . ,def))))
+ (,@(cl-loop for (symbol . def) in (eval grammar t) collect
+ `(,symbol (syntax) ,(compile `(alt . ,def))))
(evil-ex-parse-command
- (string pos)
- (let ((result (binding string pos nil)) command end)
- (when result
- (setq command (car result)
- end (cdr result))
- (cond
- ;; check whether the parsed command is followed by a slash,
- ;; dash or number and either the part before is NOT known
to be
- ;; a binding, or the complete string IS known to be a
binding
- ((and (< end (length string))
- (let ((ch (aref string end)))
- (or (memq ch '(?- ?/)) (<= ?0 ch ?9)))
- (or (evil-ex-binding
- (concat command (substring string end)) t)
- (not (evil-ex-binding command t))))
- (emacs-binding string pos nil))
- ;; parse a following "!" as bang only if the
- ;; command has the property :ex-bang t
- ((and (evil-ex-command-force-p command)
- (< end (length string))
- (eq (aref string end) ?!))
- (cons (concat command "!") (1+ end)))
- (t result))))))
+ ()
+ (let* ((result (binding nil))
+ (command (car result)))
+ (cond
+ ((not result) nil)
+ ;; Check whether the parsed command is followed by a slash,
+ ;; dash or number and either the part before is NOT known to
be
+ ;; a binding, or the complete string IS known to be a
binding.
+ ((and (let ((ch (char-after)))
+ (and ch (or (memq ch '(?- ?/)) (<= ?0 ch ?9))))
+ (or (evil-ex-binding
+ (concat command (buffer-substring (point)
(point-max))) t)
+ (not (evil-ex-binding command t))))
+ (backward-char (length command))
+ (emacs-binding nil))
+ ;; Parse a following "!" as bang only if the command
+ ;; has the property :ex-bang t.
+ ((when (eq (char-after) ?!)
+ (let ((binding (evil-ex-completed-binding command t)))
+ (and binding (evil-get-command-property binding
:ex-bang))))
+ (forward-char)
+ (setcar result (concat command "!"))
+ result)
+ (t result)))))
(pcase symbol
- ,@(cl-loop
- for sym in entrypoints collect
- `(',sym (let ((pos 0)) ,(compile sym))))
+ ,@(cl-loop for sym in entrypoints collect `(',sym ,(compile sym)))
(_ (error "Unknown entrypoint `%s'" symbol))))))))
-(defvar evil-ex-echo-overlay nil
- "Overlay used for displaying info messages during Ex.")
+(defvar evil-ex-argument-types nil
+ "Association list of argument handlers.")
+
+(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.")
+
+(define-error 'evil-ex-error "Ex syntax error")
(defun evil-ex-p ()
"Whether Ex is currently active."
@@ -337,15 +326,12 @@ The following symbols have reserved meanings within a
grammar:
(evil-define-command evil-ex (&optional initial-input)
"Enter an Ex command.
-The ex command line is initialized with the value of
-INITIAL-INPUT. If the command is called interactively the initial
-input depends on the current state. If the current state is
-normal state and no count argument is given then the initial
-input is empty. If a prefix count is given the initial input is
-.,.+count. If the current state is visual state then the initial
-input is the visual region '<,'> or `<,`>. If the value of the
-global variable `evil-ex-initial-input' is non-nil, its content
-is appended to the line."
+The Ex command line is initialized with the value of INITIAL-INPUT. If
+the command is called interactively the initial input depends on the
+current state. In Normal state if a prefix count is given then the
+initial input is \".,.+count\", otherwise it is empty. In Visual state
+the initial input is the visual region '<,'> or `<,`>. The variable
+`evil-ex-initial-input', if non-nil, is appended to the line."
:keep-visual t
:repeat abort
(interactive
@@ -364,47 +350,57 @@ is appended to the line."
evil-ex-initial-input)))
(list (unless (string= s "") s))))
(let ((evil-ex-current-buffer (current-buffer))
- (evil-ex-previous-command (unless initial-input
- (car evil-ex-history)))
- evil-ex-argument-handler result)
+ (previous-command (when evil-want-empty-ex-last-command
+ (car evil-ex-history)))
+ evil--ex-expression evil--ex-cmd evil-ex-argument-handler s)
(minibuffer-with-setup-hook
(lambda ()
(evil-ex-setup)
- (when initial-input (evil-ex-update)))
- (setq result
- (read-from-minibuffer
- ":"
- (or initial-input
- (and evil-ex-previous-command
- evil-want-empty-ex-last-command
- (propertize evil-ex-previous-command 'face 'shadow)))
- evil-ex-completion-map
- nil
- 'evil-ex-history
- (when evil-want-empty-ex-last-command evil-ex-previous-command)
- t)))
- (evil-ex-execute result)))
-
-(defun evil-ex-execute (result)
- "Execute RESULT as an ex command on `evil-ex-current-buffer'."
- ;; empty input means repeating the previous command
- (when (and (zerop (length result))
- evil-want-empty-ex-last-command)
- (setq result evil-ex-previous-command))
- ;; parse data
- (evil-ex-update nil nil nil result)
- ;; execute command
- (unless (zerop (length result))
- (eval (or evil-ex-expression (user-error "Ex: syntax error")))))
+ (if initial-input (evil--ex-update)
+ (when previous-command
+ (add-hook 'pre-command-hook #'evil-ex-remove-default nil t))))
+ (setq s (read-from-minibuffer
+ ":"
+ (or initial-input
+ (and previous-command (propertize previous-command 'face
'shadow)))
+ evil-ex-completion-map nil 'evil-ex-history nil t)))
+ (and (string= s "") previous-command (setq s previous-command))
+ (unless (string= s "") (evil-ex-execute s))))
+
+(defun evil-ex-execute (string)
+ "Execute STRING as an Ex command on `evil-ex-current-buffer'."
+ (let ((evil-ex-current-buffer (or evil-ex-current-buffer (current-buffer)))
+ (expr (or evil--ex-expression (evil-ex-parse string)
+ (signal 'evil-ex-error string))))
+ (eval expr t)))
+
+(defun evil-ex-parse (string &optional syntax entrypoint)
+ "Parse STRING as an Ex expression and return an 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'."
+ (let ((parse
+ (lambda ()
+ (let ((result (funcall (evil-parser evil-ex-grammar expression
range)
+ (or entrypoint 'expression) syntax)))
+ (and result
+ ;; Disallow incomplete matches (ignore trailing WS)
+ (not (search-forward "[^ \t\n\r]" nil t))
+ (car result))))))
+ (if (not string) (funcall parse)
+ (with-temp-buffer
+ (insert string)
+ (goto-char (point-min))
+ (funcall parse)))))
(defun evil-ex-delete-backward-char ()
"Close the minibuffer if it is empty.
Otherwise behaves like `delete-backward-char'."
(interactive)
(call-interactively
- (if (zerop (length (minibuffer-contents-no-properties)))
- #'abort-recursive-edit
- #'delete-backward-char)))
+ (if (< (minibuffer-prompt-end) (point-max))
+ #'delete-backward-char
+ #'abort-recursive-edit)))
(defun evil-ex-abort ()
"Cancel Ex state when another buffer is selected."
@@ -412,36 +408,17 @@ Otherwise behaves like `delete-backward-char'."
(memq this-command '(mouse-drag-region choose-completion)))
(abort-recursive-edit)))
-(defun evil-ex-command-window-execute (config result)
- (select-window (active-minibuffer-window) t)
- (set-window-configuration config)
- (delete-minibuffer-contents)
- (insert result)
- (exit-minibuffer))
-
-(defun evil--ex-elisp-p ()
- "Return whether an Elisp expression is being entered on the Ex command line."
- (string-prefix-p "(" (minibuffer-contents-no-properties)))
-
-(defun evil-ex-elisp-completion-at-point ()
- "Complete an `evil-ex' Elisp expression."
- (and (evil--ex-elisp-p)
- (fboundp 'elisp-completion-at-point)
- (elisp-completion-at-point)))
+(define-obsolete-function-alias
+ 'evil-ex-elisp-completion-at-point #'elisp-completion-at-point "1.15.0")
(defun evil-ex-setup ()
"Initialize Ex minibuffer.
This function registers hooks that are used for the interactive
actions during Ex state."
(add-hook 'post-command-hook #'evil-ex-abort)
- (add-hook 'after-change-functions #'evil-ex-update nil t)
+ (add-hook 'after-change-functions #'evil--ex-update nil t)
(add-hook 'minibuffer-exit-hook #'evil-ex-teardown nil t)
- (when evil-ex-previous-command
- (add-hook 'pre-command-hook #'evil-ex-remove-default nil t))
- (set (make-local-variable 'completion-at-point-functions)
- '(evil-ex-elisp-completion-at-point
- evil-ex-command-completion-at-point
- evil-ex-argument-completion-at-point)))
+ (add-hook 'completion-at-point-functions #'evil-ex-completion-at-point nil
t))
(defun evil-ex-teardown ()
"Deinitialize Ex minibuffer.
@@ -450,114 +427,100 @@ Clean up everything set up by `evil-ex-setup'."
(when evil-ex-argument-handler
(let ((runner (evil-ex-argument-handler-runner
evil-ex-argument-handler)))
- (when runner
- (funcall runner 'stop)))))
+ (when runner (funcall runner 'stop)))))
(put 'evil-ex-teardown 'permanent-local-hook t)
-(defun evil-ex-update (&optional beg _end _len string)
+(defsubst evil--ex-bang-p (command)
+ "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)
"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
`after-change-functions'), then an error description is shown
in case of incomplete or unknown commands."
- (let* ((prompt (minibuffer-prompt-end))
- (string (or string (minibuffer-contents-no-properties)))
- arg bang cmd count expr func handler range type)
- (if (and (eq this-command #'self-insert-command)
- (commandp (setq cmd (lookup-key evil-ex-map string))))
- (progn
- (setq evil-ex-expression `(call-interactively #',cmd))
- (when (minibufferp) (exit-minibuffer)))
- (setq cmd nil)
- ;; store the buffer position of each character
- ;; as the `ex-index' text property
- (dotimes (i (length string))
- (put-text-property i (1+ i) 'ex-index (+ i prompt) string))
+ (when (and beg (eq this-command #'self-insert-command))
+ (let ((cmd (lookup-key evil-ex-map (minibuffer-contents-no-properties))))
+ (when (commandp cmd)
+ (setq evil--ex-expression `(call-interactively #',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)
(with-current-buffer evil-ex-current-buffer
- (setq expr (evil-ex-parse string))
- (when (eq (car expr) #'evil-ex-call-command)
- (setq count (eval (nth 1 expr))
- cmd (eval (nth 2 expr))
- arg (eval (nth 3 expr))
- range (cond
- ((evil-range-p count) count)
- ((numberp count) (evil-ex-range count count)))
- bang (when (string-match-p ".!$" cmd) t))))
- (setq evil-ex-expression expr
- evil-ex-range range
- evil-ex-cmd cmd
- evil-ex-bang bang
- evil-ex-argument arg)
- ;; test the current command
- (when (and cmd (minibufferp))
- (setq func (evil-ex-completed-binding cmd t))
- (cond
- ;; update argument-handler
- (func
- (when (setq type (evil-get-command-property func :ex-arg))
- (setq handler (cdr-safe
- (assoc type
- evil-ex-argument-types))))
- (unless (eq handler evil-ex-argument-handler)
- (let ((runner (and evil-ex-argument-handler
- (evil-ex-argument-handler-runner
- evil-ex-argument-handler))))
- (when runner (funcall runner 'stop)))
- (setq evil-ex-argument-handler handler)
- (let ((runner (and evil-ex-argument-handler
- (evil-ex-argument-handler-runner
- evil-ex-argument-handler))))
- (when runner (funcall runner 'start evil-ex-argument))))
- (let ((runner (and evil-ex-argument-handler
- (evil-ex-argument-handler-runner
- evil-ex-argument-handler))))
- (when runner (funcall runner 'update evil-ex-argument))))
- ;; show error message only when called from `after-change-functions'
- (beg
- (let ((prefix (try-completion cmd (evil-ex-completion-table))))
- (cond
- ((stringp prefix) (evil-ex-echo "Incomplete command"))
- ((null prefix) (evil-ex-echo "Unknown command"))))))))))
+ (let* ((range (eval (nth 1 evil--ex-expression) 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-bang (evil--ex-bang-p evil--ex-cmd)
+ evil-ex-argument (eval (nth 3 evil--ex-expression) t))))
+ (cond
+ ((not beg))
+ ;; Test the current command when called from `after-change-functions'
+ ((setq func (evil-ex-completed-binding evil--ex-cmd t))
+ ;; Update argument handler
+ (let ((type (evil-get-command-property func :ex-arg)))
+ (when type (setq handler (cdr (assq type evil-ex-argument-types)))))
+ (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)))
+ (when runner (funcall runner 'stop)))
+ (setq evil-ex-argument-handler handler)
+ (let ((runner (evil-ex-argument-handler-runner handler)))
+ (when runner (funcall runner 'start evil-ex-argument)))))
+ (t (let* ((evil-ex-complete-emacs-commands 'in-turn)
+ (prefix (try-completion evil--ex-cmd
(evil-ex-completion-table))))
+ (cond ((stringp prefix) (evil-ex-echo "Incomplete command"))
+ ((null prefix) (evil-ex-echo "Unknown command")))))))))
(defun evil-ex-echo (string &rest args)
"Display a message after the current Ex command."
- (with-selected-window (minibuffer-window)
- (unless (or evil-no-display (zerop (length string)))
- (let ((string (format " [%s]" (apply #'format string args)))
- (ov (or evil-ex-echo-overlay
- (setq evil-ex-echo-overlay (make-overlay (point-min)
(point-max) nil t t))))
- after-change-functions before-change-functions)
- (put-text-property 0 (length string) 'face 'evil-ex-info string)
- ;; The following "trick" causes point to be shown before the
- ;; message instead of behind. It is shamelessly stolen from
- ;; the implementation of `minibuffer-message'.
- (put-text-property 0 1 'cursor t string)
- (move-overlay ov (point-max) (point-max))
- (overlay-put ov 'after-string string)
- (add-hook 'pre-command-hook #'evil--ex-remove-echo-overlay nil t)))))
-
-(defun evil--ex-remove-echo-overlay ()
- "Remove echo overlay from Ex minibuffer."
- (when evil-ex-echo-overlay
- (delete-overlay evil-ex-echo-overlay)
- (setq evil-ex-echo-overlay nil))
- (remove-hook 'pre-command-hook #'evil--ex-remove-echo-overlay t))
-
-(defun evil-ex-completion ()
- "Complete the current Ex command or argument."
- (interactive)
- (let (after-change-functions)
- (evil-ex-update)
- (completion-at-point)
- (remove-list-of-text-properties
- (minibuffer-prompt-end) (point-max) '(face evil))))
-
-(defun evil-ex-command-completion-at-point ()
- (let ((beg (if evil-ex-cmd
- (get-text-property 0 'ex-index evil-ex-cmd)
- (point)))
- (end (point)))
- (list beg end (evil-ex-completion-table) :exclusive 'no)))
+ (unless (or evil-no-display (string= string ""))
+ (let ((message (concat " [" (apply #'format string args) "]")))
+ (add-face-text-property 1 (length message) 'evil-ex-info nil message)
+ (minibuffer-message message))))
+
+(define-obsolete-function-alias 'evil-ex-completion #'completion-at-point
"1.15.0")
+
+(cl-defun evil-ex-completion-at-point ()
+ "Function used for `completion-at-point-functions' in Ex state."
+ (cl-flet ((fix-beg (b) (min (save-excursion
+ (+ (goto-char b) (skip-chars-forward "
\t\n\r")))
+ (point))))
+ (pcase (nreverse (evil--ex-syntactic-context))
+ ((or (and 'nil (let beg (minibuffer-prompt-end)))
+ `((expression) (command . ,beg) . ,_)
+ (and `((expression) (line) . ,_)
+ (guard (looking-at-p "[ \t\n\r]*\\'"))
+ (let beg (point))))
+ (list (fix-beg beg) (point) (evil-ex-completion-table)))
+ (`((expression) (argument . ,beg))
+ (setq beg (fix-beg beg))
+ ;; If it's an autoload, load the function; this allows external
+ ;; packages to register autoloaded Ex commands which will be
+ ;; loaded when ex argument completion is triggered.
+ (let ((binding (evil-ex-binding evil--ex-cmd t))) (autoload-do-load
binding))
+
+ (let* ((binding (evil-ex-completed-binding evil--ex-cmd))
+ (arg-type (evil-get-command-property binding :ex-arg))
+ (arg-handler (cdr (assq arg-type evil-ex-argument-types))))
+ (pcase (evil-ex-argument-handler-completer arg-handler)
+ (`(collection . ,table) (list beg (point-max) table))
+ (`(completion-at-point . ,completer)
+ (save-restriction (narrow-to-region beg (point-max))
+ (funcall completer))))))
+ (`((expression) (sexp . ,_))
+ (when (fboundp 'elisp-completion-at-point)
(elisp-completion-at-point))))))
+
+(define-obsolete-function-alias
+ 'evil-ex-command-completion-at-point #'evil-ex-completion-at-point "1.15.0")
(defun evil-ex-completion-table ()
(let ((ex-cmds
@@ -567,19 +530,16 @@ in case of incomplete or unknown commands."
;; Append ! to all commands that may take a bang argument
when (evil-get-command-property fun :ex-bang)
collect (concat cmd "!")))
- (emacs-cmds
- (lambda (str pred action)
- (completion-table-with-predicate
- obarray #'commandp t str pred action))))
- (when (eq evil-ex-complete-emacs-commands t)
- (setq ex-cmds
- (mapcar (lambda (str) (propertize str 'face 'evil-ex-commands))
- ex-cmds)))
+ (emacs-cmds (lambda (str pred action)
+ (completion-table-with-predicate
+ obarray #'commandp t str pred action))))
(cond
((null evil-ex-complete-emacs-commands) ex-cmds)
((eq evil-ex-complete-emacs-commands 'in-turn)
(completion-table-in-turn ex-cmds emacs-cmds))
- (t (evil-completion-table-concat ex-cmds emacs-cmds)))))
+ (t (cl-loop for s in-ref ex-cmds do
+ (setf s (propertize s 'face 'evil-ex-commands)))
+ (evil-completion-table-concat ex-cmds emacs-cmds)))))
(defun evil-completion-table-concat (table1 table2)
(lambda (string pred action)
@@ -605,65 +565,26 @@ in case of incomplete or unknown commands."
(defun evil-ex-sort-completions (completions)
(sort completions
- #'(lambda (str1 str2)
- (let ((p1 (eq 'evil-ex-commands (get-text-property 0 'face str1)))
- (p2 (eq 'evil-ex-commands (get-text-property 0 'face str2))))
- (if (equal p1 p2)
- (string< str1 str2)
- p1)))))
-
-(defun evil-ex-command-collection (string predicate action)
- (declare (obsolete evil-ex-completion-table "1.15.0"))
- (let* (evil-ex-complete-emacs-commands
- (commands (evil-ex-completion-table)))
- (cond
- ((eq action nil) (try-completion string commands predicate))
- ((eq action t) (all-completions string commands predicate))
- ((eq action 'lambda) (test-completion string commands))
- ((eq (car-safe action) 'boundaries)
- `(boundaries 0 . ,(length (cdr action)))))))
-
-(defun evil-ex-argument-completion-at-point ()
- (let ((context (evil-ex-syntactic-context)))
- (when (memq 'argument context)
- ;; if it's an autoload, load the function; this allows external
- ;; packages to register autoloaded ex commands which will be
- ;; loaded when ex argument completion is triggered
- (let ((binding-definition (symbol-function (evil-ex-binding
evil-ex-cmd))))
- (when (autoloadp binding-definition)
- (autoload-do-load binding-definition)))
-
- (let* ((beg (or (and evil-ex-argument
- (get-text-property 0 'ex-index evil-ex-argument))
- (point)))
- (end (1+ (or (and evil-ex-argument
- (get-text-property (1- (length
evil-ex-argument))
- 'ex-index evil-ex-argument))
- (1- (point)))))
- (binding (evil-ex-completed-binding evil-ex-cmd))
- (arg-type (evil-get-command-property binding :ex-arg))
- (arg-handler (assoc arg-type evil-ex-argument-types))
- (completer (when arg-handler
- (evil-ex-argument-handler-completer
- (cdr arg-handler)))))
- (when completer
- (if (eq (car completer) 'collection)
- (list beg end (cdr completer))
- (save-restriction
- (narrow-to-region beg (point-max))
- (funcall (cdr completer)))))))))
+ (lambda (str1 str2)
+ (let ((p1 (eq (get-text-property 0 'face str1) 'evil-ex-commands))
+ (p2 (eq (get-text-property 0 'face str2) 'evil-ex-commands)))
+ (if (eq p1 p2) (string< str1 str2) p1)))))
+
+(defalias 'evil-ex-argument-completion-at-point #'ignore)
+(make-obsolete
+ 'evil-ex-argument-completion-at-point #'evil-ex-completion-at-point "1.15.0")
(defun evil-ex-define-cmd (cmd function)
"Bind the function FUNCTION to the command CMD."
- (if (string-match "^[^][]*\\(\\[\\(.*\\)\\]\\)[^][]*$" cmd)
- (let ((abbrev (replace-match "" nil t cmd 1))
- (full (replace-match "\\2" nil nil cmd 1)))
+ (if (string-match "\\[\\(.*\\)\\]" cmd)
+ (let ((abbrev (replace-match "" nil t cmd))
+ (full (replace-match "\\1" nil nil cmd)))
(evil--add-to-alist evil-ex-commands
full function
abbrev full))
(evil--add-to-alist evil-ex-commands cmd function)))
-(defun evil-ex-make-argument-handler (runner completer)
+(defsubst evil-ex-make-argument-handler (runner completer)
(list runner completer))
(defun evil-ex-argument-handler-runner (arg-handler)
@@ -674,8 +595,8 @@ in case of incomplete or unknown commands."
(defmacro evil-ex-define-argument-type (arg-type doc &rest body)
"Define a new handler for argument-type ARG-TYPE.
-DOC is the documentation string. It is followed by a list of
-keywords and function:
+DOC is the documentation string. It is followed by a list of keywords
+and function:
:collection COLLECTION
@@ -683,25 +604,23 @@ keywords and function:
:completion-at-point FUNC
- Function to be called to initialize a potential
- completion. FUNC must match the requirements as described for
- the variable `completion-at-point-functions'. When FUNC is
- called the minibuffer content is narrowed to exactly match the
- argument.
+ Function to be called to initialize a potential completion. FUNC
+ must match the requirements as described for the variable
+ `completion-at-point-functions'. When FUNC is called the minibuffer
+ content is narrowed to exactly match the argument.
:runner FUNC
- Function to be called when the type of the current argument
- changes or when the content of this argument changes. This
- function should take one obligatory argument FLAG followed by
- an optional argument ARG. FLAG is one of three symbol 'start,
- 'stop or 'update. When the argument type is recognized for the
- first time and this handler is started the FLAG is 'start. If
- the argument type changes to something else or ex state
- finished the handler FLAG is 'stop. If the content of the
- argument has changed FLAG is 'update. If FLAG is either 'start
- or 'update then ARG is the current value of this argument. If
- FLAG is 'stop then arg is nil."
+ Function to be called when the type of the current argument changes
+ or when the content of this argument changes. This function should
+ take one obligatory argument FLAG followed by an optional argument
+ ARG. FLAG is one of three symbol `start', `stop' or `update'. When
+ the argument type is recognized for the first time and this handler
+ is started the FLAG is `start'. If the argument type changes to
+ something else or ex state finished the handler FLAG is `stop'. If
+ the content of the argument has changed FLAG is `update'. If FLAG is
+ either `start' or `update' then ARG is the current value of this
+ argument. If FLAG is `stop' then arg is nil."
(declare (indent defun)
(doc-string 2)
(debug (&define name
@@ -709,7 +628,7 @@ keywords and function:
[&rest [keywordp function-form]])))
(unless (stringp doc) (push doc body))
(let (runner completer)
- (while (keywordp (car-safe body))
+ (while (keywordp (car body))
(let ((key (pop body))
(func (pop body)))
(cond
@@ -719,9 +638,8 @@ keywords and function:
(setq completer (cons 'collection func)))
((eq key :completion-at-point)
(setq completer (cons 'completion-at-point func))))))
- `(eval-and-compile
- (evil--add-to-alist evil-ex-argument-types
- ',arg-type '(,runner ,completer)))))
+ `(evil--add-to-alist evil-ex-argument-types
+ ',arg-type '(,runner ,completer))))
(evil-ex-define-argument-type file
"Handle a file argument."
@@ -734,23 +652,23 @@ keywords and function:
(declare-function comint-completion-at-point "comint")
(declare-function shell-completion-vars "shell" ())
+(defvar-local evil--ex-shell-argument-initialized nil
+ "This variable is set to t if shell command completion has been initialized.
+See `evil-ex-init-shell-argument-completion'.")
+
(defun evil-ex-init-shell-argument-completion (flag &optional _arg)
"Prepare the current minibuffer for completion of shell commands.
This function must be called from the :runner function of some
argument handler that requires shell completion."
(when (and (eq flag 'start)
- (not evil-ex-shell-argument-initialized))
- (set (make-local-variable 'evil-ex-shell-argument-initialized) t)
+ (not evil--ex-shell-argument-initialized))
+ (setq evil--ex-shell-argument-initialized t)
(require 'shell)
;; Set up Comint for Shell mode, except
;; `comint-completion-at-point' will be called manually.
(let (completion-at-point-functions)
(shell-completion-vars))))
-(define-obsolete-function-alias
- 'evil-ex-shell-command-completion-at-point
- 'comint-completion-at-point "1.2.13")
-
(evil-ex-define-argument-type shell
"Shell argument type, supports completion."
:completion-at-point comint-completion-at-point
@@ -773,16 +691,14 @@ works accordingly."
(defun evil-ex-binding (command &optional noerror)
"Return the final binding of COMMAND."
- (string-match "^\\(.+?\\)\\!?$" command)
- (let ((binding (match-string 1 command)))
+ (let ((binding (if (evil--ex-bang-p command) (substring command 0 -1)
+ command)))
(while (stringp
(setq binding (cdr (assoc binding evil-ex-commands)))))
- (unless binding
- (setq binding (intern-soft command)))
+ (unless binding (setq binding (intern-soft command)))
(if (commandp binding)
(or (command-remapping binding) binding)
- (unless noerror
- (user-error "Unknown command: `%s'" command)))))
+ (unless noerror (user-error "Unknown command: `%s'" command)))))
(defun evil-ex-completed-binding (command &optional noerror)
"Return the final binding of the completion of COMMAND."
@@ -791,7 +707,7 @@ works accordingly."
(or completion command))
noerror)))
-;;; TODO: extensions likes :p :~ <cfile> ...
+;; TODO: extensions like :p :~ <cfile> ...
(defun evil-ex-replace-special-filenames (file-name)
"Replace special symbols in FILE-NAME.
Replaces % by the current file-name,
@@ -833,68 +749,46 @@ This function interprets special file names like # and %."
(when count
(goto-char (point-min))
(forward-line (1- count)))
- (let ((evil-ex-current-buffer (current-buffer))
- (hist evil-ex-history))
- (while hist
- (let ((evil-ex-last-cmd (pop hist)))
- (when evil-ex-last-cmd
- (evil-ex-update nil nil nil evil-ex-last-cmd)
- (let ((binding (evil-ex-binding evil-ex-cmd)))
- (unless (eq binding #'evil-ex-repeat)
- (setq hist nil)
- (eval (or evil-ex-expression
- (user-error "Ex: syntax error"))))))))))
+ (cl-loop
+ with evil-ex-current-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))))))
(defun evil-ex-call-command (range command argument)
"Execute the given command COMMAND."
- (let* ((count (when (numberp range) range))
- (range (when (evil-range-p range) range))
- (bang (when (string-match-p ".!$" command) t))
- (evil-ex-point (point))
- (evil-ex-range
- (or range (and count (evil-ex-range count count))))
- (evil-ex-command (evil-ex-completed-binding command))
- (restore-point (when (evil-get-command-property evil-ex-command
:restore-point)
- (if (evil-visual-state-p)
- (min (point) (or (mark) most-positive-fixnum))
- (point))))
- (evil-ex-bang bang)
- (evil-ex-argument (copy-sequence argument))
+ (let* ((count (when (integerp range) range))
+ (evil-ex-range (if count (evil-ex-range count count) range))
+ (cmd (evil-ex-completed-binding command))
+ (evil-ex-bang (evil--ex-bang-p command))
+ (evil-ex-argument argument)
(evil-this-type (evil-type evil-ex-range))
- (current-prefix-arg count)
- (prefix-arg current-prefix-arg))
- (when (stringp evil-ex-argument)
- (set-text-properties
- 0 (length evil-ex-argument) nil evil-ex-argument))
+ (evil-ex-point (point))
+ (restore-point
+ (and evil-ex-range
+ (evil-get-command-property cmd :restore-point)
+ (if (evil-visual-state-p) evil-visual-beginning evil-ex-point)))
+ (current-prefix-arg count))
(when evil-ex-reverse-range
(setq evil-ex-reverse-range nil)
(unless (y-or-n-p "Backward range given, OK to swap? ")
(user-error "")))
- (let ((buf (current-buffer)))
- (unwind-protect
- (cond
- ((not evil-ex-range)
- (setq this-command evil-ex-command)
- (evil-exit-visual-state)
- (run-hooks 'pre-command-hook)
- (call-interactively evil-ex-command)
- (run-hooks 'post-command-hook))
- (t
- ;; set visual selection to match the region if an explicit
- ;; range has been specified
- (cl-destructuring-bind (beg end &rest)
- (evil-expand-range evil-ex-range t)
- (setq this-command evil-ex-command)
- (run-hooks 'pre-command-hook)
- (set-mark end)
- (goto-char beg)
- (activate-mark)
- (call-interactively evil-ex-command)
- (run-hooks 'post-command-hook)
- (when restore-point (goto-char restore-point)))))
- (when (buffer-live-p buf)
- (with-current-buffer buf
- (deactivate-mark)))))))
+
+ (evil-exit-visual-state)
+ (deactivate-mark)
+ (when evil-ex-range
+ ;; Set region if an explicit range has been specified
+ (cl-destructuring-bind (beg end &rest) (evil-expand-range evil-ex-range
t)
+ (goto-char beg)
+ (set-marker (mark-marker) end)))
+ (setq this-command cmd)
+ (let ((mark-active evil-ex-range))
+ (run-hooks 'pre-command-hook)
+ (call-interactively cmd))
+ (run-hooks 'post-command-hook)
+ (when restore-point (goto-char restore-point))))
(defun evil-ex-line (base &optional offset)
"Return the line number of BASE plus OFFSET."
@@ -919,14 +813,14 @@ This function interprets special file names like # and %."
(defun evil-ex-range (beg-line &optional end-line)
"Return the first and last position of the current range."
- (when (and end-line (< end-line beg-line))
- (setq evil-ex-reverse-range t)
- (evil-swap beg-line end-line))
- (evil-range
- (evil-line-position beg-line)
- (evil-line-position (or end-line beg-line) -1)
- 'line
- :expanded t))
+ (let* ((beg (if beg-line (evil-line-position beg-line)
+ (line-beginning-position)))
+ (end (if end-line (evil-line-position (1+ end-line))
+ (save-excursion (goto-char beg) (line-beginning-position 2)))))
+ (when (< end beg)
+ (setq evil-ex-reverse-range t)
+ (evil-swap beg end))
+ (evil-range beg end 'line :expanded t)))
(defun evil-ex-full-range ()
"Return a range encompassing the whole buffer."
@@ -948,13 +842,13 @@ Signal an error if MARKER is in a different buffer."
(defun evil-ex-char-marker-range (beg end)
(setq beg (evil-get-marker (if (stringp beg) (aref beg 0) beg))
end (evil-get-marker (if (stringp end) (aref end 0) end)))
- (if (and (numberp beg) (numberp end))
- (evil-expand-range
- (evil-range beg end
- (if (evil-visual-state-p)
- (evil-visual-type)
- 'inclusive)))
- (user-error "Ex does not support markers in other files")))
+ (unless (and (numberp beg) (numberp end))
+ (user-error "Ex does not support markers in other files"))
+ (evil-expand-range
+ (evil-range beg end
+ (if (evil-visual-state-p)
+ (evil-visual-type)
+ 'inclusive))))
(declare-function evil-ex-make-search-pattern "evil-search")
@@ -963,17 +857,17 @@ Signal an error if MARKER is in a different buffer."
Return the line number of the match."
(when evil-ex-search-vim-style-regexp
(setq pattern (evil-transform-vim-style-regexp pattern)))
+ (set-text-properties 0 (length pattern) nil pattern)
(setq evil-ex-search-pattern (evil-ex-make-search-pattern pattern)
evil-ex-search-direction 'forward)
(condition-case err
(save-excursion
- (set-text-properties 0 (length pattern) nil pattern)
- (evil-move-end-of-line)
+ (evil-move-beginning-of-line 2)
(when (or (re-search-forward pattern nil t)
(progn
(goto-char (point-min))
(re-search-forward pattern nil t)))
- (line-number-at-pos (1- (match-end 0)))))
+ (line-number-at-pos (match-beginning 0))))
(invalid-regexp
(evil-ex-echo (cadr err))
nil)))
@@ -983,11 +877,11 @@ Return the line number of the match."
Return the line number of the match."
(when evil-ex-search-vim-style-regexp
(setq pattern (evil-transform-vim-style-regexp pattern)))
+ (set-text-properties 0 (length pattern) nil pattern)
(setq evil-ex-search-pattern (evil-ex-make-search-pattern pattern)
evil-ex-search-direction 'backward)
(condition-case err
(save-excursion
- (set-text-properties 0 (length pattern) nil pattern)
(evil-move-beginning-of-line)
(when (or (re-search-backward pattern nil t)
(progn
@@ -1006,52 +900,38 @@ Return the line number of the match."
NUMBER defaults to 1."
(funcall sign (or number 1)))
-;; function `evil-ex-eval' has been superseded by `evil-ex-parse' plus `eval'
-(make-obsolete 'evil-ex-eval 'evil-ex-parse "1.2.14")
-
-(defun evil-ex-parse (string &optional syntax start)
- "Parse STRING as an Ex expression and return an evaluation tree.
-If SYNTAX is non-nil, return a syntax tree instead.
-START is the start symbol, which defaults to `expression'."
- (let ((result (funcall
- (evil-parser evil-ex-grammar expression range)
- string (or start 'expression) syntax)))
- (and result
- ;; Disallow incomplete matches (ignore trailing WS)
- (not (string-match-p "[^ \f\t\n\r\v]" string (cdr result)))
- (car result))))
-
(defun evil-ex-command-force-p (command)
"Whether COMMAND accepts the bang argument."
+ (declare (obsolete evil-get-command-property "1.15.0"))
(let ((binding (evil-ex-completed-binding command t)))
(when binding
(evil-get-command-property binding :ex-bang))))
-(defun evil-ex-syntactic-context (&optional pos)
- "Return the syntactical context of the character at POS.
+(cl-defun evil--ex-syntactic-context
+ (&optional (pos (point))
+ (tree (save-excursion (goto-char (minibuffer-prompt-end))
+ (evil-ex-parse nil t)))
+ &aux i result)
+ "Return the syntactical context in TREE of the character at POS.
POS defaults to the current position of point."
- (setq pos (max (- (or pos (point)) (minibuffer-prompt-end)) 0))
- (let* ((tree (evil-ex-parse (minibuffer-contents-no-properties) t))
- (i 0) j result)
- ;; Iterate over syntax tree leaves (i.e. the strings), and return
- ;; the path to the leaf containing the cursor. Or, if not found,
- ;; e.g. because of trailing whitespace, the last leaf allowed to
- ;; be one past the rightmost non-empty string.
- (cl-labels
- ((traverse
- (tree path)
- (when (symbolp (car tree)) (setq path (cons (pop tree) path)))
- (dolist (child tree)
- (if (not (stringp child))
- (traverse child path)
- (setq i (+ i (length child)))
- (when (cond ((>= i pos) (throw 'done path))
- ((null result) (setq j i))
- ((>= i j) (setq j (1+ j))))
- (setq result path))))))
- (catch 'done
- (traverse tree nil)
- result))))
+ ;; Iterate over syntax tree leaves (i.e. the strings), and return
+ ;; the path to the leaf containing the cursor. Or, if not found,
+ ;; e.g. because of trailing whitespace, the leaf at most one char
+ ;; past the rightmost non-empty string.
+ (cl-labels
+ ((traverse
+ (node path)
+ (while (and (consp node) (symbolp (car node)))
+ (push (cons (pop node) i) path))
+ (if (listp node)
+ (dolist (child node) (traverse child path))
+ ;; NODE is the end position of a parsed string
+ (when (>= node pos) (cl-return-from evil--ex-syntactic-context path))
+ (when (or (null result) (> node i))
+ (setq i node
+ result path)))))
+ (traverse tree ()))
+ result)
(provide 'evil-ex)
diff --git a/evil-maps.el b/evil-maps.el
index 81b2790b48..678ebfd80d 100644
--- a/evil-maps.el
+++ b/evil-maps.el
@@ -609,17 +609,16 @@ included in `evil-insert-state-bindings' by default."
;; ex command line
(define-key evil-ex-completion-map "\d" #'evil-ex-delete-backward-char)
-(define-key evil-ex-completion-map "\t" #'evil-ex-completion)
-(define-key evil-ex-completion-map [tab] #'evil-ex-completion)
-(define-key evil-ex-completion-map [remap completion-at-point]
#'evil-ex-completion)
-(define-key evil-ex-completion-map "\C-a" 'evil-ex-completion)
+(define-key evil-ex-completion-map "\t" 'completion-at-point)
+(define-key evil-ex-completion-map [tab] 'completion-at-point)
+(define-key evil-ex-completion-map "\C-a" 'completion-at-point)
(define-key evil-ex-completion-map "\C-b" 'move-beginning-of-line)
(define-key evil-ex-completion-map "\C-c" 'abort-recursive-edit)
-(define-key evil-ex-completion-map "\C-d" 'evil-ex-completion)
+(define-key evil-ex-completion-map "\C-d" 'completion-at-point)
(define-key evil-ex-completion-map "\C-f" 'evil-ex-command-window)
(define-key evil-ex-completion-map "\C-g" 'abort-recursive-edit)
(define-key evil-ex-completion-map "\C-k" 'evil-insert-digraph)
-(define-key evil-ex-completion-map "\C-l" 'evil-ex-completion)
+(define-key evil-ex-completion-map "\C-l" 'completion-at-point)
(define-key evil-ex-completion-map "\C-p" #'previous-complete-history-element)
(define-key evil-ex-completion-map "\C-r" 'evil-paste-from-register)
(define-key evil-ex-completion-map "\C-n" #'next-complete-history-element)
diff --git a/evil-tests.el b/evil-tests.el
index a6c76bce10..9d8e42e170 100644
--- a/evil-tests.el
+++ b/evil-tests.el
@@ -7513,12 +7513,12 @@ golf h[o]>tel")))
(string-to-number "1"))))))
(save-excursion
(and l1 (string= "," ";") (goto-line l1))
- (evil-ex-range (or l1 (evil-ex-current-line))
- (evil-ex-line
- nil
- (+ (evil-ex-signed-number
- (intern "+")
- (string-to-number "2")))))))
+ (evil-ex-range
+ l1 (evil-ex-line
+ nil
+ (+ (evil-ex-signed-number
+ (intern "+")
+ (string-to-number "2")))))))
"t"
"-1"))))
@@ -7531,8 +7531,7 @@ golf h[o]>tel")))
`(let ((l1 ,(when a `(evil-ex-line ,@a))))
(save-excursion
(and l1 (string= ,(if relative ";" ",") ";") (goto-line l1))
- (evil-ex-range (or l1 (evil-ex-current-line))
- ,(when b `(evil-ex-line ,@b)))))))
+ (evil-ex-range l1 ,(when b `(evil-ex-line ,@b)))))))
(should (equal (evil-ex-parse "%" nil 'range)
'(evil-ex-full-range)))
(should (equal (evil-ex-parse "*" nil 'range)
@@ -8974,44 +8973,51 @@ parameter set."
(ert-deftest evil-test-parser ()
"Test `evil-parser'"
- (cl-flet ((parse
- (evil-parser
- '((number "[0-9]+" #'string-to-number)
- (plus "\\+" #'intern)
- (minus "-" #'intern)
- (operator
- plus
- minus)
- (sign (\? operator))
- (signed-number (sign number))
- (expr
- ("foo" (& "bar"))
- ("xxx" (! "yyy"))
- (number operator number))
- (epsilon nil))
- expr operator plus signed-number number epsilon)))
- (ert-info ("Nothing")
- (should (equal (parse "1+2" 'epsilon) '(nil . 0))))
- (ert-info ("Symbols")
- (should (equal (parse "+" 'plus) '((intern "+") . 1)))
- (should (equal (parse "+" 'operator) '((intern "+") . 1))))
- (ert-info ("Leading whitespace")
- (should (equal (parse " 1" 'number) '((string-to-number "1") . 2))))
- (ert-info ("Syntax tree")
- (should (equal (parse "1" 'signed-number t)
- '((signed-number (sign "") (number "1")) . 1))))
- (ert-info ("Lookahead")
- (should (equal (parse "foobar" 'expr) '((list "foo") . 3)))
- (should (equal (parse "foobaz" 'expr) nil))
- (should (equal (parse "xxxyyy" 'expr) nil))
- (should (equal (parse "xxxzzz" 'expr) '((list "xxx") . 3))))
- (ert-info ("Semantic actions")
- (should (equal (parse "1+1" 'expr)
- '((list
- (string-to-number "1")
- (intern "+")
- (string-to-number "1"))
- . 3))))))
+ (with-temp-buffer
+ (cl-flet
+ ((parse
+ (s &rest args)
+ (erase-buffer)
+ (insert s)
+ (goto-char (point-min))
+ (apply
+ (evil-parser
+ '((number "[0-9]+" #'string-to-number)
+ (plus "\\+" #'intern)
+ (minus "-" #'intern)
+ (operator
+ plus
+ minus)
+ (sign (\? operator))
+ (signed-number (sign number))
+ (expr
+ ("foo" (& "bar"))
+ ("xxx" (! "yyy"))
+ (number operator number))
+ (epsilon nil))
+ expr operator plus signed-number number epsilon)
+ args)))
+ (ert-info ("Nothing")
+ (should (equal (parse "1+2" 'epsilon) '(nil))))
+ (ert-info ("Symbols")
+ (should (equal (parse "+" 'plus) '((intern "+"))))
+ (should (equal (parse "+" 'operator) '((intern "+")))))
+ (ert-info ("Leading whitespace")
+ (should (equal (parse " 1" 'number) '((string-to-number "1")))))
+ (ert-info ("Syntax tree")
+ (should (equal (parse "1" 'signed-number t)
+ '((signed-number (sign . 1) (number . 2))))))
+ (ert-info ("Lookahead")
+ (should (equal (parse "foobar" 'expr) '((list "foo"))))
+ (should (equal (parse "foobaz" 'expr) nil))
+ (should (equal (parse "xxxyyy" 'expr) nil))
+ (should (equal (parse "xxxzzz" 'expr) '((list "xxx")))))
+ (ert-info ("Semantic actions")
+ (should (equal (parse "1+1" 'expr)
+ '((list
+ (string-to-number "1")
+ (intern "+")
+ (string-to-number "1")))))))))
(ert-deftest evil-test-delimited-arguments ()
"Test `evil-delimited-arguments'"
diff --git a/evil-vars.el b/evil-vars.el
index 2d8532a165..3b3a3d0c48 100644
--- a/evil-vars.el
+++ b/evil-vars.el
@@ -1900,13 +1900,9 @@ Key sequences bound in this map are immediately
executed.")
"Completion keymap for Ex.")
(defvar evil-ex-initial-input nil
- "Additional initial content of the ex command line.
-This content of this variable is appended to the ex command line
-if ex is started interactively.")
-
-(defvar evil-ex-shell-argument-initialized nil
- "This variable is set to t if shell command completion has been initialized.
-See `evil-ex-init-shell-argument-completion'.")
+ "Additional initial content of the Ex command line.
+This content of this variable is appended to the Ex command line
+when Ex is started interactively.")
(defvar evil-ex-commands nil
"Association list of command bindings and functions.")
@@ -1917,23 +1913,8 @@ See `evil-ex-init-shell-argument-completion'.")
(defvar evil-ex-current-buffer nil
"The buffer from which Ex was started.")
-(defvar evil-ex-expression nil
- "The evaluation tree.")
-
-(defvar evil-ex-reverse-range nil
- "Whether the current ex range was entered reversed.")
-
-(defvar evil-ex-command nil
- "The current Ex command.")
-
-(defvar evil-ex-previous-command nil
- "The previously executed Ex command.")
-
-(defvar evil-ex-cmd nil
- "The current Ex command string.")
-
(defvar evil-ex-point nil
- "The position of `point' when the ex command has been called.")
+ "The point position when the Ex command was called.")
(defvar evil-ex-range nil
"The current range of the Ex command.")
@@ -1944,12 +1925,6 @@ See `evil-ex-init-shell-argument-completion'.")
(defvar evil-ex-argument nil
"The current argument of the Ex command.")
-(defvar evil-ex-argument-handler nil
- "The argument handler for the current Ex command.")
-
-(defvar evil-ex-argument-types nil
- "Association list of argument handlers.")
-
(defvar evil-previous-shell-command nil
"The last shell command.")
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [nongnu] elpa/evil f84d3453b3: Read Ex commands from buffer,
ELPA Syncer <=