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\\)".
44 "Incremental vertical completion."
47 (defface ivy-current-match
48 '((t (:inherit highlight)))
49 "Face used by Ivy for highlighting first match.")
51 (defcustom ivy-height 10
52 "Number of lines for the minibuffer window."
55 (defcustom ivy-count-format "%-4d "
56 "The style of showing the current candidate count for `ivy-read'.
57 Set this to nil if you don't want the count."
60 (defcustom ivy-wrap nil
61 "Whether to wrap around after the first and last candidate."
64 (defcustom ivy-on-del-error-function 'minibuffer-keyboard-quit
65 "The handler for when `ivy-backward-delete-char' throws.
66 This is usually meant as a quick exit out of the minibuffer."
69 (defcustom ivy-extra-directories '("../" "./")
70 "Add this to the front of the list when completing file names.
71 Only \"./\" and \"../\" apply here. They appear in reverse order."
77 (defvar ivy-minibuffer-map
78 (let ((map (make-sparse-keymap)))
79 (define-key map (kbd "C-m") 'ivy-done)
80 (define-key map (kbd "C-j") 'ivy-alt-done)
81 (define-key map (kbd "C-n") 'ivy-next-line)
82 (define-key map (kbd "C-p") 'ivy-previous-line)
83 (define-key map (kbd "C-s") 'ivy-next-line-or-history)
84 (define-key map (kbd "C-r") 'ivy-previous-line-or-history)
85 (define-key map (kbd "SPC") 'self-insert-command)
86 (define-key map (kbd "DEL") 'ivy-backward-delete-char)
87 (define-key map (kbd "M-<") 'ivy-beginning-of-buffer)
88 (define-key map (kbd "M->") 'ivy-end-of-buffer)
89 (define-key map (kbd "M-n") 'ivy-next-history-element)
90 (define-key map (kbd "M-p") 'ivy-previous-history-element)
91 (define-key map (kbd "C-g") 'minibuffer-keyboard-quit)
93 "Keymap used in the minibuffer.")
95 (defvar ivy-history nil
96 "History list of candidates entered in the minibuffer.
98 Maximum length of the history list is determined by the value
99 of `history-length', which see.")
101 (defvar ivy-require-match t
102 "Store require-match. See `completing-read'.")
104 (defvar ivy--directory nil
105 "Current directory when completing file names.")
107 (defvar ivy--length 0
108 "Store the amount of viable candidates.")
111 "Store the user's string as it is typed in.")
113 (defvar ivy--current ""
114 "Current candidate.")
117 "Store the index of the current candidate.")
120 "Store 'done if the completion was successfully selected.
121 Otherwise, store nil.")
123 (defvar ivy--action nil
124 "Store a function to call at the end of `ivy--read'.")
126 (defvar ivy--all-candidates nil
127 "Store the candidates passed to `ivy-read'.")
129 (defvar ivy--default nil
130 "Default initial input.")
132 (defvar ivy--update-fn nil
133 "Current function to call when current candidate(s) update.")
135 (defvar ivy--prompt nil
136 "Store the format-style prompt.
137 When non-nil, it should contain one %d.")
139 (defvar ivy--old-re nil
140 "Store the old regexp.")
142 (defvar ivy--old-cands nil
143 "Store the candidates matched by `ivy--old-re'.")
147 "Exit the minibuffer with the selected candidate."
149 (delete-minibuffer-contents)
150 (if (zerop ivy--length)
151 (when (memq ivy-require-match '(nil confirm confirm-after-completion))
153 (setq ivy-exit 'done))
155 (insert (expand-file-name ivy--current ivy--directory))
156 (insert ivy--current))
157 (setq ivy-exit 'done))
160 (defun ivy-alt-done ()
161 "Exit the minibuffer with the selected candidate."
164 (cond ((and ivy--directory
166 (= 0 (length ivy-text)))
171 (setq dir (expand-file-name
172 ivy--current ivy--directory))))
179 (defun ivy-beginning-of-buffer ()
180 "Select the first completion candidate."
184 (defun ivy-end-of-buffer ()
185 "Select the last completion candidate."
187 (setq ivy--index (1- ivy--length)))
189 (defun ivy-next-line (&optional arg)
190 "Move cursor vertically down ARG candidates."
192 (setq arg (or arg 1))
193 (cl-incf ivy--index arg)
194 (when (>= ivy--index (1- ivy--length))
196 (ivy-beginning-of-buffer)
197 (setq ivy--index (1- ivy--length)))))
199 (defun ivy-next-line-or-history (&optional arg)
200 "Move cursor vertically down ARG candidates.
201 If the input is empty, select the previous history element instead."
203 (when (string= ivy-text "")
204 (ivy-previous-history-element 1))
207 (defun ivy-previous-line (&optional arg)
208 "Move cursor vertically up ARG candidates."
210 (setq arg (or arg 1))
211 (cl-decf ivy--index arg)
212 (when (< ivy--index 0)
215 (setq ivy--index 0))))
217 (defun ivy-previous-line-or-history (arg)
218 "Move cursor vertically up ARG candidates.
219 If the input is empty, select the previous history element instead."
221 (when (string= ivy-text "")
222 (ivy-previous-history-element 1))
223 (ivy-previous-line arg))
225 (defun ivy-previous-history-element (arg)
226 "Forward to `previous-history-element' with ARG."
228 (previous-history-element arg)
229 (move-end-of-line 1))
231 (defun ivy-next-history-element (arg)
232 "Forward to `next-history-element' with ARG."
234 (next-history-element arg)
235 (move-end-of-line 1))
238 "When completing file names, move to directory DIR."
239 (if (null ivy--directory)
241 (setq ivy--old-cands nil)
242 (setq ivy--all-candidates
243 (ivy--sorted-files (setq ivy--directory dir)))
245 (delete-minibuffer-contents)))
247 (defun ivy-backward-delete-char ()
248 "Forward to `backward-delete-char'.
249 On error (read-only), call `ivy-on-del-error-function'."
251 (if (and ivy--directory (= (minibuffer-prompt-end) (point)))
253 (ivy--cd (file-name-directory
254 (directory-file-name ivy--directory)))
257 (backward-delete-char 1)
259 (when ivy-on-del-error-function
260 (funcall ivy-on-del-error-function))))))
262 (defun ivy--sorted-files (dir)
263 "Return the list of files in DIR.
264 Directories come first."
265 (let* ((default-directory dir)
266 (seq (all-completions "" 'read-file-name-internal)))
270 (delete "./" (delete "../" seq))
272 (if (file-directory-p x)
273 (if (file-directory-p y)
276 (if (file-directory-p y)
279 (dolist (dir ivy-extra-directories)
284 (defun ivy-read (prompt collection
285 &optional predicate initial-input keymap preselect update-fn)
286 "Read a string in the minibuffer, with completion.
288 PROMPT is a string to prompt with; normally it ends in a colon
289 and a space. When PROMPT contains %d, it will be updated with
290 the current number of matching candidates.
291 See also `ivy-count-format'.
293 COLLECTION is a list of strings.
295 If INITIAL-INPUT is non-nil, insert it in the minibuffer initially.
297 KEYMAP is composed together with `ivy-minibuffer-map'.
299 If PRESELECT is non-nil select the corresponding candidate out of
300 the ones that match INITIAL-INPUT.
302 UPDATE-FN is called each time the current candidate(s) is changed."
303 (setq ivy--directory nil)
304 (cond ((eq collection 'Info-read-node-name-1)
305 (if (equal Info-current-file "dir")
307 (mapcar (lambda (x) (format "(%s)" x))
308 (cl-delete-duplicates
309 (all-completions "(" collection predicate)
311 (setq collection (all-completions "" collection predicate))))
312 ((eq collection 'read-file-name-internal)
313 (setq ivy--directory default-directory)
314 (setq initial-input nil)
316 (ivy--sorted-files default-directory)))
317 ((or (functionp collection)
318 (vectorp collection))
319 (setq collection (all-completions "" collection predicate)))
320 ((hash-table-p collection)
321 (error "Hash table as a collection unsupported"))
322 ((listp (car collection))
323 (setq collection (all-completions "" collection predicate))))
325 (unless (or ivy-require-match
326 (all-completions preselect collection))
327 (setq collection (cons preselect collection))))
328 (cl-case (length collection)
334 (ivy--preselect-index
335 collection initial-input preselect))
337 (setq ivy--old-re nil)
338 (setq ivy--old-cands nil)
340 (setq ivy--all-candidates collection)
341 (setq ivy--update-fn update-fn)
343 (setq ivy--default (or (thing-at-point 'symbol) ""))
345 (cond ((string-match "%.*d" prompt)
347 ((string-match "%.*d" ivy-count-format)
348 (concat ivy-count-format prompt))
353 (setq ivy--action nil)
356 (minibuffer-with-setup-hook
357 #'ivy--minibuffer-setup
358 (let ((res (read-from-minibuffer
361 (make-composed-keymap keymap ivy-minibuffer-map)
364 (when (eq ivy-exit 'done)
367 (cons ivy-text (delete ivy-text ivy-history)))
369 (remove-hook 'post-command-hook #'ivy--exhibit))
371 (funcall ivy--action))))))
373 (defun ivy-completing-read (prompt collection
374 &optional predicate require-match initial-input
375 _history def _inherit-input-method)
376 "Read a string in the minibuffer, with completion.
378 This is an interface that conforms to `completing-read', so that
379 it can be used for `completing-read-function'.
381 PROMPT is a string to prompt with; normally it ends in a colon and a space.
382 COLLECTION can be a list of strings, an alist, an obarray or a hash table.
383 PREDICATE limits completion to a subset of COLLECTION.
385 REQUIRE-MATCH is stored into `ivy-require-match'. See `completing-read'.
386 INITIAL-INPUT is a string that can be inserted into the minibuffer initially.
387 _HISTORY is ignored for now.
388 DEF is the default value.
389 _INHERIT-INPUT-METHOD is ignored for now.
391 The history, defaults and input-method arguments are ignored for now."
393 (setq def (car def)))
394 (setq ivy-require-match require-match)
395 (ivy-read prompt collection predicate initial-input nil def))
398 (define-minor-mode ivy-mode
399 "Toggle Ivy mode on or off.
400 With ARG, turn Ivy mode on if arg is positive, off otherwise.
401 Turning on Ivy mode will set `completing-read-function' to
402 `ivy-completing-read'.
404 \\{ivy-minibuffer-map}"
409 (setq completing-read-function 'ivy-completing-read)
410 (setq completing-read-function 'completing-read-default)))
412 (defun ivy--preselect-index (candidates initial-input preselect)
413 "Return the index in CANDIDATES filtered by INITIAL-INPUT for PRESELECT."
418 (string-match initial-input x))
422 (string-match preselect x))
427 (defvar ivy--subexps 0
428 "Number of groups in the current `ivy--regex'.")
430 (defvar ivy--regex-hash
431 (make-hash-table :test 'equal)
432 "Store pre-computed regex.")
434 (defun ivy--regex (str)
435 "Re-build regex from STR in case it has a space."
436 (let ((hashed (gethash str ivy--regex-hash)))
439 (setq ivy--subexps (car hashed)))
441 (let ((subs (split-string str " +" t)))
442 (if (= (length subs) 1)
444 (setq ivy--subexps 0)
447 (setq ivy--subexps (length subs))
449 (lambda (x) (format "\\(%s\\)" x))
455 (defun ivy--minibuffer-setup ()
456 "Setup ivy completion in the minibuffer."
457 (set (make-local-variable 'completion-show-inline-help) nil)
458 (set (make-local-variable 'minibuffer-default-add-function)
460 (list ivy--default)))
461 (use-local-map (make-composed-keymap ivy-minibuffer-map
462 (current-local-map)))
463 (setq-local max-mini-window-height ivy-height)
464 (add-hook 'post-command-hook #'ivy--exhibit nil t)
465 ;; show completions with empty input
469 "Return the current minibuffer input."
470 ;; assume one-line minibuffer input
471 (buffer-substring-no-properties
472 (minibuffer-prompt-end)
473 (line-end-position)))
475 (defun ivy--cleanup ()
476 "Delete the displayed completion candidates."
478 (goto-char (minibuffer-prompt-end))
479 (delete-region (line-end-position) (point-max))))
481 (defun ivy--insert-prompt ()
482 "Update the prompt according to `ivy--prompt'."
484 (let ((inhibit-read-only t)
488 (concat ivy--prompt (abbreviate-file-name ivy--directory))
489 ivy--prompt) ivy--length)))
491 (goto-char (point-min))
492 (delete-region (point-min) (minibuffer-prompt-end))
495 '(front-sticky t rear-nonsticky t field t read-only t face minibuffer-prompt)
498 ;; get out of the prompt area
499 (constrain-to-field nil (point-max)))))
501 (defun ivy--exhibit ()
502 "Insert Ivy completions display.
503 Should be run via minibuffer `post-command-hook'."
504 (setq ivy-text (ivy--input))
507 (if (string-match "/$" ivy-text)
508 (if (member ivy-text ivy--all-candidates)
509 (ivy--cd (expand-file-name ivy-text ivy--directory))
511 (if (string-match "~$" ivy-text)
512 (ivy--cd (expand-file-name "~/")))))
513 (let ((text (ivy-completions
515 ivy--all-candidates))
519 (funcall ivy--update-fn))
521 ;; Do nothing if while-no-input was aborted.
527 (defun ivy--add-face (str face)
528 "Propertize STR with FACE.
529 `font-lock-append-text-property' is used, since it's better than
530 `propertize' or `add-face-text-property' in this case."
531 (font-lock-append-text-property 0 (length str) 'face face str)
534 (defun ivy-completions (name candidates)
535 "Return as text the current completions.
536 NAME is a string of words separated by spaces that is used to
538 CANDIDATES is a list of strings."
539 (let* ((re (ivy--regex name))
540 (cands (if (and (equal re ivy--old-re)
545 (lambda (x) (string-match re x))
547 (tail (nthcdr ivy--index ivy--old-cands))
550 (when (and tail ivy--old-cands)
551 (unless (and (not (equal re ivy--old-re))
552 (setq ivy--index (cl-position re cands :test 'equal)))
553 (while (and tail (null idx))
554 ;; Compare with eq to handle equal duplicates in cands
555 (setq idx (cl-position (pop tail) cands)))
556 (setq ivy--index (or idx 0))))
557 (setq ivy--old-re re)
558 (setq ivy--length (length cands))
559 (setq ivy--old-cands cands)
560 (when (>= ivy--index ivy--length)
561 (setq ivy--index (max (1- ivy--length) 0)))
564 (let* ((half-height (/ ivy-height 2))
565 (start (max 0 (- ivy--index half-height)))
566 (end (min (+ start (1- ivy-height)) ivy--length))
567 (cands (cl-subseq cands start end))
568 (index (min ivy--index half-height (1- (length cands)))))
569 (setq ivy--current (copy-sequence (nth index cands)))
570 (setf (nth index cands)
571 (ivy--add-face ivy--current 'ivy-current-match))
572 (let ((res (concat "\n" (mapconcat
574 (if (> (length s) ww)
575 (concat (substring s 0 (- ww 3)) "...")
578 (put-text-property 0 (length res) 'read-only nil res)