diff options
Diffstat (limited to 'configs/shared/emacs/.emacs.d/elpa/evil-20180912.957/evil-search.el')
-rw-r--r-- | configs/shared/emacs/.emacs.d/elpa/evil-20180912.957/evil-search.el | 1294 |
1 files changed, 0 insertions, 1294 deletions
diff --git a/configs/shared/emacs/.emacs.d/elpa/evil-20180912.957/evil-search.el b/configs/shared/emacs/.emacs.d/elpa/evil-20180912.957/evil-search.el deleted file mode 100644 index 896b3b58b2ef..000000000000 --- a/configs/shared/emacs/.emacs.d/elpa/evil-20180912.957/evil-search.el +++ /dev/null @@ -1,1294 +0,0 @@ -;;; evil-search.el --- Search and substitute - -;; Author: Vegard Øye <vegard_oye at hotmail.com> -;; 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/>. - -(require 'evil-core) -(require 'evil-common) -(require 'evil-ex) - -;;; Code: - -(defun evil-select-search-module (option module) - "Change the search module according to MODULE. -If MODULE is `isearch', then Emacs' isearch module is used. -If MODULE is `evil-search', then Evil's own interactive -search module is used." - (let ((search-functions - '(forward - backward - word-forward - word-backward - unbounded-word-forward - unbounded-word-backward - next - previous))) - (dolist (fun search-functions) - (let ((isearch (intern (format "evil-search-%s" fun))) - (evil-search (intern (format "evil-ex-search-%s" fun)))) - (if (eq module 'isearch) - (substitute-key-definition - evil-search isearch evil-motion-state-map) - (substitute-key-definition - isearch evil-search evil-motion-state-map))))) - (set-default option module)) - -;; this customization is here because it requires -;; the knowledge of `evil-select-search-mode' -(defcustom evil-search-module 'isearch - "The search module to be used." - :type '(radio (const :tag "Emacs built-in isearch." :value isearch) - (const :tag "Evil interactive search." :value evil-search)) - :group 'evil - :set 'evil-select-search-module - :initialize 'evil-custom-initialize-pending-reset) - -(defun evil-push-search-history (string forward) - "Push STRING into the appropriate search history (determined by FORWARD)." - (let* ((history-var (if forward - 'evil-search-forward-history - 'evil-search-backward-history)) - (history (symbol-value history-var))) - (unless (equal (car-safe history) string) - (set history-var (cons string history))))) - -(defun evil-search-incrementally (forward regexp-p) - "Search incrementally for user-entered text." - (let ((evil-search-prompt (evil-search-prompt forward)) - (isearch-search-fun-function 'evil-isearch-function) - (point (point)) - search-nonincremental-instead) - (setq isearch-forward forward) - (evil-save-echo-area - (evil-without-input-method-hooks - ;; set the input method locally rather than globally to ensure that - ;; isearch clears the input method when it's finished - (setq current-input-method evil-input-method) - (if forward - (isearch-forward regexp-p) - (isearch-backward regexp-p)) - (evil-push-search-history isearch-string forward) - (setq current-input-method nil)) - (when (/= (point) point) - ;; position the point at beginning of the match only if the call to - ;; `isearch' has really moved the point. `isearch' doesn't move the - ;; point only if "C-g" is hit twice to exit the search, in which case we - ;; shouldn't move the point either. - (when (and forward isearch-other-end) - (goto-char isearch-other-end)) - (when (and (eq point (point)) - (not (string= isearch-string ""))) - (if forward - (isearch-repeat-forward) - (isearch-repeat-backward)) - (isearch-exit) - (when (and forward isearch-other-end) - (goto-char isearch-other-end))) - (evil-flash-search-pattern - (evil-search-message isearch-string forward)))))) - -(defun evil-flash-search-pattern (string &optional all) - "Flash last search matches for duration of `evil-flash-delay'. -If ALL is non-nil, flash all matches. STRING is a message -to display in the echo area." - (let ((lazy-highlight-initial-delay 0) - (isearch-search-fun-function 'evil-isearch-function) - (isearch-case-fold-search case-fold-search) - (disable #'(lambda (&optional arg) (evil-flash-hook t)))) - (when evil-flash-timer - (cancel-timer evil-flash-timer)) - (unless (or (null string) - (string= string "")) - (evil-echo-area-save) - (evil-echo "%s" string) - (isearch-highlight (match-beginning 0) (match-end 0)) - (when all - (setq isearch-lazy-highlight-wrapped nil - isearch-lazy-highlight-start (point) - isearch-lazy-highlight-end (point)) - (isearch-lazy-highlight-new-loop) - (unless isearch-lazy-highlight-overlays - (isearch-lazy-highlight-update))) - (add-hook 'pre-command-hook #'evil-flash-hook nil t) - (add-hook 'evil-operator-state-exit-hook #'evil-flash-hook nil t) - (add-hook 'pre-command-hook #'evil-clean-isearch-overlays nil t) - (setq evil-flash-timer - (run-at-time evil-flash-delay nil disable))))) - -(defun evil-clean-isearch-overlays () - "Clean isearch overlays unless `this-command' is search." - (remove-hook 'pre-command-hook #'evil-clean-isearch-overlays t) - (unless (memq this-command - '(evil-search-backward - evil-search-forward - evil-search-next - evil-search-previous - evil-search-word-backward - evil-search-word-forward)) - (isearch-clean-overlays))) -(put 'evil-clean-isearch-overlays 'permanent-local-hook t) - -(defun evil-flash-hook (&optional force) - "Disable hightlighting if `this-command' is not search. -Disable anyway if FORCE is t." - (when (or force - ;; to avoid flicker, don't disable highlighting - ;; if the next command is also a search command - (not (memq this-command - '(evil-search-backward - evil-search-forward - evil-search-next - evil-search-previous - evil-search-word-backward - evil-search-word-forward)))) - (evil-echo-area-restore) - (isearch-dehighlight) - (setq isearch-lazy-highlight-last-string nil) - (lazy-highlight-cleanup t) - (when evil-flash-timer - (cancel-timer evil-flash-timer))) - (remove-hook 'pre-command-hook #'evil-flash-hook t) - (remove-hook 'evil-operator-state-exit-hook #'evil-flash-hook t)) -(put 'evil-flash-hook 'permanent-local-hook t) - -(defun evil-search-function (&optional forward regexp-p wrap) - "Return a search function. -If FORWARD is nil, search backward, otherwise forward. -If REGEXP-P is non-nil, the input is a regular expression. -If WRAP is non-nil, the search wraps around the top or bottom -of the buffer." - `(lambda (string &optional bound noerror count) - (let ((start (point)) - (search-fun ',(if regexp-p - (if forward - 're-search-forward - 're-search-backward) - (if forward - 'search-forward - 'search-backward))) - result) - (setq result (funcall search-fun string bound - ,(if wrap t 'noerror) count)) - (when (and ,wrap (null result)) - (goto-char ,(if forward '(point-min) '(point-max))) - (unwind-protect - (setq result (funcall search-fun string bound noerror count)) - (unless result - (goto-char start)))) - result))) - -(defun evil-isearch-function () - "Return a search function for use with isearch. -Based on `isearch-regexp' and `isearch-forward'." - (evil-search-function isearch-forward evil-regexp-search evil-search-wrap)) - -(defun evil-search (string forward &optional regexp-p start) - "Search for STRING and highlight matches. -If FORWARD is nil, search backward, otherwise forward. -If REGEXP-P is non-nil, STRING is taken to be a regular expression. -START is the position to search from; if unspecified, it is -one more than the current position." - (when (and (stringp string) - (not (string= string ""))) - (let* ((orig (point)) - (start (or start - (if forward - (min (point-max) (1+ orig)) - orig))) - (isearch-regexp regexp-p) - (isearch-forward forward) - (case-fold-search - (unless (and search-upper-case - (not (isearch-no-upper-case-p string nil))) - case-fold-search)) - (search-func (evil-search-function - forward regexp-p evil-search-wrap))) - ;; no text properties, thank you very much - (set-text-properties 0 (length string) nil string) - ;; position to search from - (goto-char start) - (setq isearch-string string) - (isearch-update-ring string regexp-p) - (condition-case nil - (funcall search-func string) - (search-failed - (goto-char orig) - (user-error "\"%s\": %s not found" - string (if regexp-p "pattern" "string")))) - ;; handle opening and closing of invisible area - (cond - ((boundp 'isearch-filter-predicates) - (dolist (pred isearch-filter-predicates) - (funcall pred (match-beginning 0) (match-end 0)))) - ((boundp 'isearch-filter-predicate) - (funcall isearch-filter-predicate (match-beginning 0) (match-end 0)))) - ;; always position point at the beginning of the match - (goto-char (match-beginning 0)) - ;; determine message for echo area - (cond - ((and forward (< (point) start)) - (setq string "Search wrapped around BOTTOM of buffer")) - ((and (not forward) (> (point) start)) - (setq string "Search wrapped around TOP of buffer")) - (t - (setq string (evil-search-message string forward)))) - (evil-flash-search-pattern string t)))) - -(defun evil-search-word (forward unbounded symbol) - "Search for word near point. -If FORWARD is nil, search backward, otherwise forward. If SYMBOL -is non-nil then the functions searches for the symbol at point, -otherwise for the word at point." - (let ((string (car-safe regexp-search-ring)) - (move (if forward #'forward-char #'backward-char)) - (end (if forward #'eobp #'bobp))) - (setq isearch-forward forward) - (cond - ((and (memq last-command - '(evil-search-word-forward - evil-search-word-backward)) - (stringp string) - (not (string= string ""))) - (evil-search string forward t)) - (t - (setq string (evil-find-thing forward (if symbol 'symbol 'evil-word))) - (cond - ((null string) - (user-error "No word under point")) - (unbounded - (setq string (regexp-quote string))) - (t - (setq string - (format (if symbol "\\_<%s\\_>" "\\<%s\\>") - (regexp-quote string))))) - (evil-push-search-history string forward) - (evil-search string forward t))))) - -(defun evil-find-thing (forward thing) - "Return THING near point as a string. -THING should be a symbol understood by `thing-at-point', -e.g. 'symbol or 'word. If FORWARD is nil, search backward, -otherwise forward. Returns nil if nothing is found." - (let ((move (if forward #'forward-char #'backward-char)) - (end (if forward #'eobp #'bobp)) - string) - (save-excursion - (setq string (thing-at-point thing)) - ;; if there's nothing under point, go forwards - ;; (or backwards) to find it - (while (and (null string) (not (funcall end))) - (funcall move) - (setq string (thing-at-point thing))) - (when (stringp string) - (set-text-properties 0 (length string) nil string)) - (when (> (length string) 0) - string)))) - -(defun evil-find-word (forward) - "Return word near point as a string. -If FORWARD is nil, search backward, otherwise forward. Returns -nil if nothing is found." - (evil-find-thing forward 'word)) - -(defun evil-find-symbol (forward) - "Return word near point as a string. -If FORWARD is nil, search backward, otherwise forward. Returns -nil if nothing is found." - (evil-find-thing forward 'symbol)) - -(defun evil-search-prompt (forward) - "Return the search prompt for the given direction." - (if forward "/" "?")) - -(defun evil-search-message (string forward) - "Prefix STRING with the search prompt." - (format "%s%s" (evil-search-prompt forward) string)) - -(defadvice isearch-message-prefix (around evil activate) - "Use `evil-search-prompt'." - (if evil-search-prompt - (setq ad-return-value evil-search-prompt) - ad-do-it)) - -(defadvice isearch-delete-char (around evil activate) - "Exit search if no search string." - (cond - ((and evil-search-prompt (string= isearch-string "")) - (let (search-nonincremental-instead) - (setq isearch-success nil) - (isearch-exit))) - (t - ad-do-it))) - -(defadvice isearch-lazy-highlight-search (around evil activate) - "Never wrap the search in this context." - (let (evil-search-wrap) - ad-do-it)) - -;;; Ex search - -(defun evil-ex-regex-without-case (re) - "Return the regular expression without all occurrences of \\c and \\C." - (evil-transform-regexp re '((?c . "") (?C . "")))) - -(defun evil-ex-regex-case (re default-case) - "Return the case as implied by \\c or \\C in regular expression RE. -If \\c appears anywhere in the pattern, the pattern is case -insensitive. If \\C appears, the pattern is case sensitive. -Only the first occurrence of \\c or \\C is used, all others are -ignored. If neither \\c nor \\C appears in the pattern, the case -specified by DEFAULT-CASE is used. DEFAULT-CASE should be either -`sensitive', `insensitive' or `smart'. In the latter case, the pattern -will be case-sensitive if and only if it contains an upper-case -letter, otherwise it will be case-insensitive." - (cond - ((string-match "\\(?:^\\|[^\\\\]\\)\\(?:\\\\\\\\\\)*\\\\\\([cC]\\)" re) - (if (eq (aref (match-string 1 re) 0) ?c) 'insensitive 'sensitive)) - ((eq default-case 'smart) - (if (isearch-no-upper-case-p re t) - 'insensitive - 'sensitive)) - (t default-case))) - -;; a pattern -(defun evil-ex-make-substitute-pattern (regexp flags) - "Creates a PATTERN for substitution with FLAGS. -This function respects the values of `evil-ex-substitute-case' -and `evil-ex-substitute-global'." - (evil-ex-make-pattern regexp - (cond - ((memq ?i flags) 'insensitive) - ((memq ?I flags) 'sensitive) - ((not evil-ex-substitute-case) - evil-ex-search-case) - (t evil-ex-substitute-case)) - (or (and evil-ex-substitute-global - (not (memq ?g flags))) - (and (not evil-ex-substitute-global) - (memq ?g flags))))) - -(defun evil-ex-make-search-pattern (regexp) - "Creates a PATTERN for search. -This function respects the values of `evil-ex-search-case'." - (evil-ex-make-pattern regexp evil-ex-search-case t)) - -(defun evil-ex-make-pattern (regexp case whole-line) - "Create a new search pattern. -REGEXP is the regular expression to be searched for. CASE should -be either 'sensitive, 'insensitive for case-sensitive and -case-insensitive search, respectively, or anything else. In the -latter case the pattern is smart-case, i.e. it is automatically -sensitive of the pattern contains one upper case letter, -otherwise it is insensitive. The input REGEXP is considered a -Vim-style regular expression if `evil-ex-search-vim-style-regexp' -is non-nil, in which case it is transformed to an Emacs style -regular expression (i.e. certain backslash-codes are -transformed. Otherwise REGEXP must be an Emacs style regular -expression and is not transformed." - (let ((re (evil-ex-regex-without-case regexp)) - (ignore-case (eq (evil-ex-regex-case regexp case) 'insensitive))) - ;; possibly transform regular expression from vim-style to - ;; Emacs-style. - (if evil-ex-search-vim-style-regexp - (setq re (evil-transform-vim-style-regexp re)) - ;; Even for Emacs regular expressions we translate certain - ;; whitespace sequences - (setq re (evil-transform-regexp re - '((?t . "\t") - (?n . "\n") - (?r . "\r"))))) - (list re ignore-case whole-line))) - -(defun evil-ex-pattern-regex (pattern) - "Return the regular expression of a search PATTERN." - (nth 0 pattern)) - -(defun evil-ex-pattern-ignore-case (pattern) - "Return t if and only if PATTERN should ignore case." - (nth 1 pattern)) - -(defun evil-ex-pattern-whole-line (pattern) - "Return t if and only if PATTERN should match all occurences of a line. -Otherwise PATTERN matches only the first occurence." - (nth 2 pattern)) - -;; Highlight -(defun evil-ex-make-hl (name &rest args) - "Create a new highlight object with name NAME and properties ARGS. -The following properties are supported: -:face The face to be used for the highlighting overlays. -:win The window in which the highlighting should be shown. - Note that the highlight will be visible in all windows showing - the corresponding buffer, but only the matches visible in the - specified window will actually be highlighted. If :win is nil, - the matches in all windows will be highlighted. -:min The minimal buffer position for highlighted matches. -:max The maximal buffer position for highlighted matches. -:match-hook A hook to be called once for each highlight. - The hook must take two arguments, the highlight and - the overlay for that highlight. -:update-hook A hook called once after updating the highlighting - with two arguments, the highlight and a message string - describing the current match status." - (unless (symbolp name) - (user-error "Expected symbol as name of highlight")) - (let ((face 'evil-ex-lazy-highlight) - (win (selected-window)) - min max match-hook update-hook) - (while args - (let ((key (pop args)) - (val (pop args))) - (cond - ((eq key :face) (setq face val)) - ((eq key :win) (setq win val)) - ((eq key :min) (setq min val)) - ((eq key :max) (setq max val)) - ((eq key :match-hook) (setq match-hook val)) - ((eq key :update-hook) (setq update-hook val)) - (t (user-error "Unexpected keyword: %s" key))))) - (when (assoc name evil-ex-active-highlights-alist) - (evil-ex-delete-hl name)) - (when (null evil-ex-active-highlights-alist) - (add-hook 'window-scroll-functions - #'evil-ex-hl-update-highlights-scroll nil t) - (add-hook 'window-size-change-functions - #'evil-ex-hl-update-highlights-resize nil)) - (push (cons name (vector name - nil - face - win - min - max - match-hook - update-hook - nil)) - evil-ex-active-highlights-alist))) - -(defun evil-ex-hl-name (hl) - "Return the name of the highlight HL." - (aref hl 0)) - -(defun evil-ex-hl-pattern (hl) - "Return the pattern of the highlight HL." - (aref hl 1)) - -(defun evil-ex-hl-set-pattern (hl pattern) - "Set the pattern of the highlight HL to PATTERN." - (aset hl 1 pattern)) - -(defun evil-ex-hl-face (hl) - "Return the face of the highlight HL." - (aref hl 2)) - -(defun evil-ex-hl-window (hl) - "Return the window of the highlight HL." - (aref hl 3)) - -(defun evil-ex-hl-min (hl) - "Return the minimal buffer position of the highlight HL." - (aref hl 4)) - -(defun evil-ex-hl-set-min (hl min) - "Set the minimal buffer position of the highlight HL to MIN." - (aset hl 4 min)) - -(defun evil-ex-hl-max (hl) - "Return the maximal buffer position of the highlight HL." - (aref hl 5)) - -(defun evil-ex-hl-set-max (hl max) - "Set the minimal buffer position of the highlight HL to MAX." - (aset hl 5 max)) - -(defun evil-ex-hl-match-hook (hl) - "Return the match-hook of the highlight HL." - (aref hl 6)) - -(defun evil-ex-hl-update-hook (hl) - "Return the update-hook of the highlight HL." - (aref hl 7)) - -(defun evil-ex-hl-overlays (hl) - "Return the list of active overlays of the highlight HL." - (aref hl 8)) - -(defun evil-ex-hl-set-overlays (hl overlays) - "Set the list of active overlays of the highlight HL to OVERLAYS." - (aset hl 8 overlays)) - -(defun evil-ex-delete-hl (name) - "Remove the highlighting object with a certain NAME." - (let ((hl (cdr-safe (assoc name evil-ex-active-highlights-alist)))) - (when hl - (mapc #'delete-overlay (evil-ex-hl-overlays hl)) - (setq evil-ex-active-highlights-alist - (assq-delete-all name evil-ex-active-highlights-alist)) - (evil-ex-hl-update-highlights)) - (when (null evil-ex-active-highlights-alist) - (remove-hook 'window-scroll-functions - #'evil-ex-hl-update-highlights-scroll t) - (remove-hook 'window-size-change-functions - #'evil-ex-hl-update-highlights-resize)))) - -(defun evil-ex-hl-active-p (name) - "Whether the highlight with a certain NAME is active." - (and (assoc name evil-ex-active-highlights-alist) t)) - -(defun evil-ex-hl-change (name pattern) - "Set the regular expression of highlight NAME to PATTERN." - (let ((hl (cdr-safe (assoc name evil-ex-active-highlights-alist)))) - (when hl - (evil-ex-hl-set-pattern hl - (if (zerop (length pattern)) - nil - pattern)) - (evil-ex-hl-idle-update)))) - -(defun evil-ex-hl-set-region (name beg end &optional type) - "Set minimal and maximal position of highlight NAME to BEG and END." - (let ((hl (cdr-safe (assoc name evil-ex-active-highlights-alist)))) - (when hl - (evil-ex-hl-set-min hl beg) - (evil-ex-hl-set-max hl end) - (evil-ex-hl-idle-update)))) - -(defun evil-ex-hl-get-max (name) - "Return the maximal position of the highlight with name NAME." - (let ((hl (cdr-safe (assoc name evil-ex-active-highlights-alist)))) - (and hl (evil-ex-hl-max hl)))) - -(defun evil-ex-hl-update-highlights () - "Update the overlays of all active highlights." - (dolist (hl (mapcar #'cdr evil-ex-active-highlights-alist)) - (let* ((old-ovs (evil-ex-hl-overlays hl)) - new-ovs - (pattern (evil-ex-hl-pattern hl)) - (case-fold-search (evil-ex-pattern-ignore-case pattern)) - (case-replace case-fold-search) - (face (evil-ex-hl-face hl)) - (match-hook (evil-ex-hl-match-hook hl)) - result) - (if pattern - ;; collect all visible ranges - (let (ranges sranges) - (dolist (win (if (eq evil-ex-interactive-search-highlight - 'all-windows) - (get-buffer-window-list (current-buffer) nil t) - (list (evil-ex-hl-window hl)))) - (let ((beg (max (window-start win) - (or (evil-ex-hl-min hl) (point-min)))) - (end (min (window-end win) - (or (evil-ex-hl-max hl) (point-max))))) - (when (< beg end) - (push (cons beg end) ranges)))) - (setq ranges - (sort ranges #'(lambda (r1 r2) (< (car r1) (car r2))))) - (while ranges - (let ((r1 (pop ranges)) - (r2 (pop ranges))) - (cond - ;; last range - ((null r2) - (push r1 sranges)) - ;; ranges overlap, union - ((>= (cdr r1) (car r2)) - (push (cons (car r1) - (max (cdr r1) (cdr r2))) - ranges)) - ;; ranges distinct - (t - (push r1 sranges) - (push r2 ranges))))) - - ;; run through all ranges - (condition-case lossage - (save-match-data - (dolist (r sranges) - (let ((beg (car r)) - (end (cdr r))) - (save-excursion - (goto-char beg) - ;; set the overlays for the current highlight, - ;; reusing old overlays (if possible) - (while (and (not (eobp)) - (evil-ex-search-find-next-pattern pattern) - (<= (match-end 0) end) - (not (and (= (match-end 0) end) - (string= (evil-ex-pattern-regex pattern) - "^")))) - (let ((ov (or (pop old-ovs) (make-overlay 0 0)))) - (move-overlay ov (match-beginning 0) (match-end 0)) - (overlay-put ov 'face face) - (overlay-put ov 'evil-ex-hl (evil-ex-hl-name hl)) - (overlay-put ov 'priority 1000) - (push ov new-ovs) - (when match-hook (funcall match-hook hl ov))) - (cond - ((and (not (evil-ex-pattern-whole-line pattern)) - (not (string-match-p "\n" (buffer-substring-no-properties - (match-beginning 0) - (match-end 0))))) - (forward-line)) - ((= (match-beginning 0) (match-end 0)) - (forward-char)) - (t (goto-char (match-end 0)))))))) - (mapc #'delete-overlay old-ovs) - (evil-ex-hl-set-overlays hl new-ovs) - (if (or (null pattern) new-ovs) - (setq result t) - ;; Maybe the match could just not be found somewhere else? - (save-excursion - (goto-char (or (evil-ex-hl-min hl) (point-min))) - (if (and (evil-ex-search-find-next-pattern pattern) - (< (match-end 0) (or (evil-ex-hl-max hl) - (point-max)))) - (setq result (format "Match in line %d" - (line-number-at-pos - (match-beginning 0)))) - (setq result "No match"))))) - - (invalid-regexp - (setq result (cadr lossage))) - - (search-failed - (setq result (nth 2 lossage))) - - (error - (setq result (format "%s" (cadr lossage)))) - - (user-error - (setq result (format "%s" (cadr lossage)))))) - ;; no pattern, remove all highlights - (mapc #'delete-overlay old-ovs) - (evil-ex-hl-set-overlays hl new-ovs)) - (when (evil-ex-hl-update-hook hl) - (funcall (evil-ex-hl-update-hook hl) hl result))))) - -(defun evil-ex-search-find-next-pattern (pattern &optional direction) - "Look for the next occurrence of PATTERN in a certain DIRECTION. -Note that this function ignores the whole-line property of PATTERN." - (setq direction (or direction 'forward)) - (let ((case-fold-search (evil-ex-pattern-ignore-case pattern))) - (cond - ((eq direction 'forward) - (re-search-forward (evil-ex-pattern-regex pattern) nil t)) - ((eq direction 'backward) - (let* ((pnt (point)) - (ret (re-search-backward (evil-ex-pattern-regex pattern) nil t)) - (m (and ret (match-data)))) - (if ret - (forward-char) - (goto-char (point-min))) - (let ((fwdret - (re-search-forward (evil-ex-pattern-regex pattern) nil t))) - (cond - ((and fwdret (< (match-beginning 0) pnt)) - (setq ret fwdret) - (goto-char (match-beginning 0))) - (ret - (set-match-data m) - (goto-char (match-beginning 0))) - (t - (goto-char pnt) - ret))))) - (t - (user-error "Unknown search direction: %s" direction))))) - -(defun evil-ex-hl-idle-update () - "Triggers the timer to update the highlights in the current buffer." - (when (and evil-ex-interactive-search-highlight - evil-ex-active-highlights-alist) - (when evil-ex-hl-update-timer - (cancel-timer evil-ex-hl-update-timer)) - (setq evil-ex-hl-update-timer - (run-at-time evil-ex-hl-update-delay nil - #'evil-ex-hl-do-update-highlight - (current-buffer))))) - -(defun evil-ex-hl-do-update-highlight (&optional buffer) - "Timer function for updating the highlights." - (when (buffer-live-p buffer) - (with-current-buffer buffer - (evil-ex-hl-update-highlights))) - (setq evil-ex-hl-update-timer nil)) - -(defun evil-ex-hl-update-highlights-scroll (win beg) - "Update highlights after scrolling in some window." - (with-current-buffer (window-buffer win) - (evil-ex-hl-idle-update))) -(put 'evil-ex-hl-update-highlights-scroll 'permanent-local-hook t) - -(defun evil-ex-hl-update-highlights-resize (frame) - "Update highlights after resizing a window." - (let ((buffers (delete-dups (mapcar #'window-buffer (window-list frame))))) - (dolist (buf buffers) - (with-current-buffer buf - (evil-ex-hl-idle-update))))) -(put 'evil-ex-hl-update-highlights-resize 'permanent-local-hook t) - -;; interactive search -(defun evil-ex-search-activate-highlight (pattern) - "Activate highlighting of the search pattern set to PATTERN. -This function does nothing if `evil-ex-search-interactive' or -`evil-ex-search-highlight-all' is nil. " - (when (and evil-ex-search-interactive evil-ex-search-highlight-all) - (with-current-buffer (or evil-ex-current-buffer (current-buffer)) - (unless (evil-ex-hl-active-p 'evil-ex-search) - (evil-ex-make-hl 'evil-ex-search - :win (minibuffer-selected-window))) - (if pattern - (evil-ex-hl-change 'evil-ex-search pattern))))) - -(defun evil-ex-search (&optional count) - "Search forward or backward COUNT times for the current ex search pattern. -The search pattern is determined by `evil-ex-search-pattern' and -the direcion is determined by `evil-ex-search-direction'." - (setq evil-ex-search-start-point (point) - evil-ex-last-was-search t - count (or count 1)) - (let ((orig (point)) - wrapped) - (dotimes (i (or count 1)) - (when (eq evil-ex-search-direction 'forward) - (unless (eobp) (forward-char)) - ;; maybe skip end-of-line - (when (and evil-move-cursor-back (eolp) (not (eobp))) - (forward-char))) - (let ((res (evil-ex-find-next nil nil (not evil-search-wrap)))) - (cond - ((not res) - (goto-char orig) - (signal 'search-failed - (list (evil-ex-pattern-regex evil-ex-search-pattern)))) - ((eq res 'wrapped) (setq wrapped t))))) - (if wrapped - (let (message-log-max) - (message "Search wrapped"))) - (goto-char (match-beginning 0)) - (setq evil-ex-search-match-beg (match-beginning 0) - evil-ex-search-match-end (match-end 0)) - (evil-ex-search-goto-offset evil-ex-search-offset) - (evil-ex-search-activate-highlight evil-ex-search-pattern))) - -(defun evil-ex-find-next (&optional pattern direction nowrap) - "Search for the next occurrence of the PATTERN in DIRECTION. -PATTERN must be created using `evil-ex-make-pattern', DIRECTION -is either 'forward or 'backward. If NOWRAP is non nil, the search -does not wrap at buffer boundaries. Furthermore this function -only searches invisible text if `search-invisible' is t. If -PATTERN is not specified the current global pattern -`evil-ex-search-pattern' and if DIRECTION is not specified the -current global direction `evil-ex-search-direction' is used. -This function returns t if the search was successful, nil if it -was unsuccessful and 'wrapped if the search was successful but -has been wrapped at the buffer boundaries." - (setq pattern (or pattern evil-ex-search-pattern) - direction (or direction evil-ex-search-direction)) - (unless (and pattern (evil-ex-pattern-regex pattern)) - (signal 'search-failed (list "No search pattern"))) - (catch 'done - (let (wrapped) - (while t - (let ((search-result (evil-ex-search-find-next-pattern pattern - direction))) - (cond - ((and search-result - (or (eq search-invisible t) - (not (isearch-range-invisible - (match-beginning 0) (match-end 0))))) - ;; successful search and not invisible - (throw 'done (if wrapped 'wrapped t))) - ((not search-result) - ;; unsuccessful search - (if nowrap - (throw 'done nil) - (setq nowrap t - wrapped t) - (goto-char (if (eq direction 'forward) - (point-min) - (point-max))))))))))) - -(defun evil-ex-search-update (pattern offset beg end message) - "Update the highlighting and info-message for the search pattern. -PATTERN is the search pattern and OFFSET the associated offset. -BEG and END specifiy the current match, MESSAGE is the info -message to be shown. This function does nothing if -`evil-ex-search-interactive' is nil." - (when evil-ex-search-interactive - (cond - ((and beg end) - ;; update overlay - (if evil-ex-search-overlay - (move-overlay evil-ex-search-overlay beg end) - (setq evil-ex-search-overlay - (make-overlay beg end)) - (overlay-put evil-ex-search-overlay 'priority 1001) - (overlay-put evil-ex-search-overlay 'face 'evil-ex-search)) - ;; move point - (goto-char beg) - (evil-ex-search-goto-offset offset) - ;; update highlights - (when evil-ex-search-highlight-all - (evil-ex-hl-change 'evil-ex-search pattern))) - (t - ;; no match - (when evil-ex-search-overlay - ;; remove overlay - (delete-overlay evil-ex-search-overlay) - (setq evil-ex-search-overlay nil)) - ;; no highlights - (when evil-ex-search-highlight-all - (evil-ex-hl-change 'evil-ex-search nil)) - ;; and go to initial position - (goto-char evil-ex-search-start-point))) - (when (stringp message) - (evil-ex-echo "%s" message)))) - -(defun evil-ex-search-start-session () - "Initialize Ex for interactive search." - (remove-hook 'minibuffer-setup-hook #'evil-ex-search-start-session) - (add-hook 'after-change-functions #'evil-ex-search-update-pattern nil t) - (add-hook 'minibuffer-exit-hook #'evil-ex-search-stop-session) - (evil-ex-search-activate-highlight nil)) -(put 'evil-ex-search-start-session 'permanent-local-hook t) - -(defun evil-ex-search-stop-session () - "Stop interactive search." - (with-current-buffer evil-ex-current-buffer - ;; TODO: This is a bad fix to remove duplicates. The duplicates - ;; exist because `isearch-range-invisible' may add a single - ;; overlay multiple times if we are in an unlucky situation - ;; of overlapping overlays. This happens in our case because - ;; of the overlays that are used for (lazy) highlighting. - ;; Perhaps it would be better to disable those overlays - ;; temporarily before calling `isearch-range-invisible'. - (setq isearch-opened-overlays (delete-dups isearch-opened-overlays)) - (isearch-clean-overlays)) - (remove-hook 'minibuffer-exit-hook #'evil-ex-search-stop-session) - (remove-hook 'after-change-functions #'evil-ex-search-update-pattern t) - (when evil-ex-search-overlay - (delete-overlay evil-ex-search-overlay) - (setq evil-ex-search-overlay nil))) -(put 'evil-ex-search-stop-session 'permanent-local-hook t) - -(defun evil-ex-split-search-pattern (pattern direction) - "Split PATTERN in regexp, offset and next-pattern parts. -Returns a triple (regexp offset next-search)." - (save-match-data - (if (or (and (eq direction 'forward) - (string-match "\\(?:^\\|[^\\\\]\\)\\(?:\\\\\\\\\\)*\\(/\\([^;]*\\)\\(?:;\\([/?].*\\)?\\)?\\)?$" - pattern)) - (and (eq direction 'backward) - (string-match "\\(?:^\\|[^\\\\]\\)\\(?:\\\\\\\\\\)*\\(\\?\\([^;]*\\)\\(?:;\\([/?].*\\)?\\)?\\)?$" - pattern))) - (list (substring pattern 0 (match-beginning 1)) - (match-string 2 pattern) - (match-string 3 pattern)) - (list pattern nil nil)))) - -(defun evil-ex-search-full-pattern (pattern-string count direction) - "Search for a full search pattern PATTERN-STRING in DIRECTION. -This function split PATTERN-STRING in -pattern/offset/;next-pattern parts and performs the search in -DIRECTION which must be either 'forward or 'backward. The first -search is repeated COUNT times. If the pattern part of -PATTERN-STRING is empty, the last global pattern stored in -`evil-ex-search-pattern' is used instead if in addition the -offset part is nil (i.e. no pattern/offset separator), the last -global offset stored in `evil-ex-search-offset' is used as -offset. The current match data will correspond to the last -successful match. This function returns a triple (RESULT PATTERN -OFFSET) where RESULT is - - t the search has been successful without wrap - 'wrap the search has been successful with wrap - 'empty-pattern the last pattern has been empty - nil the search has not been successful - -and PATTERN and OFFSET are the last pattern and offset this -function searched for. Note that this function does not handle -any error conditions." - (setq count (or count 1)) - (catch 'done - (while t - (let* ((res (evil-ex-split-search-pattern pattern-string direction)) - (pat (pop res)) - (offset (pop res)) - (next-pat (pop res))) - ;; use last pattern of no new pattern has been specified - (if (not (zerop (length pat))) - (setq pat (evil-ex-make-search-pattern pat)) - (setq pat evil-ex-search-pattern - offset (or offset evil-ex-search-offset))) - (when (zerop (length pat)) - (throw 'done (list 'empty-pattern pat offset))) - (let (search-result) - (while (> count 0) - (let ((result (evil-ex-find-next pat direction - (not evil-search-wrap)))) - (if (not result) (setq search-result nil count 0) - (setq search-result - (if (or (eq result 'wrap) - (eq search-result 'wrap)) - 'wrap t) - count (1- count))))) - (cond - ;; search failed - ((not search-result) (throw 'done (list nil pat offset))) - ;; no next pattern, search complete - ((zerop (length next-pat)) - (evil-ex-search-goto-offset offset) - (throw 'done (list search-result pat offset))) - ;; next pattern but empty - ((= 1 (length next-pat)) - (evil-ex-search-goto-offset offset) - (throw 'done (list 'empty-pattern pat offset))) - ;; next non-empty pattern, next search iteration - (t - (evil-ex-search-goto-offset offset) - (setq count 1 - pattern-string (substring next-pat 1) - direction (if (= (aref next-pat 0) ?/) - 'forward - 'backward))))))))) - -(defun evil-ex-search-update-pattern (beg end range) - "Update the current search pattern." - (save-match-data - (let ((pattern-string (minibuffer-contents))) - (with-current-buffer evil-ex-current-buffer - (with-selected-window (minibuffer-selected-window) - (goto-char (1+ evil-ex-search-start-point)) - (condition-case err - (let* ((result (evil-ex-search-full-pattern pattern-string - (or evil-ex-search-count 1) - evil-ex-search-direction)) - (success (pop result)) - (pattern (pop result)) - (offset (pop result))) - (cond - ((eq success 'wrap) - (evil-ex-search-update pattern offset - (match-beginning 0) (match-end 0) - "Wrapped")) - ((eq success 'empty-pattern) - (evil-ex-search-update nil nil nil nil nil)) - (success - (evil-ex-search-update pattern offset - (match-beginning 0) (match-end 0) - nil)) - (t - (evil-ex-search-update nil nil - nil nil - "search failed")))) - (invalid-regexp - (evil-ex-search-update nil nil nil nil (cadr err))) - (error - (evil-ex-search-update nil nil nil nil (format "%s" err))))))))) -(put 'evil-ex-search-update-pattern 'permanent-local-hook t) - -(defun evil-ex-search-exit () - "Exit interactive search, keeping lazy highlighting active." - (interactive) - (evil-ex-search-stop-session) - (exit-minibuffer)) - -(defun evil-ex-search-abort () - "Abort interactive search, disabling lazy highlighting." - (interactive) - (evil-ex-search-stop-session) - (evil-ex-delete-hl 'evil-ex-search) - (abort-recursive-edit)) - -(defun evil-ex-search-goto-offset (offset) - "Move point according to search OFFSET and set `evil-this-type' accordingly. -This function assumes that the current match data represents the -current search result." - (unless (zerop (length offset)) - (let ((beg (match-beginning 0)) - (end (match-end 0))) - (save-match-data - (unless - (string-match - "^\\([esb]\\)?\\(\\([-+]\\)?\\([0-9]*\\)\\)$" - offset) - (user-error "Invalid search offset: %s" offset)) - (let ((count (if (= (match-beginning 4) (match-end 4)) - (cond - ((not (match-beginning 3)) 0) - ((= (aref offset (match-beginning 3)) ?+) +1) - (t -1)) - (string-to-number (match-string 2 offset))))) - (cond - ((not (match-beginning 1)) - (setq evil-this-type 'line) - (forward-line count)) - ((= (aref offset (match-beginning 1)) ?e) - (goto-char (+ end count -1)) - (setq evil-this-type 'inclusive)) - ((memq (aref offset (match-beginning 1)) '(?s ?b)) - (goto-char (+ beg count)) - (setq evil-this-type 'inclusive)))))))) - -(defun evil-ex-search-setup () - "Hook to initialize the minibuffer for ex search." - (add-hook 'pre-command-hook #'evil-ex-remove-default)) - -(defun evil-ex-start-search (direction count) - "Start a new search in a certain DIRECTION." - ;; store buffer and window where the search started - (let ((evil-ex-current-buffer (current-buffer))) - (setq evil-ex-search-count count - evil-ex-search-direction direction - evil-ex-search-start-point (point) - evil-ex-last-was-search t) - (progn - ;; ensure minibuffer is initialized accordingly - (add-hook 'minibuffer-setup-hook #'evil-ex-search-start-session) - ;; read the search string - (let* ((minibuffer-local-map evil-ex-search-keymap) - (search-string - (condition-case err - (minibuffer-with-setup-hook - #'evil-ex-search-setup - (read-string (if (eq evil-ex-search-direction 'forward) - "/" "?") - (and evil-ex-search-history - (propertize - (car evil-ex-search-history) - 'face 'shadow)) - 'evil-ex-search-history)) - (quit - (evil-ex-search-stop-session) - (evil-ex-delete-hl 'evil-ex-search) - (goto-char evil-ex-search-start-point) - (signal (car err) (cdr err)))))) - ;; pattern entered successful - (goto-char (1+ evil-ex-search-start-point)) - (let* ((result - (evil-ex-search-full-pattern search-string - evil-ex-search-count - evil-ex-search-direction)) - (success (pop result)) - (pattern (pop result)) - (offset (pop result))) - (setq evil-ex-search-pattern pattern - evil-ex-search-offset offset) - (cond - ((memq success '(t wrap)) - (goto-char (match-beginning 0)) - (setq evil-ex-search-match-beg (match-beginning 0) - evil-ex-search-match-end (match-end 0)) - (evil-ex-search-goto-offset offset) - (evil-push-search-history search-string (eq direction 'forward)) - (unless evil-ex-search-persistent-highlight - (evil-ex-delete-hl 'evil-ex-search))) - (t - (goto-char evil-ex-search-start-point) - (evil-ex-delete-hl 'evil-ex-search) - (signal 'search-failed (list search-string))))))))) - -(defun evil-ex-start-word-search (unbounded direction count &optional symbol) - "Search for the symbol under point. -The search matches the COUNT-th occurrence of the word. If the -UNBOUNDED argument is nil, the search matches only at symbol -boundaries, otherwise it matches anywhere. The DIRECTION -argument should be either `forward' or `backward', determining -the search direction. If SYMBOL is non-nil then the functions -searches for the symbol at point, otherwise for the word at -point." - (let ((string (evil-find-thing (eq direction 'forward) - (if symbol 'symbol 'word)))) - (if (null string) - (user-error "No word under point") - (let ((regex (if unbounded - (regexp-quote string) - (format (if symbol "\\_<%s\\_>" "\\<%s\\>") - (regexp-quote string))))) - (setq evil-ex-search-count count - evil-ex-search-direction direction - evil-ex-search-pattern - (evil-ex-make-search-pattern regex) - evil-ex-search-offset nil - evil-ex-last-was-search t) - ;; update search history unless this pattern equals the - ;; previous pattern - (unless (equal (car-safe evil-ex-search-history) regex) - (push regex evil-ex-search-history)) - (evil-push-search-history regex (eq direction 'forward))) - (evil-ex-delete-hl 'evil-ex-search) - (when (fboundp 'evil-ex-search-next) - (evil-ex-search-next count))))) - -;; substitute -(evil-ex-define-argument-type substitution - "A substitution pattern argument /pattern/replacement/flags. -This handler highlights the pattern of the current substitution." - :runner - (lambda (flag &optional arg) - (with-selected-window (minibuffer-selected-window) - (with-current-buffer evil-ex-current-buffer - (cond - ((eq flag 'start) - (evil-ex-make-hl - 'evil-ex-substitute - :face 'evil-ex-substitute-matches - :update-hook #'evil-ex-pattern-update-ex-info - :match-hook (and evil-ex-substitute-interactive-replace - #'evil-ex-pattern-update-replacement)) - (setq flag 'update)) - - ((eq flag 'stop) - (evil-ex-delete-hl 'evil-ex-substitute)))) - - (when (and (eq flag 'update) - evil-ex-substitute-highlight-all - (not (zerop (length arg)))) - (condition-case lossage - (let* ((result (evil-ex-get-substitute-info arg t)) - (pattern (pop result)) - (replacement (pop result)) - (range (or (evil-copy-range evil-ex-range) - (evil-range (line-beginning-position) - (line-end-position) - 'line - :expanded t)))) - (setq evil-ex-substitute-current-replacement replacement) - (evil-expand-range range) - (evil-ex-hl-set-region 'evil-ex-substitute - (evil-range-beginning range) - (evil-range-end range)) - (evil-ex-hl-change 'evil-ex-substitute pattern)) - (end-of-file - (evil-ex-pattern-update-ex-info nil - "incomplete replacement")) - (user-error - (evil-ex-pattern-update-ex-info nil - (format "%s" lossage)))))))) - -(defun evil-ex-pattern-update-ex-info (hl result) - "Update the Ex info string." - (when (stringp result) - (evil-ex-echo "%s" result))) - -(defun evil-ex-pattern-update-replacement (hl overlay) - "Update the replacement display." - (when (fboundp 'match-substitute-replacement) - (let ((fixedcase (not case-replace)) - repl) - (setq repl (if evil-ex-substitute-current-replacement - (evil-match-substitute-replacement - evil-ex-substitute-current-replacement - fixedcase) - "")) - (put-text-property 0 (length repl) - 'face 'evil-ex-substitute-replacement - repl) - (overlay-put overlay 'after-string repl)))) - -(defun evil-ex-parse-global (string) - "Parse STRING as a global argument." - (let* ((args (evil-delimited-arguments string 2)) - (pattern (nth 0 args)) - (command (nth 1 args))) - ;; use last pattern if none given - (when (zerop (length pattern)) - (setq pattern - (cond - ((and (eq evil-search-module 'evil-search) evil-ex-search-pattern) - (evil-ex-pattern-regex evil-ex-search-pattern)) - ((and (eq evil-search-module 'isearch) (not (zerop (length isearch-string)))) - isearch-string) - (t (user-error "No previous pattern"))))) - (list pattern command))) - -(defun evil-ex-get-substitute-info (string &optional implicit-r) - "Returns the substitution info of command line STRING. -This function returns a three-element list \(PATTERN REPLACEMENT -FLAGS) consisting of the substitution parts of STRING. PATTERN is -a ex-pattern (see `evil-ex-make-pattern') and REPLACEMENT in a -compiled replacement expression (see `evil-compile-replacement'). -The information returned is the actual substitution information -w.r.t. to special situations like empty patterns or repetition of -previous substitution commands. If IMPLICIT-R is non-nil, then -the flag 'r' is assumed, i.e. in the case of an empty pattern the -last search pattern is used. This will be used when called from -a :substitute command with arguments." - (let (pattern replacement flags) - (cond - ((or (null string) (string-match "^[a-zA-Z]" string)) - ;; starts with letter so there is no pattern because the - ;; separator must not be a letter repeat last substitute - (setq replacement evil-ex-substitute-replacement) - ;; flags are everything that is not a white space - (when (and string (string-match "[^[:space:]]+" string)) - (setq flags (match-string 0 string)))) - (t - (let ((args (evil-delimited-arguments string 3))) - (setq pattern (pop args) - replacement (pop args) - flags (pop args)) - ;; if replacment equals "~" use previous replacement - (if (equal replacement "~") - (setq replacement evil-ex-substitute-replacement) - (setq replacement (evil-compile-replacement replacement))) - ;; append implicit "r" flag if required - (when (and implicit-r (not (memq ?r (append flags nil)))) - (setq flags (concat flags "r")))))) - ;; if flags equals "&" add previous flags - (if (and (not (zerop (length flags))) - (= (aref flags 0) ?&)) - (setq flags (append (substring flags 1) - evil-ex-substitute-flags)) - (setq flags (append flags nil))) - ;; if no pattern, use previous pattern, either search or - ;; substitute pattern depending on `evil-ex-last-was-search' and - ;; the r flag - (when (zerop (length pattern)) - (setq pattern - (if (eq evil-search-module 'evil-search) - (if (and evil-ex-last-was-search (memq ?r flags)) - (and evil-ex-search-pattern - (evil-ex-pattern-regex evil-ex-search-pattern)) - (and evil-ex-substitute-pattern - (evil-ex-pattern-regex evil-ex-substitute-pattern))) - (if (eq case-fold-search t) - isearch-string - (concat isearch-string "\\C"))) - flags (remq ?r flags))) - ;; generate pattern - (when pattern - (setq pattern (evil-ex-make-substitute-pattern pattern flags))) - (list pattern replacement flags))) - -(defun evil-ex-nohighlight () - "Disable the active search highlightings." - (interactive) - (evil-ex-delete-hl 'evil-ex-substitute) - (evil-ex-delete-hl 'evil-ex-search)) - -(provide 'evil-search) - -;;; evil-search.el ends here |