1 ;;; ivy.el --- Incremental Vertical completYon -*- lexical-binding: t -*-
3 ;; Copyright (C) 2015 Free Software Foundation, Inc.
5 ;; Author: Oleh Krehel <ohwoeowho@gmail.com>
6 ;; URL: https://github.com/abo-abo/swiper
8 ;; Package-Requires: ((emacs "24.1"))
11 ;; This file is part of GNU Emacs.
13 ;; This file is free software; you can redistribute it and/or modify
14 ;; it under the terms of the GNU General Public License as published by
15 ;; the Free Software Foundation; either version 3, or (at your option)
18 ;; This program is distributed in the hope that it will be useful,
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ;; GNU General Public License for more details.
23 ;; For a full copy of the GNU General Public License
24 ;; see <http://www.gnu.org/licenses/>.
28 ;; This package provides `ivy-read' as an alternative to
29 ;; `completing-read' and similar functions.
31 ;; There's no intricate code to determine the best candidate.
32 ;; Instead, the user can navigate to it with `ivy-next-line' and
33 ;; `ivy-previous-line'.
35 ;; The matching is done by splitting the input text by spaces and
36 ;; re-building it into a regex.
37 ;; So "for example" is transformed into "\\(for\\).*\\(example\\)".
46 "Incremental vertical completion."
49 (defface ivy-current-match
50 '((t (:inherit highlight)))
51 "Face used by Ivy for highlighting first match.")
55 "Face used by Ivy for highlighting subdirs in the alternatives.")
57 (defcustom ivy-height 10
58 "Number of lines for the minibuffer window."
61 (defcustom ivy-count-format "%-4d "
62 "The style of showing the current candidate count for `ivy-read'.
63 Set this to nil if you don't want the count."
66 (defcustom ivy-wrap nil
67 "Whether to wrap around after the first and last candidate."
70 (defcustom ivy-on-del-error-function 'minibuffer-keyboard-quit
71 "The handler for when `ivy-backward-delete-char' throws.
72 This is usually meant as a quick exit out of the minibuffer."
75 (defcustom ivy-extra-directories '("../" "./")
76 "Add this to the front of the list when completing file names.
77 Only \"./\" and \"../\" apply here. They appear in reverse order."
83 (defvar ivy-minibuffer-map
84 (let ((map (make-sparse-keymap)))
85 (define-key map (kbd "C-m") 'ivy-done)
86 (define-key map (kbd "C-j") 'ivy-alt-done)
87 (define-key map (kbd "C-n") 'ivy-next-line)
88 (define-key map (kbd "C-p") 'ivy-previous-line)
89 (define-key map (kbd "<down>") 'ivy-next-line)
90 (define-key map (kbd "<up>") 'ivy-previous-line)
91 (define-key map (kbd "C-s") 'ivy-next-line-or-history)
92 (define-key map (kbd "C-r") 'ivy-previous-line-or-history)
93 (define-key map (kbd "SPC") 'self-insert-command)
94 (define-key map (kbd "DEL") 'ivy-backward-delete-char)
95 (define-key map (kbd "M-<") 'ivy-beginning-of-buffer)
96 (define-key map (kbd "M->") 'ivy-end-of-buffer)
97 (define-key map (kbd "<left>") 'ivy-beginning-of-buffer)
98 (define-key map (kbd "<right>") 'ivy-end-of-buffer)
99 (define-key map (kbd "M-n") 'ivy-next-history-element)
100 (define-key map (kbd "M-p") 'ivy-previous-history-element)
101 (define-key map (kbd "C-g") 'minibuffer-keyboard-quit)
102 (define-key map (kbd "C-v") 'ivy-scroll-up-command)
103 (define-key map (kbd "M-v") 'ivy-scroll-down-command)
104 (define-key map (kbd "C-M-n") 'ivy-next-line-and-call)
105 (define-key map (kbd "C-M-p") 'ivy-previous-line-and-call)
106 (define-key map (kbd "M-q") 'ivy-toggle-regexp-quote)
108 "Keymap used in the minibuffer.")
110 (defvar ivy-history nil
111 "History list of candidates entered in the minibuffer.
113 Maximum length of the history list is determined by the value
114 of `history-length', which see.")
116 (defvar ivy-require-match t
117 "Store require-match. See `completing-read'.")
119 (defvar ivy--directory nil
120 "Current directory when completing file names.")
122 (defvar ivy--length 0
123 "Store the amount of viable candidates.")
126 "Store the user's string as it is typed in.")
128 (defvar ivy-window nil
129 "Store the window in which `ivy-read' was called.")
131 (defvar ivy--current ""
132 "Current candidate.")
135 "Store the index of the current candidate.")
138 "Store 'done if the completion was successfully selected.
139 Otherwise, store nil.")
141 (defvar ivy--action nil
142 "Store a function to call at the end of `ivy--read'.")
144 (defvar ivy--persistent-action nil
145 "Store a function to call for current candidate without exiting.")
147 (defvar ivy--all-candidates nil
148 "Store the candidates passed to `ivy-read'.")
150 (defvar ivy--default nil
151 "Default initial input.")
153 (defvar ivy--update-fn nil
154 "Current function to call when current candidate(s) update.")
156 (defvar ivy--prompt nil
157 "Store the format-style prompt.
158 When non-nil, it should contain one %d.")
160 (defvar ivy--old-re nil
161 "Store the old regexp.")
163 (defvar ivy--old-cands nil
164 "Store the candidates matched by `ivy--old-re'.")
166 (defvar ivy--regex-function 'ivy--regex
167 "Current function for building a regex.")
171 "Exit the minibuffer with the selected candidate."
173 (delete-minibuffer-contents)
174 (when (cond (ivy--directory
176 (cond ((string= ivy-text "")
177 (if (equal ivy--current "./")
179 (if (string-match "\\*" ivy--current)
181 (expand-file-name ivy--current ivy--directory))))
183 (expand-file-name ivy-text ivy--directory))
185 (expand-file-name ivy--current ivy--directory))))
186 (setq ivy-exit 'done))
188 (if (memq ivy-require-match
189 '(nil confirm confirm-after-completion))
192 (setq ivy-exit 'done))
193 (unless (string-match "match required" ivy--prompt)
195 (if (string-match ": $" ivy--prompt)
197 (substring ivy--prompt 0 -2)
198 " (match required): ")
201 "(match required) "))))
206 (insert ivy--current)
207 (setq ivy-exit 'done)))
210 (defun ivy-alt-done (&optional arg)
211 "Exit the minibuffer with the selected candidate.
212 When ARG is t, exit with current text, ignoring the candidates."
217 (cond ((and ivy--directory
219 (= 0 (length ivy-text)))
223 (cl-plusp ivy--length)
225 (setq dir (expand-file-name
226 ivy--current ivy--directory))))
233 (defun ivy-immediate-done ()
234 "Exit the minibuffer with the current input."
236 (delete-minibuffer-contents)
238 (setq ivy-exit 'done)
241 (defun ivy-beginning-of-buffer ()
242 "Select the first completion candidate."
246 (defun ivy-end-of-buffer ()
247 "Select the last completion candidate."
249 (setq ivy--index (1- ivy--length)))
251 (defun ivy-scroll-up-command ()
252 "Scroll the candidates upward by the minibuffer height."
254 (setq ivy--index (min (+ ivy--index ivy-height)
257 (defun ivy-scroll-down-command ()
258 "Scroll the candidates downward by the minibuffer height."
260 (setq ivy--index (max (- ivy--index ivy-height)
263 (defun ivy-next-line (&optional arg)
264 "Move cursor vertically down ARG candidates."
266 (setq arg (or arg 1))
267 (cl-incf ivy--index arg)
268 (when (>= ivy--index (1- ivy--length))
270 (ivy-beginning-of-buffer)
271 (setq ivy--index (1- ivy--length)))))
273 (defun ivy-next-line-or-history (&optional arg)
274 "Move cursor vertically down ARG candidates.
275 If the input is empty, select the previous history element instead."
277 (when (string= ivy-text "")
278 (ivy-previous-history-element 1))
281 (defun ivy-previous-line (&optional arg)
282 "Move cursor vertically up ARG candidates."
284 (setq arg (or arg 1))
285 (cl-decf ivy--index arg)
286 (when (< ivy--index 0)
289 (setq ivy--index 0))))
291 (defun ivy-previous-line-or-history (arg)
292 "Move cursor vertically up ARG candidates.
293 If the input is empty, select the previous history element instead."
295 (when (string= ivy-text "")
296 (ivy-previous-history-element 1))
297 (ivy-previous-line arg))
299 (defun ivy-next-line-and-call (&optional arg)
300 "Move cursor vertically down ARG candidates."
304 (when ivy--persistent-action
305 (with-selected-window ivy-window
306 (funcall ivy--persistent-action ivy--current))))
308 (defun ivy-previous-line-and-call (&optional arg)
309 "Move cursor vertically down ARG candidates."
311 (ivy-previous-line arg)
313 (when ivy--persistent-action
314 (with-selected-window ivy-window
315 (funcall ivy--persistent-action ivy--current))))
317 (defun ivy-previous-history-element (arg)
318 "Forward to `previous-history-element' with ARG."
320 (previous-history-element arg)
321 (move-end-of-line 1))
323 (defun ivy-next-history-element (arg)
324 "Forward to `next-history-element' with ARG."
326 (next-history-element arg)
327 (move-end-of-line 1))
330 "When completing file names, move to directory DIR."
331 (if (null ivy--directory)
333 (setq ivy--old-cands nil)
334 (setq ivy--all-candidates
335 (ivy--sorted-files (setq ivy--directory dir)))
337 (delete-minibuffer-contents)))
339 (defun ivy-backward-delete-char ()
340 "Forward to `backward-delete-char'.
341 On error (read-only), call `ivy-on-del-error-function'."
343 (if (and ivy--directory (= (minibuffer-prompt-end) (point)))
345 (ivy--cd (file-name-directory
346 (directory-file-name ivy--directory)))
349 (backward-delete-char 1)
351 (when ivy-on-del-error-function
352 (funcall ivy-on-del-error-function))))))
354 (defvar ivy--regexp-quote 'regexp-quote
355 "Store the regexp quoting state.")
357 (defun ivy-toggle-regexp-quote ()
358 "Toggle the regexp quoting."
360 (setq ivy--old-re nil)
361 (cl-rotatef ivy--regex-function ivy--regexp-quote))
363 (defun ivy-sort-file-function-default (x y)
364 "Compare two files X and Y.
365 Prioritize directories."
366 (if (get-text-property 0 'dirp x)
367 (if (get-text-property 0 'dirp y)
370 (if (get-text-property 0 'dirp y)
374 (defvar ivy-sort-functions-alist
375 '((read-file-name-internal . ivy-sort-file-function-default)
376 (internal-complete-buffer . nil)
377 (counsel-git-grep-function . nil)
379 "An alist of sorting functions for each collection function.
380 For each entry, nil means no sorting.
381 The entry associated to t is used for all fall-through cases.")
383 (defvar ivy-re-builders-alist
385 "An alist of regex building functions for each collection function.
386 Each function should take a string and return a valid regex.
387 The entry associated to t is used for all fall-through cases.
388 Possible choices: `ivy--regex', `regexp-quote'.")
390 (defcustom ivy-sort-max-size 30000
391 "Sorting won't be done for collections larger than this."
394 (defun ivy--sorted-files (dir)
395 "Return the list of files in DIR.
396 Directories come first."
397 (let* ((default-directory dir)
398 (seq (all-completions "" 'read-file-name-internal))
402 (setq seq (delete "./" (delete "../" seq)))
403 (when (eq (setq sort-fn (cdr (assoc 'read-file-name-internal
404 ivy-sort-functions-alist)))
405 'ivy-sort-file-function-default)
406 (setq seq (mapcar (lambda (x)
407 (propertize x 'dirp (string-match-p "/$" x)))
410 (setq seq (cl-sort seq sort-fn)))
411 (dolist (dir ivy-extra-directories)
416 (cl-defun ivy-read (prompt collection
417 &key predicate require-match initial-input
418 history preselect keymap update-fn sort)
419 "Read a string in the minibuffer, with completion.
421 PROMPT is a string to prompt with; normally it ends in a colon
422 and a space. When PROMPT contains %d, it will be updated with
423 the current number of matching candidates.
424 See also `ivy-count-format'.
426 COLLECTION is a list of strings.
428 If INITIAL-INPUT is non-nil, insert it in the minibuffer initially.
430 KEYMAP is composed together with `ivy-minibuffer-map'.
432 If PRESELECT is non-nil select the corresponding candidate out of
433 the ones that match INITIAL-INPUT.
435 UPDATE-FN is called each time the current candidate(s) is changed.
437 When SORT is t, refer to `ivy-sort-functions-alist' for sorting."
438 (setq ivy--directory nil)
439 (setq ivy-require-match require-match)
440 (setq ivy-window (selected-window))
441 (setq ivy--regex-function
442 (or (and (functionp collection)
443 (cdr (assoc collection ivy-re-builders-alist)))
444 (cdr (assoc t ivy-re-builders-alist))
446 (setq ivy--subexps 0)
447 (setq ivy--regexp-quote 'regexp-quote)
449 (cond ((eq collection 'Info-read-node-name-1)
450 (if (equal Info-current-file "dir")
452 (mapcar (lambda (x) (format "(%s)" x))
453 (cl-delete-duplicates
454 (all-completions "(" collection predicate)
456 (setq coll (all-completions "" collection predicate))))
457 ((eq collection 'read-file-name-internal)
458 (setq ivy--directory default-directory)
460 (ivy--sorted-files default-directory))
462 (unless (or require-match
463 (equal initial-input default-directory))
464 (setq coll (cons initial-input coll)))
465 (setq initial-input nil)))
466 ((or (functionp collection)
468 (listp (car collection)))
469 (setq coll (all-completions "" collection predicate)))
470 ((hash-table-p collection)
471 (error "Hash table as a collection unsupported"))
473 (setq coll collection)))
475 (if (and (functionp collection)
476 (setq sort-fn (assoc collection ivy-sort-functions-alist)))
477 (when (and (setq sort-fn (cdr sort-fn))
478 (not (eq collection 'read-file-name-internal)))
479 (setq coll (cl-sort coll sort-fn)))
480 (if (and (setq sort-fn (cdr (assoc t ivy-sort-functions-alist)))
481 (<= (length coll) ivy-sort-max-size))
482 (setq coll (cl-sort (copy-sequence coll) sort-fn)))))
484 (unless (or require-match
485 (member preselect coll))
486 (setq coll (cons preselect coll))))
489 (ivy--preselect-index
490 coll initial-input preselect))
492 (setq ivy--old-re nil)
493 (setq ivy--old-cands nil)
495 (setq ivy--all-candidates coll)
496 (setq ivy--update-fn update-fn)
498 (setq ivy--default (or (thing-at-point 'symbol) ""))
500 (cond ((string-match "%.*d" prompt)
502 ((string-match "%.*d" ivy-count-format)
503 (concat ivy-count-format prompt))
508 (setq ivy--action nil)
511 (minibuffer-with-setup-hook
512 #'ivy--minibuffer-setup
513 (let* ((hist (or history 'ivy-history))
514 (res (read-from-minibuffer
517 (make-composed-keymap keymap ivy-minibuffer-map)
520 (when (eq ivy-exit 'done)
521 (set hist (cons ivy-text
523 (cdr (symbol-value hist)))))
525 (remove-hook 'post-command-hook #'ivy--exhibit))
527 (funcall ivy--action)))))
529 (defun ivy-completing-read (prompt collection
530 &optional predicate require-match initial-input
531 history def _inherit-input-method)
532 "Read a string in the minibuffer, with completion.
534 This is an interface that conforms to `completing-read', so that
535 it can be used for `completing-read-function'.
537 PROMPT is a string to prompt with; normally it ends in a colon and a space.
538 COLLECTION can be a list of strings, an alist, an obarray or a hash table.
539 PREDICATE limits completion to a subset of COLLECTION.
541 REQUIRE-MATCH is stored into `ivy-require-match'. See `completing-read'.
542 INITIAL-INPUT is a string that can be inserted into the minibuffer initially.
543 _HISTORY is ignored for now.
544 DEF is the default value.
545 _INHERIT-INPUT-METHOD is ignored for now.
547 The history, defaults and input-method arguments are ignored for now."
549 (setq def (car def)))
550 (ivy-read prompt collection
552 :require-match require-match
553 :initial-input initial-input
560 (define-minor-mode ivy-mode
561 "Toggle Ivy mode on or off.
562 With ARG, turn Ivy mode on if arg is positive, off otherwise.
563 Turning on Ivy mode will set `completing-read-function' to
564 `ivy-completing-read'.
566 \\{ivy-minibuffer-map}"
571 (setq completing-read-function 'ivy-completing-read)
572 (setq completing-read-function 'completing-read-default)))
574 (defun ivy--preselect-index (candidates initial-input preselect)
575 "Return the index in CANDIDATES filtered by INITIAL-INPUT for PRESELECT."
580 (string-match initial-input x))
582 (or (cl-position preselect candidates :test 'equal)
585 (string-match preselect x))
590 (defvar ivy--subexps 0
591 "Number of groups in the current `ivy--regex'.")
593 (defvar ivy--regex-hash
594 (make-hash-table :test 'equal)
595 "Store pre-computed regex.")
597 (defun ivy--regex (str &optional greedy)
598 "Re-build regex from STR in case it has a space.
599 When GREEDY is non-nil, join words in a greedy way."
600 (let ((hashed (unless greedy
601 (gethash str ivy--regex-hash))))
604 (setq ivy--subexps (car hashed)))
606 (let ((subs (split-string str " +" t)))
607 (if (= (length subs) 1)
609 (setq ivy--subexps 0)
612 (setq ivy--subexps (length subs))
615 (if (string-match "^\\\\(.*\\\\)$" x)
617 (format "\\(%s\\)" x)))
625 (defun ivy--minibuffer-setup ()
626 "Setup ivy completion in the minibuffer."
627 (set (make-local-variable 'completion-show-inline-help) nil)
628 (set (make-local-variable 'minibuffer-default-add-function)
630 (list ivy--default)))
631 (setq-local max-mini-window-height ivy-height)
632 (add-hook 'post-command-hook #'ivy--exhibit nil t)
633 ;; show completions with empty input
637 "Return the current minibuffer input."
638 ;; assume one-line minibuffer input
639 (buffer-substring-no-properties
640 (minibuffer-prompt-end)
641 (line-end-position)))
643 (defun ivy--cleanup ()
644 "Delete the displayed completion candidates."
646 (goto-char (minibuffer-prompt-end))
647 (delete-region (line-end-position) (point-max))))
649 (defvar ivy--dynamic-function nil
650 "When this is non-nil, call it for each input change to get new candidates.")
652 (defvar ivy--full-length nil
653 "When `ivy--dynamic-function' is non-nil, this can be the total amount of candidates.")
655 (defvar ivy--old-text nil
656 "Store old `ivy-text' for dynamic completion.")
658 (defun ivy--insert-prompt ()
659 "Update the prompt according to `ivy--prompt'."
661 (let ((inhibit-read-only t)
665 (concat ivy--prompt (abbreviate-file-name ivy--directory))
667 (or (and ivy--dynamic-function
671 (goto-char (point-min))
672 (delete-region (point-min) (minibuffer-prompt-end))
675 '(front-sticky t rear-nonsticky t field t read-only t face minibuffer-prompt)
678 ;; get out of the prompt area
679 (constrain-to-field nil (point-max)))))
681 (defun ivy--exhibit ()
682 "Insert Ivy completions display.
683 Should be run via minibuffer `post-command-hook'."
684 (setq ivy-text (ivy--input))
685 (if ivy--dynamic-function
686 ;; while-no-input would cause annoying
687 ;; "Waiting for process to die...done" message interruptions
688 (let ((inhibit-message t))
690 (unless (equal ivy--old-text ivy-text)
691 (let ((store ivy--dynamic-function)
692 (ivy--dynamic-function nil))
693 (setq ivy--all-candidates (funcall store ivy-text)))
694 (setq ivy--old-text ivy-text))
695 (ivy--insert-minibuffer (ivy--format ivy--all-candidates))))
697 (if (string-match "/$" ivy-text)
698 (if (member ivy-text ivy--all-candidates)
699 (ivy--cd (expand-file-name ivy-text ivy--directory))
701 (if (string-match "~$" ivy-text)
702 (ivy--cd (expand-file-name "~/")))))
703 (ivy--insert-minibuffer
705 (ivy--filter ivy-text ivy--all-candidates)))))
707 (defun ivy--insert-minibuffer (text)
709 (let ((buffer-undo-list t)
712 (funcall ivy--update-fn))
714 ;; Do nothing if while-no-input was aborted.
720 (defun ivy--add-face (str face)
721 "Propertize STR with FACE.
722 `font-lock-append-text-property' is used, since it's better than
723 `propertize' or `add-face-text-property' in this case."
725 (font-lock-append-text-property 0 (length str) 'face face str))
728 (defun ivy--filter (name candidates)
729 "Return the matches for NAME for CANDIDATES.
730 CANDIDATES are assumed to be static."
731 (let* ((re (funcall ivy--regex-function name))
732 (cands (cond ((and (equal re ivy--old-re)
736 (not (string-match "\\\\" ivy--old-re))
737 (not (equal ivy--old-re ""))
739 (if (string-match "\\\\)$" ivy--old-re)
740 (substring ivy--old-re 0 -2)
745 (lambda (x) (string-match re x))
750 (lambda (x) (string-match re x))
752 (tail (nthcdr ivy--index ivy--old-cands))
754 (when (and tail ivy--old-cands)
755 (unless (and (not (equal re ivy--old-re))
758 (cl-position re cands
762 (concat re "/") cands
764 (while (and tail (null idx))
765 ;; Compare with eq to handle equal duplicates in cands
766 (setq idx (cl-position (pop tail) cands)))
767 (setq ivy--index (or idx 0))))
768 (setq ivy--old-re re)
769 (setq ivy--old-cands cands)))
771 (defun ivy--format (cands)
772 "Return a string for CANDS suitable for display in the minibuffer.
773 CANDS is a list of strings."
774 (setq ivy--length (length cands))
775 (when (>= ivy--index ivy--length)
776 (setq ivy--index (max (1- ivy--length) 0)))
779 (let* ((half-height (/ ivy-height 2))
780 (start (max 0 (- ivy--index half-height)))
781 (end (min (+ start (1- ivy-height)) ivy--length))
782 (cands (cl-subseq cands start end))
783 (index (min ivy--index half-height (1- (length cands)))))
785 (setq cands (mapcar (lambda (x)
786 (if (string-match-p "/$" x)
787 (propertize x 'face 'ivy-subdir)
790 (setq ivy--current (copy-sequence (nth index cands)))
791 (setf (nth index cands)
792 (ivy--add-face ivy--current 'ivy-current-match))
793 (let* ((ww (window-width))
794 (res (concat "\n" (mapconcat
796 (if (> (length s) ww)
797 (concat (substring s 0 (- ww 3)) "...")
800 (put-text-property 0 (length res) 'read-only nil res)