Personal emacs config
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1675 lines
59 KiB

  1. ;;; swiper.el --- Isearch with an overview. Oh, man! -*- lexical-binding: t -*-
  2. ;; Copyright (C) 2015-2019 Free Software Foundation, Inc.
  3. ;; Author: Oleh Krehel <ohwoeowho@gmail.com>
  4. ;; URL: https://github.com/abo-abo/swiper
  5. ;; Package-Version: 0.13.0
  6. ;; Package-Commit: cd634c6f51458f81898ecf2821ac3169cb65a1eb
  7. ;; Version: 0.13.0
  8. ;; Package-Requires: ((emacs "24.5") (ivy "0.13.0"))
  9. ;; Keywords: matching
  10. ;; This file is part of GNU Emacs.
  11. ;; This file is free software; you can redistribute it and/or modify
  12. ;; it under the terms of the GNU General Public License as published by
  13. ;; the Free Software Foundation; either version 3, or (at your option)
  14. ;; any later version.
  15. ;; This program is distributed in the hope that it will be useful,
  16. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. ;; GNU General Public License for more details.
  19. ;; For a full copy of the GNU General Public License
  20. ;; see <https://www.gnu.org/licenses/>.
  21. ;;; Commentary:
  22. ;; This package gives an overview of the current regex search
  23. ;; candidates. The search regex can be split into groups with a
  24. ;; space. Each group is highlighted with a different face.
  25. ;;
  26. ;; It can double as a quick `regex-builder', although only single
  27. ;; lines will be matched.
  28. ;;; Code:
  29. (require 'ivy)
  30. (defgroup swiper nil
  31. "`isearch' with an overview."
  32. :group 'matching
  33. :prefix "swiper-")
  34. (defface swiper-match-face-1
  35. '((t (:inherit lazy-highlight)))
  36. "The background face for `swiper' matches."
  37. :group 'ivy-faces)
  38. (defface swiper-match-face-2
  39. '((t (:inherit isearch)))
  40. "Face for `swiper' matches modulo 1."
  41. :group 'ivy-faces)
  42. (defface swiper-match-face-3
  43. '((t (:inherit match)))
  44. "Face for `swiper' matches modulo 2."
  45. :group 'ivy-faces)
  46. (defface swiper-match-face-4
  47. '((t (:inherit isearch-fail)))
  48. "Face for `swiper' matches modulo 3."
  49. :group 'ivy-faces)
  50. (defface swiper-background-match-face-1
  51. '((t (:inherit swiper-match-face-1)))
  52. "The background face for non-current `swiper' matches."
  53. :group 'ivy-faces)
  54. (defface swiper-background-match-face-2
  55. '((t (:inherit swiper-match-face-2)))
  56. "Face for non-current `swiper' matches modulo 1."
  57. :group 'ivy-faces)
  58. (defface swiper-background-match-face-3
  59. '((t (:inherit swiper-match-face-3)))
  60. "Face for non-current `swiper' matches modulo 2."
  61. :group 'ivy-faces)
  62. (defface swiper-background-match-face-4
  63. '((t (:inherit swiper-match-face-4)))
  64. "Face for non-current `swiper' matches modulo 3."
  65. :group 'ivy-faces)
  66. (defface swiper-line-face
  67. '((t (:inherit highlight)))
  68. "Face for current `swiper' line."
  69. :group 'ivy-faces)
  70. (defcustom swiper-faces '(swiper-match-face-1
  71. swiper-match-face-2
  72. swiper-match-face-3
  73. swiper-match-face-4)
  74. "List of `swiper' faces for group matches."
  75. :group 'ivy-faces
  76. :type '(repeat face))
  77. (defvar swiper-background-faces
  78. '(swiper-background-match-face-1
  79. swiper-background-match-face-2
  80. swiper-background-match-face-3
  81. swiper-background-match-face-4)
  82. "Like `swiper-faces', but used for all matches except the current one.")
  83. (defun swiper--recompute-background-faces ()
  84. (let ((faces '(swiper-background-match-face-1
  85. swiper-background-match-face-2
  86. swiper-background-match-face-3
  87. swiper-background-match-face-4))
  88. (colir-compose-method #'colir-compose-soft-light))
  89. (cl-mapc (lambda (f1 f2)
  90. (let ((bg (face-background f1)))
  91. (when bg
  92. (set-face-background
  93. f2
  94. (colir-blend
  95. (colir-color-parse bg)
  96. (colir-color-parse "#ffffff"))))))
  97. swiper-faces
  98. faces)))
  99. (swiper--recompute-background-faces)
  100. (defcustom swiper-min-highlight 2
  101. "Only highlight matches for regexps at least this long."
  102. :type 'integer)
  103. (defcustom swiper-include-line-number-in-search nil
  104. "Include line number in text of search candidates."
  105. :type 'boolean
  106. :group 'swiper)
  107. (defcustom swiper-goto-start-of-match nil
  108. "When non-nil, go to the start of the match, not its end.
  109. Treated as non-nil when searching backwards."
  110. :type 'boolean
  111. :group 'swiper)
  112. (defvar swiper-map
  113. (let ((map (make-sparse-keymap)))
  114. (define-key map (kbd "M-q") 'swiper-query-replace)
  115. (define-key map (kbd "C-l") 'swiper-recenter-top-bottom)
  116. (define-key map (kbd "C-'") 'swiper-avy)
  117. (define-key map (kbd "C-7") 'swiper-mc)
  118. (define-key map (kbd "C-c C-f") 'swiper-toggle-face-matching)
  119. map)
  120. "Keymap for swiper.")
  121. (defvar swiper--query-replace-overlays nil)
  122. (defun swiper--query-replace-updatefn ()
  123. (let ((lisp (ignore-errors (nth 2 (query-replace-compile-replacement ivy-text t)))))
  124. (dolist (ov swiper--query-replace-overlays)
  125. (when lisp
  126. (dolist (x (overlay-get ov 'matches))
  127. (setq lisp (cl-subst (cadr x) (car x) lisp :test #'equal)))
  128. (setq lisp (ignore-errors (eval lisp))))
  129. (overlay-put
  130. ov 'after-string
  131. (propertize
  132. (if (stringp lisp)
  133. lisp
  134. ivy-text)
  135. 'face 'error)))))
  136. (defun swiper--query-replace-cleanup ()
  137. (while swiper--query-replace-overlays
  138. (delete-overlay (pop swiper--query-replace-overlays))))
  139. (defun swiper--query-replace-setup ()
  140. (with-ivy-window
  141. (let ((end (window-end (selected-window) t))
  142. (re (ivy--regex ivy-text)))
  143. (save-excursion
  144. (beginning-of-line)
  145. (while (and (re-search-forward re end t)
  146. (not (eobp)))
  147. (let ((ov (make-overlay (1- (match-end 0)) (match-end 0)))
  148. (md (match-data)))
  149. (overlay-put
  150. ov 'matches
  151. (mapcar
  152. (lambda (x)
  153. (list `(match-string ,x) (match-string x)))
  154. (number-sequence 0 (1- (/ (length md) 2)))))
  155. (push ov swiper--query-replace-overlays))
  156. (unless (> (match-end 0) (match-beginning 0))
  157. (forward-char)))))))
  158. (defun swiper-query-replace ()
  159. "Start `query-replace' with string to replace from last search string."
  160. (interactive)
  161. (cond ((null (window-minibuffer-p))
  162. (user-error "Should only be called in the minibuffer through `swiper-map'"))
  163. ((string= "" ivy-text)
  164. (user-error "Empty input"))
  165. (t
  166. (swiper--query-replace-setup)
  167. (unwind-protect
  168. (let* ((enable-recursive-minibuffers t)
  169. (from (ivy--regex ivy-text))
  170. (default
  171. (format "\\,(concat %s)"
  172. (if (<= ivy--subexps 1)
  173. "\\&"
  174. (mapconcat (lambda (i) (format "\\%d" i))
  175. (number-sequence 1 ivy--subexps)
  176. " \" \" "))))
  177. (to
  178. (query-replace-compile-replacement
  179. (ivy-read
  180. (format "Query replace %s with: " from) nil
  181. :def default
  182. :caller 'swiper-query-replace)
  183. t)))
  184. (swiper--cleanup)
  185. (ivy-exit-with-action
  186. (lambda (_)
  187. (with-ivy-window
  188. (move-beginning-of-line 1)
  189. (let ((inhibit-read-only t))
  190. (perform-replace from to
  191. t t nil))))))
  192. (swiper--query-replace-cleanup)))))
  193. (ivy-configure 'swiper-query-replace
  194. :update-fn #'swiper--query-replace-updatefn)
  195. (defvar inhibit-message)
  196. (defun swiper-all-query-replace ()
  197. "Start `query-replace' with string to replace from last search string."
  198. (interactive)
  199. (if (null (window-minibuffer-p))
  200. (user-error
  201. "Should only be called in the minibuffer through `swiper-all-map'")
  202. (let* ((enable-recursive-minibuffers t)
  203. (from (ivy--regex ivy-text))
  204. (to (query-replace-read-to from "Query replace" t)))
  205. (swiper--cleanup)
  206. (ivy-exit-with-action
  207. (lambda (_)
  208. (let ((wnd-conf (current-window-configuration))
  209. (inhibit-message t))
  210. (unwind-protect
  211. (dolist (cand ivy--old-cands)
  212. (let ((buffer (get-text-property 0 'buffer cand)))
  213. (switch-to-buffer buffer)
  214. (goto-char (point-min))
  215. (perform-replace from to t t nil)))
  216. (set-window-configuration wnd-conf))))))))
  217. (defvar avy-all-windows)
  218. (defvar avy-style)
  219. (defvar avy-keys)
  220. (declare-function avy--overlay-post "ext:avy")
  221. (declare-function avy-action-goto "ext:avy")
  222. (declare-function avy-candidate-beg "ext:avy")
  223. (declare-function avy--done "ext:avy")
  224. (declare-function avy--make-backgrounds "ext:avy")
  225. (declare-function avy-window-list "ext:avy")
  226. (declare-function avy-read "ext:avy")
  227. (declare-function avy-read-de-bruijn "ext:avy")
  228. (declare-function avy-tree "ext:avy")
  229. (declare-function avy-push-mark "ext:avy")
  230. (declare-function avy--remove-leading-chars "ext:avy")
  231. (defun swiper--avy-candidates ()
  232. (let* (
  233. ;; We'll have overlapping overlays, so we sort all the
  234. ;; overlays in the visible region by their start, and then
  235. ;; throw out non-Swiper overlays or overlapping Swiper
  236. ;; overlays.
  237. (visible-overlays (cl-sort (with-ivy-window
  238. (overlays-in (window-start)
  239. (window-end)))
  240. #'< :key #'overlay-start))
  241. (min-overlay-start 0)
  242. (overlays-for-avy
  243. (cl-remove-if-not
  244. (lambda (ov)
  245. (when (and (>= (overlay-start ov)
  246. min-overlay-start)
  247. (memq (overlay-get ov 'face)
  248. (append swiper-faces swiper-background-faces)))
  249. (setq min-overlay-start (overlay-start ov))))
  250. visible-overlays))
  251. (offset (if (eq (ivy-state-caller ivy-last) 'swiper) 1 0)))
  252. (nconc
  253. (mapcar (lambda (ov)
  254. (cons (overlay-start ov)
  255. (overlay-get ov 'window)))
  256. overlays-for-avy)
  257. (save-excursion
  258. (save-restriction
  259. (narrow-to-region (window-start) (window-end))
  260. (goto-char (point-min))
  261. (forward-line)
  262. (let ((win (selected-window))
  263. cands)
  264. (while (not (eobp))
  265. (push (cons (+ (point) offset) win)
  266. cands)
  267. (forward-line))
  268. cands))))))
  269. (defun swiper--avy-candidate ()
  270. (let ((candidates (swiper--avy-candidates))
  271. (avy-all-windows nil))
  272. (unwind-protect
  273. (prog2
  274. (avy--make-backgrounds
  275. (append (avy-window-list)
  276. (list (ivy-state-window ivy-last))))
  277. (if (eq avy-style 'de-bruijn)
  278. (avy-read-de-bruijn candidates avy-keys)
  279. (avy-read (avy-tree candidates avy-keys)
  280. #'avy--overlay-post
  281. #'avy--remove-leading-chars))
  282. (avy-push-mark))
  283. (avy--done))))
  284. (defun swiper--avy-goto (candidate)
  285. (cond ((let ((win (cdr-safe candidate)))
  286. (and win (window-minibuffer-p win)))
  287. (let ((nlines (count-lines (point-min) (point-max))))
  288. (ivy-set-index
  289. (+ (car (ivy--minibuffer-index-bounds
  290. ivy--index ivy--length ivy-height))
  291. (line-number-at-pos (car candidate))
  292. (if (or (= nlines (1+ ivy-height))
  293. (< ivy--length ivy-height))
  294. 0
  295. (- ivy-height nlines))
  296. -2)))
  297. (ivy--exhibit)
  298. (ivy-done)
  299. (ivy-call))
  300. ((or (consp candidate)
  301. (number-or-marker-p candidate))
  302. (ivy-quit-and-run
  303. (avy-action-goto (avy-candidate-beg candidate))))))
  304. ;;;###autoload
  305. (defun swiper-avy ()
  306. "Jump to one of the current swiper candidates."
  307. (interactive)
  308. (unless (require 'avy nil 'noerror)
  309. (error "Package avy isn't installed"))
  310. (cl-case (length ivy-text)
  311. (0
  312. (user-error "Need at least one char of input"))
  313. (1
  314. (let ((swiper-min-highlight 1))
  315. (swiper--update-input-ivy))))
  316. (swiper--avy-goto (swiper--avy-candidate)))
  317. (declare-function mc/create-fake-cursor-at-point "ext:multiple-cursors-core")
  318. (declare-function multiple-cursors-mode "ext:multiple-cursors-core")
  319. (defun swiper-mc ()
  320. "Create a fake cursor for each `swiper' candidate.
  321. Make sure `swiper-mc' is on `mc/cmds-to-run-once' list."
  322. (interactive)
  323. (unless (require 'multiple-cursors nil t)
  324. (error "Multiple-cursors isn't installed"))
  325. (unless (window-minibuffer-p)
  326. (error "Call me only from `swiper'"))
  327. (let ((cands (nreverse ivy--old-cands))
  328. (action (ivy--get-action ivy-last)))
  329. (unless (string= ivy-text "")
  330. (ivy-exit-with-action
  331. (lambda (_)
  332. (let (cand)
  333. (while (setq cand (pop cands))
  334. (funcall action cand)
  335. (when cands
  336. (mc/create-fake-cursor-at-point))))
  337. (multiple-cursors-mode 1))))))
  338. (defvar swiper--current-window-start nil
  339. "Store `window-start' to restore it later.
  340. This prevents a \"jumping\" behavior which occurs when variables
  341. such as `scroll-conservatively' are set to a high value.")
  342. (defun swiper-recenter-top-bottom (&optional arg)
  343. "Call (`recenter-top-bottom' ARG)."
  344. (interactive "P")
  345. (with-ivy-window
  346. (recenter-top-bottom arg)
  347. (setq swiper--current-window-start (window-start))))
  348. (defvar swiper-font-lock-exclude
  349. '(Man-mode
  350. adoc-mode
  351. bbdb-mode
  352. bongo-library-mode
  353. bongo-mode
  354. bongo-playlist-mode
  355. bookmark-bmenu-mode
  356. circe-channel-mode
  357. circe-query-mode
  358. circe-server-mode
  359. deadgrep-mode
  360. debbugs-gnu-mode
  361. dired-mode
  362. elfeed-search-mode
  363. elfeed-show-mode
  364. emms-playlist-mode
  365. emms-stream-mode
  366. erc-mode
  367. eshell-mode
  368. eww-mode
  369. forth-block-mode
  370. forth-mode
  371. fundamental-mode
  372. gnus-article-mode
  373. gnus-group-mode
  374. gnus-summary-mode
  375. help-mode
  376. helpful-mode
  377. jabber-chat-mode
  378. magit-popup-mode
  379. matrix-client-mode
  380. matrix-client-room-list-mode
  381. mu4e-headers-mode
  382. mu4e-view-mode
  383. nix-mode
  384. notmuch-search-mode
  385. notmuch-tree-mode
  386. occur-edit-mode
  387. occur-mode
  388. org-agenda-mode
  389. package-menu-mode
  390. rcirc-mode
  391. sauron-mode
  392. treemacs-mode
  393. twittering-mode
  394. vc-dir-mode
  395. w3m-mode
  396. woman-mode
  397. xref--xref-buffer-mode)
  398. "List of major-modes that are incompatible with `font-lock-ensure'.")
  399. (defun swiper-font-lock-ensure-p ()
  400. "Return non-nil if we should `font-lock-ensure'."
  401. (or (derived-mode-p 'magit-mode)
  402. (bound-and-true-p magit-blame-mode)
  403. (memq major-mode swiper-font-lock-exclude)
  404. (not (derived-mode-p 'prog-mode))))
  405. (defun swiper-font-lock-ensure ()
  406. "Ensure the entire buffer is highlighted."
  407. (unless (swiper-font-lock-ensure-p)
  408. (unless (or (> (buffer-size) 100000) (null font-lock-mode))
  409. (if (fboundp 'font-lock-ensure)
  410. (font-lock-ensure)
  411. (with-no-warnings (font-lock-fontify-buffer))))))
  412. (defvar swiper--format-spec ""
  413. "Store the current candidates format spec.")
  414. (defvar swiper--width nil
  415. "Store the number of digits needed for the longest line number.")
  416. (defvar swiper-use-visual-line nil
  417. "When non-nil, use `line-move' instead of `forward-line'.")
  418. (defvar dired-isearch-filenames)
  419. (declare-function dired-move-to-filename "dired")
  420. (defun swiper--line ()
  421. (let* ((beg (cond ((and (eq major-mode 'dired-mode)
  422. (bound-and-true-p dired-isearch-filenames))
  423. (dired-move-to-filename)
  424. (point))
  425. (swiper-use-visual-line
  426. (save-excursion
  427. (beginning-of-visual-line)
  428. (point)))
  429. (t
  430. (point))))
  431. (end (if swiper-use-visual-line
  432. (save-excursion
  433. (end-of-visual-line)
  434. (point))
  435. (line-end-position))))
  436. (concat
  437. " "
  438. (buffer-substring beg end))))
  439. (declare-function outline-show-all "outline")
  440. (defvar swiper-use-visual-line-p
  441. (lambda (n-lines)
  442. (and visual-line-mode
  443. ;; super-slow otherwise
  444. (< (buffer-size) 20000)
  445. (< n-lines 400)))
  446. "A predicate that decides whether `line-move' or `forward-line' is used.
  447. Note that `line-move' can be very slow.")
  448. (defun swiper--candidates (&optional numbers-width)
  449. "Return a list of this buffer lines.
  450. NUMBERS-WIDTH, when specified, is used for width spec of line
  451. numbers; replaces calculating the width from buffer line count."
  452. (let* ((inhibit-field-text-motion t)
  453. (n-lines (count-lines (point-min) (point-max))))
  454. (if (funcall swiper-use-visual-line-p n-lines)
  455. (progn
  456. (when (eq major-mode 'org-mode)
  457. (require 'outline)
  458. (if (fboundp 'outline-show-all)
  459. (outline-show-all)
  460. (with-no-warnings
  461. (show-all))))
  462. (setq swiper-use-visual-line t))
  463. (setq swiper-use-visual-line nil))
  464. (unless (zerop n-lines)
  465. (setq swiper--width (or numbers-width
  466. (1+ (floor (log n-lines 10)))))
  467. (setq swiper--format-spec
  468. (format "%%-%dd " swiper--width))
  469. (let ((line-number 1)
  470. (advancer (if swiper-use-visual-line
  471. (lambda (arg) (line-move arg t))
  472. #'forward-line))
  473. candidates)
  474. (save-excursion
  475. (goto-char (point-min))
  476. (swiper-font-lock-ensure)
  477. (while (< (point) (point-max))
  478. (when (swiper-match-usable-p)
  479. (let ((str (swiper--line)))
  480. (setq str (ivy-cleanup-string str))
  481. (let ((line-number-str
  482. (format swiper--format-spec line-number)))
  483. (if swiper-include-line-number-in-search
  484. (setq str (concat line-number-str str))
  485. (put-text-property
  486. 0 1 'display line-number-str str))
  487. (put-text-property
  488. 0 1 'swiper-line-number line-number str))
  489. (push str candidates)))
  490. (funcall advancer 1)
  491. (cl-incf line-number))
  492. (nreverse candidates))))))
  493. (defvar swiper--opoint 1
  494. "The point when `swiper' starts.")
  495. ;;;###autoload
  496. (defun swiper-backward (&optional initial-input)
  497. "`isearch-backward' with an overview.
  498. When non-nil, INITIAL-INPUT is the initial search pattern."
  499. (interactive)
  500. (let ((ivy-index-functions-alist
  501. '((swiper . ivy-recompute-index-swiper-backward))))
  502. (swiper initial-input)))
  503. ;;;###autoload
  504. (defun swiper-thing-at-point ()
  505. "`swiper' with `ivy-thing-at-point'."
  506. (interactive)
  507. (let ((thing (ivy-thing-at-point)))
  508. (when (use-region-p)
  509. (deactivate-mark))
  510. (swiper thing)))
  511. ;;;###autoload
  512. (defun swiper-all-thing-at-point ()
  513. "`swiper-all' with `ivy-thing-at-point'."
  514. (interactive)
  515. (let ((thing (ivy-thing-at-point)))
  516. (when (use-region-p)
  517. (deactivate-mark))
  518. (swiper-all thing)))
  519. (defun swiper--extract-matches (regex cands)
  520. "Extract captured REGEX groups from CANDS."
  521. (let (res)
  522. (dolist (cand cands)
  523. (setq cand (substring cand 1))
  524. (when (string-match regex cand)
  525. (push (mapconcat (lambda (n) (match-string-no-properties n cand))
  526. (number-sequence
  527. 1
  528. (/ (- (length (match-data)) 2) 2))
  529. " ")
  530. res)))
  531. (nreverse res)))
  532. (defun swiper--occur-cands (fname cands)
  533. (when cands
  534. (with-current-buffer (ivy-state-buffer ivy-last)
  535. (when (eq (ivy-state-caller ivy-last) 'swiper-isearch)
  536. (setq cands (mapcar #'swiper--line-at-point cands)))
  537. (let* ((pt-min (point-min))
  538. (line-delta
  539. (save-restriction
  540. (widen)
  541. (1- (line-number-at-pos pt-min))))
  542. (lines
  543. (if (eq (ivy-state-caller ivy-last) 'swiper-isearch)
  544. (swiper--isearch-occur-cands cands)
  545. (mapcar (lambda (s)
  546. (let ((n (get-text-property 0 'swiper-line-number s)))
  547. (setq s (substring s 1))
  548. (add-text-properties 0 1 (list 'swiper-line-number n) s)
  549. (cons n s)))
  550. cands)))
  551. (offset (+ (length fname) 2)))
  552. (mapcar (lambda (x)
  553. (let ((nn (number-to-string
  554. (+ (car x) line-delta))))
  555. (remove-text-properties 0 1 '(display) (cdr x))
  556. (put-text-property 0 (length nn) 'face 'ivy-grep-line-number nn)
  557. (put-text-property 0 1 'offset (+ offset (length nn)) fname)
  558. (format "%s:%s:%s" fname nn (cdr x))))
  559. lines)))))
  560. (defun swiper--isearch-occur-cands (cands)
  561. (let* ((last-pt (get-text-property 0 'point (car cands)))
  562. (line (1+ (line-number-at-pos last-pt)))
  563. res pt)
  564. (dolist (cand cands)
  565. (setq pt (get-text-property 0 'point cand))
  566. (cl-incf line (1- (count-lines last-pt pt)))
  567. (push (cons line cand) res)
  568. (setq last-pt pt))
  569. (nreverse res)))
  570. (defun swiper--occur-insert-lines (cands)
  571. (let ((inhibit-read-only t))
  572. ;; Need precise number of header lines for `wgrep' to work.
  573. (insert (format "-*- mode:grep; default-directory: %S -*-\n\n\n"
  574. default-directory))
  575. (insert (format "%d candidates:\n" (length cands)))
  576. (ivy--occur-insert-lines cands)
  577. (goto-char (point-min))
  578. (forward-line 4)))
  579. (defun swiper--occur-buffer ()
  580. (let ((buffer (ivy-state-buffer ivy-last)))
  581. (unless (buffer-live-p buffer)
  582. (setq buffer
  583. (setf (ivy-state-buffer ivy-last)
  584. (find-file-noselect
  585. (plist-get (ivy-state-extra-props ivy-last) :fname))))
  586. (save-selected-window
  587. (pop-to-buffer buffer))
  588. (setf (ivy-state-window ivy-last) (selected-window)))
  589. buffer))
  590. (defun swiper-occur (&optional cands)
  591. "Generate a custom occur buffer for `swiper'.
  592. When capture groups are present in the input, print them instead of lines."
  593. (let* ((buffer (swiper--occur-buffer))
  594. (fname (propertize
  595. (with-ivy-window
  596. (if (buffer-file-name buffer)
  597. (file-name-nondirectory
  598. (buffer-file-name buffer))
  599. (buffer-name buffer)))
  600. 'face
  601. 'ivy-grep-info))
  602. (ivy-text (progn (string-match "\"\\(.*\\)\"" (buffer-name))
  603. (match-string 1 (buffer-name))))
  604. (re (mapconcat #'identity (ivy--split ivy-text) ".*?"))
  605. (cands
  606. (swiper--occur-cands
  607. fname
  608. (or cands
  609. (save-window-excursion
  610. (setq ivy--old-re nil)
  611. (switch-to-buffer buffer)
  612. (if (eq (ivy-state-caller ivy-last) 'swiper)
  613. (let ((ivy--regex-function 'swiper--re-builder))
  614. (ivy--filter re (swiper--candidates)))
  615. (swiper-isearch-function ivy-text)))))))
  616. (if (string-match-p "\\\\(" re)
  617. (insert
  618. (mapconcat #'identity
  619. (swiper--extract-matches
  620. re (with-current-buffer buffer
  621. (swiper--candidates)))
  622. "\n"))
  623. (unless (eq major-mode 'ivy-occur-grep-mode)
  624. (ivy-occur-grep-mode)
  625. (font-lock-mode -1))
  626. (swiper--occur-insert-lines
  627. (mapcar (lambda (cand) (concat "./" cand)) cands)))))
  628. (declare-function evil-set-jump "ext:evil-jumps")
  629. (defvar swiper--current-line nil)
  630. (defvar swiper--current-match-start nil)
  631. (defvar swiper--point-min nil)
  632. (defvar swiper--point-max nil)
  633. (defvar swiper--reveal-mode nil)
  634. (defun swiper--init ()
  635. "Perform initialization common to both completion methods."
  636. (setq swiper--current-line nil)
  637. (setq swiper--current-match-start nil)
  638. (setq swiper--current-window-start nil)
  639. (setq swiper--opoint (point))
  640. (setq swiper--point-min (point-min))
  641. (setq swiper--point-max (point-max))
  642. (when (setq swiper--reveal-mode
  643. (bound-and-true-p reveal-mode))
  644. (reveal-mode -1))
  645. (lazy-highlight-cleanup t)
  646. (setq isearch-opened-overlays nil)
  647. (when (bound-and-true-p evil-mode)
  648. (evil-set-jump)))
  649. (declare-function char-fold-to-regexp "char-fold")
  650. (defun swiper--re-builder (str)
  651. "Transform STR into a swiper regex.
  652. This is the regex used in the minibuffer where candidates have
  653. line numbers. For the buffer, use `ivy--regex' instead."
  654. (let* ((re-builder (ivy-alist-setting ivy-re-builders-alist))
  655. (re (cond
  656. ((equal str "")
  657. "")
  658. ((equal str "^")
  659. (setq ivy--subexps 0)
  660. ".")
  661. ((= (aref str 0) ?^)
  662. (let* ((re (funcall re-builder (substring str 1)))
  663. (re (if (listp re)
  664. (mapconcat (lambda (x)
  665. (format "\\(%s\\)" (car x)))
  666. (cl-remove-if-not #'cdr re)
  667. ".*?")
  668. re)))
  669. (cond
  670. ((string= re "$")
  671. "^$")
  672. ((zerop ivy--subexps)
  673. (prog1 (format "^ ?\\(%s\\)" re)
  674. (setq ivy--subexps 1)))
  675. (t
  676. (format "^ %s" re)))))
  677. ((eq (bound-and-true-p search-default-mode) 'char-fold-to-regexp)
  678. (if (string-match "\\`\\\\_<\\(.+\\)\\\\_>\\'" str)
  679. (concat
  680. "\\_<"
  681. (char-fold-to-regexp (match-string 1 str))
  682. "\\_>")
  683. (let ((subs (ivy--split str)))
  684. (setq ivy--subexps (length subs))
  685. (mapconcat
  686. (lambda (s) (format "\\(%s\\)" (char-fold-to-regexp s)))
  687. subs
  688. ".*?"))))
  689. (t
  690. (funcall re-builder str)))))
  691. re))
  692. (defvar swiper-history nil
  693. "History for `swiper'.")
  694. (defvar swiper-invocation-face nil
  695. "The face at the point of invocation of `swiper'.")
  696. (defcustom swiper-stay-on-quit nil
  697. "When non-nil don't go back to search start on abort."
  698. :type 'boolean)
  699. ;;;###autoload
  700. (defun swiper (&optional initial-input)
  701. "`isearch-forward' with an overview.
  702. When non-nil, INITIAL-INPUT is the initial search pattern."
  703. (interactive)
  704. (let ((candidates (swiper--candidates)))
  705. (swiper--init)
  706. (setq swiper-invocation-face
  707. (plist-get (text-properties-at (point)) 'face))
  708. (let ((preselect
  709. (if (or swiper-use-visual-line (null search-invisible))
  710. (count-screen-lines
  711. (point-min)
  712. (save-excursion (beginning-of-visual-line) (point)))
  713. (1- (line-number-at-pos))))
  714. (minibuffer-allow-text-properties t)
  715. res)
  716. (unwind-protect
  717. (and
  718. (setq res
  719. (ivy-read
  720. "Swiper: "
  721. candidates
  722. :initial-input initial-input
  723. :keymap swiper-map
  724. :preselect
  725. (if initial-input
  726. (cl-position-if
  727. (lambda (x)
  728. (= (1+ preselect) (get-text-property 0 'swiper-line-number x)))
  729. (progn
  730. (setq ivy--old-re nil)
  731. (ivy--filter initial-input candidates)))
  732. preselect)
  733. :require-match t
  734. :action #'swiper--action
  735. :re-builder #'swiper--re-builder
  736. :history 'swiper-history
  737. :extra-props (list :fname (buffer-file-name))
  738. :caller 'swiper))
  739. (point))
  740. (unless (or res swiper-stay-on-quit)
  741. (goto-char swiper--opoint))
  742. (unless (or res (string= ivy-text ""))
  743. (cl-pushnew ivy-text swiper-history))
  744. (setq swiper--current-window-start nil)
  745. (when swiper--reveal-mode
  746. (reveal-mode 1))))))
  747. (ivy-configure 'swiper
  748. :occur #'swiper-occur
  749. :update-fn #'swiper--update-input-ivy
  750. :unwind-fn #'swiper--cleanup
  751. :index-fn #'ivy-recompute-index-swiper)
  752. (defun swiper-toggle-face-matching ()
  753. "Toggle matching only the candidates with `swiper-invocation-face'."
  754. (interactive)
  755. (setf (ivy-state-matcher ivy-last)
  756. (if (ivy-state-matcher ivy-last)
  757. nil
  758. #'swiper--face-matcher))
  759. (setq ivy--old-re nil))
  760. (defun swiper--face-matcher (regexp candidates)
  761. "Return REGEXP matching CANDIDATES.
  762. Matched candidates should have `swiper-invocation-face'."
  763. (cl-remove-if-not
  764. (lambda (x)
  765. (and (string-match regexp x)
  766. (let* ((s (match-string 0 x))
  767. (n (length s))
  768. (i 0))
  769. (while (and (< i n)
  770. (text-property-any
  771. i (1+ i)
  772. 'face swiper-invocation-face
  773. s))
  774. (cl-incf i))
  775. (= i n))))
  776. candidates))
  777. (defun swiper--ensure-visible ()
  778. "Remove overlays hiding point."
  779. (let ((overlays (overlays-at (1- (point))))
  780. ov expose)
  781. (while (setq ov (pop overlays))
  782. (if (and (invisible-p (overlay-get ov 'invisible))
  783. (setq expose (overlay-get ov 'isearch-open-invisible)))
  784. (funcall expose ov)))))
  785. (defvar swiper--overlays nil
  786. "Store overlays.")
  787. (defvar swiper--isearch-highlight-timer nil
  788. "This timer used by `swiper--delayed-add-overlays'.")
  789. (defun swiper--cleanup ()
  790. "Clean up the overlays."
  791. (while swiper--overlays
  792. (delete-overlay (pop swiper--overlays)))
  793. ;; force cleanup unless it's :unwind
  794. (lazy-highlight-cleanup
  795. (if (eq ivy-exit 'done) lazy-highlight-cleanup t))
  796. (when (timerp swiper--isearch-highlight-timer)
  797. (cancel-timer swiper--isearch-highlight-timer)
  798. (setq swiper--isearch-highlight-timer nil)))
  799. (defun swiper--add-cursor-overlay (wnd)
  800. (let* ((special (or (eolp) (looking-at "\t")))
  801. (ov (make-overlay (point) (if special (point) (1+ (point))))))
  802. (if special
  803. (overlay-put ov 'after-string (propertize " " 'face 'ivy-cursor))
  804. (overlay-put ov 'face 'ivy-cursor))
  805. (overlay-put ov 'window wnd)
  806. (overlay-put ov 'priority 2)
  807. (push ov swiper--overlays)))
  808. (defun swiper--add-line-overlay (wnd)
  809. (let ((beg (if visual-line-mode
  810. (save-excursion
  811. (beginning-of-visual-line)
  812. (point))
  813. (line-beginning-position)))
  814. (end (if visual-line-mode
  815. (save-excursion
  816. (end-of-visual-line)
  817. (point))
  818. (1+ (line-end-position)))))
  819. (push (swiper--make-overlay beg end 'swiper-line-face wnd 0)
  820. swiper--overlays)))
  821. (defun swiper--make-overlay (beg end face wnd priority)
  822. "Create an overlay bound by BEG and END.
  823. FACE, WND and PRIORITY are properties corresponding to
  824. the face, window and priority of the overlay."
  825. (let ((overlay (make-overlay beg end)))
  826. (overlay-put overlay 'face face)
  827. (overlay-put overlay 'window wnd)
  828. (overlay-put overlay 'priority priority)
  829. overlay))
  830. (defun swiper--recenter-p ()
  831. (or (display-graphic-p)
  832. (not recenter-redisplay)))
  833. (defun swiper--positive-regexps (str)
  834. (let ((regexp-or-regexps
  835. (funcall ivy--regex-function str)))
  836. (if (listp regexp-or-regexps)
  837. (mapcar #'car (cl-remove-if-not #'cdr regexp-or-regexps))
  838. (list regexp-or-regexps))))
  839. (defun swiper--update-input-ivy ()
  840. "Called when `ivy' input is updated."
  841. (with-ivy-window
  842. (swiper--cleanup)
  843. (when (> (length (ivy-state-current ivy-last)) 0)
  844. (let ((regexps (swiper--positive-regexps ivy-text))
  845. (re-idx -1)
  846. (case-fold-search (ivy--case-fold-p ivy-text)))
  847. (dolist (re regexps)
  848. (setq re-idx (1+ re-idx))
  849. (let* ((re (replace-regexp-in-string
  850. " " "\t"
  851. re))
  852. (num (get-text-property 0 'swiper-line-number (ivy-state-current ivy-last))))
  853. (unless (memq this-command '(ivy-yank-word
  854. ivy-yank-symbol
  855. ivy-yank-char
  856. scroll-other-window))
  857. (when (cl-plusp num)
  858. (unless (if swiper--current-line
  859. (eq swiper--current-line num)
  860. (eq (line-number-at-pos) num))
  861. (goto-char swiper--point-min)
  862. (if swiper-use-visual-line
  863. (line-move (1- num))
  864. (forward-line (1- num))))
  865. (if (and (equal ivy-text "")
  866. (>= swiper--opoint (line-beginning-position))
  867. (<= swiper--opoint (line-end-position)))
  868. (goto-char swiper--opoint)
  869. (if (eq swiper--current-line num)
  870. (when swiper--current-match-start
  871. (goto-char swiper--current-match-start))
  872. (setq swiper--current-line num))
  873. (when (re-search-forward re (line-end-position) t)
  874. (setq swiper--current-match-start (match-beginning 0))))
  875. (isearch-range-invisible (line-beginning-position)
  876. (line-end-position))
  877. (swiper--maybe-recenter)))
  878. (swiper--add-overlays
  879. re
  880. (max
  881. (if (swiper--recenter-p)
  882. (window-start)
  883. (line-beginning-position (- (window-height))))
  884. swiper--point-min)
  885. (min
  886. (if (swiper--recenter-p)
  887. (window-end (selected-window) t)
  888. (line-end-position (window-height)))
  889. swiper--point-max)
  890. nil
  891. re-idx)))))))
  892. (defun swiper--add-overlays (re &optional beg end wnd re-idx)
  893. "Add overlays for RE regexp in visible part of the current buffer.
  894. BEG and END, when specified, are the point bounds.
  895. WND, when specified is the window."
  896. (setq wnd (or wnd (ivy-state-window ivy-last)))
  897. (swiper--add-line-overlay wnd)
  898. (let* ((pt (point))
  899. (wh (window-height))
  900. (beg (or beg (save-excursion
  901. (forward-line (- wh))
  902. (point))))
  903. (end (or end (save-excursion
  904. (forward-line wh)
  905. (point))))
  906. (case-fold-search (ivy--case-fold-p re)))
  907. (when (>= (length re) swiper-min-highlight)
  908. (save-excursion
  909. (goto-char beg)
  910. ;; RE can become an invalid regexp
  911. (while (and (ignore-errors (re-search-forward re end t))
  912. (> (- (match-end 0) (match-beginning 0)) 0))
  913. ;; Don't highlight a match if it spans multiple
  914. ;; lines. `count-lines' returns 1 if the match is within a
  915. ;; single line, even if it includes the newline, and 2 or
  916. ;; greater otherwise. We hope that the inclusion of the
  917. ;; newline will not ever be a problem in practice.
  918. (when (< (count-lines (match-beginning 0) (match-end 0)) 2)
  919. (let* ((faces (if (= (match-end 0) pt)
  920. swiper-faces
  921. swiper-background-faces))
  922. (adder-fn (lambda (beg end face priority)
  923. (push (swiper--make-overlay beg end face wnd priority)
  924. isearch-lazy-highlight-overlays))))
  925. (unless (and (consp ivy--old-re)
  926. (null
  927. (save-match-data
  928. (ivy--re-filter ivy--old-re
  929. (list
  930. (buffer-substring-no-properties
  931. (line-beginning-position)
  932. (line-end-position)))))))
  933. (swiper--add-properties faces adder-fn re-idx)))))))))
  934. (defun swiper--add-properties (faces adder-fn &optional re-idx)
  935. (let ((mb (match-beginning 0))
  936. (me (match-end 0)))
  937. (unless (> (- me mb) 2017)
  938. (funcall adder-fn
  939. mb me
  940. (if (zerop ivy--subexps)
  941. (nth (1+ (mod (or re-idx 0) (1- (length faces)))) faces)
  942. (car faces))
  943. 0)))
  944. (let ((i 1)
  945. (j 0))
  946. (while (<= (cl-incf j) ivy--subexps)
  947. (let ((bm (match-beginning j))
  948. (em (match-end j)))
  949. (when (and (integerp em)
  950. (integerp bm))
  951. (while (and (< j ivy--subexps)
  952. (integerp (match-beginning (+ j 1)))
  953. (= em (match-beginning (+ j 1))))
  954. (setq em (match-end (cl-incf j))))
  955. (funcall adder-fn
  956. bm em
  957. (nth (1+ (mod (+ i 2) (1- (length faces))))
  958. faces)
  959. i)
  960. (cl-incf i))))))
  961. (defcustom swiper-action-recenter nil
  962. "When non-nil, recenter after exiting `swiper'."
  963. :type 'boolean)
  964. (defvar evil-search-module)
  965. (defvar evil-ex-search-pattern)
  966. (defvar evil-ex-search-persistent-highlight)
  967. (defvar evil-ex-search-direction)
  968. (declare-function evil-ex-search-activate-highlight "evil-ex")
  969. (defun swiper--maybe-recenter ()
  970. (cond (swiper-action-recenter
  971. (recenter))
  972. ((swiper--recenter-p)
  973. (when swiper--current-window-start
  974. (set-window-start (selected-window) swiper--current-window-start))
  975. (when (or
  976. (< (point) (window-start))
  977. (> (point) (window-end (ivy-state-window ivy-last) t)))
  978. (recenter))))
  979. (setq swiper--current-window-start (window-start)))
  980. (defun swiper--action (x)
  981. "Goto line X."
  982. (let ((ln (1- (get-text-property 0 'swiper-line-number x)))
  983. (re (ivy--regex ivy-text))
  984. (case-fold-search (ivy--case-fold-p ivy-text)))
  985. (if (null x)
  986. (user-error "No candidates")
  987. (with-ivy-window
  988. (unless (equal (current-buffer)
  989. (ivy-state-buffer ivy-last))
  990. (switch-to-buffer (ivy-state-buffer ivy-last)))
  991. (goto-char
  992. (if (buffer-narrowed-p)
  993. swiper--point-min
  994. (point-min)))
  995. (funcall (if swiper-use-visual-line
  996. #'line-move
  997. #'forward-line)
  998. ln)
  999. (when (and (re-search-forward re (line-end-position) t) swiper-goto-start-of-match)
  1000. (goto-char (match-beginning 0)))
  1001. (swiper--ensure-visible)
  1002. (swiper--maybe-recenter)
  1003. (when (/= (point) swiper--opoint)
  1004. (unless (and transient-mark-mode mark-active)
  1005. (when (eq ivy-exit 'done)
  1006. (push-mark swiper--opoint t)
  1007. (message "Mark saved where search started"))))
  1008. (add-to-history
  1009. 'regexp-search-ring
  1010. re
  1011. regexp-search-ring-max)
  1012. ;; integration with evil-mode's search
  1013. (when (bound-and-true-p evil-mode)
  1014. (when (eq evil-search-module 'isearch)
  1015. (setq isearch-string ivy-text))
  1016. (when (eq evil-search-module 'evil-search)
  1017. (add-to-history 'evil-ex-search-history re)
  1018. (setq evil-ex-search-pattern (list re t t))
  1019. (setq evil-ex-search-direction 'forward)
  1020. (when evil-ex-search-persistent-highlight
  1021. (evil-ex-search-activate-highlight evil-ex-search-pattern))))))))
  1022. (defun swiper-from-isearch ()
  1023. "Invoke `swiper' from isearch."
  1024. (interactive)
  1025. (let ((query (if isearch-regexp
  1026. isearch-string
  1027. (regexp-quote isearch-string))))
  1028. (isearch-exit)
  1029. (swiper query)))
  1030. (defvar swiper-multi-buffers nil
  1031. "Store the current list of buffers.")
  1032. (defvar swiper-multi-candidates nil
  1033. "Store the list of candidates for `swiper-multi'.")
  1034. (defun swiper-multi-prompt ()
  1035. "Return prompt for `swiper-multi'."
  1036. (format "Buffers (%s): "
  1037. (mapconcat #'identity swiper-multi-buffers ", ")))
  1038. (defvar swiper-window-width 80)
  1039. (defun swiper-multi ()
  1040. "Select one or more buffers.
  1041. Run `swiper' for those buffers."
  1042. (interactive)
  1043. (setq swiper-multi-buffers nil)
  1044. (let ((ivy-use-virtual-buffers nil))
  1045. (ivy-read (swiper-multi-prompt)
  1046. #'internal-complete-buffer
  1047. :action #'swiper-multi-action-1))
  1048. (let ((swiper-window-width (- (- (frame-width) (if (display-graphic-p) 0 1)) 4)))
  1049. (ivy-read "Swiper: " swiper-multi-candidates
  1050. :action #'swiper-multi-action-2
  1051. :caller 'swiper-multi)))
  1052. (ivy-configure 'swiper-multi
  1053. :unwind-fn #'swiper--cleanup
  1054. :index-fn #'ivy-recompute-index-swiper
  1055. :format-fn #'swiper--all-format-function)
  1056. (defun swiper-multi-action-1 (x)
  1057. "Add X to list of selected buffers `swiper-multi-buffers'.
  1058. If X is already part of the list, remove it instead. Quit the selection if
  1059. X is selected by either `ivy-done', `ivy-alt-done' or `ivy-immediate-done',
  1060. otherwise continue prompting for buffers."
  1061. (if (member x swiper-multi-buffers)
  1062. (progn
  1063. (setq swiper-multi-buffers (delete x swiper-multi-buffers)))
  1064. (unless (equal x "")
  1065. (setq swiper-multi-buffers (append swiper-multi-buffers (list x)))))
  1066. (let ((prompt (swiper-multi-prompt)))
  1067. (setf (ivy-state-prompt ivy-last) prompt)
  1068. (setq ivy--prompt (concat "%-4d " prompt)))
  1069. (cond ((memq this-command '(ivy-done
  1070. ivy-alt-done
  1071. ivy-immediate-done))
  1072. (setq swiper-multi-candidates
  1073. (swiper--multi-candidates
  1074. (mapcar #'get-buffer swiper-multi-buffers))))
  1075. ((eq this-command 'ivy-call)
  1076. (with-selected-window (active-minibuffer-window)
  1077. (delete-minibuffer-contents)))))
  1078. (defun swiper-multi-action-2 (x)
  1079. "Move to candidate X from `swiper-multi'."
  1080. (when (> (length x) 0)
  1081. (let ((buffer-name (get-text-property 0 'buffer x)))
  1082. (when buffer-name
  1083. (with-ivy-window
  1084. (switch-to-buffer buffer-name)
  1085. (goto-char (point-min))
  1086. (forward-line (1- (get-text-property 0 'swiper-line-number x)))
  1087. (re-search-forward
  1088. (ivy--regex ivy-text)
  1089. (line-end-position) t)
  1090. (isearch-range-invisible (line-beginning-position)
  1091. (line-end-position))
  1092. (unless (eq ivy-exit 'done)
  1093. (swiper--cleanup)
  1094. (swiper--add-overlays (ivy--regex ivy-text))))))))
  1095. (defun swiper-all-buffer-p (buffer)
  1096. "Return non-nil if BUFFER should be considered by `swiper-all'."
  1097. (let ((mode (buffer-local-value 'major-mode (get-buffer buffer))))
  1098. (cond
  1099. ;; Ignore TAGS buffers, they tend to add duplicate results.
  1100. ((eq mode #'tags-table-mode) nil)
  1101. ;; Always consider dired buffers, even though they're not backed
  1102. ;; by a file.
  1103. ((eq mode #'dired-mode) t)
  1104. ;; Always consider stash buffers too, as they may have
  1105. ;; interesting content not present in any buffers. We don't #'
  1106. ;; quote to satisfy the byte-compiler.
  1107. ((eq mode 'magit-stash-mode) t)
  1108. ;; Email buffers have no file, but are useful to search
  1109. ((eq mode 'gnus-article-mode) t)
  1110. ;; Otherwise, only consider the file if it's backed by a file.
  1111. (t (buffer-file-name buffer)))))
  1112. ;;* `swiper-all'
  1113. (defun swiper-all-function (str)
  1114. "Search in all open buffers for STR."
  1115. (or
  1116. (ivy-more-chars)
  1117. (let* ((buffers (cl-remove-if-not #'swiper-all-buffer-p (buffer-list)))
  1118. (re-full (funcall ivy--regex-function str))
  1119. re re-tail
  1120. cands match
  1121. (case-fold-search (ivy--case-fold-p str)))
  1122. (setq re (ivy-re-to-str re-full))
  1123. (when (consp re-full)
  1124. (setq re-tail (cdr re-full)))
  1125. (dolist (buffer buffers)
  1126. (with-current-buffer buffer
  1127. (save-excursion
  1128. (goto-char (point-min))
  1129. (while (re-search-forward re nil t)
  1130. (setq match (if (memq major-mode '(org-mode dired-mode))
  1131. (buffer-substring-no-properties
  1132. (line-beginning-position)
  1133. (line-end-position))
  1134. (buffer-substring
  1135. (line-beginning-position)
  1136. (line-end-position))))
  1137. (put-text-property
  1138. 0 1 'buffer
  1139. (buffer-name)
  1140. match)
  1141. (put-text-property 0 1 'point (point) match)
  1142. (when (or (null re-tail) (ivy-re-match re-tail match))
  1143. (push match cands))))))
  1144. (setq ivy--old-re re-full)
  1145. (if (null cands)
  1146. (list "")
  1147. (setq ivy--old-cands (nreverse cands))))))
  1148. (defun swiper--all-format-function (cands)
  1149. "Format CANDS for `swiper-all'.
  1150. See `ivy-format-functions-alist' for further information."
  1151. (let* ((ww swiper-window-width)
  1152. (col2 1)
  1153. (cands-with-buffer
  1154. (mapcar (lambda (s)
  1155. (let ((buffer (get-text-property 0 'buffer s)))
  1156. (setq col2 (max col2 (length buffer)))
  1157. (cons s buffer))) cands))
  1158. (col1 (- ww 4 col2)))
  1159. (setq cands
  1160. (mapcar (lambda (x)
  1161. (if (cdr x)
  1162. (let ((s (ivy--truncate-string (car x) col1)))
  1163. (concat
  1164. s
  1165. (make-string
  1166. (max 0
  1167. (- ww (string-width s) (length (cdr x))))
  1168. ?\ )
  1169. (cdr x)))
  1170. (car x)))
  1171. cands-with-buffer))
  1172. (ivy--format-function-generic
  1173. (lambda (str)
  1174. (ivy--add-face str 'ivy-current-match))
  1175. (lambda (str)
  1176. str)
  1177. cands
  1178. "\n")))
  1179. (defvar swiper-all-map
  1180. (let ((map (make-sparse-keymap)))
  1181. (define-key map (kbd "M-q") 'swiper-all-query-replace)
  1182. map)
  1183. "Keymap for `swiper-all'.")
  1184. ;;;###autoload
  1185. (defun swiper-all (&optional initial-input)
  1186. "Run `swiper' for all open buffers."
  1187. (interactive)
  1188. (let ((swiper-window-width (- (frame-width) (if (display-graphic-p) 0 1))))
  1189. (ivy-read "swiper-all: " 'swiper-all-function
  1190. :action #'swiper-all-action
  1191. :dynamic-collection t
  1192. :keymap swiper-all-map
  1193. :initial-input initial-input
  1194. :caller 'swiper-all)))
  1195. (ivy-configure 'swiper-all
  1196. :update-fn 'auto
  1197. :unwind-fn #'swiper--cleanup
  1198. :format-fn #'swiper--all-format-function)
  1199. (defun swiper-all-action (x)
  1200. "Move to candidate X from `swiper-all'."
  1201. (when (> (length x) 0)
  1202. (let ((buffer-name (get-text-property 0 'buffer x)))
  1203. (when buffer-name
  1204. (with-ivy-window
  1205. (switch-to-buffer buffer-name)
  1206. (goto-char (get-text-property 0 'point x))
  1207. (isearch-range-invisible (line-beginning-position)
  1208. (line-end-position))
  1209. (unless (eq ivy-exit 'done)
  1210. (swiper--cleanup)
  1211. (swiper--add-overlays (ivy--regex ivy-text))))))))
  1212. (defun swiper--multi-candidates (buffers)
  1213. "Extract candidates from BUFFERS."
  1214. (let ((res nil))
  1215. (dolist (buf buffers)
  1216. (with-current-buffer buf
  1217. (setq res
  1218. (nconc
  1219. (mapcar
  1220. (lambda (s) (put-text-property 0 1 'buffer (buffer-name) s) s)
  1221. (swiper--candidates 4))
  1222. res))))
  1223. res))
  1224. ;;* `swiper-isearch'
  1225. (defun swiper-isearch-function (str)
  1226. "Collect STR matches in the current buffer for `swiper-isearch'."
  1227. (with-ivy-window
  1228. (swiper--isearch-function str)))
  1229. (defun swiper-match-usable-p ()
  1230. (or search-invisible
  1231. (not (cl-find-if
  1232. (lambda (ov)
  1233. (invisible-p (overlay-get ov 'invisible)))
  1234. (overlays-at (point))))))
  1235. (defvar swiper--isearch-backward nil)
  1236. (defvar swiper--isearch-start-point nil)
  1237. (defun swiper--isearch-function-1 (re backward)
  1238. (unless (string= re ".")
  1239. (let (cands)
  1240. (save-excursion
  1241. (goto-char (if backward (point-max) (point-min)))
  1242. (while (and (funcall (if backward #'re-search-backward #'re-search-forward) re nil t)
  1243. (not (if backward (bobp) (eobp))))
  1244. (when (swiper-match-usable-p)
  1245. (let ((pos (if (or backward swiper-goto-start-of-match)
  1246. (match-beginning 0)
  1247. (point))))
  1248. (push pos cands)))
  1249. (when (= (match-beginning 0) (match-end 0))
  1250. (if backward
  1251. (backward-char)
  1252. (forward-char)))))
  1253. (if backward
  1254. cands
  1255. (nreverse cands)))))
  1256. (defun swiper--isearch-next-item (re cands)
  1257. (if swiper--isearch-backward
  1258. (or
  1259. (cl-position-if
  1260. (lambda (x)
  1261. (and
  1262. (< x swiper--isearch-start-point)
  1263. (eq 0 (string-match-p
  1264. re
  1265. (buffer-substring-no-properties
  1266. x swiper--isearch-start-point)))))
  1267. cands
  1268. :from-end t)
  1269. 0)
  1270. (or
  1271. (cl-position-if
  1272. (lambda (x) (> x swiper--isearch-start-point))
  1273. cands)
  1274. 0)))
  1275. (defun swiper--isearch-filter-ignore-order (re-full cands)
  1276. (let (filtered-cands)
  1277. (dolist (re-cons re-full cands)
  1278. (save-excursion
  1279. (dolist (cand cands)
  1280. (goto-char cand)
  1281. (beginning-of-line)
  1282. (unless (if (re-search-forward (car re-cons) (line-end-position) t)
  1283. (not (cdr re-cons))
  1284. (cdr re-cons))
  1285. (push cand filtered-cands))))
  1286. (setq cands (nreverse filtered-cands))
  1287. (setq filtered-cands nil))))
  1288. (defun swiper--isearch-function (str)
  1289. (let ((re-full (funcall ivy--regex-function str)))
  1290. (unless (equal re-full "")
  1291. (let* ((case-fold-search (ivy--case-fold-p str))
  1292. (re
  1293. (if (stringp re-full)
  1294. re-full
  1295. (mapconcat
  1296. #'ivy--regex-or-literal
  1297. (delq nil (mapcar (lambda (x) (and (cdr x) (car x))) re-full))
  1298. "\\|")))
  1299. (cands (swiper--isearch-function-1 re swiper--isearch-backward)))
  1300. (when (consp re-full)
  1301. (setq cands (swiper--isearch-filter-ignore-order re-full cands)))
  1302. (setq ivy--old-re re)
  1303. (ivy-set-index (swiper--isearch-next-item re cands))
  1304. (setq ivy--old-cands cands)))))
  1305. (defcustom swiper-isearch-highlight-delay '(2 0.2)
  1306. "When `ivy-text' is too short, delay showing the overlay.
  1307. The default value will delay showing the overlay by 0.2 seconds
  1308. if `ivy-text' is shorter than 2 characters.
  1309. The aim is to reduce the visual clutter, since it's very rare
  1310. that we search only for one character."
  1311. :type '(list
  1312. (integer :tag "Text length")
  1313. (float :tag "Delay in seconds")))
  1314. (defun swiper--delayed-add-overlays ()
  1315. (if (and swiper-isearch-highlight-delay
  1316. (< (length ivy-text) (car swiper-isearch-highlight-delay)))
  1317. (setq swiper--isearch-highlight-timer
  1318. (run-with-idle-timer
  1319. (cadr swiper-isearch-highlight-delay) nil
  1320. (lambda ()
  1321. (with-ivy-window
  1322. (swiper--add-overlays (ivy--regex ivy-text))))))
  1323. (dolist (re (swiper--positive-regexps ivy-text))
  1324. (swiper--add-overlays re))))
  1325. (defun swiper-isearch-action (x)
  1326. "Move to X for `swiper-isearch'."
  1327. (if (or (numberp x)
  1328. (and (> (length x) 0)
  1329. (setq x (get-text-property 0 'point x))))
  1330. (with-ivy-window
  1331. (goto-char x)
  1332. (when (and (or (eq this-command 'ivy-previous-line-or-history)
  1333. (and (eq this-command 'ivy-done)
  1334. (eq last-command 'ivy-previous-line-or-history)))
  1335. (looking-back ivy--old-re (line-beginning-position)))
  1336. (goto-char (match-beginning 0)))
  1337. (isearch-range-invisible (point) (1+ (point)))
  1338. (swiper--maybe-recenter)
  1339. (unless (eq ivy-exit 'done)
  1340. (swiper--cleanup)
  1341. (swiper--delayed-add-overlays)
  1342. (swiper--add-cursor-overlay
  1343. (ivy-state-window ivy-last))))
  1344. (swiper--cleanup)))
  1345. (defun swiper-action-copy (_x)
  1346. "Copy line at point and go back."
  1347. (kill-new
  1348. (buffer-substring-no-properties
  1349. (line-beginning-position) (line-end-position)))
  1350. (goto-char swiper--opoint))
  1351. (ivy-add-actions 'swiper-isearch '(("w" swiper-action-copy "copy")))
  1352. (ivy-add-actions 'swiper '(("w" swiper-action-copy "copy")))
  1353. (defun swiper-isearch-thing-at-point ()
  1354. "Insert `symbol-at-point' into the minibuffer of `swiper-isearch'.
  1355. When not running `swiper-isearch' already, start it."
  1356. (interactive)
  1357. (if (window-minibuffer-p)
  1358. (let (bnd str regionp)
  1359. (with-ivy-window
  1360. (setq bnd
  1361. (if (setq regionp (region-active-p))
  1362. (prog1 (cons (region-beginning) (region-end))
  1363. (deactivate-mark))
  1364. (bounds-of-thing-at-point 'symbol)))
  1365. (setq str (buffer-substring-no-properties (car bnd) (cdr bnd))))
  1366. (insert str)
  1367. (unless regionp
  1368. (ivy--insert-symbol-boundaries)))
  1369. (let (thing)
  1370. (if (use-region-p)
  1371. (progn
  1372. (setq thing (buffer-substring-no-properties
  1373. (region-beginning) (region-end)))
  1374. (goto-char (region-beginning))
  1375. (deactivate-mark))
  1376. (let ((bnd (bounds-of-thing-at-point 'symbol)))
  1377. (when bnd
  1378. (goto-char (car bnd)))
  1379. (setq thing (ivy-thing-at-point))))
  1380. (swiper-isearch thing))))
  1381. (defvar swiper-isearch-map
  1382. (let ((map (make-sparse-keymap)))
  1383. (set-keymap-parent map swiper-map)
  1384. (define-key map (kbd "M-n") 'swiper-isearch-thing-at-point)
  1385. map)
  1386. "Keymap for `swiper-isearch'.")
  1387. (defun swiper--isearch-same-line-p (s1 s2)
  1388. "Check if S1 and S2 are equal and on the same line."
  1389. (and (equal s1 s2)
  1390. (<= (count-lines
  1391. (get-text-property 0 'point s2)
  1392. (get-text-property 0 'point s1))
  1393. 1)))
  1394. (defun swiper-isearch-format-function (cands)
  1395. (if (numberp (car-safe cands))
  1396. (if (string= ivy--old-re "^$")
  1397. ""
  1398. (swiper--isearch-format
  1399. ivy--index ivy--length ivy--old-cands
  1400. ivy--old-re
  1401. (ivy-state-current ivy-last)
  1402. (ivy-state-buffer ivy-last)))
  1403. (ivy-format-function-default cands)))
  1404. (defun swiper--line-at-point (pt)
  1405. (save-excursion
  1406. (goto-char pt)
  1407. (let ((s (buffer-substring
  1408. (line-beginning-position)
  1409. (line-end-position))))
  1410. (put-text-property 0 1 'point pt s)
  1411. (ivy-cleanup-string s))))
  1412. (defun swiper--isearch-highlight (str &optional current)
  1413. (let ((start 0)
  1414. (i 0))
  1415. (while (string-match ivy--old-re str start)
  1416. (setq start (match-end 0))
  1417. (swiper--add-properties
  1418. (if (eq current i)
  1419. swiper-faces
  1420. swiper-background-faces)
  1421. (lambda (beg end face _priority)
  1422. (ivy-add-face-text-property
  1423. beg end face str)))
  1424. (cl-incf i))
  1425. str))
  1426. (defun swiper--isearch-format (index length cands regex current buffer)
  1427. (let* ((half-height (/ ivy-height 2))
  1428. (i (1- index))
  1429. (j 0)
  1430. (len 0)
  1431. res s)
  1432. (with-current-buffer buffer
  1433. (while (and (>= i 0)
  1434. (swiper--isearch-same-line-p
  1435. (swiper--line-at-point (nth i cands))
  1436. (swiper--line-at-point current)))
  1437. (cl-decf i)
  1438. (cl-incf j))
  1439. (while (and (>= i 0)
  1440. (< len half-height))
  1441. (setq s (swiper--line-at-point (nth i cands)))
  1442. (unless (swiper--isearch-same-line-p s (car res))
  1443. (push (swiper--isearch-highlight s) res)
  1444. (cl-incf len))
  1445. (cl-decf i))
  1446. (setq res (nreverse res))
  1447. (let ((current-str
  1448. (swiper--line-at-point current))
  1449. (start 0))
  1450. (dotimes (_ (1+ j))
  1451. (string-match regex current-str start)
  1452. (setq start (match-end 0)))
  1453. (swiper--isearch-highlight current-str j)
  1454. (font-lock-append-text-property
  1455. 0 (length current-str)
  1456. 'face 'swiper-line-face current-str)
  1457. (push current-str res))
  1458. (cl-incf len)
  1459. (setq i (1+ index))
  1460. (while (and (< i length)
  1461. (swiper--isearch-same-line-p
  1462. (swiper--line-at-point (nth i cands))
  1463. (swiper--line-at-point current)))
  1464. (cl-incf i))
  1465. (while (and (< i length)
  1466. (< len ivy-height))
  1467. (setq s (swiper--line-at-point (nth i cands)))
  1468. (unless (swiper--isearch-same-line-p s (car res))
  1469. (push (swiper--isearch-highlight s) res)
  1470. (cl-incf len))
  1471. (cl-incf i))
  1472. (mapconcat #'identity (nreverse res) "\n"))))
  1473. ;;;###autoload
  1474. (defun swiper-isearch (&optional initial-input)
  1475. "A `swiper' that's not line-based."
  1476. (interactive)
  1477. (swiper--init)
  1478. (setq swiper--isearch-start-point (point))
  1479. (swiper-font-lock-ensure)
  1480. (let ((ivy-fixed-height-minibuffer t)
  1481. (cursor-in-non-selected-windows nil)
  1482. (swiper-min-highlight 1)
  1483. res)
  1484. (unwind-protect
  1485. (and
  1486. (setq res
  1487. (ivy-read
  1488. "Swiper: "
  1489. #'swiper-isearch-function
  1490. :initial-input initial-input
  1491. :keymap swiper-isearch-map
  1492. :dynamic-collection t
  1493. :require-match t
  1494. :action #'swiper-isearch-action
  1495. :re-builder #'swiper--re-builder
  1496. :history 'swiper-history
  1497. :extra-props (list :fname (buffer-file-name))
  1498. :caller 'swiper-isearch))
  1499. (point))
  1500. (unless (or res swiper-stay-on-quit)
  1501. (goto-char swiper--opoint))
  1502. (isearch-clean-overlays)
  1503. (swiper--ensure-visible)
  1504. (unless (or res (string= ivy-text ""))
  1505. (cl-pushnew ivy-text swiper-history)))))
  1506. (ivy-configure 'swiper-isearch
  1507. :occur #'swiper-occur
  1508. :update-fn 'auto
  1509. :unwind-fn #'swiper--cleanup
  1510. :format-fn #'swiper-isearch-format-function)
  1511. ;;;###autoload
  1512. (defun swiper-isearch-backward (&optional initial-input)
  1513. "Like `swiper-isearch' but the first result is before the point."
  1514. (interactive)
  1515. (let ((swiper--isearch-backward t))
  1516. (swiper-isearch initial-input)))
  1517. (defun swiper-isearch-toggle ()
  1518. "Two-way toggle between `swiper-isearch' and isearch.
  1519. Intended to be bound in `isearch-mode-map' and `swiper-map'."
  1520. (interactive)
  1521. (if isearch-mode
  1522. (let ((query (if isearch-regexp
  1523. isearch-string
  1524. (regexp-quote isearch-string))))
  1525. (isearch-exit)
  1526. (goto-char (or (and isearch-forward isearch-other-end)
  1527. (point)))
  1528. (swiper-isearch query))
  1529. (ivy-exit-with-action
  1530. (lambda (_)
  1531. (when (looking-back ivy--old-re (line-beginning-position))
  1532. (goto-char (match-beginning 0)))
  1533. (isearch-mode t)
  1534. (unless (string= ivy-text "")
  1535. (isearch-yank-string ivy-text))))))
  1536. (provide 'swiper)
  1537. ;;; swiper.el ends here