about summary refs log tree commit diff
path: root/configs/shared/emacs/.emacs.d/elpa/evil-20180912.957/evil-ex.el
diff options
context:
space:
mode:
Diffstat (limited to 'configs/shared/emacs/.emacs.d/elpa/evil-20180912.957/evil-ex.el')
-rw-r--r--configs/shared/emacs/.emacs.d/elpa/evil-20180912.957/evil-ex.el1169
1 files changed, 1169 insertions, 0 deletions
diff --git a/configs/shared/emacs/.emacs.d/elpa/evil-20180912.957/evil-ex.el b/configs/shared/emacs/.emacs.d/elpa/evil-20180912.957/evil-ex.el
new file mode 100644
index 000000000000..e7e5e5ab3b48
--- /dev/null
+++ b/configs/shared/emacs/.emacs.d/elpa/evil-20180912.957/evil-ex.el
@@ -0,0 +1,1169 @@
+;;; evil-ex.el --- Ex-mode
+
+;; Author: Frank Fischer <frank fischer at mathematik.tu-chemnitz.de>
+;; Maintainer: Vegard Øye <vegard_oye at hotmail.com>
+
+;; Version: 1.2.13
+
+;;
+;; 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 <http://www.gnu.org/licenses/>.
+
+;;; 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-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.
+
+(require 'evil-common)
+(require 'evil-states)
+(require 'shell)
+
+;;; Code:
+
+(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:]-]+")
+    (bang
+     (\? (! space) "!" #'$1))
+    (argument
+     ((\? space) (\? "\\(?:.\\|\n\\)+") #'$2))
+    (range
+     ("%" #'(evil-ex-full-range))
+     (line ";" line #'(let ((tmp1 $1))
+                        (save-excursion
+                          (goto-line tmp1)
+                          (evil-ex-range tmp1 $3))))
+     (line "," line #'(evil-ex-range $1 $3))
+     (line #'(evil-ex-range $1 nil))
+     ("`" "[-a-zA-Z_<>']" ",`" "[-a-zA-Z_<>']"
+      #'(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)
+      #'(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))
+    (base
+     number
+     marker
+     search
+     ("\\^" #'(evil-ex-first-line))
+     ("\\$" #'(evil-ex-last-line))
+     ("\\." #'(evil-ex-current-line)))
+    (offset
+     (+ signed-number #'+))
+    (marker
+     ("'" "[-a-zA-Z_<>']" #'(evil-ex-marker $2)))
+    (search
+     forward
+     backward
+     next
+     prev
+     subst)
+    (forward
+     ("/" "\\(?:[\\].\\|[^/,; ]\\)+" (! "/")
+      #'(evil-ex-re-fwd $2))
+     ("/" "\\(?:[\\].\\|[^/]\\)+" "/"
+      #'(evil-ex-re-fwd $2)))
+    (backward
+     ("\\?" "\\(?:[\\].\\|[^?,; ]\\)+" (! "\\?")
+      #'(evil-ex-re-bwd $2))
+     ("\\?" "\\(?:[\\].\\|[^?]\\)+" "\\?"
+      #'(evil-ex-re-bwd $2)))
+    (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)
+    (space
+     "[ ]+")
+    (sexp
+     "(.*)" #'(car-safe (read-from-string $1))))
+  "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.")
+
+(defvar evil-ex-echo-overlay nil
+  "Overlay used for displaying info messages during ex.")
+
+(defun evil-ex-p ()
+  "Whether Ex is currently active."
+  (and evil-ex-current-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. 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."
+  :keep-visual t
+  :repeat abort
+  (interactive
+   (list
+    (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)))
+      (and (> (length s) 0) s))))
+  (let ((evil-ex-current-buffer (current-buffer))
+        (evil-ex-previous-command (unless initial-input
+                                    (car-safe evil-ex-history)))
+        evil-ex-argument-handler
+        evil-ex-info-string
+        result)
+    (minibuffer-with-setup-hook
+        (if initial-input #'evil-ex-setup-and-update #'evil-ex-setup)
+      (setq result
+            (read-from-minibuffer
+             ":"
+             (or initial-input
+                 (and evil-ex-previous-command
+                      (propertize evil-ex-previous-command 'face 'shadow)))
+             evil-ex-completion-map
+             nil
+             'evil-ex-history
+             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 (zerop (length result))
+    (setq result evil-ex-previous-command))
+  ;; parse data
+  (evil-ex-update nil nil nil result)
+  ;; execute command
+  (unless (zerop (length result))
+    (if evil-ex-expression
+        (eval evil-ex-expression)
+      (user-error "Ex: syntax error"))))
+
+(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)))
+       #'abort-recursive-edit
+     #'delete-backward-char)))
+
+(defun evil-ex-abort ()
+  "Cancel ex state when another buffer is selected."
+  (unless (minibufferp)
+    (abort-recursive-edit)))
+
+(defun evil-ex-setup ()
+  "Initialize Ex minibuffer.
+This function registers several 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 'minibuffer-exit-hook #'evil-ex-teardown nil t)
+  (when evil-ex-previous-command
+    (add-hook 'pre-command-hook #'evil-ex-remove-default))
+  (remove-hook 'minibuffer-setup-hook #'evil-ex-setup)
+  (with-no-warnings
+    (make-variable-buffer-local 'completion-at-point-functions))
+  (setq completion-at-point-functions
+        '(evil-ex-command-completion-at-point
+          evil-ex-argument-completion-at-point)))
+(put 'evil-ex-setup 'permanent-local-hook t)
+
+(defun evil-ex-setup-and-update ()
+  "Initialize Ex minibuffer with `evil-ex-setup', then call `evil-ex-update'."
+  (evil-ex-setup)
+  (evil-ex-update))
+
+(defun evil-ex-teardown ()
+  "Deinitialize Ex minibuffer.
+Clean up everything set up by `evil-ex-setup'."
+  (remove-hook 'post-command-hook #'evil-ex-abort)
+  (remove-hook 'minibuffer-exit-hook #'evil-ex-teardown t)
+  (remove-hook 'after-change-functions #'evil-ex-update t)
+  (when evil-ex-argument-handler
+    (let ((runner (evil-ex-argument-handler-runner
+                   evil-ex-argument-handler)))
+      (when runner
+        (funcall runner 'stop)))))
+(put 'evil-ex-teardown 'permanent-local-hook t)
+
+(defun evil-ex-remove-default ()
+  "Remove the default text shown in the ex minibuffer.
+When ex starts, the previous command is shown enclosed in
+parenthesis. This function removes this text when the first key
+is pressed."
+  (when (and (not (eq this-command 'exit-minibuffer))
+             (/= (minibuffer-prompt-end) (point-max)))
+    (if (eq this-command 'evil-ex-delete-backward-char)
+        (setq this-command 'ignore))
+    (delete-minibuffer-contents))
+  (remove-hook 'pre-command-hook #'evil-ex-remove-default))
+(put 'evil-ex-remove-default 'permanent-local-hook t)
+
+(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 (buffer-substring prompt (point-max))))
+         arg bang cmd count expr func handler range tree type)
+    (cond
+     ((and (eq this-command #'self-insert-command)
+           (commandp (setq cmd (lookup-key evil-ex-map string))))
+      (setq evil-ex-expression `(call-interactively #',cmd))
+      (when (minibufferp)
+        (exit-minibuffer)))
+     (t
+      (setq cmd nil)
+      ;; store the buffer position of each character
+      ;; as the `ex-index' text property
+      (dotimes (i (length string))
+        (add-text-properties
+         i (1+ i) (list 'ex-index (+ i prompt)) string))
+      (with-current-buffer evil-ex-current-buffer
+        (setq tree (evil-ex-parse string t)
+              expr (evil-ex-parse string))
+        (when (eq (car-safe 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 (and (save-match-data (string-match ".!$" cmd)) t))))
+      (setq evil-ex-tree tree
+            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))))
+         (beg
+          ;; show error message only when called from `after-change-functions'
+          (let ((n (length (all-completions cmd (evil-ex-completion-table)))))
+            (cond
+             ((> n 1) (evil-ex-echo "Incomplete command"))
+             ((= n 0) (evil-ex-echo "Unknown command")))))))))))
+(put 'evil-ex-update 'permanent-local-hook t)
+
+(defun evil-ex-echo (string &rest args)
+  "Display a message after the current Ex command."
+  (with-selected-window (minibuffer-window)
+    (with-current-buffer (window-buffer (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 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 ()
+  "Completes the current ex command or argument."
+  (interactive)
+  (let (after-change-functions)
+    (evil-ex-update)
+    (completion-at-point)
+    (remove-text-properties (minibuffer-prompt-end) (point-max) '(face nil evil))))
+
+(defun evil-ex-command-completion-at-point ()
+  (let ((context (evil-ex-syntactic-context (1- (point)))))
+    (when (memq 'command context)
+      (let ((beg (or (get-text-property 0 'ex-index evil-ex-cmd)
+                     (point)))
+            (end (1+ (or (get-text-property (1- (length evil-ex-cmd))
+                                            'ex-index
+                                            evil-ex-cmd)
+                         (1- (point))))))
+        (list beg end (evil-ex-completion-table))))))
+
+(defun evil-ex-completion-table ()
+  (cond
+   ((eq evil-ex-complete-emacs-commands nil)
+    #'evil-ex-command-collection)
+   ((eq evil-ex-complete-emacs-commands 'in-turn)
+    (completion-table-in-turn
+     #'evil-ex-command-collection
+     #'(lambda (str pred flag)
+         (completion-table-with-predicate
+          obarray #'commandp t str pred flag))))
+   (t
+    #'(lambda (str pred flag)
+        (evil-completion-table-concat
+         #'evil-ex-command-collection
+         #'(lambda (str pred flag)
+             (completion-table-with-predicate
+              obarray #'commandp t str pred flag))
+         str pred flag)))))
+
+(defun evil-completion-table-concat (table1 table2 string pred flag)
+  (cond
+   ((eq flag nil)
+    (let ((result1 (try-completion string table1 pred))
+          (result2 (try-completion string table2 pred)))
+      (cond
+       ((null result1) result2)
+       ((null result2) result1)
+       ((and (eq result1 t) (eq result2 t)) t)
+       (t result1))))
+   ((eq flag t)
+    (delete-dups
+     (append (all-completions string table1 pred)
+             (all-completions string table2 pred))))
+   ((eq flag 'lambda)
+    (and (or (eq t (test-completion string table1 pred))
+             (eq t (test-completion string table2 pred)))
+         t))
+   ((eq (car-safe flag) 'boundaries)
+    (or (completion-boundaries string table1 pred (cdr flag))
+        (completion-boundaries string table2 pred (cdr flag))))
+   ((eq flag 'metadata)
+    '(metadata (display-sort-function . evil-ex-sort-completions)))))
+
+(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 (cmd predicate flag)
+  "Called to complete a command."
+  (let (commands)
+    ;; append ! to all commands that may take a bang argument
+    (dolist (cmd (mapcar #'car evil-ex-commands))
+      (push cmd commands)
+      (if (evil-ex-command-force-p cmd)
+          (push (concat cmd "!") commands)))
+    (when (eq evil-ex-complete-emacs-commands t)
+      (setq commands
+            (mapcar #'(lambda (str) (propertize str 'face 'evil-ex-commands))
+                    commands)))
+    (cond
+     ((eq flag nil) (try-completion cmd commands predicate))
+     ((eq flag t) (all-completions cmd commands predicate))
+     ((eq flag 'lambda) (test-completion cmd commands))
+     ((eq (car-safe flag) 'boundaries)
+      `(boundaries 0 . ,(length (cdr flag)))))))
+
+(defun evil-ex-argument-completion-at-point ()
+  (let ((context (evil-ex-syntactic-context (1- (point)))))
+    (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 (and 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)))))))))
+
+(defun evil-ex-define-cmd (cmd function)
+  "Binds the function FUNCTION to the command CMD."
+  (save-match-data
+    (if (string-match "^[^][]*\\(\\[\\(.*\\)\\]\\)[^][]*$" cmd)
+        (let ((abbrev (replace-match "" nil t cmd 1))
+              (full (replace-match "\\2" nil nil cmd 1)))
+          (evil-add-to-alist 'evil-ex-commands full function)
+          (evil-add-to-alist 'evil-ex-commands abbrev full))
+      (evil-add-to-alist 'evil-ex-commands cmd function))))
+
+(defun evil-ex-make-argument-handler (runner completer)
+  (list runner completer))
+
+(defun evil-ex-argument-handler-runner (arg-handler)
+  (car arg-handler))
+
+(defun evil-ex-argument-handler-completer (arg-handler)
+  (cadr arg-handler))
+
+(defmacro evil-ex-define-argument-type (arg-type doc &rest body)
+  "Defines 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)
+           (debug (&define name
+                           [&optional stringp]
+                           [&rest [keywordp function-form]])))
+  (unless (stringp doc) (push doc body))
+  (let (runner completer)
+    (while (keywordp (car-safe 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))))))
+    `(eval-and-compile
+       (evil-add-to-alist
+        'evil-ex-argument-types
+        ',arg-type
+        '(,runner ,completer)))))
+
+(evil-ex-define-argument-type file
+  "Handles 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 shell-completion-vars "shell" ())
+
+(defun evil-ex-init-shell-argument-completion (flag &optional arg)
+  "Prepares 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)
+    (cond
+     ;; Emacs 24
+     ((fboundp 'comint-completion-at-point)
+      (shell-completion-vars))
+     (t
+      (set (make-local-variable 'minibuffer-default-add-function)
+           'minibuffer-default-add-shell-commands)))
+    (setq completion-at-point-functions
+          '(evil-ex-command-completion-at-point
+            evil-ex-argument-completion-at-point))))
+
+(define-obsolete-function-alias
+  'evil-ex-shell-command-completion-at-point
+  'comint-completion-at-point)
+
+(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 (and (< (point-min) (point-max))
+           (= (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)
+  "Returns the final binding of COMMAND."
+  (save-match-data
+    (let ((binding command))
+      (when binding
+        (string-match "^\\(.+?\\)\\!?$" binding)
+        (setq binding (match-string 1 binding))
+        (while (progn
+                 (setq binding (cdr (assoc binding evil-ex-commands)))
+                 (stringp binding)))
+        (unless binding
+          (setq binding (intern command)))
+        (if (commandp binding)
+            ;; check for remaps
+            (or (command-remapping binding) binding)
+          (unless noerror
+            (user-error "Unknown command: `%s'" command)))))))
+
+(defun evil-ex-completed-binding (command &optional noerror)
+  "Returns 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 likes :p :~ <cfile> ...
+(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 ()
+  "Returns 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)))
+
+(defun evil-ex-repeat (count)
+  "Repeats the last ex command."
+  (interactive "P")
+  (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)
+              (if evil-ex-expression
+                  (eval evil-ex-expression)
+                (user-error "Ex: syntax error")))))))))
+
+(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 (and (save-match-data (string-match ".!$" 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))
+         (evil-ex-bang (and bang t))
+         (evil-ex-argument (copy-sequence 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))
+    (let ((buf (current-buffer)))
+      (unwind-protect
+          (cond
+           ((not evil-ex-range)
+            (setq this-command evil-ex-command)
+            (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
+            (let ((ex-range (evil-copy-range evil-ex-range))
+                  beg end)
+              (evil-expand-range ex-range)
+              (setq beg (evil-range-beginning ex-range)
+                    end (evil-range-end ex-range))
+              (evil-sort beg end)
+              (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 (buffer-live-p buf)
+          (with-current-buffer buf
+            (deactivate-mark)))))))
+
+(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 (point)))
+
+(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)
+  "Returns the first and last position of the current range."
+  (evil-range
+   (evil-line-position beg-line)
+   (evil-line-position (or end-line beg-line) -1)
+   'line
+   :expanded t))
+
+(defun evil-ex-full-range ()
+  "Return a range encompassing the whole buffer."
+  (evil-range (point-min) (point-max) '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."
+  (when (stringp marker)
+    (setq marker (aref marker 0)))
+  (setq marker (evil-get-marker 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)
+  (when (stringp beg) (setq beg (aref beg 0)))
+  (when (stringp end) (setq end (aref end 0)))
+  (setq beg (evil-get-marker beg)
+        end (evil-get-marker 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")))
+
+(defun evil-ex-re-fwd (pattern)
+  "Search forward for PATTERN.
+Returns the line number of the match."
+  (condition-case err
+      (save-match-data
+        (save-excursion
+          (set-text-properties 0 (length pattern) nil pattern)
+          (evil-move-end-of-line)
+          (and (re-search-forward pattern nil t)
+               (line-number-at-pos (1- (match-end 0))))))
+    (invalid-regexp
+     (evil-ex-echo (cadr err))
+     nil)))
+
+(defun evil-ex-re-bwd (pattern)
+  "Search backward for PATTERN.
+Returns the line number of the match."
+  (condition-case err
+      (save-match-data
+        (save-excursion
+          (set-text-properties 0 (length pattern) nil pattern)
+          (evil-move-beginning-of-line)
+          (and (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)))
+
+;; 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* ((start (or start (car-safe (car-safe evil-ex-grammar))))
+         (match (evil-parser
+                 string start evil-ex-grammar t syntax)))
+    (car-safe match)))
+
+(defun evil-ex-parse-command (string)
+  "Parse STRING as an Ex binding."
+  (let ((result (evil-parser string 'binding evil-ex-grammar))
+        bang command)
+    (when result
+      (setq command (car-safe result)
+            string (cdr-safe result))
+      ;; check whether the parsed command is followed by a slash or
+      ;; number and the part before it is not a known ex binding
+      (when (and (> (length string) 0)
+                 (string-match-p "^[/[:digit:]]" string)
+                 (not (evil-ex-binding command t)))
+        ;; if this is the case, assume the slash or number and all
+        ;; following symbol characters form an (Emacs-)command
+        (setq result (evil-parser (concat command string)
+                                  'emacs-binding
+                                  evil-ex-grammar)
+              command (car-safe result)
+              string (cdr-safe result)))
+      ;; parse a following "!" as bang only if
+      ;; the command has the property :ex-bang t
+      (when (evil-ex-command-force-p command)
+        (setq result (evil-parser string 'bang evil-ex-grammar)
+              bang (or (car-safe result) "")
+              string (cdr-safe result)
+              command (concat command bang)))
+      (cons command string))))
+
+(defun evil-ex-command-force-p (command)
+  "Whether COMMAND accepts the bang argument."
+  (let ((binding (evil-ex-completed-binding command t)))
+    (when binding
+      (evil-get-command-property binding :ex-bang))))
+
+(defun evil-flatten-syntax-tree (tree)
+  "Find all paths from the root of TREE to its leaves.
+TREE is a syntax tree, i.e., all its leave nodes are strings.
+The `nth' element in the result is the syntactic context
+for the corresponding string index (counted from zero)."
+  (let* ((result nil)
+         (traverse nil)
+         (traverse
+          #'(lambda (tree path)
+              (if (stringp tree)
+                  (dotimes (char (length tree))
+                    (push path result))
+                (let ((path (cons (car tree) path)))
+                  (dolist (subtree (cdr tree))
+                    (funcall traverse subtree path)))))))
+    (funcall traverse tree nil)
+    (nreverse result)))
+
+(defun evil-ex-syntactic-context (&optional pos)
+  "Return the syntactical context of the character at POS.
+POS defaults to the current position of point."
+  (let* ((contexts (evil-flatten-syntax-tree evil-ex-tree))
+         (length (length contexts))
+         (pos (- (or pos (point)) (minibuffer-prompt-end))))
+    (when (>= pos length)
+      (setq pos (1- length)))
+    (when (< pos 0)
+      (setq pos 0))
+    (when contexts
+      (nth pos contexts))))
+
+(defun evil-parser (string symbol grammar &optional greedy syntax)
+  "Parse STRING as a SYMBOL in GRAMMAR.
+If GREEDY is non-nil, the whole of STRING must match.
+If the parse succeeds, the return value is a cons cell
+\(RESULT . TAIL), where RESULT is a parse tree and TAIL is
+the remainder of STRING. Otherwise, the return value is nil.
+
+GRAMMAR is an association list of symbols and their definitions.
+A definition is either a list of production rules, which are
+tried in succession, or a #'-quoted function, which is called
+to parse the input.
+
+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 leave 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."
+  (let ((string (or string ""))
+        func pair result rules tail)
+    (cond
+     ;; epsilon
+     ((member symbol '("" nil))
+      (setq pair (cons (if syntax "" nil) string)))
+     ;; token
+     ((stringp symbol)
+      (save-match-data
+        (when (or (eq (string-match symbol string) 0)
+                  ;; ignore leading whitespace
+                  (and (eq (string-match "^[ \f\t\n\r\v]+" string) 0)
+                       (eq (match-end 0)
+                           (string-match
+                            symbol string (match-end 0)))))
+          (setq result (match-string 0 string)
+                tail (substring string (match-end 0))
+                pair (cons result tail))
+          (when (and syntax pair)
+            (setq result (substring string 0
+                                    (- (length string)
+                                       (length tail))))
+            (setcar pair result)))))
+     ;; symbol
+     ((symbolp symbol)
+      (let ((context symbol))
+        (setq rules (cdr-safe (assq symbol grammar)))
+        (setq pair (evil-parser string `(alt ,@rules)
+                                grammar greedy syntax))
+        (when (and syntax pair)
+          (setq result (car pair))
+          (if (and (listp result) (sequencep (car result)))
+              (setq result `(,symbol ,@result))
+            (setq result `(,symbol ,result)))
+          (setcar pair result))))
+     ;; function
+     ((eq (car-safe symbol) 'function)
+      (setq symbol (cadr symbol)
+            pair (funcall symbol string))
+      (when (and syntax pair)
+        (setq tail (or (cdr pair) "")
+              result (substring string 0
+                                (- (length string)
+                                   (length tail))))
+        (setcar pair result)))
+     ;; list
+     ((listp symbol)
+      (setq rules symbol
+            symbol (car-safe rules))
+      (if (memq symbol '(& ! \? * + alt seq))
+          (setq rules (cdr rules))
+        (setq symbol 'seq))
+      (when (and (memq symbol '(+ alt seq))
+                 (> (length rules) 1))
+        (setq func (car (last rules)))
+        (if (eq (car-safe func) 'function)
+            (setq rules (delq func (copy-sequence rules))
+                  func (cadr func))
+          (setq func nil)))
+      (cond
+       ;; positive lookahead
+       ((eq symbol '&)
+        (when (evil-parser string rules grammar greedy syntax)
+          (setq pair (evil-parser string nil grammar nil syntax))))
+       ;; negative lookahead
+       ((eq symbol '!)
+        (unless (evil-parser string rules grammar greedy syntax)
+          (setq pair (evil-parser string nil grammar nil syntax))))
+       ;; zero or one
+       ((eq symbol '\?)
+        (setq rules (if (> (length rules) 1)
+                        `(alt ,rules nil)
+                      `(alt ,@rules nil))
+              pair (evil-parser string rules grammar greedy syntax)))
+       ;; zero or more
+       ((eq symbol '*)
+        (setq rules `(alt (+ ,@rules) nil)
+              pair (evil-parser string rules grammar greedy syntax)))
+       ;; one or more
+       ((eq symbol '+)
+        (let (current results)
+          (catch 'done
+            (while (setq current (evil-parser
+                                  string rules grammar nil syntax))
+              (setq result (car-safe current)
+                    tail (or (cdr-safe current) "")
+                    results (append results (if syntax result
+                                              (cdr-safe result))))
+              ;; stop if stuck
+              (if (equal string tail)
+                  (throw 'done nil)
+                (setq string tail))))
+          (when results
+            (setq func (or func 'list)
+                  pair (cons results tail)))))
+       ;; alternatives
+       ((eq symbol 'alt)
+        (catch 'done
+          (dolist (rule rules)
+            (when (setq pair (evil-parser
+                              string rule grammar greedy syntax))
+              (throw 'done pair)))))
+       ;; sequence
+       (t
+        (setq func (or func 'list))
+        (let ((last (car-safe (last rules)))
+              current results rule)
+          (catch 'done
+            (while rules
+              (setq rule (pop rules)
+                    current (evil-parser string rule grammar
+                                         (when greedy
+                                           (null rules))
+                                         syntax))
+              (cond
+               ((null current)
+                (setq results nil)
+                (throw 'done nil))
+               (t
+                (setq result (car-safe current)
+                      tail (cdr-safe current))
+                (unless (memq (car-safe rule) '(& !))
+                  (if (and syntax
+                           (or (null result)
+                               (and (listp result)
+                                    (listp rule)
+                                    ;; splice in single-element
+                                    ;; (\? ...) expressions
+                                    (not (and (eq (car-safe rule) '\?)
+                                              (eq (length rule) 2))))))
+                      (setq results (append results result))
+                    (setq results (append results (list result)))))
+                (setq string (or tail ""))))))
+          (when results
+            (setq pair (cons results tail))))))
+      ;; semantic action
+      (when (and pair func (not syntax))
+        (setq result (car pair))
+        (let* ((dexp
+                #'(lambda (obj)
+                    (when (symbolp obj)
+                      (let ((str (symbol-name obj)))
+                        (save-match-data
+                          (when (string-match "\\$\\([0-9]+\\)" str)
+                            (string-to-number (match-string 1 str))))))))
+               ;; traverse a tree for dollar expressions
+               (dval nil)
+               (dval
+                #'(lambda (obj)
+                    (if (listp obj)
+                        (mapcar dval obj)
+                      (let ((num (funcall dexp obj)))
+                        (if num
+                            (if (not (listp result))
+                                result
+                              (if (eq num 0)
+                                  `(list ,@result)
+                                (nth (1- num) result)))
+                          obj))))))
+          (cond
+           ((null func)
+            (setq result nil))
+           ;; lambda function
+           ((eq (car-safe func) 'lambda)
+            (if (memq symbol '(+ seq))
+                (setq result `(funcall ,func ,@result))
+              (setq result `(funcall ,func ,result))))
+           ;; string replacement
+           ((or (stringp func) (stringp (car-safe func)))
+            (let* ((symbol (or (car-safe (cdr-safe func))
+                               (and (boundp 'context) context)
+                               (car-safe (car-safe grammar))))
+                   (string (if (stringp func) func (car-safe func))))
+              (setq result (car-safe (evil-parser string symbol grammar
+                                                  greedy syntax)))))
+           ;; dollar expression
+           ((funcall dexp func)
+            (setq result (funcall dval func)))
+           ;; function call
+           ((listp func)
+            (setq result (funcall dval func)))
+           ;; symbol
+           (t
+            (if (memq symbol '(+ seq))
+                (setq result `(,func ,@result))
+              (setq result `(,func ,result))))))
+        (setcar pair result))))
+    ;; weed out incomplete matches
+    (when pair
+      (if (not greedy) pair
+        (if (null (cdr pair)) pair
+          ;; ignore trailing whitespace
+          (when (save-match-data (string-match "^[ \f\t\n\r\v]*$" (cdr pair)))
+            (unless syntax (setcdr pair nil))
+            pair))))))
+
+(provide 'evil-ex)
+
+;;; evil-ex.el ends here