X-Git-Url: https://code.delx.au/gnu-emacs-elpa/blobdiff_plain/bc335af4d94d80d3605b66ed51a15d2476ad2179..8c4f59542ada593ddd1c7b9317d332a415c9a5a9:/swiper.el diff --git a/swiper.el b/swiper.el index 7955817bc..b6b4c84d3 100644 --- a/swiper.el +++ b/swiper.el @@ -4,7 +4,7 @@ ;; Author: Oleh Krehel ;; URL: https://github.com/abo-abo/swiper -;; Version: 0.4.0 +;; Version: 0.7.0 ;; Package-Requires: ((emacs "24.1")) ;; Keywords: matching @@ -69,7 +69,9 @@ swiper-match-face-2 swiper-match-face-3 swiper-match-face-4) - "List of `swiper' faces for group matches.") + "List of `swiper' faces for group matches." + :group 'ivy-faces + :type 'list) (defcustom swiper-min-highlight 2 "Only highlight matches for regexps at least this long." @@ -80,12 +82,11 @@ (define-key map (kbd "M-q") 'swiper-query-replace) (define-key map (kbd "C-l") 'swiper-recenter-top-bottom) (define-key map (kbd "C-'") 'swiper-avy) + (define-key map (kbd "C-7") 'swiper-mc) + (define-key map (kbd "C-c C-f") 'swiper-toggle-face-matching) map) "Keymap for swiper.") -(defvar swiper--window nil - "Store the current window.") - (defun swiper-query-replace () "Start `query-replace' with string to replace from last search string." (interactive) @@ -93,55 +94,150 @@ (user-error "Should only be called in the minibuffer through `swiper-map'") (let* ((enable-recursive-minibuffers t) (from (ivy--regex ivy-text)) - (to (query-replace-read-to from "Query replace" t))) - (delete-minibuffer-contents) - (ivy-set-action (lambda () - (with-selected-window swiper--window - (perform-replace from to - t t nil)))) + (to (minibuffer-with-setup-hook + (lambda () + (setq minibuffer-default + (if (string-match "\\`\\\\_<\\(.*\\)\\\\_>\\'" ivy-text) + (match-string 1 ivy-text) + ivy-text))) + (read-from-minibuffer (format "Query replace %s with: " from))))) (swiper--cleanup) - (exit-minibuffer)))) + (ivy-exit-with-action + (lambda (_) + (with-ivy-window + (move-beginning-of-line 1) + (perform-replace from to + t t nil))))))) (defvar avy-background) +(defvar avy-all-windows) +(defvar avy-style) +(defvar avy-keys) (declare-function avy--regex-candidates "ext:avy") (declare-function avy--process "ext:avy") (declare-function avy--overlay-post "ext:avy") -(declare-function avy--goto "ext:avy") +(declare-function avy-action-goto "ext:avy") +(declare-function avy--done "ext:avy") +(declare-function avy--make-backgrounds "ext:avy") +(declare-function avy-window-list "ext:avy") +(declare-function avy-read "ext:avy") +(declare-function avy-read-de-bruijn "ext:avy") +(declare-function avy-tree "ext:avy") +(declare-function avy-push-mark "ext:avy") +(declare-function avy--remove-leading-chars "ext:avy") ;;;###autoload (defun swiper-avy () "Jump to one of the current swiper candidates." (interactive) - (with-selected-window (ivy-state-window ivy-last) - (let* ((candidates - (avy--regex-candidates - (ivy--regex ivy-text))) - (avy-background nil) - (candidate - (avy--process candidates #'avy--overlay-post))) - (ivy-quit-and-run - (avy--goto candidate))))) + (unless (string= ivy-text "") + (let* ((avy-all-windows nil) + (candidates (append + (with-ivy-window + (avy--regex-candidates + (ivy--regex ivy-text))) + (save-excursion + (save-restriction + (narrow-to-region (window-start) (window-end)) + (goto-char (point-min)) + (forward-line) + (let ((cands)) + (while (< (point) (point-max)) + (push (cons (1+ (point)) + (selected-window)) + cands) + (forward-line)) + cands))))) + (candidate (unwind-protect + (prog2 + (avy--make-backgrounds + (append (avy-window-list) + (list (ivy-state-window ivy-last)))) + (if (eq avy-style 'de-bruijn) + (avy-read-de-bruijn + candidates avy-keys) + (avy-read (avy-tree candidates avy-keys) + #'avy--overlay-post + #'avy--remove-leading-chars)) + (avy-push-mark)) + (avy--done)))) + (if (window-minibuffer-p (cdr candidate)) + (progn + (ivy-set-index (- (line-number-at-pos (car candidate)) 2)) + (ivy--exhibit) + (ivy-done) + (ivy-call)) + (ivy-quit-and-run + (avy-action-goto (caar candidate))))))) + +(declare-function mc/create-fake-cursor-at-point "ext:multiple-cursors-core") +(declare-function multiple-cursors-mode "ext:multiple-cursors-core") + +;;;###autoload +(defun swiper-mc () + (interactive) + (unless (require 'multiple-cursors nil t) + (error "multiple-cursors isn't installed")) + (let ((cands (nreverse ivy--old-cands))) + (unless (string= ivy-text "") + (ivy-exit-with-action + (lambda (_) + (let (cand) + (while (setq cand (pop cands)) + (swiper--action cand) + (when cands + (mc/create-fake-cursor-at-point)))) + (multiple-cursors-mode 1)))))) (defun swiper-recenter-top-bottom (&optional arg) - "Call (`recenter-top-bottom' ARG) in `swiper--window'." + "Call (`recenter-top-bottom' ARG)." (interactive "P") - (with-selected-window swiper--window + (with-ivy-window (recenter-top-bottom arg))) +(defvar swiper-font-lock-exclude + '(package-menu-mode + gnus-summary-mode + gnus-article-mode + gnus-group-mode + emms-playlist-mode + emms-stream-mode + erc-mode + org-agenda-mode + dired-mode + jabber-chat-mode + elfeed-search-mode + elfeed-show-mode + fundamental-mode + Man-mode + woman-mode + mu4e-view-mode + mu4e-headers-mode + help-mode + debbugs-gnu-mode + occur-mode + occur-edit-mode + bongo-mode + bongo-library-mode + bongo-playlist-mode + eww-mode + twittering-mode + vc-dir-mode + rcirc-mode + sauron-mode + w3m-mode) + "List of major-modes that are incompatible with font-lock-ensure.") + +(defun swiper-font-lock-ensure-p () + "Return non-nil if we should font-lock-ensure." + (or (derived-mode-p 'magit-mode) + (bound-and-true-p magit-blame-mode) + (memq major-mode swiper-font-lock-exclude))) + (defun swiper-font-lock-ensure () "Ensure the entired buffer is highlighted." - (unless (or (derived-mode-p 'magit-mode) - (memq major-mode '(package-menu-mode - gnus-summary-mode - gnus-article-mode - gnus-group-mode - emms-playlist-mode erc-mode - org-agenda-mode - dired-mode - jabber-chat-mode - elfeed-search-mode - fundamental-mode))) - (unless (> (buffer-size) 100000) + (unless (swiper-font-lock-ensure-p) + (unless (or (> (buffer-size) 100000) (null font-lock-mode)) (if (fboundp 'font-lock-ensure) (font-lock-ensure) (with-no-warnings (font-lock-fontify-buffer)))))) @@ -150,28 +246,67 @@ "Store the current candidates format spec.") (defvar swiper--width nil - "Store the amount of digits needed for the longest line nubmer.") - -(defun swiper--candidates () - "Return a list of this buffer lines." + "Store the number of digits needed for the longest line nubmer.") + +(defvar swiper-use-visual-line nil + "When non-nil, use `line-move' instead of `forward-line'.") + +(declare-function outline-show-all "outline") + +(defun swiper--candidates (&optional numbers-width) + "Return a list of this buffer lines. + +NUMBERS-WIDTH, when specified, is used for width spec of line +numbers; replaces calculating the width from buffer line count." + (if (and visual-line-mode + ;; super-slow otherwise + (< (buffer-size) 20000)) + (progn + (when (eq major-mode 'org-mode) + (require 'outline) + (if (fboundp 'outline-show-all) + (outline-show-all) + (with-no-warnings + (show-all)))) + (setq swiper-use-visual-line t)) + (setq swiper-use-visual-line nil)) (let ((n-lines (count-lines (point-min) (point-max)))) (unless (zerop n-lines) - (setq swiper--width (1+ (floor (log n-lines 10)))) + (setq swiper--width (or numbers-width + (1+ (floor (log n-lines 10))))) (setq swiper--format-spec - (format "%%-%dd %%s" swiper--width)) + (format "%%-%dd " swiper--width)) (let ((line-number 0) + (advancer (if swiper-use-visual-line + (lambda (arg) (line-move arg t)) + #'forward-line)) candidates) (save-excursion (goto-char (point-min)) (swiper-font-lock-ensure) (while (< (point) (point-max)) - (push (format swiper--format-spec - (cl-incf line-number) - (buffer-substring - (line-beginning-position) - (line-end-position))) - candidates) - (forward-line 1)) + (let ((str (concat + " " + (replace-regexp-in-string + "\t" " " + (if swiper-use-visual-line + (buffer-substring + (save-excursion + (beginning-of-visual-line) + (point)) + (save-excursion + (end-of-visual-line) + (point))) + (buffer-substring + (point) + (line-end-position))))))) + (remove-text-properties 0 (length str) '(field) str) + (put-text-property 0 1 'display + (format swiper--format-spec + (cl-incf line-number)) + str) + (push str candidates)) + (funcall advancer 1)) (nreverse candidates)))))) (defvar swiper--opoint 1 @@ -182,79 +317,161 @@ "`isearch' with an overview. When non-nil, INITIAL-INPUT is the initial search pattern." (interactive) - (swiper--ivy initial-input)) + (swiper--ivy (swiper--candidates) initial-input)) + +(declare-function string-trim-right "subr-x") + +(defun swiper-occur (&optional revert) + "Generate a custom occur buffer for `swiper'. +When REVERT is non-nil, regenerate the current *ivy-occur* buffer." + (let* ((buffer (ivy-state-buffer ivy-last)) + (fname (propertize + (with-ivy-window + (if (buffer-file-name buffer) + (file-name-nondirectory + (buffer-file-name buffer)) + (buffer-name buffer))) + 'face + 'compilation-info)) + (cands (mapcar + (lambda (s) + (format "%s:%s:%s" + fname + (propertize + (string-trim-right + (get-text-property 0 'display s)) + 'face 'compilation-line-number) + (substring s 1))) + (if (null revert) + ivy--old-cands + (setq ivy--old-re nil) + (let ((ivy--regex-function 'swiper--re-builder)) + (ivy--filter + (progn (string-match "\"\\(.*\\)\"" (buffer-name)) + (match-string 1 (buffer-name))) + (with-current-buffer buffer + (swiper--candidates)))))))) + (unless (eq major-mode 'ivy-occur-grep-mode) + (ivy-occur-grep-mode) + (font-lock-mode -1)) + (insert (format "-*- mode:grep; default-directory: %S -*-\n\n\n" + default-directory)) + (insert (format "%d candidates:\n" (length cands))) + (ivy--occur-insert-lines + (mapcar + (lambda (cand) (concat "./" cand)) + cands)) + (goto-char (point-min)) + (forward-line 4))) + +(ivy-set-occur 'swiper 'swiper-occur) -(defvar swiper--anchor nil - "A line number to which the search should be anchored.") +(declare-function evil-jumper--set-jump "ext:evil-jumper") -(defvar swiper--len 0 - "The last length of input for which an anchoring was made.") +(defvar swiper--current-line nil) +(defvar swiper--current-match-start nil) (defun swiper--init () "Perform initialization common to both completion methods." - (deactivate-mark) + (setq swiper--current-line nil) + (setq swiper--current-match-start nil) (setq swiper--opoint (point)) - (setq swiper--len 0) - (setq swiper--anchor (line-number-at-pos)) - (setq swiper--window (selected-window))) + (when (bound-and-true-p evil-jumper-mode) + (evil-jumper--set-jump))) (defun swiper--re-builder (str) "Transform STR into a swiper regex. -This is the regex used in the minibuffer, since the candidates -there have line numbers. In the buffer, `ivy--regex' should be used." - (cond - ((equal str "") - "") - ((equal str "^") - ".") - ((string-match "^\\^" str) - (setq ivy--old-re "") - (let ((re (ivy--regex-plus (substring str 1)))) - (format "^[0-9][0-9 ]\\{%d\\}%s" - swiper--width - (if (zerop ivy--subexps) - (prog1 (format "\\(%s\\)" re) - (setq ivy--subexps 1)) - re)))) - (t - (ivy--regex-plus str)))) - -(defun swiper--ivy (&optional initial-input) - "`isearch' with an overview using `ivy'. +This is the regex used in the minibuffer where candidates have +line numbers. For the buffer, use `ivy--regex' instead." + (replace-regexp-in-string + "\t" " " + (cond + ((equal str "") + "") + ((equal str "^") + (setq ivy--subexps 0) + ".") + ((string-match "^\\^" str) + (setq ivy--old-re "") + (let ((re (ivy--regex-plus (substring str 1)))) + (if (zerop ivy--subexps) + (prog1 (format "^ ?\\(%s\\)" re) + (setq ivy--subexps 1)) + (format "^ %s" re)))) + (t + (ivy--regex-plus str))))) + +(defvar swiper-history nil + "History for `swiper'.") + +(defvar swiper-invocation-face nil + "The face at the point of invocation of `swiper'.") + +(defun swiper--ivy (candidates &optional initial-input) + "Select one of CANDIDATES and move there. When non-nil, INITIAL-INPUT is the initial search pattern." (interactive) - (unless (eq (length (help-function-arglist 'ivy-read)) 4) - (warn "You seem to be using the outdated stand-alone \"ivy\" package. -Please remove it and update the \"swiper\" package.")) (swiper--init) - (let ((candidates (swiper--candidates)) - (preselect (format - swiper--format-spec - (line-number-at-pos) - (regexp-quote - (buffer-substring-no-properties - (line-beginning-position) - (line-end-position))))) + (setq swiper-invocation-face + (plist-get (text-properties-at (point)) 'face)) + (let ((preselect + (if swiper-use-visual-line + (count-screen-lines + (point-min) + (save-excursion (beginning-of-visual-line) (point))) + (1- (line-number-at-pos)))) + (minibuffer-allow-text-properties t) res) (unwind-protect - (setq res (ivy-read - (replace-regexp-in-string - "%s" "pattern: " swiper--format-spec) - candidates - :initial-input initial-input - :keymap swiper-map - :preselect preselect - :require-match t - :update-fn #'swiper--update-input-ivy - :unwind #'swiper--cleanup - :re-builder #'swiper--re-builder)) - (if (null ivy-exit) - (goto-char swiper--opoint) - (swiper--action res ivy-text))))) + (and + (setq res + (ivy-read + "Swiper: " + candidates + :initial-input initial-input + :keymap swiper-map + :preselect preselect + :require-match t + :update-fn #'swiper--update-input-ivy + :unwind #'swiper--cleanup + :action #'swiper--action + :re-builder #'swiper--re-builder + :history 'swiper-history + :caller 'swiper)) + (point)) + (unless res + (goto-char swiper--opoint))))) + +(defun swiper-toggle-face-matching () + "Toggle matching only the candidates with `swiper-invocation-face'." + (interactive) + (setf (ivy-state-matcher ivy-last) + (if (ivy-state-matcher ivy-last) + nil + #'swiper--face-matcher)) + (setq ivy--old-re nil)) + +(defun swiper--face-matcher (regexp candidates) + "Return REGEXP-matching CANDIDATES. +Matched candidates should have `swiper-invocation-face'." + (cl-remove-if-not + (lambda (x) + (and + (string-match regexp x) + (let ((s (match-string 0 x)) + (i 0)) + (while (and (< i (length s)) + (text-property-any + i (1+ i) + 'face swiper-invocation-face + s)) + (cl-incf i)) + (eq i (length s))))) + candidates)) (defun swiper--ensure-visible () "Remove overlays hiding point." - (let ((overlays (overlays-at (point))) + (let ((overlays (overlays-at (1- (point)))) ov expose) (while (setq ov (pop overlays)) (if (and (invisible-p (overlay-get ov 'invisible)) @@ -274,78 +491,231 @@ Please remove it and update the \"swiper\" package.")) (defun swiper--update-input-ivy () "Called when `ivy' input is updated." - (swiper--cleanup) - (let* ((re (ivy--regex ivy-text)) - (str ivy--current) - (num (if (string-match "^[0-9]+" str) - (string-to-number (match-string 0 str)) - 0))) - (with-selected-window swiper--window - (goto-char (point-min)) - (when (cl-plusp num) - (goto-char (point-min)) - (forward-line (1- num)) - (isearch-range-invisible (line-beginning-position) - (line-end-position)) - (unless (and (>= (point) (window-start)) - (<= (point) (window-end swiper--window t))) - (recenter))) - (swiper--add-overlays re)))) - -(defun swiper--add-overlays (re &optional beg end) + (with-ivy-window + (swiper--cleanup) + (when (> (length ivy--current) 0) + (let* ((re (replace-regexp-in-string + " " "\t" + (funcall ivy--regex-function ivy-text))) + (re (if (stringp re) re (caar re))) + (str (get-text-property 0 'display ivy--current)) + (num (if (string-match "^[0-9]+" str) + (string-to-number (match-string 0 str)) + 0))) + (unless (eq this-command 'ivy-yank-word) + (when (cl-plusp num) + (unless (if swiper--current-line + (eq swiper--current-line num) + (eq (line-number-at-pos) num)) + (goto-char (point-min)) + (if swiper-use-visual-line + (line-move (1- num)) + (forward-line (1- num)))) + (if (and (equal ivy-text "") + (>= swiper--opoint (line-beginning-position)) + (<= swiper--opoint (line-end-position))) + (goto-char swiper--opoint) + (if (eq swiper--current-line num) + (when swiper--current-match-start + (goto-char swiper--current-match-start)) + (setq swiper--current-line num)) + (when (re-search-forward re (line-end-position) t) + (setq swiper--current-match-start (match-beginning 0)))) + (isearch-range-invisible (line-beginning-position) + (line-end-position)) + (unless (and (>= (point) (window-start)) + (<= (point) (window-end (ivy-state-window ivy-last) t))) + (recenter)))) + (swiper--add-overlays re))))) + +(defun swiper--add-overlays (re &optional beg end wnd) "Add overlays for RE regexp in visible part of the current buffer. -BEG and END, when specified, are the point bounds." - (let ((ov (make-overlay - (line-beginning-position) - (1+ (line-end-position))))) +BEG and END, when specified, are the point bounds. +WND, when specified is the window." + (setq wnd (or wnd (ivy-state-window ivy-last))) + (let ((ov (if visual-line-mode + (make-overlay + (save-excursion + (beginning-of-visual-line) + (point)) + (save-excursion + (end-of-visual-line) + (point))) + (make-overlay + (line-beginning-position) + (1+ (line-end-position)))))) (overlay-put ov 'face 'swiper-line-face) - (overlay-put ov 'window swiper--window) - (push ov swiper--overlays)) - (let* ((wh (window-height)) - (beg (or beg (save-excursion - (forward-line (- wh)) - (point)))) - (end (or end (save-excursion - (forward-line wh) - (point))))) - (when (>= (length re) swiper-min-highlight) - (save-excursion - (goto-char beg) - ;; RE can become an invalid regexp - (while (and (ignore-errors (re-search-forward re end t)) - (> (- (match-end 0) (match-beginning 0)) 0)) - (let ((i 0)) - (while (<= i ivy--subexps) - (when (match-beginning i) - (let ((overlay (make-overlay (match-beginning i) - (match-end i))) - (face - (cond ((zerop ivy--subexps) - (cadr swiper-faces)) - ((zerop i) - (car swiper-faces)) - (t - (nth (1+ (mod (+ i 2) (1- (length swiper-faces)))) - swiper-faces))))) - (push overlay swiper--overlays) - (overlay-put overlay 'face face) - (overlay-put overlay 'window swiper--window) - (overlay-put overlay 'priority i))) - (cl-incf i)))))))) - -(defun swiper--action (x input) - "Goto line X and search for INPUT." - (if (null x) - (user-error "No candidates") - (goto-char (point-min)) - (forward-line (1- (read x))) - (re-search-forward - (ivy--regex input) (line-end-position) t) - (swiper--ensure-visible) - (when (/= (point) swiper--opoint) - (unless (and transient-mark-mode mark-active) - (push-mark swiper--opoint t) - (message "Mark saved where search started"))))) + (overlay-put ov 'window wnd) + (push ov swiper--overlays) + (let* ((wh (window-height)) + (beg (or beg (save-excursion + (forward-line (- wh)) + (point)))) + (end (or end (save-excursion + (forward-line wh) + (point))))) + (when (>= (length re) swiper-min-highlight) + (save-excursion + (goto-char beg) + ;; RE can become an invalid regexp + (while (and (ignore-errors (re-search-forward re end t)) + (> (- (match-end 0) (match-beginning 0)) 0)) + (let ((i 0)) + (while (<= i ivy--subexps) + (when (match-beginning i) + (let ((overlay (make-overlay (match-beginning i) + (match-end i))) + (face + (cond ((zerop ivy--subexps) + (cadr swiper-faces)) + ((zerop i) + (car swiper-faces)) + (t + (nth (1+ (mod (+ i 2) (1- (length swiper-faces)))) + swiper-faces))))) + (push overlay swiper--overlays) + (overlay-put overlay 'face face) + (overlay-put overlay 'window wnd) + (overlay-put overlay 'priority i))) + (cl-incf i))))))))) + +(defun swiper--action (x) + "Goto line X." + (let ((ln (1- (read (or (get-text-property 0 'display x) + (and (string-match ":\\([0-9]+\\):.*\\'" x) + (match-string-no-properties 1 x)))))) + (re (ivy--regex ivy-text))) + (if (null x) + (user-error "No candidates") + (with-ivy-window + (unless (equal (current-buffer) + (ivy-state-buffer ivy-last)) + (switch-to-buffer (ivy-state-buffer ivy-last))) + (goto-char (point-min)) + (funcall (if swiper-use-visual-line + #'line-move + #'forward-line) + ln) + (re-search-forward re (line-end-position) t) + (swiper--ensure-visible) + (when (/= (point) swiper--opoint) + (unless (and transient-mark-mode mark-active) + (when (eq ivy-exit 'done) + (push-mark swiper--opoint t) + (message "Mark saved where search started")))) + (add-to-history + 'regexp-search-ring + re + regexp-search-ring-max))))) + +;; (define-key isearch-mode-map (kbd "C-o") 'swiper-from-isearch) +(defun swiper-from-isearch () + "Invoke `swiper' from isearch." + (interactive) + (let ((query (if isearch-regexp + isearch-string + (regexp-quote isearch-string)))) + (isearch-exit) + (swiper query))) + +(defvar swiper-multi-buffers nil + "Store the current list of buffers.") + +(defvar swiper-multi-candidates nil + "Store the list of candidates for `swiper-multi'.") + +(defun swiper-multi-prompt () + (format "Buffers (%s): " + (mapconcat #'identity swiper-multi-buffers ", "))) + +(defun swiper-multi () + "Select one or more buffers. +Run `swiper' for those buffers." + (interactive) + (setq swiper-multi-buffers nil) + (ivy-read (swiper-multi-prompt) + 'internal-complete-buffer + :action 'swiper-multi-action-1) + (ivy-read "Swiper: " swiper-multi-candidates + :action 'swiper-multi-action-2 + :unwind #'swiper--cleanup + :caller 'swiper-multi)) + +(defun swiper-all () + "Run `swiper' for all opened buffers." + (interactive) + (ivy-read "Swiper: " (swiper--multi-candidates + (cl-remove-if-not + #'buffer-file-name + (buffer-list))) + :action 'swiper-multi-action-2 + :unwind #'swiper--cleanup + :update-fn (lambda () + (swiper-multi-action-2 ivy--current)) + :caller 'swiper-multi)) + +(defun swiper--multi-candidates (buffers) + (let* ((ww (window-width)) + (res nil) + (column-2 (apply #'max + (mapcar + (lambda (b) + (length (buffer-name b))) + buffers))) + (column-1 (- ww 4 column-2 1))) + (dolist (buf buffers) + (with-current-buffer buf + (setq res + (append + (mapcar + (lambda (s) + (setq s (concat (ivy--truncate-string s column-1) " ")) + (let ((len (length s))) + (put-text-property + (1- len) len 'display + (concat + (make-string + (- ww (string-width s) (length (buffer-name)) 3) + ?\ ) + (buffer-name)) + s) + s)) + (swiper--candidates 4)) + res)) + nil)) + res)) + +(defun swiper-multi-action-1 (x) + (if (member x swiper-multi-buffers) + (progn + (setq swiper-multi-buffers (delete x swiper-multi-buffers))) + (unless (equal x "") + (setq swiper-multi-buffers (append swiper-multi-buffers (list x))))) + (let ((prompt (swiper-multi-prompt))) + (setf (ivy-state-prompt ivy-last) prompt) + (setq ivy--prompt (concat "%-4d " prompt))) + (cond ((memq this-command '(ivy-done + ivy-alt-done + ivy-immediate-done)) + (setq swiper-multi-candidates + (swiper--multi-candidates + (mapcar #'get-buffer swiper-multi-buffers)))) + ((eq this-command 'ivy-call) + (delete-minibuffer-contents)))) + +(defun swiper-multi-action-2 (x) + (let ((buf-space (get-text-property (1- (length x)) 'display x))) + (with-ivy-window + (when (string-match "\\` *\\([^ ]+\\)\\'" buf-space) + (switch-to-buffer (match-string 1 buf-space)) + (goto-char (point-min)) + (forward-line (1- (read (get-text-property 0 'display x)))) + (re-search-forward + (ivy--regex ivy-text) + (line-end-position) t) + (unless (eq ivy-exit 'done) + (swiper--cleanup) + (swiper--add-overlays (ivy--regex ivy-text))))))) (provide 'swiper)