]> code.delx.au - gnu-emacs-elpa/blob - ivy.el
Add work-around for minibuffer not re-sizing for many frames
[gnu-emacs-elpa] / ivy.el
1 ;;; ivy.el --- Incremental Vertical completYon -*- lexical-binding: t -*-
2
3 ;; Copyright (C) 2015 Free Software Foundation, Inc.
4
5 ;; Author: Oleh Krehel <ohwoeowho@gmail.com>
6 ;; URL: https://github.com/abo-abo/swiper
7 ;; Package-Requires: ((emacs "24.1"))
8 ;; Keywords: matching
9
10 ;; This file is part of GNU Emacs.
11
12 ;; This file is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 3, or (at your option)
15 ;; any later version.
16
17 ;; This program is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ;; GNU General Public License for more details.
21
22 ;; For a full copy of the GNU General Public License
23 ;; see <http://www.gnu.org/licenses/>.
24
25 ;;; Commentary:
26 ;;
27 ;; This package provides `ivy-read' as an alternative to
28 ;; `completing-read' and similar functions.
29 ;;
30 ;; There's no intricate code to determine the best candidate.
31 ;; Instead, the user can navigate to it with `ivy-next-line' and
32 ;; `ivy-previous-line'.
33 ;;
34 ;; The matching is done by splitting the input text by spaces and
35 ;; re-building it into a regex.
36 ;; So "for example" is transformed into "\\(for\\).*\\(example\\)".
37
38 ;;; Code:
39 (require 'cl-lib)
40
41 ;;* Customization
42 (defgroup ivy nil
43 "Incremental vertical completion."
44 :group 'convenience)
45
46 (defface ivy-current-match
47 '((((class color) (background light))
48 :background "#1a4b77" :foreground "white")
49 (((class color) (background dark))
50 :background "#65a7e2" :foreground "black"))
51 "Face used by Ivy for highlighting first match.")
52
53 (defface ivy-confirm-face
54 '((t :foreground "ForestGreen" :inherit minibuffer-prompt))
55 "Face used by Ivy to issue a confirmation prompt.")
56
57 (defface ivy-match-required-face
58 '((t :foreground "red" :inherit minibuffer-prompt))
59 "Face used by Ivy to issue a match required prompt.")
60
61 (defface ivy-subdir
62 '((t (:inherit 'dired-directory)))
63 "Face used by Ivy for highlighting subdirs in the alternatives.")
64
65 (defface ivy-remote
66 '((t (:foreground "#110099")))
67 "Face used by Ivy for highlighting remotes in the alternatives.")
68
69 (defcustom ivy-height 10
70 "Number of lines for the minibuffer window."
71 :type 'integer)
72
73 (defcustom ivy-count-format "%-4d "
74 "The style of showing the current candidate count for `ivy-read'.
75 Set this to nil if you don't want the count. You can also set it
76 to e.g. \"(%d/%d) \" if you want to see both the candidate index
77 and the candidate count."
78 :type '(choice (const :tag "Count disabled" nil) string))
79
80 (defcustom ivy-wrap nil
81 "Whether to wrap around after the first and last candidate."
82 :type 'boolean)
83
84 (defcustom ivy-display-style nil
85 "The style for formatting the minibuffer.
86
87 By default, the matched strings will be copied as they are.
88
89 With the fancy method, the matching parts of the regexp will be
90 additionally highlighted, just like `swiper' does it."
91 :type '(choice
92 (const :tag "Plain" nil)
93 (const :tag "Fancy" fancy)))
94
95 (defcustom ivy-on-del-error-function 'minibuffer-keyboard-quit
96 "The handler for when `ivy-backward-delete-char' throws.
97 This is usually meant as a quick exit out of the minibuffer."
98 :type 'function)
99
100 (defcustom ivy-extra-directories '("../" "./")
101 "Add this to the front of the list when completing file names.
102 Only \"./\" and \"../\" apply here. They appear in reverse order."
103 :type 'list)
104
105 (defcustom ivy-use-virtual-buffers nil
106 "When non-nil, add `recentf-mode' and bookmarks to the list of buffers."
107 :type 'boolean)
108
109 (defvar ivy--actions-list nil
110 "A list of extra actions per command.")
111
112 (defun ivy-set-actions (cmd actions)
113 "Set CMD extra exit points to ACTIONS."
114 (setq ivy--actions-list
115 (plist-put ivy--actions-list cmd actions)))
116
117 ;;* Keymap
118 (require 'delsel)
119 (defvar ivy-minibuffer-map
120 (let ((map (make-sparse-keymap)))
121 (define-key map (kbd "C-m") 'ivy-done)
122 (define-key map (kbd "C-M-m") 'ivy-call)
123 (define-key map (kbd "C-j") 'ivy-alt-done)
124 (define-key map (kbd "C-M-j") 'ivy-immediate-done)
125 (define-key map (kbd "TAB") 'ivy-partial-or-done)
126 (define-key map (kbd "C-n") 'ivy-next-line)
127 (define-key map (kbd "C-p") 'ivy-previous-line)
128 (define-key map (kbd "<down>") 'ivy-next-line)
129 (define-key map (kbd "<up>") 'ivy-previous-line)
130 (define-key map (kbd "C-s") 'ivy-next-line-or-history)
131 (define-key map (kbd "C-r") 'ivy-reverse-i-search)
132 (define-key map (kbd "SPC") 'self-insert-command)
133 (define-key map (kbd "DEL") 'ivy-backward-delete-char)
134 (define-key map (kbd "M-DEL") 'ivy-backward-kill-word)
135 (define-key map (kbd "C-d") 'ivy-delete-char)
136 (define-key map (kbd "C-f") 'ivy-forward-char)
137 (define-key map (kbd "M-d") 'ivy-kill-word)
138 (define-key map (kbd "M-<") 'ivy-beginning-of-buffer)
139 (define-key map (kbd "M->") 'ivy-end-of-buffer)
140 (define-key map (kbd "<left>") 'ivy-beginning-of-buffer)
141 (define-key map (kbd "<right>") 'ivy-end-of-buffer)
142 (define-key map (kbd "M-n") 'ivy-next-history-element)
143 (define-key map (kbd "M-p") 'ivy-previous-history-element)
144 (define-key map (kbd "C-g") 'minibuffer-keyboard-quit)
145 (define-key map (kbd "C-v") 'ivy-scroll-up-command)
146 (define-key map (kbd "M-v") 'ivy-scroll-down-command)
147 (define-key map (kbd "C-M-n") 'ivy-next-line-and-call)
148 (define-key map (kbd "C-M-p") 'ivy-previous-line-and-call)
149 (define-key map (kbd "M-q") 'ivy-toggle-regexp-quote)
150 (define-key map (kbd "M-j") 'ivy-yank-word)
151 (define-key map (kbd "M-i") 'ivy-insert-current)
152 (define-key map (kbd "C-o") 'hydra-ivy/body)
153 (define-key map (kbd "M-o") 'ivy-dispatching-done)
154 (define-key map (kbd "C-k") 'ivy-kill-line)
155 (define-key map (kbd "S-SPC") 'ivy-restrict-to-matches)
156 (define-key map (kbd "M-w") 'ivy-kill-ring-save)
157 map)
158 "Keymap used in the minibuffer.")
159 (autoload 'hydra-ivy/body "ivy-hydra" "" t)
160
161 (defvar ivy-mode-map
162 (let ((map (make-sparse-keymap)))
163 (define-key map [remap switch-to-buffer] 'ivy-switch-buffer)
164 map)
165 "Keymap for `ivy-mode'.")
166
167 ;;* Globals
168 (cl-defstruct ivy-state
169 prompt collection
170 predicate require-match initial-input
171 history preselect keymap update-fn sort
172 ;; The window in which `ivy-read' was called
173 window
174 action
175 unwind
176 re-builder
177 matcher
178 ;; When this is non-nil, call it for each input change to get new candidates
179 dynamic-collection)
180
181 (defvar ivy-last nil
182 "The last parameters passed to `ivy-read'.")
183
184 (defsubst ivy-set-action (action)
185 (setf (ivy-state-action ivy-last) action))
186
187 (defvar ivy-history nil
188 "History list of candidates entered in the minibuffer.
189
190 Maximum length of the history list is determined by the value
191 of `history-length', which see.")
192
193 (defvar ivy--directory nil
194 "Current directory when completing file names.")
195
196 (defvar ivy--length 0
197 "Store the amount of viable candidates.")
198
199 (defvar ivy-text ""
200 "Store the user's string as it is typed in.")
201
202 (defvar ivy--current ""
203 "Current candidate.")
204
205 (defvar ivy--index 0
206 "Store the index of the current candidate.")
207
208 (defvar ivy-exit nil
209 "Store 'done if the completion was successfully selected.
210 Otherwise, store nil.")
211
212 (defvar ivy--all-candidates nil
213 "Store the candidates passed to `ivy-read'.")
214
215 (defvar ivy--default nil
216 "Default initial input.")
217
218 (defvar ivy--prompt nil
219 "Store the format-style prompt.
220 When non-nil, it should contain one %d.")
221
222 (defvar ivy--prompt-extra ""
223 "Temporary modifications to the prompt.")
224
225 (defvar ivy--old-re nil
226 "Store the old regexp.")
227
228 (defvar ivy--old-cands nil
229 "Store the candidates matched by `ivy--old-re'.")
230
231 (defvar ivy--regex-function 'ivy--regex
232 "Current function for building a regex.")
233
234 (defvar ivy--subexps 0
235 "Number of groups in the current `ivy--regex'.")
236
237 (defvar ivy--full-length nil
238 "When :dynamic-collection is non-nil, this can be the total amount of candidates.")
239
240 (defvar ivy--old-text ""
241 "Store old `ivy-text' for dynamic completion.")
242
243 (defvar Info-current-file)
244
245 (defmacro ivy-quit-and-run (&rest body)
246 "Quit the minibuffer and run BODY afterwards."
247 `(progn
248 (put 'quit 'error-message "")
249 (run-at-time nil nil
250 (lambda ()
251 (put 'quit 'error-message "Quit")
252 ,@body))
253 (minibuffer-keyboard-quit)))
254
255 (defmacro with-ivy-window (&rest body)
256 "Execute BODY in the window from which `ivy-read' was called."
257 (declare (indent 0)
258 (debug t))
259 `(with-selected-window (ivy-state-window ivy-last)
260 ,@body))
261
262 (defun ivy--done (text)
263 "Insert TEXT and exit minibuffer."
264 (if (and ivy--directory
265 (not (eq (ivy-state-history ivy-last) 'grep-files-history)))
266 (insert (setq ivy--current (expand-file-name
267 text ivy--directory)))
268 (insert (setq ivy--current text)))
269 (setq ivy-exit 'done)
270 (exit-minibuffer))
271
272 ;;* Commands
273 (defun ivy-done ()
274 "Exit the minibuffer with the selected candidate."
275 (interactive)
276 (delete-minibuffer-contents)
277 (cond ((> ivy--length 0)
278 (ivy--done ivy--current))
279 ((memq (ivy-state-collection ivy-last)
280 '(read-file-name-internal internal-complete-buffer))
281 (if (or (not (eq confirm-nonexistent-file-or-buffer t))
282 (equal " (confirm)" ivy--prompt-extra))
283 (ivy--done ivy-text)
284 (setq ivy--prompt-extra " (confirm)")
285 (insert ivy-text)
286 (ivy--exhibit)))
287 ((memq (ivy-state-require-match ivy-last)
288 '(nil confirm confirm-after-completion))
289 (ivy--done ivy-text))
290 (t
291 (setq ivy--prompt-extra " (match required)")
292 (insert ivy-text)
293 (ivy--exhibit))))
294
295 (defun ivy-dispatching-done ()
296 "Select one of the available actions and call `ivy-done'."
297 (interactive)
298 (let ((actions (ivy-state-action ivy-last)))
299 (if (null (ivy--actionp actions))
300 (ivy-done)
301 (let* ((hint (concat ivy--current
302 "\n"
303 (mapconcat
304 (lambda (x)
305 (format "%s: %s"
306 (propertize
307 (car x)
308 'face 'font-lock-builtin-face)
309 (nth 2 x)))
310 (cdr actions)
311 "\n")
312 "\n"))
313 (key (string (read-key hint)))
314 (action (assoc key (cdr actions))))
315 (cond ((string= key "\a"))
316 ((null action)
317 (error "%s is not bound" key))
318 (t
319 (message "")
320 (ivy-set-action (nth 1 action))
321 (ivy-done)))))))
322
323 (defun ivy-build-tramp-name (x)
324 "Reconstruct X into a path.
325 Is is a cons cell, related to `tramp-get-completion-function'."
326 (let ((user (car x))
327 (domain (cadr x)))
328 (if user
329 (concat user "@" domain)
330 domain)))
331
332 (declare-function tramp-get-completion-function "tramp")
333 (declare-function Info-find-node "info")
334
335 (defun ivy-alt-done (&optional arg)
336 "Exit the minibuffer with the selected candidate.
337 When ARG is t, exit with current text, ignoring the candidates."
338 (interactive "P")
339 (let (dir)
340 (cond (arg
341 (ivy-immediate-done))
342 ((and ivy--directory
343 (or
344 (and
345 (not (string= ivy--current "./"))
346 (cl-plusp ivy--length)
347 (file-directory-p
348 (setq dir (expand-file-name
349 ivy--current ivy--directory))))))
350 (ivy--cd dir)
351 (ivy--exhibit))
352 ((eq (ivy-state-collection ivy-last) 'Info-read-node-name-1)
353 (if (or (equal ivy--current "(./)")
354 (equal ivy--current "(../)"))
355 (ivy-quit-and-run
356 (ivy-read "Go to file: " 'read-file-name-internal
357 :action (lambda (x)
358 (Info-find-node
359 (expand-file-name x ivy--directory)
360 "Top"))))
361 (ivy-done)))
362 ((and ivy--directory
363 (string-match "\\`/[^/]+:.*:.*\\'" ivy-text))
364 (ivy-done))
365 ((and ivy--directory
366 (string-match
367 "\\`/\\([^/]+?\\):\\(?:\\(.*\\)@\\)?\\(.*\\)\\'"
368 ivy-text))
369 (let ((method (match-string 1 ivy-text))
370 (user (match-string 2 ivy-text))
371 (rest (match-string 3 ivy-text))
372 res)
373 (require 'tramp)
374 (dolist (x (tramp-get-completion-function method))
375 (setq res (append res (funcall (car x) (cadr x)))))
376 (setq res (delq nil res))
377 (when user
378 (dolist (x res)
379 (setcar x user)))
380 (setq res (cl-delete-duplicates res :test #'equal))
381 (let* ((old-ivy-last ivy-last)
382 (enable-recursive-minibuffers t)
383 (host (ivy-read "Find File: "
384 (mapcar #'ivy-build-tramp-name res)
385 :initial-input rest)))
386 (setq ivy-last old-ivy-last)
387 (when host
388 (setq ivy--directory "/")
389 (ivy--cd (concat "/" method ":" host ":"))))))
390 (t
391 (ivy-done)))))
392
393 (defcustom ivy-tab-space nil
394 "When non-nil, `ivy-partial-or-done' should insert a space."
395 :type 'boolean)
396
397 (defun ivy-partial-or-done ()
398 "Complete the minibuffer text as much as possible.
399 If the text hasn't changed as a result, forward to `ivy-alt-done'."
400 (interactive)
401 (if (and (eq (ivy-state-collection ivy-last) #'read-file-name-internal)
402 (string-match "\\`/" ivy-text))
403 (let ((default-directory ivy--directory))
404 (minibuffer-complete)
405 (setq ivy-text (ivy--input))
406 (when (and (file-directory-p ivy-text)
407 (= ivy--length 1))
408 (ivy--cd (expand-file-name ivy-text))))
409 (or (ivy-partial)
410 (when (or (eq this-command last-command)
411 (eq ivy--length 1))
412 (ivy-alt-done)))))
413
414 (defun ivy-partial ()
415 "Complete the minibuffer text as much as possible."
416 (interactive)
417 (let* ((parts (or (split-string ivy-text " " t) (list "")))
418 (postfix (car (last parts)))
419 (completion-ignore-case t)
420 (startp (string-match "^\\^" postfix))
421 (new (try-completion (if startp
422 (substring postfix 1)
423 postfix)
424 (mapcar (lambda (str) (substring str (string-match postfix str)))
425 ivy--old-cands))))
426 (cond ((eq new t) nil)
427 ((string= new ivy-text) nil)
428 (new
429 (delete-region (minibuffer-prompt-end) (point-max))
430 (setcar (last parts)
431 (if startp
432 (concat "^" new)
433 new))
434 (insert (mapconcat #'identity parts " ")
435 (if ivy-tab-space " " ""))
436 t))))
437
438 (defun ivy-immediate-done ()
439 "Exit the minibuffer with the current input."
440 (interactive)
441 (delete-minibuffer-contents)
442 (insert (setq ivy--current ivy-text))
443 (setq ivy-exit 'done)
444 (exit-minibuffer))
445
446 (defun ivy-resume ()
447 "Resume the last completion session."
448 (interactive)
449 (ivy-read
450 (ivy-state-prompt ivy-last)
451 (ivy-state-collection ivy-last)
452 :predicate (ivy-state-predicate ivy-last)
453 :require-match (ivy-state-require-match ivy-last)
454 :initial-input ivy-text
455 :history (ivy-state-history ivy-last)
456 :preselect (unless (eq (ivy-state-collection ivy-last)
457 'read-file-name-internal)
458 (regexp-quote ivy--current))
459 :keymap (ivy-state-keymap ivy-last)
460 :update-fn (ivy-state-update-fn ivy-last)
461 :sort (ivy-state-sort ivy-last)
462 :action (ivy-state-action ivy-last)
463 :unwind (ivy-state-unwind ivy-last)
464 :re-builder (ivy-state-re-builder ivy-last)
465 :matcher (ivy-state-matcher ivy-last)
466 :dynamic-collection (ivy-state-dynamic-collection ivy-last)))
467
468 (defvar ivy-calling nil
469 "When non-nil, call the current action when `ivy--index' changes.")
470
471 (defun ivy-set-index (index)
472 "Set `ivy--index' to INDEX."
473 (setq ivy--index index)
474 (when ivy-calling
475 (ivy--exhibit)
476 (ivy-call)))
477
478 (defun ivy-beginning-of-buffer ()
479 "Select the first completion candidate."
480 (interactive)
481 (ivy-set-index 0))
482
483 (defun ivy-end-of-buffer ()
484 "Select the last completion candidate."
485 (interactive)
486 (ivy-set-index (1- ivy--length)))
487
488 (defun ivy-scroll-up-command ()
489 "Scroll the candidates upward by the minibuffer height."
490 (interactive)
491 (ivy-set-index (min (+ ivy--index ivy-height)
492 (1- ivy--length))))
493
494 (defun ivy-scroll-down-command ()
495 "Scroll the candidates downward by the minibuffer height."
496 (interactive)
497 (ivy-set-index (max (- ivy--index ivy-height)
498 0)))
499 (defun ivy-minibuffer-grow ()
500 "Grow the minibuffer window by 1 line."
501 (interactive)
502 (setq-local max-mini-window-height
503 (cl-incf ivy-height)))
504
505 (defun ivy-minibuffer-shrink ()
506 "Shrink the minibuffer window by 1 line."
507 (interactive)
508 (unless (<= ivy-height 2)
509 (setq-local max-mini-window-height
510 (cl-decf ivy-height))
511 (window-resize (selected-window) -1)))
512
513 (defun ivy-next-line (&optional arg)
514 "Move cursor vertically down ARG candidates."
515 (interactive "p")
516 (setq arg (or arg 1))
517 (let ((index (+ ivy--index arg)))
518 (if (> index (1- ivy--length))
519 (if ivy-wrap
520 (ivy-beginning-of-buffer)
521 (ivy-set-index (1- ivy--length)))
522 (ivy-set-index index))))
523
524 (defun ivy-next-line-or-history (&optional arg)
525 "Move cursor vertically down ARG candidates.
526 If the input is empty, select the previous history element instead."
527 (interactive "p")
528 (when (string= ivy-text "")
529 (ivy-previous-history-element 1))
530 (ivy-next-line arg))
531
532 (defun ivy-previous-line (&optional arg)
533 "Move cursor vertically up ARG candidates."
534 (interactive "p")
535 (setq arg (or arg 1))
536 (let ((index (- ivy--index arg)))
537 (if (< index 0)
538 (if ivy-wrap
539 (ivy-end-of-buffer)
540 (ivy-set-index 0))
541 (ivy-set-index index))))
542
543 (defun ivy-previous-line-or-history (arg)
544 "Move cursor vertically up ARG candidates.
545 If the input is empty, select the previous history element instead."
546 (interactive "p")
547 (when (string= ivy-text "")
548 (ivy-previous-history-element 1))
549 (ivy-previous-line arg))
550
551 (defun ivy-toggle-calling ()
552 "Flip `ivy-calling'."
553 (interactive)
554 (when (setq ivy-calling (not ivy-calling))
555 (ivy-call)))
556
557 (defun ivy--get-action (state)
558 "Get the action function from STATE."
559 (let ((action (ivy-state-action state)))
560 (when action
561 (if (functionp action)
562 action
563 (cadr (nth (car action) action))))))
564
565 (defun ivy--actionp (x)
566 "Return non-nil when X is a list of actions."
567 (and x (listp x) (not (eq (car x) 'closure))))
568
569 (defun ivy-next-action ()
570 "When the current action is a list, scroll it forwards."
571 (interactive)
572 (let ((action (ivy-state-action ivy-last)))
573 (when (ivy--actionp action)
574 (unless (>= (car action) (1- (length action)))
575 (cl-incf (car action))))))
576
577 (defun ivy-prev-action ()
578 "When the current action is a list, scroll it backwards."
579 (interactive)
580 (let ((action (ivy-state-action ivy-last)))
581 (when (ivy--actionp action)
582 (unless (<= (car action) 1)
583 (cl-decf (car action))))))
584
585 (defun ivy-action-name ()
586 "Return the name associated with the current action."
587 (let ((action (ivy-state-action ivy-last)))
588 (if (ivy--actionp action)
589 (format "[%d/%d] %s"
590 (car action)
591 (1- (length action))
592 (nth 2 (nth (car action) action)))
593 "[1/1] default")))
594
595 (defun ivy-call ()
596 "Call the current action without exiting completion."
597 (interactive)
598 (let ((action (ivy--get-action ivy-last)))
599 (when action
600 (let* ((collection (ivy-state-collection ivy-last))
601 (x (if (and (consp collection)
602 (consp (car collection)))
603 (cdr (assoc ivy--current collection))
604 (if (equal ivy--current "")
605 ivy-text
606 ivy--current))))
607 (funcall action x)))))
608
609 (defun ivy-next-line-and-call (&optional arg)
610 "Move cursor vertically down ARG candidates.
611 Call the permanent action if possible."
612 (interactive "p")
613 (ivy-next-line arg)
614 (ivy--exhibit)
615 (ivy-call))
616
617 (defun ivy-previous-line-and-call (&optional arg)
618 "Move cursor vertically down ARG candidates.
619 Call the permanent action if possible."
620 (interactive "p")
621 (ivy-previous-line arg)
622 (ivy--exhibit)
623 (ivy-call))
624
625 (defun ivy-previous-history-element (arg)
626 "Forward to `previous-history-element' with ARG."
627 (interactive "p")
628 (previous-history-element arg)
629 (ivy--cd-maybe)
630 (move-end-of-line 1)
631 (ivy--maybe-scroll-history))
632
633 (defun ivy-next-history-element (arg)
634 "Forward to `next-history-element' with ARG."
635 (interactive "p")
636 (next-history-element arg)
637 (ivy--cd-maybe)
638 (move-end-of-line 1)
639 (ivy--maybe-scroll-history))
640
641 (defun ivy--cd-maybe ()
642 "Check if the current input points to a different directory.
643 If so, move to that directory, while keeping only the file name."
644 (when ivy--directory
645 (let* ((input (expand-file-name (ivy--input)))
646 (file (file-name-nondirectory input))
647 (dir (expand-file-name (file-name-directory input))))
648 (if (string= dir ivy--directory)
649 (progn
650 (delete-minibuffer-contents)
651 (insert file))
652 (ivy--cd dir)
653 (insert file)))))
654
655 (defun ivy--maybe-scroll-history ()
656 "If the selected history element has an index, scroll there."
657 (let ((idx (ignore-errors
658 (get-text-property
659 (minibuffer-prompt-end)
660 'ivy-index))))
661 (when idx
662 (ivy--exhibit)
663 (setq ivy--index idx))))
664
665 (defun ivy--cd (dir)
666 "When completing file names, move to directory DIR."
667 (if (null ivy--directory)
668 (error "Unexpected")
669 (setq ivy--old-cands nil)
670 (setq ivy--old-re nil)
671 (setq ivy--index 0)
672 (setq ivy--all-candidates
673 (ivy--sorted-files (setq ivy--directory dir)))
674 (setq ivy-text "")
675 (delete-minibuffer-contents)))
676
677 (defun ivy-backward-delete-char ()
678 "Forward to `backward-delete-char'.
679 On error (read-only), call `ivy-on-del-error-function'."
680 (interactive)
681 (if (and ivy--directory (= (minibuffer-prompt-end) (point)))
682 (progn
683 (ivy--cd (file-name-directory
684 (directory-file-name
685 (expand-file-name
686 ivy--directory))))
687 (ivy--exhibit))
688 (condition-case nil
689 (backward-delete-char 1)
690 (error
691 (when ivy-on-del-error-function
692 (funcall ivy-on-del-error-function))))))
693
694 (defun ivy-delete-char (arg)
695 "Forward to `delete-char' ARG."
696 (interactive "p")
697 (unless (= (point) (line-end-position))
698 (delete-char arg)))
699
700 (defun ivy-forward-char (arg)
701 "Forward to `forward-char' ARG."
702 (interactive "p")
703 (unless (= (point) (line-end-position))
704 (forward-char arg)))
705
706 (defun ivy-kill-word (arg)
707 "Forward to `kill-word' ARG."
708 (interactive "p")
709 (unless (= (point) (line-end-position))
710 (kill-word arg)))
711
712 (defun ivy-kill-line ()
713 "Forward to `kill-line'."
714 (interactive)
715 (if (eolp)
716 (kill-region (minibuffer-prompt-end) (point))
717 (kill-line)))
718
719 (defun ivy-backward-kill-word ()
720 "Forward to `backward-kill-word'."
721 (interactive)
722 (if (and ivy--directory (= (minibuffer-prompt-end) (point)))
723 (progn
724 (ivy--cd (file-name-directory
725 (directory-file-name
726 (expand-file-name
727 ivy--directory))))
728 (ivy--exhibit))
729 (ignore-errors
730 (let ((pt (point)))
731 (forward-word -1)
732 (delete-region (point) pt)))))
733
734 (defvar ivy--regexp-quote 'regexp-quote
735 "Store the regexp quoting state.")
736
737 (defun ivy-toggle-regexp-quote ()
738 "Toggle the regexp quoting."
739 (interactive)
740 (setq ivy--old-re nil)
741 (cl-rotatef ivy--regex-function ivy--regexp-quote))
742
743 (defun ivy-sort-file-function-default (x y)
744 "Compare two files X and Y.
745 Prioritize directories."
746 (if (get-text-property 0 'dirp x)
747 (if (get-text-property 0 'dirp y)
748 (string< x y)
749 t)
750 (if (get-text-property 0 'dirp y)
751 nil
752 (string< x y))))
753
754 (defvar ivy-sort-functions-alist
755 '((read-file-name-internal . ivy-sort-file-function-default)
756 (internal-complete-buffer . nil)
757 (counsel-git-grep-function . nil)
758 (Man-goto-section . nil)
759 (org-refile . nil)
760 (t . string-lessp))
761 "An alist of sorting functions for each collection function.
762 Interactive functions that call completion fit in here as well.
763
764 For each entry, nil means no sorting. It's very useful to turn
765 off the sorting for functions that have candidates in the natural
766 buffer order, like `org-refile' or `Man-goto-section'.
767
768 The entry associated to t is used for all fall-through cases.")
769
770 (defvar ivy-re-builders-alist
771 '((t . ivy--regex-plus))
772 "An alist of regex building functions for each collection function.
773 Each function should take a string and return a valid regex or a
774 regex sequence (see below).
775
776 The entry associated to t is used for all fall-through cases.
777 Possible choices: `ivy--regex', `regexp-quote', `ivy--regex-plus'.
778
779 In case a function returns a list, it should look like this:
780 '((\"matching-regexp\" . t) (\"non-matching-regexp\") ...).
781
782 The matches will be filtered in a sequence, you can mix the
783 regexps that should match and that should not match as you
784 like.")
785
786 (defvar ivy-initial-inputs-alist
787 '((org-refile . "^")
788 (org-agenda-refile . "^")
789 (org-capture-refile . "^")
790 (counsel-M-x . "^")
791 (counsel-describe-function . "^")
792 (counsel-describe-variable . "^")
793 (man . "^")
794 (woman . "^"))
795 "Command to initial input table.")
796
797 (defcustom ivy-sort-max-size 30000
798 "Sorting won't be done for collections larger than this."
799 :type 'integer)
800
801 (defun ivy--sorted-files (dir)
802 "Return the list of files in DIR.
803 Directories come first."
804 (let* ((default-directory dir)
805 (seq (all-completions "" 'read-file-name-internal))
806 sort-fn)
807 (if (equal dir "/")
808 seq
809 (setq seq (delete "./" (delete "../" seq)))
810 (when (eq (setq sort-fn (cdr (assoc 'read-file-name-internal
811 ivy-sort-functions-alist)))
812 #'ivy-sort-file-function-default)
813 (setq seq (mapcar (lambda (x)
814 (propertize x 'dirp (string-match-p "/\\'" x)))
815 seq)))
816 (when sort-fn
817 (setq seq (cl-sort seq sort-fn)))
818 (dolist (dir ivy-extra-directories)
819 (push dir seq))
820 seq)))
821
822 ;;** Entry Point
823 (cl-defun ivy-read (prompt collection
824 &key predicate require-match initial-input
825 history preselect keymap update-fn sort
826 action unwind re-builder matcher dynamic-collection)
827 "Read a string in the minibuffer, with completion.
828
829 PROMPT is a string to prompt with; normally it ends in a colon
830 and a space. When PROMPT contains %d, it will be updated with
831 the current number of matching candidates. If % appears elsewhere
832 in the PROMPT it should be quoted as %%.
833 See also `ivy-count-format'.
834
835 COLLECTION is a list of strings.
836
837 If INITIAL-INPUT is non-nil, insert it in the minibuffer initially.
838
839 KEYMAP is composed together with `ivy-minibuffer-map'.
840
841 If PRESELECT is non-nil select the corresponding candidate out of
842 the ones that match INITIAL-INPUT.
843
844 UPDATE-FN is called each time the current candidate(s) is changed.
845
846 When SORT is t, refer to `ivy-sort-functions-alist' for sorting.
847
848 ACTION is a lambda to call after a result was selected. It should
849 take a single argument, usually a string.
850
851 UNWIND is a lambda to call before exiting.
852
853 RE-BUILDER is a lambda that transforms text into a regex.
854
855 MATCHER can completely override matching.
856
857 DYNAMIC-COLLECTION is a function to call to update the list of
858 candidates with each input."
859 (let ((extra-actions (plist-get ivy--actions-list this-command)))
860 (when extra-actions
861 (setq action
862 (if (functionp action)
863 `(1
864 ("o" ,action "default")
865 ,@extra-actions)
866 (delete-dups (append action extra-actions))))))
867 (setq ivy-last
868 (make-ivy-state
869 :prompt prompt
870 :collection collection
871 :predicate predicate
872 :require-match require-match
873 :initial-input initial-input
874 :history history
875 :preselect preselect
876 :keymap keymap
877 :update-fn update-fn
878 :sort sort
879 :action action
880 :window (selected-window)
881 :unwind unwind
882 :re-builder re-builder
883 :matcher matcher
884 :dynamic-collection dynamic-collection))
885 (ivy--reset-state ivy-last)
886 (prog1
887 (unwind-protect
888 (minibuffer-with-setup-hook
889 #'ivy--minibuffer-setup
890 (let* ((hist (or history 'ivy-history))
891 (minibuffer-completion-table collection)
892 (minibuffer-completion-predicate predicate)
893 (res (read-from-minibuffer
894 prompt
895 (ivy-state-initial-input ivy-last)
896 (make-composed-keymap keymap ivy-minibuffer-map)
897 nil
898 hist)))
899 (when (eq ivy-exit 'done)
900 (let ((item (if ivy--directory
901 ivy--current
902 ivy-text)))
903 (unless (equal item "")
904 (set hist (cons (propertize item 'ivy-index ivy--index)
905 (delete item
906 (cdr (symbol-value hist)))))))
907 res)))
908 (remove-hook 'post-command-hook #'ivy--exhibit)
909 (when (setq unwind (ivy-state-unwind ivy-last))
910 (funcall unwind)))
911 (ivy-call)))
912
913 (defun ivy--reset-state (state)
914 "Reset the ivy to STATE.
915 This is useful for recursive `ivy-read'."
916 (let ((prompt (ivy-state-prompt state))
917 (collection (ivy-state-collection state))
918 (predicate (ivy-state-predicate state))
919 (history (ivy-state-history state))
920 (preselect (ivy-state-preselect state))
921 (sort (ivy-state-sort state))
922 (re-builder (ivy-state-re-builder state))
923 (dynamic-collection (ivy-state-dynamic-collection state))
924 (initial-input (ivy-state-initial-input state))
925 (require-match (ivy-state-require-match state))
926 (matcher (ivy-state-matcher state)))
927 (unless initial-input
928 (setq initial-input (cdr (assoc this-command
929 ivy-initial-inputs-alist))))
930 (setq ivy--directory nil)
931 (setq ivy--regex-function
932 (or re-builder
933 (and (functionp collection)
934 (cdr (assoc collection ivy-re-builders-alist)))
935 (cdr (assoc t ivy-re-builders-alist))
936 'ivy--regex))
937 (setq ivy--subexps 0)
938 (setq ivy--regexp-quote 'regexp-quote)
939 (setq ivy--old-text "")
940 (setq ivy--full-length nil)
941 (setq ivy-text "")
942 (setq ivy-calling nil)
943 (let (coll sort-fn)
944 (cond ((eq collection 'Info-read-node-name-1)
945 (if (equal Info-current-file "dir")
946 (setq coll
947 (mapcar (lambda (x) (format "(%s)" x))
948 (cl-delete-duplicates
949 (all-completions "(" collection predicate)
950 :test #'equal)))
951 (setq coll (all-completions "" collection predicate))))
952 ((eq collection 'read-file-name-internal)
953 (setq ivy--directory default-directory)
954 (require 'dired)
955 (when preselect
956 (let ((preselect-directory (file-name-directory preselect)))
957 (unless (or (null preselect-directory)
958 (string= preselect-directory
959 default-directory))
960 (setq ivy--directory preselect-directory))
961 (setq preselect (file-name-nondirectory preselect))))
962 (setq coll (ivy--sorted-files ivy--directory))
963 (when initial-input
964 (unless (or require-match
965 (equal initial-input default-directory)
966 (equal initial-input ""))
967 (setq coll (cons initial-input coll)))
968 (setq initial-input nil)))
969 ((eq collection 'internal-complete-buffer)
970 (setq coll (ivy--buffer-list "" ivy-use-virtual-buffers)))
971 ((or (functionp collection)
972 (byte-code-function-p collection)
973 (vectorp collection)
974 (listp (car collection)))
975 (setq coll (all-completions "" collection predicate)))
976 ((hash-table-p collection)
977 (error "Hash table as a collection unsupported"))
978 (t
979 (setq coll collection)))
980 (when sort
981 (if (and (functionp collection)
982 (setq sort-fn (assoc collection ivy-sort-functions-alist)))
983 (when (and (setq sort-fn (cdr sort-fn))
984 (not (eq collection 'read-file-name-internal)))
985 (setq coll (cl-sort coll sort-fn)))
986 (unless (eq history 'org-refile-history)
987 (if (and (setq sort-fn (cdr (assoc t ivy-sort-functions-alist)))
988 (<= (length coll) ivy-sort-max-size))
989 (setq coll (cl-sort (copy-sequence coll) sort-fn))))))
990 (when preselect
991 (unless (or (and require-match
992 (not (eq collection 'internal-complete-buffer)))
993 (let ((re (format "\\`%s" (regexp-quote preselect))))
994 (cl-find-if (lambda (x) (string-match re x))
995 coll)))
996 (setq coll (cons preselect coll))))
997 (setq ivy--index (or
998 (and dynamic-collection
999 ivy--index)
1000 (and preselect
1001 (ivy--preselect-index
1002 coll initial-input preselect matcher))
1003 0))
1004 (setq ivy--old-re nil)
1005 (setq ivy--old-cands nil)
1006 (setq ivy--all-candidates coll))
1007 (setq ivy-exit nil)
1008 (setq ivy--default (or (thing-at-point 'symbol) ""))
1009 (setq ivy--prompt
1010 (cond ((string-match "%.*d" prompt)
1011 prompt)
1012 ((null ivy-count-format)
1013 nil)
1014 ((string-match "%d.*%d" ivy-count-format)
1015 (let ((w (length (number-to-string
1016 (length ivy--all-candidates))))
1017 (s (copy-sequence ivy-count-format)))
1018 (string-match "%d" s)
1019 (match-end 0)
1020 (string-match "%d" s (match-end 0))
1021 (setq s (replace-match (format "%%-%dd" w) nil nil s))
1022 (string-match "%d" s)
1023 (concat (replace-match (format "%%%dd" w) nil nil s)
1024 prompt)))
1025 ((string-match "%.*d" ivy-count-format)
1026 (concat ivy-count-format prompt))
1027 (ivy--directory
1028 prompt)
1029 (t
1030 nil)))
1031 (setf (ivy-state-initial-input ivy-last) initial-input)))
1032
1033 (defun ivy-completing-read (prompt collection
1034 &optional predicate require-match initial-input
1035 history def _inherit-input-method)
1036 "Read a string in the minibuffer, with completion.
1037
1038 This is an interface that conforms to `completing-read', so that
1039 it can be used for `completing-read-function'.
1040
1041 PROMPT is a string to prompt with; normally it ends in a colon and a space.
1042 COLLECTION can be a list of strings, an alist, an obarray or a hash table.
1043 PREDICATE limits completion to a subset of COLLECTION.
1044 REQUIRE-MATCH is considered boolean. See `completing-read'.
1045 INITIAL-INPUT is a string that can be inserted into the minibuffer initially.
1046 _HISTORY is ignored for now.
1047 DEF is the default value.
1048 _INHERIT-INPUT-METHOD is ignored for now.
1049
1050 The history, defaults and input-method arguments are ignored for now."
1051 (ivy-read (replace-regexp-in-string "%" "%%" prompt)
1052 collection
1053 :predicate predicate
1054 :require-match require-match
1055 :initial-input (if (consp initial-input)
1056 (car initial-input)
1057 (if (and (stringp initial-input)
1058 (string-match "\\+" initial-input))
1059 (replace-regexp-in-string
1060 "\\+" "\\\\+" initial-input)
1061 initial-input))
1062 :preselect (if (listp def) (car def) def)
1063 :history history
1064 :keymap nil
1065 :sort
1066 (let ((sort (assoc this-command ivy-sort-functions-alist)))
1067 (if sort
1068 (cdr sort)
1069 t))))
1070
1071 ;;;###autoload
1072 (define-minor-mode ivy-mode
1073 "Toggle Ivy mode on or off.
1074 With ARG, turn Ivy mode on if arg is positive, off otherwise.
1075 Turning on Ivy mode will set `completing-read-function' to
1076 `ivy-completing-read'.
1077
1078 Global bindings:
1079 \\{ivy-mode-map}
1080
1081 Minibuffer bindings:
1082 \\{ivy-minibuffer-map}"
1083 :group 'ivy
1084 :global t
1085 :keymap ivy-mode-map
1086 :lighter " ivy"
1087 (if ivy-mode
1088 (setq completing-read-function 'ivy-completing-read)
1089 (setq completing-read-function 'completing-read-default)))
1090
1091 (defun ivy--preselect-index (candidates initial-input preselect matcher)
1092 "Return the index in CANDIDATES filtered by INITIAL-INPUT for PRESELECT.
1093 When MATCHER is non-nil it's used instead of `cl-remove-if-not'."
1094 (if initial-input
1095 (progn
1096 (setq initial-input (ivy--regex-plus initial-input))
1097 (setq candidates
1098 (if matcher
1099 (funcall matcher initial-input candidates)
1100 (cl-remove-if-not
1101 (lambda (x)
1102 (string-match initial-input x))
1103 candidates))))
1104 (when matcher
1105 (setq candidates (funcall matcher "" candidates))))
1106 (or (cl-position preselect candidates :test #'equal)
1107 (cl-position-if
1108 (lambda (x)
1109 (string-match (regexp-quote preselect) x))
1110 candidates)))
1111
1112 ;;* Implementation
1113 ;;** Regex
1114 (defvar ivy--regex-hash
1115 (make-hash-table :test #'equal)
1116 "Store pre-computed regex.")
1117
1118 (defun ivy--split (str)
1119 "Split STR into a list by single spaces.
1120 The remaining spaces stick to their left.
1121 This allows to \"quote\" N spaces by inputting N+1 spaces."
1122 (let ((len (length str))
1123 start0
1124 (start1 0)
1125 res s
1126 match-len)
1127 (while (and (string-match " +" str start1)
1128 (< start1 len))
1129 (setq match-len (- (match-end 0) (match-beginning 0)))
1130 (if (= match-len 1)
1131 (progn
1132 (when start0
1133 (setq start1 start0)
1134 (setq start0 nil))
1135 (push (substring str start1 (match-beginning 0)) res)
1136 (setq start1 (match-end 0)))
1137 (setq str (replace-match
1138 (make-string (1- match-len) ?\ )
1139 nil nil str))
1140 (setq start0 (or start0 start1))
1141 (setq start1 (1- (match-end 0)))))
1142 (if start0
1143 (push (substring str start0) res)
1144 (setq s (substring str start1))
1145 (unless (= (length s) 0)
1146 (push s res)))
1147 (nreverse res)))
1148
1149 (defun ivy--regex (str &optional greedy)
1150 "Re-build regex from STR in case it has a space.
1151 When GREEDY is non-nil, join words in a greedy way."
1152 (let ((hashed (unless greedy
1153 (gethash str ivy--regex-hash))))
1154 (if hashed
1155 (prog1 (cdr hashed)
1156 (setq ivy--subexps (car hashed)))
1157 (when (string-match "\\([^\\]\\|^\\)\\\\$" str)
1158 (setq str (substring str 0 -1)))
1159 (cdr (puthash str
1160 (let ((subs (ivy--split str)))
1161 (if (= (length subs) 1)
1162 (cons
1163 (setq ivy--subexps 0)
1164 (car subs))
1165 (cons
1166 (setq ivy--subexps (length subs))
1167 (mapconcat
1168 (lambda (x)
1169 (if (string-match "\\`\\\\(.*\\\\)\\'" x)
1170 x
1171 (format "\\(%s\\)" x)))
1172 subs
1173 (if greedy
1174 ".*"
1175 ".*?")))))
1176 ivy--regex-hash)))))
1177
1178 (defun ivy--regex-ignore-order (str)
1179 "Re-build regex from STR by splitting it on spaces.
1180 Ignore the order of each group."
1181 (let* ((subs (split-string str " +" t))
1182 (len (length subs)))
1183 (cl-case len
1184 (1
1185 (setq ivy--subexps 0)
1186 (car subs))
1187 (t
1188 (setq ivy--subexps len)
1189 (let ((all (mapconcat #'identity subs "\\|")))
1190 (mapconcat
1191 (lambda (x)
1192 (if (string-match "\\`\\\\(.*\\\\)\\'" x)
1193 x
1194 (format "\\(%s\\)" x)))
1195 (make-list len all)
1196 ".*?"))))))
1197
1198 (defun ivy--regex-plus (str)
1199 "Build a regex sequence from STR.
1200 Spaces are wild, everything before \"!\" should match.
1201 Everything after \"!\" should not match."
1202 (let ((parts (split-string str "!" t)))
1203 (cl-case (length parts)
1204 (0
1205 "")
1206 (1
1207 (ivy--regex (car parts)))
1208 (2
1209 (let ((res
1210 (mapcar #'list
1211 (split-string (cadr parts) " " t))))
1212 (cons (cons (ivy--regex (car parts)) t)
1213 res)))
1214 (t (error "Unexpected: use only one !")))))
1215
1216 (defun ivy--regex-fuzzy (str)
1217 "Build a regex sequence from STR.
1218 Insert .* between each char."
1219 (if (string-match "\\`\\(\\^?\\)\\(.*?\\)\\(\\$?\\)\\'" str)
1220 (concat (match-string 1 str)
1221 (mapconcat #'string (string-to-list (match-string 2 str)) ".*")
1222 (match-string 3 str))
1223 str))
1224
1225 ;;** Rest
1226 (defun ivy--minibuffer-setup ()
1227 "Setup ivy completion in the minibuffer."
1228 (set (make-local-variable 'completion-show-inline-help) nil)
1229 (set (make-local-variable 'minibuffer-default-add-function)
1230 (lambda ()
1231 (list ivy--default)))
1232 (when (and (display-graphic-p) (= (length (frame-list)) 1))
1233 (setq truncate-lines t))
1234 (setq-local max-mini-window-height ivy-height)
1235 (add-hook 'post-command-hook #'ivy--exhibit nil t)
1236 ;; show completions with empty input
1237 (ivy--exhibit))
1238
1239 (defun ivy--input ()
1240 "Return the current minibuffer input."
1241 ;; assume one-line minibuffer input
1242 (buffer-substring-no-properties
1243 (minibuffer-prompt-end)
1244 (line-end-position)))
1245
1246 (defun ivy--cleanup ()
1247 "Delete the displayed completion candidates."
1248 (save-excursion
1249 (goto-char (minibuffer-prompt-end))
1250 (delete-region (line-end-position) (point-max))))
1251
1252 (defun ivy--insert-prompt ()
1253 "Update the prompt according to `ivy--prompt'."
1254 (when ivy--prompt
1255 (unless (memq this-command '(ivy-done ivy-alt-done ivy-partial-or-done
1256 counsel-find-symbol))
1257 (setq ivy--prompt-extra ""))
1258 (let (head tail)
1259 (if (string-match "\\(.*\\): \\'" ivy--prompt)
1260 (progn
1261 (setq head (match-string 1 ivy--prompt))
1262 (setq tail ": "))
1263 (setq head (substring ivy--prompt 0 -1))
1264 (setq tail " "))
1265 (let ((inhibit-read-only t)
1266 (std-props '(front-sticky t rear-nonsticky t field t read-only t))
1267 (n-str
1268 (concat
1269 (if (and (bound-and-true-p minibuffer-depth-indicate-mode)
1270 (> (minibuffer-depth) 1))
1271 (format "[%d] " (minibuffer-depth))
1272 "")
1273 (concat
1274 (if (string-match "%d.*%d" ivy-count-format)
1275 (format head
1276 (1+ ivy--index)
1277 (or (and (ivy-state-dynamic-collection ivy-last)
1278 ivy--full-length)
1279 ivy--length))
1280 (format head
1281 (or (and (ivy-state-dynamic-collection ivy-last)
1282 ivy--full-length)
1283 ivy--length)))
1284 ivy--prompt-extra
1285 tail)
1286 (if ivy--directory
1287 (abbreviate-file-name ivy--directory)
1288 ""))))
1289 (save-excursion
1290 (goto-char (point-min))
1291 (delete-region (point-min) (minibuffer-prompt-end))
1292 (set-text-properties 0 (length n-str)
1293 `(face minibuffer-prompt ,@std-props)
1294 n-str)
1295 (ivy--set-match-props n-str "confirm"
1296 `(face ivy-confirm-face ,@std-props))
1297 (ivy--set-match-props n-str "match required"
1298 `(face ivy-match-required-face ,@std-props))
1299 (insert n-str))
1300 ;; get out of the prompt area
1301 (constrain-to-field nil (point-max))))))
1302
1303 (defun ivy--set-match-props (str match props)
1304 "Set STR text proprties that match MATCH to PROPS."
1305 (when (string-match match str)
1306 (set-text-properties
1307 (match-beginning 0)
1308 (match-end 0)
1309 props
1310 str)))
1311
1312 (defvar inhibit-message)
1313
1314 (defun ivy--sort-maybe (collection)
1315 "Sort COLLECTION if needed."
1316 (let ((sort (ivy-state-sort ivy-last))
1317 entry)
1318 (if (null sort)
1319 collection
1320 (let ((sort-fn (cond ((functionp sort)
1321 sort)
1322 ((setq entry (assoc (ivy-state-collection ivy-last)
1323 ivy-sort-functions-alist))
1324 (cdr entry))
1325 (t
1326 (cdr (assoc t ivy-sort-functions-alist))))))
1327 (if (functionp sort-fn)
1328 (cl-sort (copy-sequence collection) sort-fn)
1329 collection)))))
1330
1331 (defun ivy--exhibit ()
1332 "Insert Ivy completions display.
1333 Should be run via minibuffer `post-command-hook'."
1334 (when (memq 'ivy--exhibit post-command-hook)
1335 (setq ivy-text (ivy--input))
1336 (if (ivy-state-dynamic-collection ivy-last)
1337 ;; while-no-input would cause annoying
1338 ;; "Waiting for process to die...done" message interruptions
1339 (let ((inhibit-message t))
1340 (unless (equal ivy--old-text ivy-text)
1341 (while-no-input
1342 (setq ivy--all-candidates
1343 (ivy--sort-maybe
1344 (funcall (ivy-state-collection ivy-last) ivy-text)))
1345 (setq ivy--old-text ivy-text)))
1346 (when ivy--all-candidates
1347 (ivy--insert-minibuffer
1348 (ivy--format ivy--all-candidates))))
1349 (cond (ivy--directory
1350 (if (string-match "/\\'" ivy-text)
1351 (if (member ivy-text ivy--all-candidates)
1352 (ivy--cd (expand-file-name ivy-text ivy--directory))
1353 (when (string-match "//\\'" ivy-text)
1354 (if (and default-directory
1355 (string-match "\\`[[:alpha:]]:/" default-directory))
1356 (ivy--cd (match-string 0 default-directory))
1357 (ivy--cd "/")))
1358 (when (string-match "[[:alpha:]]:/" ivy-text)
1359 (let ((drive-root (match-string 0 ivy-text)))
1360 (when (file-exists-p drive-root)
1361 (ivy--cd drive-root)))))
1362 (if (string-match "\\`~\\'" ivy-text)
1363 (ivy--cd (expand-file-name "~/")))))
1364 ((eq (ivy-state-collection ivy-last) 'internal-complete-buffer)
1365 (when (or (and (string-match "\\` " ivy-text)
1366 (not (string-match "\\` " ivy--old-text)))
1367 (and (string-match "\\` " ivy--old-text)
1368 (not (string-match "\\` " ivy-text))))
1369 (setq ivy--all-candidates
1370 (if (and (> (length ivy-text) 0)
1371 (eq (aref ivy-text 0)
1372 ?\ ))
1373 (ivy--buffer-list " ")
1374 (ivy--buffer-list "" ivy-use-virtual-buffers)))
1375 (setq ivy--old-re nil))))
1376 (ivy--insert-minibuffer
1377 (ivy--format
1378 (ivy--filter ivy-text ivy--all-candidates)))
1379 (setq ivy--old-text ivy-text))))
1380
1381 (defun ivy--insert-minibuffer (text)
1382 "Insert TEXT into minibuffer with appropriate cleanup."
1383 (let ((resize-mini-windows nil)
1384 (update-fn (ivy-state-update-fn ivy-last))
1385 deactivate-mark)
1386 (ivy--cleanup)
1387 (when update-fn
1388 (funcall update-fn))
1389 (ivy--insert-prompt)
1390 ;; Do nothing if while-no-input was aborted.
1391 (when (stringp text)
1392 (let ((buffer-undo-list t))
1393 (save-excursion
1394 (forward-line 1)
1395 (insert text))))
1396 (when (display-graphic-p)
1397 (ivy--resize-minibuffer-to-fit))))
1398
1399 (defun ivy--resize-minibuffer-to-fit ()
1400 "Resize the minibuffer window so it has enough space to display
1401 all of the text contained in the minibuffer."
1402 (with-selected-window (minibuffer-window)
1403 (if (fboundp 'window-text-pixel-size)
1404 (let ((text-height (cdr (window-text-pixel-size)))
1405 (body-height (window-body-height nil t)))
1406 (when (> text-height body-height)
1407 (window-resize nil (- text-height body-height) nil t t)))
1408 (fit-window-to-buffer))))
1409
1410 (declare-function colir-blend-face-background "ext:colir")
1411
1412 (defun ivy--add-face (str face)
1413 "Propertize STR with FACE.
1414 `font-lock-append-text-property' is used, since it's better than
1415 `propertize' or `add-face-text-property' in this case."
1416 (require 'colir)
1417 (condition-case nil
1418 (progn
1419 (colir-blend-face-background 0 (length str) face str)
1420 (let ((foreground (face-foreground face)))
1421 (when foreground
1422 (add-face-text-property
1423 0 (length str)
1424 `(:foreground ,foreground)
1425 nil
1426 str))))
1427 (error
1428 (ignore-errors
1429 (font-lock-append-text-property 0 (length str) 'face face str))))
1430 str)
1431
1432 (defun ivy--filter (name candidates)
1433 "Return all items that match NAME in CANDIDATES.
1434 CANDIDATES are assumed to be static."
1435 (let* ((re (funcall ivy--regex-function name))
1436 (re-str (if (listp re) (caar re) re))
1437 (matcher (ivy-state-matcher ivy-last))
1438 (case-fold-search (string= name (downcase name)))
1439 (cands (cond
1440 (matcher
1441 (funcall matcher re candidates))
1442 ((and (equal re ivy--old-re)
1443 ivy--old-cands)
1444 ivy--old-cands)
1445 ((and ivy--old-re
1446 (stringp re)
1447 (stringp ivy--old-re)
1448 (not (string-match "\\\\" ivy--old-re))
1449 (not (equal ivy--old-re ""))
1450 (memq (cl-search
1451 (if (string-match "\\\\)\\'" ivy--old-re)
1452 (substring ivy--old-re 0 -2)
1453 ivy--old-re)
1454 re)
1455 '(0 2)))
1456 (ignore-errors
1457 (cl-remove-if-not
1458 (lambda (x) (string-match re x))
1459 ivy--old-cands)))
1460 (t
1461 (let ((re-list (if (stringp re) (list (cons re t)) re))
1462 (res candidates))
1463 (dolist (re re-list)
1464 (setq res
1465 (ignore-errors
1466 (funcall
1467 (if (cdr re)
1468 #'cl-remove-if-not
1469 #'cl-remove-if)
1470 (let ((re (car re)))
1471 (lambda (x) (string-match re x)))
1472 res))))
1473 res))))
1474 (tail (nthcdr ivy--index ivy--old-cands))
1475 idx)
1476 (when (and tail ivy--old-cands (not (equal "^" ivy--old-re)))
1477 (unless (and (not (equal re-str ivy--old-re))
1478 (or (setq ivy--index
1479 (or
1480 (cl-position (if (and (> (length re-str) 0)
1481 (eq ?^ (aref re-str 0)))
1482 (substring re-str 1)
1483 re-str) cands
1484 :test #'equal)
1485 (and ivy--directory
1486 (cl-position
1487 (concat re-str "/") cands
1488 :test #'equal))))))
1489 (while (and tail (null idx))
1490 ;; Compare with eq to handle equal duplicates in cands
1491 (setq idx (cl-position (pop tail) cands)))
1492 (setq ivy--index (or idx 0))))
1493 (when (and (string= name "") (not (equal ivy--old-re "")))
1494 (setq ivy--index
1495 (or (cl-position (ivy-state-preselect ivy-last)
1496 cands :test #'equal)
1497 ivy--index)))
1498 (setq ivy--old-re (if cands re-str ""))
1499 (setq ivy--old-cands cands)))
1500
1501 (defvar ivy-format-function 'ivy-format-function-default
1502 "Function to transform the list of candidates into a string.
1503 This string will be inserted into the minibuffer.")
1504
1505 (defun ivy-format-function-default (cands)
1506 "Transform CANDS into a string for minibuffer."
1507 (if (bound-and-true-p truncate-lines)
1508 (mapconcat #'identity cands "\n")
1509 (let ((ww (- (window-width)
1510 (if (and (boundp 'fringe-mode) (eq fringe-mode 0)) 1 0))))
1511 (mapconcat
1512 (lambda (s)
1513 (if (> (length s) ww)
1514 (concat (substring s 0 (- ww 3)) "...")
1515 s))
1516 cands "\n"))))
1517
1518 (defun ivy-format-function-arrow (cands)
1519 "Transform CANDS into a string for minibuffer."
1520 (let ((i -1))
1521 (mapconcat
1522 (lambda (s)
1523 (concat (if (eq (cl-incf i) ivy--index)
1524 "> "
1525 " ")
1526 s))
1527 cands "\n")))
1528
1529 (defcustom swiper-minibuffer-faces
1530 '(swiper-minibuffer-match-face-1
1531 swiper-minibuffer-match-face-2
1532 swiper-minibuffer-match-face-3
1533 swiper-minibuffer-match-face-4)
1534 "List of `swiper' faces for minibuffer group matches.")
1535
1536 (defun ivy--format-minibuffer-line (str)
1537 (let ((start 0)
1538 (str (copy-sequence str)))
1539 (when (eq ivy-display-style 'fancy)
1540 (unless ivy--old-re
1541 (setq ivy--old-re (funcall ivy--regex-function ivy-text)))
1542 (while (and (string-match ivy--old-re str start)
1543 (> (- (match-end 0) (match-beginning 0)) 0))
1544 (setq start (match-end 0))
1545 (let ((i 0))
1546 (while (<= i ivy--subexps)
1547 (let ((face
1548 (cond ((zerop ivy--subexps)
1549 (cadr swiper-minibuffer-faces))
1550 ((zerop i)
1551 (car swiper-minibuffer-faces))
1552 (t
1553 (nth (1+ (mod (+ i 2) (1- (length swiper-minibuffer-faces))))
1554 swiper-minibuffer-faces)))))
1555 (add-face-text-property
1556 (match-beginning i)
1557 (match-end i)
1558 face
1559 nil
1560 str))
1561 (cl-incf i)))))
1562 str))
1563
1564 (defun ivy--format (cands)
1565 "Return a string for CANDS suitable for display in the minibuffer.
1566 CANDS is a list of strings."
1567 (setq ivy--length (length cands))
1568 (when (>= ivy--index ivy--length)
1569 (setq ivy--index (max (1- ivy--length) 0)))
1570 (if (null cands)
1571 (setq ivy--current "")
1572 (let* ((half-height (/ ivy-height 2))
1573 (start (max 0 (- ivy--index half-height)))
1574 (end (min (+ start (1- ivy-height)) ivy--length))
1575 (start (max 0 (min start (- end (1- ivy-height)))))
1576 (cands (cl-subseq cands start end))
1577 (index (- ivy--index start)))
1578 (when ivy--directory
1579 (setq cands (mapcar (lambda (x)
1580 (if (string-match-p "/\\'" x)
1581 (propertize x 'face 'ivy-subdir)
1582 x))
1583 cands)))
1584 (setq ivy--current (copy-sequence (nth index cands)))
1585 (setq cands (mapcar
1586 #'ivy--format-minibuffer-line
1587 cands))
1588 (setf (nth index cands)
1589 (ivy--add-face (nth index cands) 'ivy-current-match))
1590 (let* ((ivy--index index)
1591 (res (concat "\n" (funcall ivy-format-function cands))))
1592 (put-text-property 0 (length res) 'read-only nil res)
1593 res))))
1594
1595 (defvar ivy--virtual-buffers nil
1596 "Store the virtual buffers alist.")
1597
1598 (defvar recentf-list)
1599
1600 (defface ivy-virtual '((t :inherit font-lock-builtin-face))
1601 "Face used by Ivy for matching virtual buffer names.")
1602
1603 (defun ivy--virtual-buffers ()
1604 "Adapted from `ido-add-virtual-buffers-to-list'."
1605 (unless recentf-mode
1606 (recentf-mode 1))
1607 (let ((bookmarks (and (boundp 'bookmark-alist)
1608 bookmark-alist))
1609 virtual-buffers name)
1610 (dolist (head (append
1611 recentf-list
1612 (delete " - no file -"
1613 (delq nil (mapcar (lambda (bookmark)
1614 (cdr (assoc 'filename bookmark)))
1615 bookmarks)))))
1616 (setq name (file-name-nondirectory head))
1617 (when (equal name "")
1618 (setq name (file-name-nondirectory (directory-file-name head))))
1619 (when (equal name "")
1620 (setq name head))
1621 (and (not (equal name ""))
1622 (null (get-file-buffer head))
1623 (not (assoc name virtual-buffers))
1624 (push (cons name head) virtual-buffers)))
1625 (when virtual-buffers
1626 (dolist (comp virtual-buffers)
1627 (put-text-property 0 (length (car comp))
1628 'face 'ivy-virtual
1629 (car comp)))
1630 (setq ivy--virtual-buffers (nreverse virtual-buffers))
1631 (mapcar #'car ivy--virtual-buffers))))
1632
1633 (defun ivy--buffer-list (str &optional virtual)
1634 "Return the buffers that match STR.
1635 When VIRTUAL is non-nil, add virtual buffers."
1636 (delete-dups
1637 (append
1638 (mapcar
1639 (lambda (x)
1640 (if (with-current-buffer x
1641 (file-remote-p
1642 (abbreviate-file-name default-directory)))
1643 (propertize x 'face 'ivy-remote)
1644 x))
1645 (all-completions str 'internal-complete-buffer))
1646 (and virtual
1647 (ivy--virtual-buffers)))))
1648
1649 (defun ivy--switch-buffer-action (buffer)
1650 "Switch to BUFFER.
1651 BUFFER may be a string or nil."
1652 (with-ivy-window
1653 (if (zerop (length buffer))
1654 (switch-to-buffer
1655 ivy-text nil 'force-same-window)
1656 (let ((virtual (assoc buffer ivy--virtual-buffers)))
1657 (if (and virtual
1658 (not (get-buffer buffer)))
1659 (find-file (cdr virtual))
1660 (switch-to-buffer
1661 buffer nil 'force-same-window))))))
1662
1663 (defun ivy--switch-buffer-other-window-action (buffer)
1664 "Switch to BUFFER in other window.
1665 BUFFER may be a string or nil."
1666 (if (zerop (length buffer))
1667 (switch-to-buffer-other-window ivy-text)
1668 (let ((virtual (assoc buffer ivy--virtual-buffers)))
1669 (if (and virtual
1670 (not (get-buffer buffer)))
1671 (find-file-other-window (cdr virtual))
1672 (switch-to-buffer-other-window buffer)))))
1673
1674 (defvar ivy-switch-buffer-map (make-sparse-keymap))
1675
1676 (ivy-set-actions
1677 'ivy-switch-buffer
1678 '(("k"
1679 (lambda (x)
1680 (kill-buffer x)
1681 (ivy--reset-state ivy-last))
1682 "kill")
1683 ("j"
1684 ivy--switch-buffer-other-window-action
1685 "other")))
1686
1687 (defun ivy-switch-buffer ()
1688 "Switch to another buffer."
1689 (interactive)
1690 (if (not ivy-mode)
1691 (call-interactively 'switch-to-buffer)
1692 (let ((this-command 'ivy-switch-buffer))
1693 (ivy-read "Switch to buffer: " 'internal-complete-buffer
1694 :preselect (buffer-name (other-buffer (current-buffer)))
1695 :action #'ivy--switch-buffer-action
1696 :keymap ivy-switch-buffer-map))))
1697
1698 (defun ivy-recentf ()
1699 "Find a file on `recentf-list'."
1700 (interactive)
1701 (ivy-read "Recentf: " recentf-list
1702 :action
1703 (lambda (f)
1704 (with-ivy-window
1705 (find-file f)))))
1706
1707 (defun ivy-yank-word ()
1708 "Pull next word from buffer into search string."
1709 (interactive)
1710 (let (amend)
1711 (with-ivy-window
1712 (let ((pt (point))
1713 (le (line-end-position)))
1714 (forward-word 1)
1715 (if (> (point) le)
1716 (goto-char pt)
1717 (setq amend (buffer-substring-no-properties pt (point))))))
1718 (when amend
1719 (insert amend))))
1720
1721 (defun ivy-kill-ring-save ()
1722 "Store the current candidates into the kill ring.
1723 If the region is active, forward to `kill-ring-save' instead."
1724 (interactive)
1725 (if (region-active-p)
1726 (call-interactively 'kill-ring-save)
1727 (kill-new
1728 (mapconcat
1729 #'identity
1730 ivy--old-cands
1731 "\n"))))
1732
1733 (defun ivy-insert-current ()
1734 "Make the current candidate into current input.
1735 Don't finish completion."
1736 (interactive)
1737 (delete-minibuffer-contents)
1738 (if (and ivy--directory
1739 (string-match "/$" ivy--current))
1740 (insert (substring ivy--current 0 -1))
1741 (insert ivy--current)))
1742
1743 (defun ivy-toggle-fuzzy ()
1744 "Toggle the re builder between `ivy--regex-fuzzy' and `ivy--regex-plus'."
1745 (interactive)
1746 (setq ivy--old-re nil)
1747 (if (eq ivy--regex-function 'ivy--regex-fuzzy)
1748 (setq ivy--regex-function 'ivy--regex-plus)
1749 (setq ivy--regex-function 'ivy--regex-fuzzy)))
1750
1751 (defun ivy-reverse-i-search ()
1752 "Enter a recursive `ivy-read' session using the current history.
1753 The selected history element will be inserted into the minibufer."
1754 (interactive)
1755 (let ((enable-recursive-minibuffers t)
1756 (history (symbol-value (ivy-state-history ivy-last)))
1757 (old-last ivy-last))
1758 (ivy-read "Reverse-i-search: "
1759 history
1760 :action (lambda (x)
1761 (ivy--reset-state
1762 (setq ivy-last old-last))
1763 (delete-minibuffer-contents)
1764 (insert (substring-no-properties x))
1765 (ivy--cd-maybe)))))
1766
1767 (defun ivy-restrict-to-matches ()
1768 "Restrict candidates to current matches and erase input."
1769 (interactive)
1770 (delete-minibuffer-contents)
1771 (setq ivy--all-candidates
1772 (ivy--filter ivy-text ivy--all-candidates)))
1773
1774 (provide 'ivy)
1775
1776 ;;; ivy.el ends here