From 8c4e09dff83847ac7f07bf1da7751e9328006c4d Mon Sep 17 00:00:00 2001 From: Jack Jamison Date: Thu, 30 Jul 2026 20:09:00 -0400 Subject: actual final changes and get rid of junk in lisp dir actually works fine --- .config/emacs/lisp/evil/evil-ex.el | 940 ------------------------------------- 1 file changed, 940 deletions(-) delete mode 100644 .config/emacs/lisp/evil/evil-ex.el (limited to '.config/emacs/lisp/evil/evil-ex.el') diff --git a/.config/emacs/lisp/evil/evil-ex.el b/.config/emacs/lisp/evil/evil-ex.el deleted file mode 100644 index 94edd6e..0000000 --- a/.config/emacs/lisp/evil/evil-ex.el +++ /dev/null @@ -1,940 +0,0 @@ -;;; evil-ex.el --- Ex mode -*- lexical-binding: t; -*- - -;; Author: Frank Fischer -;; Maintainer: Vegard Øye - -;; Version: 1.15.0 - -;; -;; This file is NOT part of GNU Emacs. - -;;; License: - -;; This file is part of Evil. -;; -;; Evil is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. -;; -;; Evil is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with Evil. If not, see . - -;;; Commentary: - -;; Ex is implemented as an extensible minilanguage, whose grammar -;; is stored in `evil-ex-grammar'. Ex commands are defined with -;; `evil-ex-define-cmd', which creates a binding from a string -;; 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-shortcut-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 -;; substitution command (":s/foo/bar"), the handler incrementally -;; highlights matches in the buffer as the substitution is typed. - -;;; Code: - -(require 'evil-common) -(require 'evil-states) - -(declare-function evil-goto-line "evil-commands") - -(eval-when-compile - (defconst evil-ex-grammar - '((expression - (count command argument #'evil-ex-call-command) - ((\? range) command argument #'evil-ex-call-command) - (line #'evil-goto-line) - (sexp #'eval-expression)) - (count - number) - (command #'evil-ex-parse-command) - (binding - "[~&*@<>=:#]+\\|[[:alpha:]_]+\\|!") - (emacs-binding - "[[:alpha:]-][[:alnum:][:punct:]]*") - (argument - ((\? "\\(?:.\\|\n\\)+") #'$1)) - (range - ("%" #'(evil-ex-full-range)) - ("*" #'(evil-ex-last-visual-range)) - ((\? line) "[,;]" (\? line) - #'(let ((l1 $1)) - (save-excursion - (and l1 (string= $2 ";") (goto-line l1)) - (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) - #'(save-excursion - (goto-line (evil-ex-line $1 $2)) - (evil-ex-line $3 $4))) - (base (\? offset) #'evil-ex-line) - (nil offset #'evil-ex-line)) - (base - number - ("'" marker-name #'(evil-ex-marker $2)) - search - ("\\^" #'(evil-ex-first-line)) - ("\\$" #'(evil-ex-last-line)) - ("\\." #'(evil-ex-current-line))) - (offset - (+ signed-number #'+)) - ;; TODO - handle offset & ;next-pattern search elements - (search - forward - backward - next - prev - subst) - (forward - ("/" "\\(?:\\\\.\\|[^/]\\)+" "/\\|$" #'(evil-ex-re-fwd $2))) - (backward - ("?" "\\(?:\\\\.\\|[^?]\\)+" "?\\|$" #'(evil-ex-re-bwd $2))) - (marker-name - "[]\\[-a-zA-Z_<>'}{)(]") - (next - "\\\\/" #'(evil-ex-prev-search)) - (prev - "\\\\\\?" #'(evil-ex-prev-search)) - (subst - "\\\\&" #'(evil-ex-prev-search)) - (signed-number - (sign (\? number) #'evil-ex-signed-number)) - (sign - "[+-]" #'intern) - (number - "[0-9]+" #'string-to-number) - (sexp - "(.*)?" #'(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 -reference other symbols, but the grammar cannot contain -left recursion. See `evil-parser' for a detailed explanation -of the syntax.") - - (defun evil-parser--dexp (obj) - "Parse a numerical dollar-sign symbol. -Given e.g. $4, return 4." - (when (symbolp obj) - (let ((str (symbol-name obj))) - (when (string-match "\\`\\$\\([0-9]+\\)\\'" str) - (string-to-number (match-string 1 str)))))) - - (defmacro evil-parser (grammar &rest entrypoints) - "Construct a parser for GRAMMAR with 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 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: - - nil matches the empty string. - A regular expression matches a substring. - A symbol matches a production for that symbol. - (X Y) matches X followed by Y. - (\\? X) matches zero or one of X. - (* X) matches zero or more of X. - (+ X) matches one or more of X. - (& X) matches X, but does not consume. - (! X) matches anything but X, but does not consume. - -Thus, a simple grammar may look like: - - ((plus \"\\\\+\") ; plus <- \"+\" - (minus \"-\") ; minus <- \"-\" - (operator plus minus)) ; operator <- plus / minus - -All input-consuming rules have a value. A regular expression evaluates -to the text matched, while a list evaluates to a list of values. -The value of a list may be overridden with a semantic action, which is -specified with a #\\='-quoted expression at the end: - - (X Y #\\='foo) - -The value of this rule is the result of calling foo with the values -of X and Y as arguments. Alternatively, the function call may be -specified explicitly: - - (X Y #\\='(foo $1 $2)) - -Here, $1 refers to X and $2 refers to Y. $0 refers to the whole list. -Dollar expressions can also be used directly: - - (X Y #\\='$1) - -This matches X followed by Y, but ignores the value of Y; -the value of the list is the same as the value of X. - -If the SYNTAX argument is non-nil, then all semantic actions -are ignored, and a syntax tree is constructed instead. The -syntax tree obeys the property that all the leaf nodes are -parts of the input string. Thus, by traversing the syntax tree, -one can determine how each character was parsed. - -The following symbols have reserved meanings within a grammar: -`\\?', `*', `+', `&', `!', `function', `alt', `seq' and nil." - (cl-labels - ;; Return code for parsing PRODUCTION. - ((compile - (production) - (pcase production - ('nil '(list (when syntax (point)))) ; Epsilon - ((and (pred stringp) regexp) ; Token - `(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 ((result (,symbol syntax))) - (and syntax result (push ',symbol (car result))) - result)) - (`(function ,fun) ; Function - `(let ((result (funcall #',fun))) - (and syntax result (setcar result (point))) - result)) - ;; Positive lookahead - (`(& . ,rule) `(when ,(compile rule) ,(compile nil))) - ;; Negative lookahead - (`(! . ,rule) `(unless ,(compile rule) ,(compile nil))) - ;; Zero or one - (`(\? . ,(or `(,rule) rule)) (compile `(alt ,rule nil))) - ;; Zero or more - (`(* . ,rules) (compile `(alt (+ ,@rules) nil))) - ;; Lists - ((or `(,(and (or '+ 'alt 'seq) symbol) . ,rules) - (and (pred listp) rules (let symbol 'seq))) - (let ((func (unless (eq symbol 'alt) #'list))) - (pcase (when (> (length rules) 1) (car (last rules))) - (`(function ,x) (setq func x - rules (butlast rules)))) - `(let ((cell - ,(pcase symbol - ('+ ; One or more - (when (cdr rules) (error "Too many `+' rules")) - `(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 - (macroexp-let2 nil x (compile rule) - (if (memq (car-safe rule) '(& !)) x - `(when ,x (push (car ,x) result)))) - into items finally return - `(let ((pos (point)) result) - (if (and ,@items) (list (nreverse result)) - (goto-char pos) - nil))))))) - ;; Semantic action - (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. - ;; The special value $0 is substituted with the whole list RESULT. - (dval - (x) - (if (listp x) (cons #'list (mapcar #'dval x)) - (let ((num (evil-parser--dexp x))) - (cond ((null num) `',x) - ((eq num 0) 'result) - (t `(nth (1- ,num) result))))))) - `(lambda (symbol &optional syntax) - (cl-labels - (,@(cl-loop for (symbol . def) in (eval grammar t) collect - `(,symbol (syntax) ,(compile `(alt . ,def)))) - (evil-ex-parse-command - () - (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 ,(compile sym))) - (_ (error "Unknown entrypoint `%s'" symbol)))))))) - -(defvar evil-ex-argument-types nil - "Association list of argument handlers.") - -(defvar evil-ex-commands nil - "Association list of command bindings and functions.") - -(defvar evil-ex-reverse-range nil - "Whether the current Ex range was entered reversed.") - -(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 () - "Return non-nil if currently in Ex state." - (when evil-ex-original-buffer t)) - -(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. 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 - (let ((s (concat - (cond - ((and (evil-visual-state-p) - evil-ex-visual-char-range - (memq (evil-visual-type) '(inclusive exclusive))) - "`<,`>") - ((evil-visual-state-p) "'<,'>") - (current-prefix-arg - (let ((arg (prefix-numeric-value current-prefix-arg))) - (cond ((< arg 0) (setq arg (1+ arg))) - ((> arg 0) (setq arg (1- arg)))) - (if (= arg 0) "." (format ".,.%+d" arg))))) - evil-ex-initial-input))) - (list (unless (string= s "") s)))) - (let ((buffer (current-buffer)) - (previous-command (when evil-want-empty-ex-last-command - (car evil-ex-history))) - s evil--ex-cmd evil--ex-argument-handler evil--ex-shortcut-command) - (minibuffer-with-setup-hook - (lambda () - (setq-local evil-ex-original-buffer buffer) - (evil-ex-setup) - (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))) - (if evil--ex-shortcut-command - (call-interactively evil--ex-shortcut-command) - (when (string= s "") (setq s previous-command)) - (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 (&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'." - (if string - (with-temp-buffer - (insert string) - (goto-char (point-min)) - (evil-ex-parse nil syntax entrypoint)) - (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))))) - -(defun evil-ex-delete-backward-char () - "Close the minibuffer if it is empty, otherwise call `delete-backward-char'." - (interactive) - (call-interactively - (if (< (minibuffer-prompt-end) (point-max)) - #'delete-backward-char - #'abort-recursive-edit))) - -(cl-defstruct (evil-ex-argument-handler (:type list) (:constructor nil) - (:copier nil) (:predicate nil)) - (runner nil :read-only t) (completer nil :read-only t)) - -(defun evil-ex-setup () - "Initialize Ex minibuffer. -This function registers hooks that are used for the interactive -actions during Ex state." - (add-hook 'after-change-functions #'evil--ex-update nil t) - (add-hook 'minibuffer-exit-hook #'evil-ex-teardown nil t) - (add-hook 'completion-at-point-functions #'evil-ex-completion-at-point nil t)) - -(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 _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 -`after-change-functions'), then an error description is shown -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-shortcut-command cmd) - (exit-minibuffer)))) - - (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 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 expr) t) - evil-ex-bang (evil--ex-bang-p evil--ex-cmd) - evil-ex-argument (eval (nth 3 expr) 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-teardown () - "Deinitialize Ex minibuffer. -Clean up everything set up by `evil-ex-setup'." - (let ((runner (evil-ex-argument-handler-runner evil--ex-argument-handler))) - (when runner (funcall runner 'stop)))) - -(defvar-local evil--ex-echo-overlay nil - "Overlay for displaying info messages during Ex.") - -(defun evil-ex-echo (string &rest args) - "Display a message after the current Ex command." - ;; Differs from minibuffer-message, which see, in that it does not - ;; use sit-for, since it may be called in the middle of a command. - (unless (or evil-no-display (zerop (length string))) - (let ((string (concat " [" (apply #'format string args) "]"))) - (put-text-property 0 1 'cursor t string) ; Place cursor before message - (put-text-property 1 (length string) 'face 'evil-ex-info string) - (with-selected-window (minibuffer-window) - (if evil--ex-echo-overlay - (move-overlay evil--ex-echo-overlay (point-max) (point-max)) - (setq evil--ex-echo-overlay (make-overlay (point-max) (point-max) nil t t))) - (add-hook 'pre-command-hook #'evil--ex-remove-echo-overlay nil t) - (overlay-put evil--ex-echo-overlay 'after-string string))))) - -(defun evil--ex-remove-echo-overlay () - "Remove echo overlay from Ex minibuffer." - (delete-overlay evil--ex-echo-overlay) - (setq evil--ex-echo-overlay nil) - (remove-hook 'pre-command-hook #'evil--ex-remove-echo-overlay t)) - -(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)))))) - -(defun evil-ex-completion-table () - (let ((ex-cmds - (cl-loop - for (cmd . fun) in evil-ex-commands unless (stringp fun) - collect cmd - ;; 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)))) - (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 (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) - (cond - ((null action) - (let (matches) - (dolist (table (list table1 table2) (try-completion string matches)) - (let ((x (try-completion string table pred))) - (when x (push (if (eq x 't) string x) matches)))))) - ((eq action t) - (delete-dups - (append (all-completions string table1 pred) - (all-completions string table2 pred)))) - ((eq action 'lambda) - (when (or (test-completion string table1 pred) - (test-completion string table2 pred)) - t)) - ((eq (car-safe action) 'boundaries) - (or (completion-boundaries string table1 pred (cdr action)) - (completion-boundaries string table2 pred (cdr action)))) - ((eq action 'metadata) - '(metadata (display-sort-function . evil-ex-sort-completions)))))) - -(defun evil-ex-sort-completions (completions) - (sort completions - (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))))) - -(define-obsolete-function-alias 'evil-ex-completion #'completion-at-point "1.15.0") - -(define-obsolete-function-alias - 'evil-ex-command-completion-at-point #'evil-ex-completion-at-point "1.15.0") - -(defalias 'evil-ex-argument-completion-at-point #'ignore) -(make-obsolete - 'evil-ex-argument-completion-at-point #'evil-ex-completion-at-point "1.15.0") - -(define-obsolete-function-alias - 'evil-ex-elisp-completion-at-point #'elisp-completion-at-point "1.15.0") - -(defun evil-ex-define-cmd (cmd function) - "Bind the function FUNCTION to the command CMD." - (if (not (string-match-p "\\[" cmd)) - (evil--add-to-alist evil-ex-commands cmd function) - (string-match "\\(.*\\)\\[\\(.*\\)\\]" cmd) - (let ((mandatory (match-string 1 cmd)) - (optional (match-string 2 cmd))) - (dotimes (n (1+ (length optional))) - (evil--add-to-alist evil-ex-commands - (concat mandatory (substring optional 0 n)) - function))))) - -(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: - -:collection COLLECTION - - A collection for completion as required by `all-completions'. - -: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. - -: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." - (declare (indent defun) - (doc-string 2) - (debug (&define name - [&optional stringp] - [&rest [keywordp function-form]]))) - (unless (stringp doc) (push doc body)) - (let (runner completer) - (while (keywordp (car body)) - (let ((key (pop body)) - (func (pop body))) - (cond - ((eq key :runner) - (setq runner `#',func)) - ((eq key :collection) - (setq completer `(cons 'collection #',func))) - ((eq key :completion-at-point) - (setq completer `(cons 'completion-at-point #',func)))))) - `(evil--add-to-alist evil-ex-argument-types - ',arg-type (list ,runner ,completer)))) - -(evil-ex-define-argument-type file - "Handle a file argument." - :collection read-file-name-internal) - -(evil-ex-define-argument-type buffer - "Called to complete a buffer name argument." - :collection internal-complete-buffer) - -(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)) - (setq evil--ex-shell-argument-initialized t) - (require 'shell) - ;; Set up Comint for Shell mode, except - ;; `comint-completion-at-point' will be called manually. - (shell-completion-vars) - (remove-hook 'completion-at-point-functions #'comint-completion-at-point t))) - -(evil-ex-define-argument-type shell - "Shell argument type, supports completion." - :completion-at-point comint-completion-at-point - :runner evil-ex-init-shell-argument-completion) - -(defun evil-ex-file-or-shell-command-completion-at-point () - (if (eq (char-after (point-min)) ?!) - (save-restriction - (narrow-to-region (1+ (point-min)) (point-max)) - (comint-completion-at-point)) - (list (point-min) (point-max) #'read-file-name-internal))) - -(evil-ex-define-argument-type file-or-shell - "File or shell argument type. -If the current argument starts with a ! the rest of the argument -is considered a shell command, otherwise a file-name. Completion -works accordingly." - :completion-at-point evil-ex-file-or-shell-command-completion-at-point - :runner evil-ex-init-shell-argument-completion) - -(defun evil-ex-binding (command &optional noerror) - "Return the final binding of 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))) - (if (commandp binding) - (or (command-remapping binding) binding) - (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." - (let ((completion (try-completion command evil-ex-commands))) - (evil-ex-binding (if (eq completion t) command - (or completion command)) - noerror))) - -;; TODO: extensions like :p :~ ... -(defun evil-ex-replace-special-filenames (file-name) - "Replace special symbols in FILE-NAME. -Replaces % by the current file-name, -Replaces # by the alternate file-name in FILE-NAME." - (let ((remote (file-remote-p file-name)) - (current-fname (buffer-file-name)) - (alternate-fname (and (other-buffer) - (buffer-file-name (other-buffer))))) - (setq file-name (or (file-remote-p file-name 'localname) file-name)) - (when current-fname - (setq current-fname (or (file-remote-p current-fname 'localname) - current-fname)) - (setq file-name - (replace-regexp-in-string "\\(^\\|[^\\\\]\\)\\(%\\)" - current-fname file-name - t t 2))) - (when alternate-fname - (setq alternate-fname (or (file-remote-p alternate-fname 'localname) - alternate-fname)) - (setq file-name - (replace-regexp-in-string "\\(^\\|[^\\\\]\\)\\(#\\)" - alternate-fname file-name - t t 2))) - (setq file-name - (replace-regexp-in-string "\\\\\\([#%]\\)" - "\\1" file-name t)) - (setq file-name (concat remote file-name))) - file-name) - -(defun evil-ex-file-arg () - "Return the current Ex argument as a file name. -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") - (when count - (goto-char (point-min)) - (forward-line (1- count))) - (cl-loop - with evil-ex-original-buffer = (current-buffer) - for last-cmd in evil-ex-history do - (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." - (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* ((count (when (integerp range) range)) - (current-prefix-arg count) - (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)) - (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))) - (evil-called-from-ex-p t)) - (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." - (+ (or base (line-number-at-pos)) - (or offset 0))) - -(defun evil-ex-first-line () - "Return the line number of the first line." - (line-number-at-pos (point-min))) - -(defun evil-ex-current-line () - "Return the line number of the current line." - (line-number-at-pos)) - -(defun evil-ex-last-line () - "Return the line number of the last line." - (save-excursion - (goto-char (point-max)) - (when (bolp) - (forward-line -1)) - (line-number-at-pos))) - -(defun evil-ex-range (beg-line &optional end-line) - "Return the first and last position of the current range." - (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." - (evil-range (point-min) (point-max) 'line :expanded t)) - -(defun evil-ex-last-visual-range () - "Return a linewise range of the last visual selection." - (evil-range evil-visual-mark evil-visual-point 'line)) - -(defun evil-ex-marker (marker) - "Return MARKER's line number in the current buffer. -Signal an error if MARKER is in a different buffer." - (setq marker (evil-get-marker - (if (stringp marker) (aref marker 0) marker))) - (if (numberp marker) - (line-number-at-pos marker) - (user-error "Ex does not support markers in other files"))) - -(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))) - (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") - -(defun evil-ex-re-fwd (pattern) - "Search forward for PATTERN. -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 - (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 (match-beginning 0)))) - (invalid-regexp - (evil-ex-echo (cadr err)) - nil))) - -(defun evil-ex-re-bwd (pattern) - "Search backward for PATTERN. -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 - (evil-move-beginning-of-line) - (when (or (re-search-backward pattern nil t) - (progn - (goto-char (point-max)) - (re-search-backward pattern nil t))) - (line-number-at-pos (match-beginning 0)))) - (invalid-regexp - (evil-ex-echo (cadr err)) - nil))) - -(defun evil-ex-prev-search () - (error "Previous search not yet implemented")) - -(defun evil-ex-signed-number (sign &optional number) - "Return a signed number like -3 and +1. -NUMBER defaults to 1." - (funcall sign (or number 1))) - -(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)))) - -(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." - ;; 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) - -;;; evil-ex.el ends here -- cgit v1.2.3