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.

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