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.

1721 lines
60 KiB

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