]> code.delx.au - gnu-emacs-elpa/blob - packages/swiper/ivy.el
Merge commit 'e084b5d9feab3dd1246e51ce1fddde3db6024f7d' from swiper
[gnu-emacs-elpa] / packages / swiper / 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 '((t (:inherit highlight)))
48 "Face used by Ivy for highlighting first match.")
49
50 (defface ivy-confirm-face
51 '((t :foreground "ForestGreen" :inherit minibuffer-prompt))
52 "Face used by Ivy to issue a confirmation prompt.")
53
54 (defface ivy-match-required-face
55 '((t :foreground "red" :inherit minibuffer-prompt))
56 "Face used by Ivy to issue a match required prompt.")
57
58 (defface ivy-subdir
59 '((t (:inherit 'dired-directory)))
60 "Face used by Ivy for highlighting subdirs in the alternatives.")
61
62 (defface ivy-remote
63 '((t (:foreground "#110099")))
64 "Face used by Ivy for highlighting remotes in the alternatives.")
65
66 (defcustom ivy-height 10
67 "Number of lines for the minibuffer window."
68 :type 'integer)
69
70 (defcustom ivy-count-format "%-4d "
71 "The style of showing the current candidate count for `ivy-read'.
72 Set this to nil if you don't want the count."
73 :type 'string)
74
75 (defcustom ivy-wrap nil
76 "Whether to wrap around after the first and last candidate."
77 :type 'boolean)
78
79 (defcustom ivy-on-del-error-function 'minibuffer-keyboard-quit
80 "The handler for when `ivy-backward-delete-char' throws.
81 This is usually meant as a quick exit out of the minibuffer."
82 :type 'function)
83
84 (defcustom ivy-extra-directories '("../" "./")
85 "Add this to the front of the list when completing file names.
86 Only \"./\" and \"../\" apply here. They appear in reverse order."
87 :type 'list)
88
89 (defcustom ivy-use-virtual-buffers nil
90 "When non-nil, add `recentf-mode' and bookmarks to the list of buffers."
91 :type 'boolean)
92
93 ;;* Keymap
94 (require 'delsel)
95 (defvar ivy-minibuffer-map
96 (let ((map (make-sparse-keymap)))
97 (define-key map (kbd "C-m") 'ivy-done)
98 (define-key map (kbd "C-j") 'ivy-alt-done)
99 (define-key map (kbd "TAB") 'ivy-partial-or-done)
100 (define-key map (kbd "C-n") 'ivy-next-line)
101 (define-key map (kbd "C-p") 'ivy-previous-line)
102 (define-key map (kbd "<down>") 'ivy-next-line)
103 (define-key map (kbd "<up>") 'ivy-previous-line)
104 (define-key map (kbd "C-s") 'ivy-next-line-or-history)
105 (define-key map (kbd "C-r") 'ivy-previous-line-or-history)
106 (define-key map (kbd "SPC") 'self-insert-command)
107 (define-key map (kbd "DEL") 'ivy-backward-delete-char)
108 (define-key map (kbd "M-DEL") 'ivy-backward-kill-word)
109 (define-key map (kbd "C-d") 'ivy-delete-char)
110 (define-key map (kbd "C-f") 'ivy-forward-char)
111 (define-key map (kbd "M-d") 'ivy-kill-word)
112 (define-key map (kbd "M-<") 'ivy-beginning-of-buffer)
113 (define-key map (kbd "M->") 'ivy-end-of-buffer)
114 (define-key map (kbd "<left>") 'ivy-beginning-of-buffer)
115 (define-key map (kbd "<right>") 'ivy-end-of-buffer)
116 (define-key map (kbd "M-n") 'ivy-next-history-element)
117 (define-key map (kbd "M-p") 'ivy-previous-history-element)
118 (define-key map (kbd "C-g") 'minibuffer-keyboard-quit)
119 (define-key map (kbd "C-v") 'ivy-scroll-up-command)
120 (define-key map (kbd "M-v") 'ivy-scroll-down-command)
121 (define-key map (kbd "C-M-n") 'ivy-next-line-and-call)
122 (define-key map (kbd "C-M-p") 'ivy-previous-line-and-call)
123 (define-key map (kbd "M-q") 'ivy-toggle-regexp-quote)
124 map)
125 "Keymap used in the minibuffer.")
126
127 (defvar ivy-mode-map
128 (let ((map (make-sparse-keymap)))
129 (define-key map [remap switch-to-buffer] 'ivy-switch-buffer)
130 map)
131 "Keymap for `ivy-mode'.")
132
133 ;;* Globals
134 (cl-defstruct ivy-state
135 prompt collection
136 predicate require-match initial-input
137 history preselect keymap update-fn sort
138 ;; The window in which `ivy-read' was called
139 window
140 action
141 unwind
142 re-builder
143 matcher
144 ;; When this is non-nil, call it for each input change to get new candidates
145 dynamic-collection)
146
147 (defvar ivy-last nil
148 "The last parameters passed to `ivy-read'.")
149
150 (defsubst ivy-set-action (action)
151 (setf (ivy-state-action ivy-last) action))
152
153 (defvar ivy-history nil
154 "History list of candidates entered in the minibuffer.
155
156 Maximum length of the history list is determined by the value
157 of `history-length', which see.")
158
159 (defvar ivy--directory nil
160 "Current directory when completing file names.")
161
162 (defvar ivy--length 0
163 "Store the amount of viable candidates.")
164
165 (defvar ivy-text ""
166 "Store the user's string as it is typed in.")
167
168 (defvar ivy--current ""
169 "Current candidate.")
170
171 (defvar ivy--index 0
172 "Store the index of the current candidate.")
173
174 (defvar ivy-exit nil
175 "Store 'done if the completion was successfully selected.
176 Otherwise, store nil.")
177
178 (defvar ivy--all-candidates nil
179 "Store the candidates passed to `ivy-read'.")
180
181 (defvar ivy--default nil
182 "Default initial input.")
183
184 (defvar ivy--prompt nil
185 "Store the format-style prompt.
186 When non-nil, it should contain one %d.")
187
188 (defvar ivy--prompt-extra ""
189 "Temporary modifications to the prompt.")
190
191 (defvar ivy--old-re nil
192 "Store the old regexp.")
193
194 (defvar ivy--old-cands nil
195 "Store the candidates matched by `ivy--old-re'.")
196
197 (defvar ivy--regex-function 'ivy--regex
198 "Current function for building a regex.")
199
200 (defvar ivy--subexps 0
201 "Number of groups in the current `ivy--regex'.")
202
203 (defvar ivy--full-length nil
204 "When :dynamic-collection is non-nil, this can be the total amount of candidates.")
205
206 (defvar ivy--old-text ""
207 "Store old `ivy-text' for dynamic completion.")
208
209 (defvar Info-current-file)
210
211 (defmacro ivy-quit-and-run (&rest body)
212 "Quit the minibuffer and run BODY afterwards."
213 `(progn
214 (put 'quit 'error-message "")
215 (run-at-time nil nil
216 (lambda ()
217 (put 'quit 'error-message "Quit")
218 ,@body))
219 (minibuffer-keyboard-quit)))
220
221 (defun ivy--done (text)
222 "Insert TEXT and exit minibuffer."
223 (if (and ivy--directory
224 (not (eq (ivy-state-history ivy-last) 'grep-files-history)))
225 (insert (expand-file-name
226 text ivy--directory))
227 (insert text))
228 (setq ivy-exit 'done)
229 (exit-minibuffer))
230
231 ;;* Commands
232 (defun ivy-done ()
233 "Exit the minibuffer with the selected candidate."
234 (interactive)
235 (delete-minibuffer-contents)
236 (cond ((> ivy--length 0)
237 (ivy--done ivy--current))
238 ((memq (ivy-state-collection ivy-last)
239 '(read-file-name-internal internal-complete-buffer))
240 (if (or (not (eq confirm-nonexistent-file-or-buffer t))
241 (equal " (confirm)" ivy--prompt-extra))
242 (ivy--done ivy-text)
243 (setq ivy--prompt-extra " (confirm)")
244 (insert ivy-text)
245 (ivy--exhibit)))
246 ((memq (ivy-state-require-match ivy-last)
247 '(nil confirm confirm-after-completion))
248 (ivy--done ivy-text))
249 (t
250 (setq ivy--prompt-extra " (match required)")
251 (insert ivy-text)
252 (ivy--exhibit))))
253
254 (defun ivy-build-tramp-name (x)
255 "Reconstruct X into a path.
256 Is is a cons cell, related to `tramp-get-completion-function'."
257 (let ((user (car x))
258 (domain (cadr x)))
259 (if user
260 (concat user "@" domain)
261 domain)))
262
263 (declare-function tramp-get-completion-function "tramp")
264
265 (defun ivy-alt-done (&optional arg)
266 "Exit the minibuffer with the selected candidate.
267 When ARG is t, exit with current text, ignoring the candidates."
268 (interactive "P")
269 (if arg
270 (ivy-immediate-done)
271 (let (dir)
272 (cond ((and ivy--directory
273 (or
274 (and
275 (not (string= ivy--current "./"))
276 (cl-plusp ivy--length)
277 (file-directory-p
278 (setq dir (expand-file-name
279 ivy--current ivy--directory))))))
280 (ivy--cd dir)
281 (ivy--exhibit))
282 ((string-match "\\`/\\([^/]+?\\):\\(?:\\(.*\\)@\\)?" ivy-text)
283 (let ((method (match-string 1 ivy-text))
284 (user (match-string 2 ivy-text))
285 res)
286 (dolist (x (tramp-get-completion-function method))
287 (setq res (append res (funcall (car x) (cadr x)))))
288 (setq res (delq nil res))
289 (when user
290 (dolist (x res)
291 (setcar x user)))
292 (setq res (cl-delete-duplicates res :test #'equal))
293 (let ((host (ivy-read "Find File: "
294 (mapcar #'ivy-build-tramp-name res))))
295 (when host
296 (setq ivy--directory "/")
297 (ivy--cd (concat "/" method ":" host ":"))))))
298 (t
299 (ivy-done))))))
300
301 (defcustom ivy-tab-space nil
302 "When non-nil, `ivy-partial-or-done' should insert a space."
303 :type 'boolean)
304
305 (defun ivy-partial-or-done ()
306 "Complete the minibuffer text as much as possible.
307 If the text hasn't changed as a result, forward to `ivy-alt-done'."
308 (interactive)
309 (if (and (eq (ivy-state-collection ivy-last) #'read-file-name-internal)
310 (string-match "\\`/" ivy-text))
311 (let ((default-directory ivy--directory))
312 (minibuffer-complete)
313 (setq ivy-text (ivy--input))
314 (when (and (file-directory-p ivy-text)
315 (= ivy--length 1))
316 (ivy--cd (expand-file-name ivy-text))))
317 (or (ivy-partial)
318 (when (or (eq this-command last-command)
319 (eq ivy--length 1))
320 (ivy-alt-done)))))
321
322 (defun ivy-partial ()
323 "Complete the minibuffer text as much as possible."
324 (interactive)
325 (let* ((parts (or (split-string ivy-text " " t) (list "")))
326 (postfix (car (last parts)))
327 (completion-ignore-case t)
328 (new (try-completion postfix
329 (mapcar (lambda (str) (substring str (string-match postfix str)))
330 ivy--old-cands))))
331 (cond ((eq new t) nil)
332 ((string= new ivy-text) nil)
333 (new
334 (delete-region (minibuffer-prompt-end) (point-max))
335 (setcar (last parts) new)
336 (insert (mapconcat #'identity parts " ")
337 (if ivy-tab-space " " ""))
338 t))))
339
340 (defun ivy-immediate-done ()
341 "Exit the minibuffer with the current input."
342 (interactive)
343 (delete-minibuffer-contents)
344 (insert (setq ivy--current ivy-text))
345 (setq ivy-exit 'done)
346 (exit-minibuffer))
347
348 (defun ivy-resume ()
349 "Resume the last completion session."
350 (interactive)
351 (ivy-read
352 (ivy-state-prompt ivy-last)
353 (ivy-state-collection ivy-last)
354 :predicate (ivy-state-predicate ivy-last)
355 :require-match (ivy-state-require-match ivy-last)
356 :initial-input ivy-text
357 :history (ivy-state-history ivy-last)
358 :preselect (regexp-quote ivy--current)
359 :keymap (ivy-state-keymap ivy-last)
360 :update-fn (ivy-state-update-fn ivy-last)
361 :sort (ivy-state-sort ivy-last)
362 :action (ivy-state-action ivy-last)
363 :unwind (ivy-state-unwind ivy-last)
364 :re-builder (ivy-state-re-builder ivy-last)
365 :matcher (ivy-state-matcher ivy-last)
366 :dynamic-collection (ivy-state-dynamic-collection ivy-last)))
367
368 (defun ivy-beginning-of-buffer ()
369 "Select the first completion candidate."
370 (interactive)
371 (setq ivy--index 0))
372
373 (defun ivy-end-of-buffer ()
374 "Select the last completion candidate."
375 (interactive)
376 (setq ivy--index (1- ivy--length)))
377
378 (defun ivy-scroll-up-command ()
379 "Scroll the candidates upward by the minibuffer height."
380 (interactive)
381 (setq ivy--index (min (+ ivy--index ivy-height)
382 (1- ivy--length))))
383
384 (defun ivy-scroll-down-command ()
385 "Scroll the candidates downward by the minibuffer height."
386 (interactive)
387 (setq ivy--index (max (- ivy--index ivy-height)
388 0)))
389
390 (defun ivy-next-line (&optional arg)
391 "Move cursor vertically down ARG candidates."
392 (interactive "p")
393 (setq arg (or arg 1))
394 (cl-incf ivy--index arg)
395 (when (>= ivy--index (1- ivy--length))
396 (if ivy-wrap
397 (ivy-beginning-of-buffer)
398 (setq ivy--index (1- ivy--length)))))
399
400 (defun ivy-next-line-or-history (&optional arg)
401 "Move cursor vertically down ARG candidates.
402 If the input is empty, select the previous history element instead."
403 (interactive "p")
404 (when (string= ivy-text "")
405 (ivy-previous-history-element 1))
406 (ivy-next-line arg))
407
408 (defun ivy-previous-line (&optional arg)
409 "Move cursor vertically up ARG candidates."
410 (interactive "p")
411 (setq arg (or arg 1))
412 (cl-decf ivy--index arg)
413 (when (< ivy--index 0)
414 (if ivy-wrap
415 (ivy-end-of-buffer)
416 (setq ivy--index 0))))
417
418 (defun ivy-previous-line-or-history (arg)
419 "Move cursor vertically up ARG candidates.
420 If the input is empty, select the previous history element instead."
421 (interactive "p")
422 (when (string= ivy-text "")
423 (ivy-previous-history-element 1))
424 (ivy-previous-line arg))
425
426 (defun ivy-next-line-and-call (&optional arg)
427 "Move cursor vertically down ARG candidates.
428 Call the permanent action if possible."
429 (interactive "p")
430 (ivy-next-line arg)
431 (ivy--exhibit)
432 (when (ivy-state-action ivy-last)
433 (with-selected-window (ivy-state-window ivy-last)
434 (funcall (ivy-state-action ivy-last) ivy--current))))
435
436 (defun ivy-previous-line-and-call (&optional arg)
437 "Move cursor vertically down ARG candidates.
438 Call the permanent action if possible."
439 (interactive "p")
440 (ivy-previous-line arg)
441 (ivy--exhibit)
442 (when (ivy-state-action ivy-last)
443 (with-selected-window (ivy-state-window ivy-last)
444 (funcall (ivy-state-action ivy-last) ivy--current))))
445
446 (defun ivy-previous-history-element (arg)
447 "Forward to `previous-history-element' with ARG."
448 (interactive "p")
449 (previous-history-element arg)
450 (move-end-of-line 1)
451 (ivy--maybe-scroll-history))
452
453 (defun ivy-next-history-element (arg)
454 "Forward to `next-history-element' with ARG."
455 (interactive "p")
456 (next-history-element arg)
457 (move-end-of-line 1)
458 (ivy--maybe-scroll-history))
459
460 (defun ivy--maybe-scroll-history ()
461 "If the selected history element has an index, scroll there."
462 (let ((idx (ignore-errors
463 (get-text-property
464 (minibuffer-prompt-end)
465 'ivy-index))))
466 (when idx
467 (ivy--exhibit)
468 (setq ivy--index idx))))
469
470 (defun ivy--cd (dir)
471 "When completing file names, move to directory DIR."
472 (if (null ivy--directory)
473 (error "Unexpected")
474 (setq ivy--old-cands nil)
475 (setq ivy--old-re nil)
476 (setq ivy--index 0)
477 (setq ivy--all-candidates
478 (ivy--sorted-files (setq ivy--directory dir)))
479 (setq ivy-text "")
480 (delete-minibuffer-contents)))
481
482 (defun ivy-backward-delete-char ()
483 "Forward to `backward-delete-char'.
484 On error (read-only), call `ivy-on-del-error-function'."
485 (interactive)
486 (if (and ivy--directory (= (minibuffer-prompt-end) (point)))
487 (progn
488 (ivy--cd (file-name-directory
489 (directory-file-name
490 (expand-file-name
491 ivy--directory))))
492 (ivy--exhibit))
493 (condition-case nil
494 (backward-delete-char 1)
495 (error
496 (when ivy-on-del-error-function
497 (funcall ivy-on-del-error-function))))))
498
499 (defun ivy-delete-char (arg)
500 "Forward to `delete-char' ARG."
501 (interactive "p")
502 (unless (= (point) (line-end-position))
503 (delete-char arg)))
504
505 (defun ivy-forward-char (arg)
506 "Forward to `forward-char' ARG."
507 (interactive "p")
508 (unless (= (point) (line-end-position))
509 (forward-char arg)))
510
511 (defun ivy-kill-word (arg)
512 "Forward to `kill-word' ARG."
513 (interactive "p")
514 (unless (= (point) (line-end-position))
515 (kill-word arg)))
516
517 (defun ivy-backward-kill-word ()
518 "Forward to `backward-kill-word'."
519 (interactive)
520 (if (and ivy--directory (= (minibuffer-prompt-end) (point)))
521 (progn
522 (ivy--cd (file-name-directory
523 (directory-file-name
524 (expand-file-name
525 ivy--directory))))
526 (ivy--exhibit))
527 (ignore-errors
528 (backward-kill-word 1))))
529
530 (defvar ivy--regexp-quote 'regexp-quote
531 "Store the regexp quoting state.")
532
533 (defun ivy-toggle-regexp-quote ()
534 "Toggle the regexp quoting."
535 (interactive)
536 (setq ivy--old-re nil)
537 (cl-rotatef ivy--regex-function ivy--regexp-quote))
538
539 (defun ivy-sort-file-function-default (x y)
540 "Compare two files X and Y.
541 Prioritize directories."
542 (if (get-text-property 0 'dirp x)
543 (if (get-text-property 0 'dirp y)
544 (string< x y)
545 t)
546 (if (get-text-property 0 'dirp y)
547 nil
548 (string< x y))))
549
550 (defvar ivy-sort-functions-alist
551 '((read-file-name-internal . ivy-sort-file-function-default)
552 (internal-complete-buffer . nil)
553 (counsel-git-grep-function . nil)
554 (t . string-lessp))
555 "An alist of sorting functions for each collection function.
556 For each entry, nil means no sorting.
557 The entry associated to t is used for all fall-through cases.")
558
559 (defvar ivy-re-builders-alist
560 '((t . ivy--regex-plus))
561 "An alist of regex building functions for each collection function.
562 Each function should take a string and return a valid regex or a
563 regex sequence (see below).
564
565 The entry associated to t is used for all fall-through cases.
566 Possible choices: `ivy--regex', `regexp-quote', `ivy--regex-plus'.
567
568 In case a function returns a list, it should look like this:
569 '((\"matching-regexp\" . t) (\"non-matching-regexp\") ...).
570
571 The matches will be filtered in a sequence, you can mix the
572 regexps that should match and that should not match as you
573 like.")
574
575 (defcustom ivy-sort-max-size 30000
576 "Sorting won't be done for collections larger than this."
577 :type 'integer)
578
579 (defun ivy--sorted-files (dir)
580 "Return the list of files in DIR.
581 Directories come first."
582 (let* ((default-directory dir)
583 (seq (all-completions "" 'read-file-name-internal))
584 sort-fn)
585 (if (equal dir "/")
586 seq
587 (setq seq (delete "./" (delete "../" seq)))
588 (when (eq (setq sort-fn (cdr (assoc 'read-file-name-internal
589 ivy-sort-functions-alist)))
590 #'ivy-sort-file-function-default)
591 (setq seq (mapcar (lambda (x)
592 (propertize x 'dirp (string-match-p "/\\'" x)))
593 seq)))
594 (when sort-fn
595 (setq seq (cl-sort seq sort-fn)))
596 (dolist (dir ivy-extra-directories)
597 (push dir seq))
598 seq)))
599
600 ;;** Entry Point
601 (cl-defun ivy-read (prompt collection
602 &key predicate require-match initial-input
603 history preselect keymap update-fn sort
604 action unwind re-builder matcher dynamic-collection)
605 "Read a string in the minibuffer, with completion.
606
607 PROMPT is a string to prompt with; normally it ends in a colon
608 and a space. When PROMPT contains %d, it will be updated with
609 the current number of matching candidates.
610 See also `ivy-count-format'.
611
612 COLLECTION is a list of strings.
613
614 If INITIAL-INPUT is non-nil, insert it in the minibuffer initially.
615
616 KEYMAP is composed together with `ivy-minibuffer-map'.
617
618 If PRESELECT is non-nil select the corresponding candidate out of
619 the ones that match INITIAL-INPUT.
620
621 UPDATE-FN is called each time the current candidate(s) is changed.
622
623 When SORT is t, refer to `ivy-sort-functions-alist' for sorting.
624
625 ACTION is a lambda to call after a result was selected. It should
626 take a single argument, usually a string.
627
628 UNWIND is a lambda to call before exiting.
629
630 RE-BUILDER is a lambda that transforms text into a regex.
631
632 MATCHER can completely override matching.
633
634 DYNAMIC-COLLECTION is a function to call to update the list of
635 candidates with each input."
636 (setq ivy-last
637 (make-ivy-state
638 :prompt prompt
639 :collection collection
640 :predicate predicate
641 :require-match require-match
642 :initial-input initial-input
643 :history history
644 :preselect preselect
645 :keymap keymap
646 :update-fn update-fn
647 :sort sort
648 :action action
649 :window (selected-window)
650 :unwind unwind
651 :re-builder re-builder
652 :matcher matcher
653 :dynamic-collection dynamic-collection))
654 (setq ivy--directory nil)
655 (setq ivy--regex-function
656 (or re-builder
657 (and (functionp collection)
658 (cdr (assoc collection ivy-re-builders-alist)))
659 (cdr (assoc t ivy-re-builders-alist))
660 'ivy--regex))
661 (setq ivy--subexps 0)
662 (setq ivy--regexp-quote 'regexp-quote)
663 (setq ivy--old-text "")
664 (setq ivy-text "")
665 (let (coll sort-fn)
666 (cond ((eq collection 'Info-read-node-name-1)
667 (if (equal Info-current-file "dir")
668 (setq coll
669 (mapcar (lambda (x) (format "(%s)" x))
670 (cl-delete-duplicates
671 (all-completions "(" collection predicate)
672 :test #'equal)))
673 (setq coll (all-completions "" collection predicate))))
674 ((eq collection 'read-file-name-internal)
675 (setq ivy--directory default-directory)
676 (require 'dired)
677 (setq coll
678 (ivy--sorted-files default-directory))
679 (when initial-input
680 (unless (or require-match
681 (equal initial-input default-directory))
682 (setq coll (cons initial-input coll)))
683 (setq initial-input nil)))
684 ((eq collection 'internal-complete-buffer)
685 (setq coll (ivy--buffer-list "" ivy-use-virtual-buffers)))
686 ((or (functionp collection)
687 (vectorp collection)
688 (listp (car collection)))
689 (setq coll (all-completions "" collection predicate)))
690 ((hash-table-p collection)
691 (error "Hash table as a collection unsupported"))
692 (t
693 (setq coll collection)))
694 (when sort
695 (if (and (functionp collection)
696 (setq sort-fn (assoc collection ivy-sort-functions-alist)))
697 (when (and (setq sort-fn (cdr sort-fn))
698 (not (eq collection 'read-file-name-internal)))
699 (setq coll (cl-sort coll sort-fn)))
700 (unless (eq history 'org-refile-history)
701 (if (and (setq sort-fn (cdr (assoc t ivy-sort-functions-alist)))
702 (<= (length coll) ivy-sort-max-size))
703 (setq coll (cl-sort (copy-sequence coll) sort-fn))))))
704 (when preselect
705 (unless (or require-match
706 (let ((re (format "\\`%s" preselect)))
707 (cl-find-if (lambda (x) (string-match re x))
708 coll)))
709 (setq coll (cons preselect coll))))
710 (setq ivy--index (or
711 (and dynamic-collection
712 ivy--index)
713 (and preselect
714 (ivy--preselect-index
715 coll initial-input preselect))
716 0))
717 (setq ivy--old-re nil)
718 (setq ivy--old-cands nil)
719 (setq ivy--all-candidates coll)
720 (setq ivy-exit nil)
721 (setq ivy--default (or (thing-at-point 'symbol) ""))
722 (setq ivy--prompt
723 (cond ((string-match "%.*d" prompt)
724 prompt)
725 ((string-match "%.*d" ivy-count-format)
726 (concat ivy-count-format prompt))
727 (ivy--directory
728 prompt)
729 (t
730 nil)))
731 (prog1
732 (unwind-protect
733 (minibuffer-with-setup-hook
734 #'ivy--minibuffer-setup
735 (let* ((hist (or history 'ivy-history))
736 (minibuffer-completion-table collection)
737 (minibuffer-completion-predicate predicate)
738 (res (read-from-minibuffer
739 prompt
740 initial-input
741 (make-composed-keymap keymap ivy-minibuffer-map)
742 nil
743 hist)))
744 (when (eq ivy-exit 'done)
745 (set hist (cons (propertize ivy-text 'ivy-index ivy--index)
746 (delete ivy-text
747 (cdr (symbol-value hist)))))
748 res)))
749 (remove-hook 'post-command-hook #'ivy--exhibit)
750 (when (setq unwind (ivy-state-unwind ivy-last))
751 (funcall unwind)))
752 (when (setq action (ivy-state-action ivy-last))
753 (funcall action ivy--current)))))
754
755 (defun ivy-completing-read (prompt collection
756 &optional predicate require-match initial-input
757 history def _inherit-input-method)
758 "Read a string in the minibuffer, with completion.
759
760 This is an interface that conforms to `completing-read', so that
761 it can be used for `completing-read-function'.
762
763 PROMPT is a string to prompt with; normally it ends in a colon and a space.
764 COLLECTION can be a list of strings, an alist, an obarray or a hash table.
765 PREDICATE limits completion to a subset of COLLECTION.
766 REQUIRE-MATCH is considered boolean. See `completing-read'.
767 INITIAL-INPUT is a string that can be inserted into the minibuffer initially.
768 _HISTORY is ignored for now.
769 DEF is the default value.
770 _INHERIT-INPUT-METHOD is ignored for now.
771
772 The history, defaults and input-method arguments are ignored for now."
773 (ivy-read prompt collection
774 :predicate predicate
775 :require-match require-match
776 :initial-input (if (consp initial-input)
777 (car initial-input)
778 initial-input)
779 :preselect (if (listp def) (car def) def)
780 :history history
781 :keymap nil
782 :sort t))
783
784 ;;;###autoload
785 (define-minor-mode ivy-mode
786 "Toggle Ivy mode on or off.
787 With ARG, turn Ivy mode on if arg is positive, off otherwise.
788 Turning on Ivy mode will set `completing-read-function' to
789 `ivy-completing-read'.
790
791 Global bindings:
792 \\{ivy-mode-map}
793
794 Minibuffer bindings:
795 \\{ivy-minibuffer-map}"
796 :group 'ivy
797 :global t
798 :keymap ivy-mode-map
799 :lighter " ivy"
800 (if ivy-mode
801 (setq completing-read-function 'ivy-completing-read)
802 (setq completing-read-function 'completing-read-default)))
803
804 (defun ivy--preselect-index (candidates initial-input preselect)
805 "Return the index in CANDIDATES filtered by INITIAL-INPUT for PRESELECT."
806 (when initial-input
807 (setq initial-input (ivy--regex-plus initial-input))
808 (setq candidates
809 (cl-remove-if-not
810 (lambda (x)
811 (string-match initial-input x))
812 candidates)))
813 (or (cl-position preselect candidates :test #'equal)
814 (cl-position-if
815 (lambda (x)
816 (string-match (regexp-quote preselect) x))
817 candidates)))
818
819 ;;* Implementation
820 ;;** Regex
821 (defvar ivy--regex-hash
822 (make-hash-table :test #'equal)
823 "Store pre-computed regex.")
824
825 (defun ivy--split (str)
826 "Split STR into a list by single spaces.
827 The remaining spaces stick to their left.
828 This allows to \"quote\" N spaces by inputting N+1 spaces."
829 (let ((len (length str))
830 start0
831 (start1 0)
832 res s
833 match-len)
834 (while (and (string-match " +" str start1)
835 (< start1 len))
836 (setq match-len (- (match-end 0) (match-beginning 0)))
837 (if (= match-len 1)
838 (progn
839 (when start0
840 (setq start1 start0)
841 (setq start0 nil))
842 (push (substring str start1 (match-beginning 0)) res)
843 (setq start1 (match-end 0)))
844 (setq str (replace-match
845 (make-string (1- match-len) ?\ )
846 nil nil str))
847 (setq start0 (or start0 start1))
848 (setq start1 (1- (match-end 0)))))
849 (if start0
850 (push (substring str start0) res)
851 (setq s (substring str start1))
852 (unless (= (length s) 0)
853 (push s res)))
854 (nreverse res)))
855
856 (defun ivy--regex (str &optional greedy)
857 "Re-build regex from STR in case it has a space.
858 When GREEDY is non-nil, join words in a greedy way."
859 (let ((hashed (unless greedy
860 (gethash str ivy--regex-hash))))
861 (if hashed
862 (prog1 (cdr hashed)
863 (setq ivy--subexps (car hashed)))
864 (cdr (puthash str
865 (let ((subs (ivy--split str)))
866 (if (= (length subs) 1)
867 (cons
868 (setq ivy--subexps 0)
869 (car subs))
870 (cons
871 (setq ivy--subexps (length subs))
872 (mapconcat
873 (lambda (x)
874 (if (string-match "\\`\\\\(.*\\\\)\\'" x)
875 x
876 (format "\\(%s\\)" x)))
877 subs
878 (if greedy
879 ".*"
880 ".*?")))))
881 ivy--regex-hash)))))
882
883 (defun ivy--regex-ignore-order (str)
884 "Re-build regex from STR by splitting it on spaces.
885 Ignore the order of each group."
886 (let* ((subs (split-string str " +" t))
887 (len (length subs)))
888 (cl-case len
889 (1
890 (setq ivy--subexps 0)
891 (car subs))
892 (t
893 (setq ivy--subexps len)
894 (let ((all (mapconcat #'identity subs "\\|")))
895 (mapconcat
896 (lambda (x)
897 (if (string-match "\\`\\\\(.*\\\\)\\'" x)
898 x
899 (format "\\(%s\\)" x)))
900 (make-list len all)
901 ".*?"))))))
902
903 (defun ivy--regex-plus (str)
904 "Build a regex sequence from STR.
905 Spaces are wild, everything before \"!\" should match.
906 Everything after \"!\" should not match."
907 (let ((parts (split-string str "!" t)))
908 (cl-case (length parts)
909 (0
910 "")
911 (1
912 (ivy--regex (car parts)))
913 (2
914 (let ((res
915 (mapcar #'list
916 (split-string (cadr parts) " " t))))
917 (cons (cons (ivy--regex (car parts)) t)
918 res)))
919 (t (error "Unexpected: use only one !")))))
920
921 ;;** Rest
922 (defun ivy--minibuffer-setup ()
923 "Setup ivy completion in the minibuffer."
924 (set (make-local-variable 'completion-show-inline-help) nil)
925 (set (make-local-variable 'minibuffer-default-add-function)
926 (lambda ()
927 (list ivy--default)))
928 (setq-local max-mini-window-height ivy-height)
929 (add-hook 'post-command-hook #'ivy--exhibit nil t)
930 ;; show completions with empty input
931 (ivy--exhibit))
932
933 (defun ivy--input ()
934 "Return the current minibuffer input."
935 ;; assume one-line minibuffer input
936 (buffer-substring-no-properties
937 (minibuffer-prompt-end)
938 (line-end-position)))
939
940 (defun ivy--cleanup ()
941 "Delete the displayed completion candidates."
942 (save-excursion
943 (goto-char (minibuffer-prompt-end))
944 (delete-region (line-end-position) (point-max))))
945
946 (defun ivy--insert-prompt ()
947 "Update the prompt according to `ivy--prompt'."
948 (when ivy--prompt
949 (unless (memq this-command '(ivy-done ivy-alt-done ivy-partial-or-done
950 counsel-find-symbol))
951 (setq ivy--prompt-extra ""))
952 (let (head tail)
953 (if (string-match "\\(.*\\): \\'" ivy--prompt)
954 (progn
955 (setq head (match-string 1 ivy--prompt))
956 (setq tail ": "))
957 (setq head (substring ivy--prompt 0 -1))
958 (setq tail " "))
959 (let ((inhibit-read-only t)
960 (std-props '(front-sticky t rear-nonsticky t field t read-only t))
961 (n-str
962 (format
963 (concat head
964 ivy--prompt-extra
965 tail
966 (if ivy--directory
967 (abbreviate-file-name ivy--directory)
968 ""))
969 (or (and (ivy-state-dynamic-collection ivy-last)
970 ivy--full-length)
971 ivy--length))))
972 (save-excursion
973 (goto-char (point-min))
974 (delete-region (point-min) (minibuffer-prompt-end))
975 (set-text-properties 0 (length n-str)
976 `(face minibuffer-prompt ,@std-props)
977 n-str)
978 (ivy--set-match-props n-str "confirm"
979 `(face ivy-confirm-face ,@std-props))
980 (ivy--set-match-props n-str "match required"
981 `(face ivy-match-required-face ,@std-props))
982 (insert n-str))
983 ;; get out of the prompt area
984 (constrain-to-field nil (point-max))))))
985
986 (defun ivy--set-match-props (str match props)
987 "Set STR text proprties that match MATCH to PROPS."
988 (when (string-match match str)
989 (set-text-properties
990 (match-beginning 0)
991 (match-end 0)
992 props
993 str)))
994
995 (defvar inhibit-message)
996
997 (defun ivy--exhibit ()
998 "Insert Ivy completions display.
999 Should be run via minibuffer `post-command-hook'."
1000 (setq ivy-text (ivy--input))
1001 (if (ivy-state-dynamic-collection ivy-last)
1002 ;; while-no-input would cause annoying
1003 ;; "Waiting for process to die...done" message interruptions
1004 (let ((inhibit-message t))
1005 (while-no-input
1006 (unless (equal ivy--old-text ivy-text)
1007 (cl-letf ((store (ivy-state-dynamic-collection ivy-last))
1008 ((ivy-state-dynamic-collection ivy-last) nil))
1009 (setq ivy--all-candidates (funcall store ivy-text))))
1010 (ivy--insert-minibuffer (ivy--format ivy--all-candidates))))
1011 (cond (ivy--directory
1012 (if (string-match "/\\'" ivy-text)
1013 (if (member ivy-text ivy--all-candidates)
1014 (ivy--cd (expand-file-name ivy-text ivy--directory))
1015 (when (string-match "//\\'" ivy-text)
1016 (ivy--cd "/")))
1017 (if (string-match "~\\'" ivy-text)
1018 (ivy--cd (expand-file-name "~/")))))
1019 ((eq (ivy-state-collection ivy-last) 'internal-complete-buffer)
1020 (when (or (and (string-match "\\` " ivy-text)
1021 (not (string-match "\\` " ivy--old-text)))
1022 (and (string-match "\\` " ivy--old-text)
1023 (not (string-match "\\` " ivy-text))))
1024 (setq ivy--all-candidates
1025 (if (and (> (length ivy-text) 0)
1026 (eq (aref ivy-text 0)
1027 ?\ ))
1028 (ivy--buffer-list " ")
1029 (ivy--buffer-list "" ivy-use-virtual-buffers)))
1030 (setq ivy--old-re nil))))
1031 (ivy--insert-minibuffer
1032 (ivy--format
1033 (ivy--filter ivy-text ivy--all-candidates))))
1034 (setq ivy--old-text ivy-text))
1035
1036 (defun ivy--insert-minibuffer (text)
1037 "Insert TEXT into minibuffer with appropriate cleanup."
1038 (let ((resize-mini-windows nil)
1039 (buffer-undo-list t)
1040 (update-fn (ivy-state-update-fn ivy-last))
1041 deactivate-mark)
1042 (ivy--cleanup)
1043 (when update-fn
1044 (funcall update-fn))
1045 (ivy--insert-prompt)
1046 ;; Do nothing if while-no-input was aborted.
1047 (when (stringp text)
1048 (save-excursion
1049 (forward-line 1)
1050 (insert text)))))
1051
1052 (declare-function colir-blend-face-background "ext:colir")
1053
1054 (defun ivy--add-face (str face)
1055 "Propertize STR with FACE.
1056 `font-lock-append-text-property' is used, since it's better than
1057 `propertize' or `add-face-text-property' in this case."
1058 (require 'colir)
1059 (condition-case nil
1060 (colir-blend-face-background 0 (length str) face str)
1061 (error
1062 (ignore-errors
1063 (font-lock-append-text-property 0 (length str) 'face face str))))
1064 str)
1065
1066 (defun ivy--filter (name candidates)
1067 "Return all items that match NAME in CANDIDATES.
1068 CANDIDATES are assumed to be static."
1069 (let* ((re (funcall ivy--regex-function name))
1070 (matcher (ivy-state-matcher ivy-last))
1071 (cands (cond
1072 (matcher
1073 (let ((ivy--old-re re))
1074 (cl-remove-if-not matcher candidates)))
1075 ((and (equal re ivy--old-re)
1076 ivy--old-cands)
1077 ivy--old-cands)
1078 ((and ivy--old-re
1079 (stringp re)
1080 (stringp ivy--old-re)
1081 (not (string-match "\\\\" ivy--old-re))
1082 (not (equal ivy--old-re ""))
1083 (memq (cl-search
1084 (if (string-match "\\\\)\\'" ivy--old-re)
1085 (substring ivy--old-re 0 -2)
1086 ivy--old-re)
1087 re)
1088 '(0 2)))
1089 (ignore-errors
1090 (cl-remove-if-not
1091 (lambda (x) (string-match re x))
1092 ivy--old-cands)))
1093 (t
1094 (let ((re-list (if (stringp re) (list (cons re t)) re))
1095 (res candidates))
1096 (dolist (re re-list)
1097 (setq res
1098 (ignore-errors
1099 (funcall
1100 (if (cdr re)
1101 #'cl-remove-if-not
1102 #'cl-remove-if)
1103 (let ((re (car re)))
1104 (lambda (x) (string-match re x)))
1105 res))))
1106 res))))
1107 (tail (nthcdr ivy--index ivy--old-cands))
1108 idx)
1109 (when (and tail ivy--old-cands)
1110 (unless (and (not (equal re ivy--old-re))
1111 (or (setq ivy--index
1112 (or
1113 (cl-position re cands
1114 :test #'equal)
1115 (and ivy--directory
1116 (cl-position
1117 (concat re "/") cands
1118 :test #'equal))))))
1119 (while (and tail (null idx))
1120 ;; Compare with eq to handle equal duplicates in cands
1121 (setq idx (cl-position (pop tail) cands)))
1122 (setq ivy--index (or idx 0))))
1123 (when (and (string= name "") (not (equal ivy--old-re "")))
1124 (setq ivy--index
1125 (or (cl-position (ivy-state-preselect ivy-last)
1126 cands :test #'equal)
1127 ivy--index)))
1128 (setq ivy--old-re (if cands re ""))
1129 (setq ivy--old-cands cands)))
1130
1131 (defvar ivy-format-function 'ivy-format-function-default
1132 "Function to transform the list of candidates into a string.
1133 This string will be inserted into the minibuffer.")
1134
1135 (defun ivy-format-function-default (cands)
1136 "Transform CANDS into a string for minibuffer."
1137 (let ((ww (window-width)))
1138 (mapconcat
1139 (lambda (s)
1140 (if (> (length s) ww)
1141 (concat (substring s 0 (- ww 3)) "...")
1142 s))
1143 cands "\n")))
1144
1145 (defun ivy-format-function-arrow (cands)
1146 "Transform CANDS into a string for minibuffer."
1147 (let ((i -1))
1148 (mapconcat
1149 (lambda (s)
1150 (concat (if (eq (cl-incf i) ivy--index)
1151 "==> "
1152 " ")
1153 s))
1154 cands "\n")))
1155
1156 (defun ivy--format (cands)
1157 "Return a string for CANDS suitable for display in the minibuffer.
1158 CANDS is a list of strings."
1159 (setq ivy--length (length cands))
1160 (when (>= ivy--index ivy--length)
1161 (setq ivy--index (max (1- ivy--length) 0)))
1162 (if (null cands)
1163 (setq ivy--current "")
1164 (let* ((half-height (/ ivy-height 2))
1165 (start (max 0 (- ivy--index half-height)))
1166 (end (min (+ start (1- ivy-height)) ivy--length))
1167 (cands (cl-subseq cands start end))
1168 (index (min ivy--index half-height (1- (length cands)))))
1169 (when ivy--directory
1170 (setq cands (mapcar (lambda (x)
1171 (if (string-match-p "/\\'" x)
1172 (propertize x 'face 'ivy-subdir)
1173 x))
1174 cands)))
1175 (setq ivy--current (copy-sequence (nth index cands)))
1176 (setf (nth index cands)
1177 (ivy--add-face ivy--current 'ivy-current-match))
1178 (let* ((ivy--index index)
1179 (res (concat "\n" (funcall ivy-format-function cands))))
1180 (put-text-property 0 (length res) 'read-only nil res)
1181 res))))
1182
1183 (defvar ivy--virtual-buffers nil
1184 "Store the virtual buffers alist.")
1185
1186 (defvar recentf-list)
1187 (defvar ido-use-faces)
1188
1189 (defun ivy--virtual-buffers ()
1190 "Adapted from `ido-add-virtual-buffers-to-list'."
1191 (unless recentf-mode
1192 (recentf-mode 1))
1193 (let ((bookmarks (and (boundp 'bookmark-alist)
1194 bookmark-alist))
1195 virtual-buffers name)
1196 (dolist (head (append
1197 recentf-list
1198 (delete " - no file -"
1199 (delq nil (mapcar (lambda (bookmark)
1200 (cdr (assoc 'filename bookmark)))
1201 bookmarks)))))
1202 (setq name (file-name-nondirectory head))
1203 (when (equal name "")
1204 (setq name (file-name-nondirectory (directory-file-name head))))
1205 (when (equal name "")
1206 (setq name head))
1207 (and (not (equal name ""))
1208 (null (get-file-buffer head))
1209 (not (assoc name virtual-buffers))
1210 (push (cons name head) virtual-buffers)))
1211 (when virtual-buffers
1212 (if ido-use-faces
1213 (dolist (comp virtual-buffers)
1214 (put-text-property 0 (length (car comp))
1215 'face 'ido-virtual
1216 (car comp))))
1217 (setq ivy--virtual-buffers (nreverse virtual-buffers))
1218 (mapcar #'car ivy--virtual-buffers))))
1219
1220 (defun ivy--buffer-list (str &optional virtual)
1221 "Return the buffers that match STR.
1222 When VIRTUAL is non-nil, add virtual buffers."
1223 (delete-dups
1224 (append
1225 (mapcar
1226 (lambda (x)
1227 (if (with-current-buffer x
1228 (file-remote-p
1229 (abbreviate-file-name default-directory)))
1230 (propertize x 'face 'ivy-remote)
1231 x))
1232 (all-completions str 'internal-complete-buffer))
1233 (and virtual
1234 (ivy--virtual-buffers)))))
1235
1236 (defun ivy--switch-buffer-action (buffer)
1237 "Switch to BUFFER.
1238 BUFFER may be a string or nil."
1239 (if (zerop (length buffer))
1240 (switch-to-buffer
1241 ivy-text nil 'force-same-window)
1242 (let ((virtual (assoc buffer ivy--virtual-buffers)))
1243 (if virtual
1244 (find-file (cdr virtual))
1245 (switch-to-buffer
1246 buffer nil 'force-same-window)))))
1247
1248 (defun ivy-switch-buffer ()
1249 "Switch to another buffer."
1250 (interactive)
1251 (if (not ivy-mode)
1252 (call-interactively 'switch-to-buffer)
1253 (ivy-read "Switch to buffer: " 'internal-complete-buffer
1254 :preselect (buffer-name (other-buffer (current-buffer)))
1255 :action #'ivy--switch-buffer-action)))
1256
1257 (provide 'ivy)
1258
1259 ;;; ivy.el ends here