]> code.delx.au - gnu-emacs-elpa/blobdiff - ivy.el
ivy.el: Structure all faces into ivy-faces custom group
[gnu-emacs-elpa] / ivy.el
diff --git a/ivy.el b/ivy.el
index b75cdbea5b35ec6bf1f5465756c38e0d0726142c..f2cd67f96ab3f24edd11850668fefedd3e7f8746 100644 (file)
--- a/ivy.el
+++ b/ivy.el
   "Incremental vertical completion."
   :group 'convenience)
 
+(defgroup ivy-faces nil
+  "Font-lock faces for `ivy'."
+  :group 'ivy)
+
 (defface ivy-current-match
   '((((class color) (background light))
      :background "#1a4b77" :foreground "white")
     (((class color) (background dark))
      :background "#65a7e2" :foreground "black"))
-  "Face used by Ivy for highlighting first match.")
+  "Face used by Ivy for highlighting the current match.")
+
+(defface ivy-minibuffer-match-face-1
+  '((((class color) (background light))
+     :background "#d3d3d3")
+    (((class color) (background dark))
+     :background "#555555"))
+  "The background face for `ivy' minibuffer matches.")
+
+(defface ivy-minibuffer-match-face-2
+  '((((class color) (background light))
+     :background "#e99ce8" :weight bold)
+    (((class color) (background dark))
+     :background "#777777" :weight bold))
+  "Face for `ivy' minibuffer matches modulo 1.")
+
+(defface ivy-minibuffer-match-face-3
+  '((((class color) (background light))
+     :background "#bbbbff" :weight bold)
+    (((class color) (background dark))
+     :background "#7777ff" :weight bold))
+  "Face for `ivy' minibuffer matches modulo 2.")
+
+(defface ivy-minibuffer-match-face-4
+  '((((class color) (background light))
+     :background "#ffbbff" :weight bold)
+    (((class color) (background dark))
+     :background "#8a498a" :weight bold))
+  "Face for `ivy' minibuffer matches modulo 3.")
 
 (defface ivy-confirm-face
   '((t :foreground "ForestGreen" :inherit minibuffer-prompt))
-  "Face used by Ivy to issue a confirmation prompt.")
+  "Face used by Ivy for a confirmation prompt.")
 
 (defface ivy-match-required-face
   '((t :foreground "red" :inherit minibuffer-prompt))
-  "Face used by Ivy to issue a match required prompt.")
+  "Face used by Ivy for a match required prompt.")
+
+(setcdr (assoc load-file-name custom-current-group-alist) 'ivy)
 
 (defface ivy-subdir
   '((t (:inherit 'dired-directory)))
   '((t (:foreground "#110099")))
   "Face used by Ivy for highlighting remotes in the alternatives.")
 
+(defface ivy-virtual
+  '((t :inherit font-lock-builtin-face))
+  "Face used by Ivy for matching virtual buffer names.")
+
 (defcustom ivy-height 10
   "Number of lines for the minibuffer window."
   :type 'integer)
 
 (defcustom ivy-count-format "%-4d "
-  "The style of showing the current candidate count for `ivy-read'.
-Set this to \"\" if you don't want the count.  You can also set
-it to e.g. \"(%d/%d) \" if you want to see both the candidate
-index and the candidate count."
+  "The style to use for displaying the current candidate count for `ivy-read'.
+Set this to \"\" to suppress the count visibility.
+Set this to \"(%d/%d) \" to display both the index and the count."
   :type '(choice
           (const :tag "Count disabled" "")
           (const :tag "Count matches" "%-4d ")
@@ -87,27 +124,27 @@ index and the candidate count."
           string))
 
 (defcustom ivy-wrap nil
-  "Whether to wrap around after the first and last candidate."
+  "When non-nil, wrap around after the first and the last candidate."
   :type 'boolean)
 
 (defcustom ivy-display-style (unless (version< emacs-version "24.5") 'fancy)
   "The style for formatting the minibuffer.
 
-By default, the matched strings will be copied as they are.
+By default, the matched strings are copied as is.
 
-With the fancy method, the matching parts of the regexp will be
-additionally highlighted, just like `swiper' does it.
+The fancy display style highlights matching parts of the regexp,
+a behavior similar to `swiper'.
 
 This setting depends on `add-face-text-property' - a C function
-available as of 24.5. It will behave poorly in earlier Emacs
-versions."
+available as of Emacs 24.5. Fancy style will render poorly in
+earlier versions of Emacs."
   :type '(choice
           (const :tag "Plain" nil)
           (const :tag "Fancy" fancy)))
 
 (defcustom ivy-on-del-error-function 'minibuffer-keyboard-quit
   "The handler for when `ivy-backward-delete-char' throws.
-This is usually meant as a quick exit out of the minibuffer."
+Usually a quick exit out of the minibuffer."
   :type 'function)
 
 (defcustom ivy-extra-directories '("../" "./")
@@ -214,7 +251,7 @@ This should eventually become a stack so that you could use
   "History list of candidates entered in the minibuffer.
 
 Maximum length of the history list is determined by the value
-of `history-length', which see.")
+of `history-length'.")
 
 (defvar ivy--directory nil
   "Current directory when completing file names.")
@@ -243,7 +280,7 @@ Otherwise, store nil.")
 
 (defvar ivy--prompt nil
   "Store the format-style prompt.
-When non-nil, it should contain one %d.")
+When non-nil, it should contain at least one %d.")
 
 (defvar ivy--prompt-extra ""
   "Temporary modifications to the prompt.")
@@ -285,7 +322,7 @@ When non-nil, it should contain one %d.")
   "Quit the minibuffer and call ACTION afterwards."
   (ivy-set-action
    `(lambda (x)
-      (funcall ,action x)
+      (funcall ',action x)
       (ivy-set-action ',(ivy-state-action ivy-last))))
   (setq ivy-exit 'done)
   (exit-minibuffer))
@@ -390,72 +427,88 @@ Is is a cons cell, related to `tramp-get-completion-function'."
   "Exit the minibuffer with the selected candidate.
 When ARG is t, exit with current text, ignoring the candidates."
   (interactive "P")
+  (cond (arg
+         (ivy-immediate-done))
+        (ivy--directory
+         (ivy--directory-done))
+        ((eq (ivy-state-collection ivy-last) 'Info-read-node-name-1)
+         (if (or (equal ivy--current "(./)")
+                 (equal ivy--current "(../)"))
+             (ivy-quit-and-run
+              (ivy-read "Go to file: " 'read-file-name-internal
+                        :action (lambda (x)
+                                  (Info-find-node
+                                   (expand-file-name x ivy--directory)
+                                   "Top"))))
+           (ivy-done)))
+        (t
+         (ivy-done))))
+
+(defun ivy--directory-done ()
+  "Handle exit from the minibuffer when completing file names."
   (let (dir)
-    (cond (arg
-           (ivy-immediate-done))
-          ((and ivy--directory
-                (equal ivy-text "/sudo::"))
-           (setq dir (concat ivy-text ivy--directory))
-           (ivy--cd dir)
-           (ivy--exhibit))
-          ((and ivy--directory
-                (or
-                 (and
-                  (not (equal ivy-text ""))
-                  (ignore-errors
-                    (file-directory-p
-                     (setq dir
-                           (file-name-as-directory
-                            (expand-file-name
-                             ivy-text ivy--directory))))))
-                 (and
-                  (not (string= ivy--current "./"))
-                  (cl-plusp ivy--length)
-                  (file-directory-p
-                   (setq dir (expand-file-name
-                              ivy--current ivy--directory))))))
-           (ivy--cd dir)
-           (ivy--exhibit))
-          ((eq (ivy-state-collection ivy-last) 'Info-read-node-name-1)
-           (if (or (equal ivy--current "(./)")
-                   (equal ivy--current "(../)"))
-               (ivy-quit-and-run
-                (ivy-read "Go to file: " 'read-file-name-internal
-                          :action (lambda (x)
-                                    (Info-find-node
-                                     (expand-file-name x ivy--directory)
-                                     "Top"))))
-             (ivy-done)))
-          ((and ivy--directory
-                (string-match "\\`/[^/]+:.*:.*\\'" ivy-text))
-           (ivy-done))
-          ((and ivy--directory
-                (string-match
-                 "\\`/\\([^/]+?\\):\\(?:\\(.*\\)@\\)?\\(.*\\)\\'"
-                 ivy-text))
-           (let ((method (match-string 1 ivy-text))
-                 (user (match-string 2 ivy-text))
-                 (rest (match-string 3 ivy-text))
-                 res)
-             (require 'tramp)
-             (dolist (x (tramp-get-completion-function method))
-               (setq res (append res (funcall (car x) (cadr x)))))
-             (setq res (delq nil res))
-             (when user
-               (dolist (x res)
-                 (setcar x user)))
-             (setq res (cl-delete-duplicates res :test #'equal))
-             (let* ((old-ivy-last ivy-last)
-                    (enable-recursive-minibuffers t)
-                    (host (ivy-read "Find File: "
-                                    (mapcar #'ivy-build-tramp-name res)
-                                    :initial-input rest)))
-               (setq ivy-last old-ivy-last)
-               (when host
-                 (setq ivy--directory "/")
-                 (ivy--cd (concat "/" method ":" host ":"))))))
-          (t
-           (ivy-done)))))
+    (cond
+      ((equal ivy-text "/sudo::")
+       (setq dir (concat ivy-text ivy--directory))
+       (ivy--cd dir)
+       (ivy--exhibit))
+      ((or
+        (and
+         (not (equal ivy-text ""))
+         (ignore-errors
+           (file-directory-p
+            (setq dir
+                  (file-name-as-directory
+                   (expand-file-name
+                    ivy-text ivy--directory))))))
+        (and
+         (not (string= ivy--current "./"))
+         (cl-plusp ivy--length)
+         (ignore-errors
+           (file-directory-p
+            (setq dir (file-name-as-directory
+                       (expand-file-name
+                        ivy--current ivy--directory)))))))
+       (ivy--cd dir)
+       (ivy--exhibit))
+      ((or (and (equal ivy--directory "/")
+                (string-match "\\`[^/]+:.*:.*\\'" ivy-text))
+           (string-match "\\`/[^/]+:.*:.*\\'" ivy-text))
+       (ivy-done))
+      ((or (and (equal ivy--directory "/")
+                (cond ((string-match
+                        "\\`\\([^/]+?\\):\\(?:\\(.*\\)@\\)?\\(.*\\)\\'"
+                        ivy-text))
+                      ((string-match
+                        "\\`\\([^/]+?\\):\\(?:\\(.*\\)@\\)?\\(.*\\)\\'"
+                        ivy--current)
+                       (setq ivy-text ivy--current))))
+           (string-match
+            "\\`/\\([^/]+?\\):\\(?:\\(.*\\)@\\)?\\(.*\\)\\'"
+            ivy-text))
+       (let ((method (match-string 1 ivy-text))
+             (user (match-string 2 ivy-text))
+             (rest (match-string 3 ivy-text))
+             res)
+         (require 'tramp)
+         (dolist (x (tramp-get-completion-function method))
+           (setq res (append res (funcall (car x) (cadr x)))))
+         (setq res (delq nil res))
+         (when user
+           (dolist (x res)
+             (setcar x user)))
+         (setq res (cl-delete-duplicates res :test #'equal))
+         (let* ((old-ivy-last ivy-last)
+                (enable-recursive-minibuffers t)
+                (host (ivy-read "Find File: "
+                                (mapcar #'ivy-build-tramp-name res)
+                                :initial-input rest)))
+           (setq ivy-last old-ivy-last)
+           (when host
+             (setq ivy--directory "/")
+             (ivy--cd (concat "/" method ":" host ":"))))))
+      (t
+       (ivy-done)))))
 
 (defcustom ivy-tab-space nil
   "When non-nil, `ivy-partial-or-done' should insert a space."
@@ -466,13 +519,16 @@ When ARG is t, exit with current text, ignoring the candidates."
 If the text hasn't changed as a result, forward to `ivy-alt-done'."
   (interactive)
   (if (and (eq (ivy-state-collection ivy-last) #'read-file-name-internal)
-           (string-match "\\`/" ivy-text))
+           (or (and (equal ivy--directory "/")
+                    (string-match "\\`[^/]+:.*\\'" ivy-text))
+               (string-match "\\`/" ivy-text)))
       (let ((default-directory ivy--directory))
         (minibuffer-complete)
         (setq ivy-text (ivy--input))
-        (when (and (file-directory-p ivy-text)
-                   (= ivy--length 1))
-          (ivy--cd (expand-file-name ivy-text))))
+        (when (file-directory-p
+               (expand-file-name ivy-text ivy--directory))
+          (ivy--cd (file-name-as-directory
+                    (expand-file-name ivy-text ivy--directory)))))
     (or (ivy-partial)
         (when (or (eq this-command last-command)
                   (eq ivy--length 1))
@@ -520,6 +576,8 @@ If the text hasn't changed as a result, forward to `ivy-alt-done'."
 (defun ivy-resume ()
   "Resume the last completion session."
   (interactive)
+  (when (eq (ivy-state-caller ivy-last) 'swiper)
+    (switch-to-buffer (ivy-state-buffer ivy-last)))
   (with-current-buffer (ivy-state-buffer ivy-last)
     (ivy-read
      (ivy-state-prompt ivy-last)
@@ -736,12 +794,9 @@ If so, move to that directory, while keeping only the file name."
     (let ((input (ivy--input))
           url)
       (if (setq url (ffap-url-p input))
-          (progn
-            (ivy-set-action
-             (lambda (_)
-               (funcall ffap-url-fetcher url)))
-            (setq ivy-exit 'done)
-            (exit-minibuffer))
+          (ivy-exit-with-action
+           (lambda (_)
+             (funcall ffap-url-fetcher url)))
         (setq input (expand-file-name input))
         (let ((file (file-name-nondirectory input))
               (dir (expand-file-name (file-name-directory input))))
@@ -907,11 +962,13 @@ Prioritize directories."
   "An alist of sorting functions for each collection function.
 Interactive functions that call completion fit in here as well.
 
-For each entry, nil means no sorting.  It's very useful to turn
-off the sorting for functions that have candidates in the natural
-buffer order, like `org-refile' or `Man-goto-section'.
+Nil means no sorting, which is useful to turn off the sorting for
+functions that have candidates in the natural buffer order, like
+`org-refile' or `Man-goto-section'.
 
-The entry associated to t is used for all fall-through cases."
+The entry associated with t is used for all fall-through cases.
+
+See also `ivy-sort-max-size'."
   :type
   '(alist
     :key-type (choice
@@ -927,11 +984,12 @@ The entry associated to t is used for all fall-through cases."
   '((swiper . ivy-recompute-index-swiper)
     (swiper-multi . ivy-recompute-index-swiper)
     (counsel-git-grep . ivy-recompute-index-swiper)
+    (counsel-grep . ivy-recompute-index-swiper-async)
     (t . ivy-recompute-index-zero))
   "An alist of index recomputing functions for each collection function.
-When the input changes, calling the appropriate function will
-return an integer - the index of the matched candidate that
-should be selected.")
+When the input changes, the appropriate function returns an
+integer - the index of the matched candidate that should be
+selected.")
 
 (defvar ivy-re-builders-alist
   '((t . ivy--regex-plus))
@@ -939,10 +997,10 @@ should be selected.")
 Each function should take a string and return a valid regex or a
 regex sequence (see below).
 
-The entry associated to t is used for all fall-through cases.
+The entry associated with t is used for all fall-through cases.
 Possible choices: `ivy--regex', `regexp-quote', `ivy--regex-plus'.
 
-In case a function returns a list, it should look like this:
+If a function returns a list, it should format like this:
 '((\"matching-regexp\" . t) (\"non-matching-regexp\") ...).
 
 The matches will be filtered in a sequence, you can mix the
@@ -987,47 +1045,47 @@ Directories come first."
 
 ;;** Entry Point
 (cl-defun ivy-read (prompt collection
-                    &key predicate require-match initial-input
-                      history preselect keymap update-fn sort
-                      action unwind re-builder matcher dynamic-collection caller)
+                           &key predicate require-match initial-input
+                           history preselect keymap update-fn sort
+                           action unwind re-builder matcher dynamic-collection caller)
   "Read a string in the minibuffer, with completion.
 
-PROMPT is a string to prompt with; normally it ends in a colon
-and a space.  When PROMPT contains %d, it will be updated with
-the current number of matching candidates.  If % appears elsewhere
-in the PROMPT it should be quoted as %%.
-See also `ivy-count-format'.
+PROMPT is a format string, normally ending in a colon and a
+space; %d anywhere in the string is replaced by the current
+number of matching candidates. For the literal % character,
+escape it with %%. See also `ivy-count-format'.
 
-COLLECTION is a list of strings, or a function, or an alist, or a
-hash table.
+COLLECTION is either a list of strings, a function, an alist, or
+hash table.
 
-If INITIAL-INPUT is non-nil, insert it in the minibuffer initially.
+If INITIAL-INPUT is not nil, then insert that input in the
+minibuffer initially.
 
-KEYMAP is composed together with `ivy-minibuffer-map'.
+KEYMAP is composed with `ivy-minibuffer-map'.
 
-If PRESELECT is non-nil select the corresponding candidate out of
-the ones that match INITIAL-INPUT.
+If PRESELECT is not nil, then select the corresponding candidate
+out of the ones that match the INITIAL-INPUT.
 
 UPDATE-FN is called each time the current candidate(s) is changed.
 
-When SORT is t, refer to `ivy-sort-functions-alist' for sorting.
+When SORT is t, use `ivy-sort-functions-alist' for sorting.
 
-ACTION is a lambda to call after a result was selected. It should
-take a single argument, usually a string.
+ACTION is a lambda function to call after selecting a result. It
+takes a single string argument.
 
-UNWIND is a lambda to call before exiting.
+UNWIND is a lambda function to call before exiting.
 
-RE-BUILDER is a lambda that transforms text into a regex.
+RE-BUILDER is a lambda function to call to transform text into a
+regex pattern.
 
-MATCHER can completely override matching.
+MATCHER is to override matching.
 
-DYNAMIC-COLLECTION is a boolean that determines whether to update
-the list of candidates with each input by calling COLLECTION for
-the current input.
+DYNAMIC-COLLECTION is a boolean to specify if the list of
+candidates is updated after each input by calling COLLECTION.
 
 CALLER is a symbol to uniquely identify the caller to `ivy-read'.
-It's used in conjunction with COLLECTION to indentify which
-customizations should apply to the current completion session."
+It is used, along with COLLECTION, to determine which
+customizations apply to the current completion session."
   (let ((extra-actions (plist-get ivy--actions-list this-command)))
     (when extra-actions
       (setq action
@@ -1036,7 +1094,7 @@ customizations should apply to the current completion session."
                   ("o" ,action "default")
                   ,@extra-actions)
               (delete-dups (append action extra-actions))))))
-  (let ((recursive-ivy-last (and (window-minibuffer-p) ivy-last)))
+  (let ((recursive-ivy-last (and (active-minibuffer-window) ivy-last)))
     (setq ivy-last
           (make-ivy-state
            :prompt prompt
@@ -1060,30 +1118,30 @@ customizations should apply to the current completion session."
     (ivy--reset-state ivy-last)
     (prog1
         (unwind-protect
-             (minibuffer-with-setup-hook
-                 #'ivy--minibuffer-setup
-               (let* ((hist (or history 'ivy-history))
-                      (minibuffer-completion-table collection)
-                      (minibuffer-completion-predicate predicate)
-                      (resize-mini-windows (cond
-                                             ((display-graphic-p) nil)
-                                             ((null resize-mini-windows) 'grow-only)
-                                             (t resize-mini-windows)))
-                      (res (read-from-minibuffer
-                            prompt
-                            (ivy-state-initial-input ivy-last)
-                            (make-composed-keymap keymap ivy-minibuffer-map)
-                            nil
-                            hist)))
-                 (when (eq ivy-exit 'done)
-                   (let ((item (if ivy--directory
-                                   ivy--current
-                                 ivy-text)))
-                     (unless (equal item "")
-                       (set hist (cons (propertize item 'ivy-index ivy--index)
-                                       (delete item
-                                               (cdr (symbol-value hist)))))))
-                   res)))
+            (minibuffer-with-setup-hook
+                #'ivy--minibuffer-setup
+              (let* ((hist (or history 'ivy-history))
+                     (minibuffer-completion-table collection)
+                     (minibuffer-completion-predicate predicate)
+                     (resize-mini-windows (cond
+                                           ((display-graphic-p) nil)
+                                           ((null resize-mini-windows) 'grow-only)
+                                           (t resize-mini-windows)))
+                     (res (read-from-minibuffer
+                           prompt
+                           (ivy-state-initial-input ivy-last)
+                           (make-composed-keymap keymap ivy-minibuffer-map)
+                           nil
+                           hist)))
+                (when (eq ivy-exit 'done)
+                  (let ((item (if ivy--directory
+                                  ivy--current
+                                ivy-text)))
+                    (unless (equal item "")
+                      (set hist (cons (propertize item 'ivy-index ivy--index)
+                                      (delete item
+                                              (cdr (symbol-value hist)))))))
+                  res)))
           (remove-hook 'post-command-hook #'ivy--exhibit)
           (when (setq unwind (ivy-state-unwind ivy-last))
             (funcall unwind)))
@@ -1094,7 +1152,7 @@ customizations should apply to the current completion session."
 (defun ivy--reset-state (state)
   "Reset the ivy to STATE.
 This is useful for recursive `ivy-read'."
-  (let ((prompt (ivy-state-prompt state))
+  (let ((prompt (or (ivy-state-prompt state) ""))
         (collection (ivy-state-collection state))
         (predicate (ivy-state-predicate state))
         (history (ivy-state-history state))
@@ -1103,8 +1161,7 @@ This is useful for recursive `ivy-read'."
         (re-builder (ivy-state-re-builder state))
         (dynamic-collection (ivy-state-dynamic-collection state))
         (initial-input (ivy-state-initial-input state))
-        (require-match (ivy-state-require-match state))
-        (matcher (ivy-state-matcher state)))
+        (require-match (ivy-state-require-match state)))
     (unless initial-input
       (setq initial-input (cdr (assoc this-command
                                       ivy-initial-inputs-alist))))
@@ -1173,20 +1230,32 @@ This is useful for recursive `ivy-read'."
       (when preselect
         (unless (or (and require-match
                          (not (eq collection 'internal-complete-buffer)))
+                    dynamic-collection
                     (let ((re (regexp-quote preselect)))
                       (cl-find-if (lambda (x) (string-match re x))
                                   coll)))
           (setq coll (cons preselect coll))))
-      (setq ivy--index (or
-                        (and dynamic-collection
-                             ivy--index)
-                        (and preselect
-                             (ivy--preselect-index
-                              coll initial-input preselect matcher))
-                        0))
       (setq ivy--old-re nil)
       (setq ivy--old-cands nil)
-      (setq ivy--all-candidates coll))
+      (when (integerp preselect)
+        (setq ivy--old-re "")
+        (setq ivy--index preselect))
+      (when initial-input
+        ;; Needed for anchor to work
+        (setq ivy--old-cands coll)
+        (setq ivy--old-cands (ivy--filter initial-input coll)))
+      (setq ivy--all-candidates coll)
+      (unless (integerp preselect)
+        (setq ivy--index (or
+                          (and dynamic-collection
+                               ivy--index)
+                          (and preselect
+                               (ivy--preselect-index
+                                preselect
+                                (if initial-input
+                                    ivy--old-cands
+                                  coll)))
+                          0))))
     (setq ivy-exit nil)
     (setq ivy--default (or
                         (thing-at-point 'url)
@@ -1223,19 +1292,24 @@ This is useful for recursive `ivy-read'."
                               history def _inherit-input-method)
   "Read a string in the minibuffer, with completion.
 
-This is an interface that conforms to `completing-read', so that
-it can be used for `completing-read-function'.
+This interface conforms to `completing-read' and can be used for
+`completing-read-function'.
 
 PROMPT is a string to prompt with; normally it ends in a colon and a space.
 COLLECTION can be a list of strings, an alist, an obarray or a hash table.
 PREDICATE limits completion to a subset of COLLECTION.
-REQUIRE-MATCH is considered boolean.  See `completing-read'.
+REQUIRE-MATCH is specified with a boolean value.  See `completing-read'.
 INITIAL-INPUT is a string that can be inserted into the minibuffer initially.
-_HISTORY is ignored for now.
+HISTORY is a list of previously selected inputs.
 DEF is the default value.
-_INHERIT-INPUT-METHOD is ignored for now.
-
-The history, defaults and input-method arguments are ignored for now."
+_INHERIT-INPUT-METHOD is currently ignored."
+
+  ;; See the doc of `completing-read'.
+  (when (consp history)
+    (when (numberp (cdr history))
+      (setq initial-input (nth (1- (cdr history))
+                               (symbol-value (car history)))))
+    (setq history (car history)))
   (ivy-read (replace-regexp-in-string "%" "%%" prompt)
             collection
             :predicate predicate
@@ -1259,8 +1333,8 @@ The history, defaults and input-method arguments are ignored for now."
 ;;;###autoload
 (define-minor-mode ivy-mode
   "Toggle Ivy mode on or off.
-With ARG, turn Ivy mode on if arg is positive, off otherwise.
-Turning on Ivy mode will set `completing-read-function' to
+Turn Ivy mode on if ARG is positive, off otherwise.
+Turning on Ivy mode sets `completing-read-function' to
 `ivy-completing-read'.
 
 Global bindings:
@@ -1276,28 +1350,17 @@ Minibuffer bindings:
       (setq completing-read-function 'ivy-completing-read)
     (setq completing-read-function 'completing-read-default)))
 
-(defun ivy--preselect-index (candidates initial-input preselect matcher)
-  "Return the index in CANDIDATES filtered by INITIAL-INPUT for PRESELECT.
-When MATCHER is non-nil it's used instead of `cl-remove-if-not'."
-  (if initial-input
-      (progn
-        (setq initial-input (ivy--regex-plus initial-input))
-        (setq candidates
-              (if matcher
-                  (funcall matcher initial-input candidates)
-                (cl-remove-if-not
-                 (lambda (x)
-                   (string-match initial-input x))
-                 candidates))))
-    (when matcher
-      (setq candidates (funcall matcher "" candidates))))
-  (or (cl-position preselect candidates :test #'equal)
-      (and (stringp preselect)
-           (let ((re (regexp-quote preselect)))
-             (cl-position-if
-              (lambda (x)
-                (string-match re x))
-              candidates)))))
+(defun ivy--preselect-index (preselect candidates)
+  "Return the index of PRESELECT in CANDIDATES."
+  (cond ((integerp preselect)
+         preselect)
+        ((cl-position preselect candidates :test #'equal))
+        ((stringp preselect)
+         (let ((re (regexp-quote preselect)))
+           (cl-position-if
+            (lambda (x)
+              (string-match re x))
+            candidates)))))
 
 ;;* Implementation
 ;;** Regex
@@ -1337,7 +1400,7 @@ This allows to \"quote\" N spaces by inputting N+1 spaces."
     (nreverse res)))
 
 (defun ivy--regex (str &optional greedy)
-  "Re-build regex from STR in case it has a space.
+  "Re-build regex pattern from STR in case it has a space.
 When GREEDY is non-nil, join words in a greedy way."
   (let ((hashed (unless greedy
                   (gethash str ivy--regex-hash))))
@@ -1366,8 +1429,15 @@ When GREEDY is non-nil, join words in a greedy way."
                     ivy--regex-hash)))))
 
 (defun ivy--regex-ignore-order (str)
-  "Re-build regex from STR by splitting it on spaces.
-Ignore the order of each group."
+  "Re-build regex from STR by splitting at spaces.
+Ignore the order of each group.
+
+ATTENTION: This is just a proof of concept and may not work as
+expected. Besides ignoring the order of the tokens where 'foo'
+and 'bar', 'bar' and 'foo' are matched, it also matches multiple
+occurrences of 'foo' and 'bar'. To ignore the sort order and avoid
+multiple matches, use `ivy-restrict-to-matches' instead.
+"
   (let* ((subs (split-string str " +" t))
          (len (length subs)))
     (cl-case len
@@ -1387,8 +1457,8 @@ Ignore the order of each group."
 
 (defun ivy--regex-plus (str)
   "Build a regex sequence from STR.
-Spaces are wild, everything before \"!\" should match.
-Everything after \"!\" should not match."
+Spaces are wild card characters, everything before \"!\" should
+match. Everything after \"!\" should not match."
   (let ((parts (split-string str "!" t)))
     (cl-case (length parts)
       (0
@@ -1448,7 +1518,7 @@ Insert .* between each char."
   "Update the prompt according to `ivy--prompt'."
   (when ivy--prompt
     (unless (memq this-command '(ivy-done ivy-alt-done ivy-partial-or-done
-                                 counsel-find-symbol))
+                                          counsel-find-symbol))
       (setq ivy--prompt-extra ""))
     (let (head tail)
       (if (string-match "\\(.*\\): \\'" ivy--prompt)
@@ -1504,7 +1574,7 @@ Insert .* between each char."
         (constrain-to-field nil (point-max))))))
 
 (defun ivy--set-match-props (str match props)
-  "Set STR text proprties that match MATCH to PROPS."
+  "Set STR text properties that match MATCH to PROPS."
   (when (string-match match str)
     (set-text-properties
      (match-beginning 0)
@@ -1579,8 +1649,9 @@ Should be run via minibuffer `post-command-hook'."
                        (ivy--buffer-list "" ivy-use-virtual-buffers)))
                (setq ivy--old-re nil))))
       (ivy--insert-minibuffer
-       (ivy--format
-        (ivy--filter ivy-text ivy--all-candidates)))
+       (with-current-buffer (ivy-state-buffer ivy-last)
+         (ivy--format
+          (ivy--filter ivy-text ivy--all-candidates))))
       (setq ivy--old-text ivy-text))))
 
 (defun ivy--insert-minibuffer (text)
@@ -1602,18 +1673,17 @@ Should be run via minibuffer `post-command-hook'."
       (ivy--resize-minibuffer-to-fit))))
 
 (defun ivy--resize-minibuffer-to-fit ()
-  "Resize the minibuffer window so it has enough space to display
-all of the text contained in the minibuffer."
+  "Resize the minibuffer window size to fit the text in the minibuffer."
   (with-selected-window (minibuffer-window)
     (if (fboundp 'window-text-pixel-size)
         (let ((text-height (cdr (window-text-pixel-size)))
               (body-height (window-body-height nil t)))
           (when (> text-height body-height)
             (window-resize nil (- text-height body-height) nil t t)))
-        (let ((text-height (count-screen-lines))
-              (body-height (window-body-height)))
-          (when (> text-height body-height)
-            (window-resize nil (- text-height body-height) nil t))))))
+      (let ((text-height (count-screen-lines))
+            (body-height (window-body-height)))
+        (when (> text-height body-height)
+          (window-resize nil (- text-height body-height) nil t))))))
 
 (declare-function colir-blend-face-background "ext:colir")
 
@@ -1650,7 +1720,7 @@ all of the text contained in the minibuffer."
 In any completion session, the case folding starts in auto:
 
 - when the input is all lower case, `case-fold-search' is t
-- otherwise it's nil.
+- otherwise nil.
 
 You can toggle this to make `case-fold-search' nil regardless of input."
   (interactive)
@@ -1675,15 +1745,15 @@ CANDIDATES are assumed to be static."
               (and ivy-case-fold-search
                    (string= name (downcase name))))
              (cands (cond
-                      (matcher
-                       (funcall matcher re candidates))
-                      ((and ivy--old-re
-                            (stringp re)
-                            (stringp ivy--old-re)
-                            (not (string-match "\\\\" ivy--old-re))
-                            (not (equal ivy--old-re ""))
-                            (memq (cl-search
-                                   (if (string-match "\\\\)\\'" ivy--old-re)
+                     (matcher
+                      (funcall matcher re candidates))
+                     ((and ivy--old-re
+                           (stringp re)
+                           (stringp ivy--old-re)
+                           (not (string-match "\\\\" ivy--old-re))
+                           (not (equal ivy--old-re ""))
+                           (memq (cl-search
+                                  (if (string-match "\\\\)\\'" ivy--old-re)
                                        (substring ivy--old-re 0 -2)
                                      ivy--old-re)
                                    re)
@@ -1708,10 +1778,62 @@ CANDIDATES are assumed to be static."
                          res)))))
         (ivy--recompute-index name re-str cands)
         (setq ivy--old-re (if cands re-str ""))
-        (when (and (require 'flx nil 'noerror)
-                   (eq ivy--regex-function 'ivy--regex-fuzzy))
-          (setq cands (ivy--flx-sort name cands)))
-        (setq ivy--old-cands cands)))))
+        (setq ivy--old-cands (ivy--sort name cands))))))
+
+(defcustom ivy-sort-matches-functions-alist '((t . nil))
+  "An alist of functions used to sort the matching candidates.
+
+This is different from `ivy-sort-functions-alist', which is used
+to sort the whole collection only once.  The functions taken from
+here are instead used on each input change, but they are used
+only on already matching candidates, not on all of them.
+
+The alist KEY is a collection function or t to match previously
+not matched collection functions.
+
+The alist VAL is a sorting function with the signature of
+`ivy--prefix-sort'.")
+
+(defun ivy--sort-files-by-date (_name candidates)
+  "Re-soft CANDIDATES according to file modification date."
+  (let ((default-directory ivy--directory))
+    (cl-sort (copy-sequence candidates)
+             (lambda (f1 f2)
+               (time-less-p
+                (nth 5 (file-attributes f2))
+                (nth 5 (file-attributes f1)))))))
+
+(defun ivy--sort (name candidates)
+  "Re-sort CANDIDATES by NAME.
+All CANDIDATES are assumed to match NAME."
+  (let ((key (or (ivy-state-caller ivy-last)
+                 (when (functionp (ivy-state-collection ivy-last))
+                   (ivy-state-collection ivy-last))))
+        fun)
+    (cond ((and (require 'flx nil 'noerror)
+                (eq ivy--regex-function 'ivy--regex-fuzzy))
+           (ivy--flx-sort name candidates))
+          ((setq fun (cdr (or (assoc key ivy-sort-matches-functions-alist)
+                              (assoc t ivy-sort-matches-functions-alist))))
+           (funcall fun name candidates))
+          (t
+           candidates))))
+
+(defun ivy--prefix-sort (name candidates)
+  "Re-sort CANDIDATES.
+Prefix matches to NAME are put ahead of the list."
+  (if (or (string-match "^\\^" name) (string= name ""))
+      candidates
+    (let ((re-prefix (concat "^" (funcall ivy--regex-function name)))
+          res-prefix
+          res-noprefix)
+      (dolist (s candidates)
+        (if (string-match re-prefix s)
+            (push s res-prefix)
+          (push s res-noprefix)))
+      (nconc
+       (nreverse res-prefix)
+       (nreverse res-noprefix)))))
 
 (defun ivy--recompute-index (name re-str cands)
   (let* ((caller (ivy-state-caller ivy-last))
@@ -1743,10 +1865,8 @@ CANDIDATES are assumed to be static."
                (not (equal ivy--old-re "")))
       (setq ivy--index
             (or (ivy--preselect-index
-                 cands
-                 nil
                  (ivy-state-preselect ivy-last)
-                 nil)
+                 cands)
                 ivy--index)))))
 
 (defun ivy-recompute-index-swiper (_re-str cands)
@@ -1758,6 +1878,28 @@ CANDIDATES are assumed to be static."
             ;; Compare with eq to handle equal duplicates in cands
             (setq idx (cl-position (pop tail) cands)))
           (or idx 0))
+      (if ivy--old-cands
+          ivy--index
+        ;; already in ivy-state-buffer
+        (let ((n (line-number-at-pos))
+              (res 0)
+              (i 0))
+          (dolist (c cands)
+            (when (eq n (read (get-text-property 0 'display c)))
+              (setq res i))
+            (cl-incf i))
+          res)))))
+
+(defun ivy-recompute-index-swiper-async (_re-str cands)
+  (let ((tail (nthcdr ivy--index ivy--old-cands))
+        idx)
+    (if (and tail ivy--old-cands (not (equal "^" ivy--old-re)))
+        (progn
+          (while (and tail (null idx))
+            ;; Compare with `equal', since the collection is re-created
+            ;; each time with `split-string'
+            (setq idx (cl-position (pop tail) cands :test #'equal)))
+          (or idx 0))
       ivy--index)))
 
 (defun ivy-recompute-index-zero (_re-str _cands)
@@ -1789,63 +1931,65 @@ CANDIDATES are assumed to be static."
     (error
      cands)))
 
-(defvar ivy-format-function 'ivy-format-function-default
+(defcustom ivy-format-function 'ivy-format-function-default
   "Function to transform the list of candidates into a string.
-This string will be inserted into the minibuffer.")
-
-(defun ivy-format-function-default (cands)
-  "Transform CANDS into a string for minibuffer."
-  (if (bound-and-true-p truncate-lines)
-      (mapconcat #'identity cands "\n")
-    (let ((ww (- (window-width)
-                 (if (and (boundp 'fringe-mode) (eq fringe-mode 0)) 1 0))))
-      (mapconcat
-       (if truncate-lines
-           (lambda (s)
-             (if (> (length s) ww)
-                 (concat (substring s 0 (- ww 3)) "...")
-               s))
-         #'identity)
-       cands "\n"))))
-
-(defun ivy-format-function-arrow (cands)
-  "Transform CANDS into a string for minibuffer."
+This string is inserted into the minibuffer."
+  :type '(choice
+          (const :tag "Default" ivy-format-function-default)
+          (const :tag "Arrow prefix" ivy-format-function-arrow)
+          (const :tag "Full line" ivy-format-function-line)))
+
+(defun ivy--truncate-string (str width)
+  "Truncate STR to WIDTH."
+  (if (> (string-width str) width)
+      (concat (substring str 0 (min (- width 3)
+                                    (- (length str) 3))) "...")
+    str))
+
+(defun ivy--format-function-generic (selected-fn other-fn cand-pairs separator)
+  "Transform CAND-PAIRS into a string for minibuffer.
+SELECTED-FN and OTHER-FN each take two string arguments.
+SEPARATOR is used to join the candidates."
   (let ((i -1))
     (mapconcat
-     (lambda (s)
-       (concat (if (eq (cl-incf i) ivy--index)
-                   "> "
-                 "  ")
-               s))
-     cands "\n")))
-
-(defface ivy-minibuffer-match-face-1
-  '((((class color) (background light))
-     :background "#d3d3d3")
-    (((class color) (background dark))
-     :background "#555555"))
-  "The background face for `ivy' minibuffer matches.")
-
-(defface ivy-minibuffer-match-face-2
-  '((((class color) (background light))
-     :background "#e99ce8" :weight bold)
-    (((class color) (background dark))
-     :background "#777777" :weight bold))
-  "Face for `ivy' minibuffer matches modulo 1.")
-
-(defface ivy-minibuffer-match-face-3
-  '((((class color) (background light))
-     :background "#bbbbff" :weight bold)
-    (((class color) (background dark))
-     :background "#7777ff" :weight bold))
-  "Face for `ivy' minibuffer matches modulo 2.")
-
-(defface ivy-minibuffer-match-face-4
-  '((((class color) (background light))
-     :background "#ffbbff" :weight bold)
-    (((class color) (background dark))
-     :background "#8a498a" :weight bold))
-  "Face for `ivy' minibuffer matches modulo 3.")
+     (lambda (pair)
+       (let ((str (car pair))
+             (extra (cdr pair))
+             (curr (eq (cl-incf i) ivy--index)))
+         (if curr
+             (funcall selected-fn str extra)
+           (funcall other-fn str extra))))
+     cand-pairs
+     separator)))
+
+(defun ivy-format-function-default (cand-pairs)
+  "Transform CAND-PAIRS into a string for minibuffer."
+  (ivy--format-function-generic
+   (lambda (str extra)
+     (concat (ivy--add-face str 'ivy-current-match) extra))
+   #'concat
+   cand-pairs
+   "\n"))
+
+(defun ivy-format-function-arrow (cand-pairs)
+  "Transform CAND-PAIRS into a string for minibuffer."
+  (ivy--format-function-generic
+   (lambda (str extra)
+     (concat "> " (ivy--add-face str 'ivy-current-match) extra))
+   (lambda (str extra)
+     (concat "  " str extra))
+   cand-pairs
+   "\n"))
+
+(defun ivy-format-function-line (cand-pairs)
+  "Transform CAND-PAIRS into a string for minibuffer."
+  (ivy--format-function-generic
+   (lambda (str extra)
+     (ivy--add-face (concat str extra "\n") 'ivy-current-match))
+   (lambda (str extra)
+     (concat str extra "\n"))
+   cand-pairs
+   ""))
 
 (defcustom ivy-minibuffer-faces
   '(ivy-minibuffer-match-face-1
@@ -1919,13 +2063,11 @@ CANDS is a list of strings."
                                        x)))
                                  cands))))
       (setq ivy--current (copy-sequence (nth index cands)))
-      (setq cands (mapcar
-                   #'ivy--format-minibuffer-line
-                   cands))
-      (setf (nth index cands)
-            (ivy--add-face (nth index cands) 'ivy-current-match))
       (let* ((ivy--index index)
-             (res (concat "\n" (funcall ivy-format-function cands))))
+             (cand-pairs (mapcar
+                          (lambda (cand)
+                            (cons (ivy--format-minibuffer-line cand) nil)) cands))
+             (res (concat "\n" (funcall ivy-format-function cand-pairs))))
         (put-text-property 0 (length res) 'read-only nil res)
         res))))
 
@@ -1934,9 +2076,6 @@ CANDS is a list of strings."
 
 (defvar recentf-list)
 
-(defface ivy-virtual '((t :inherit font-lock-builtin-face))
-  "Face used by Ivy for matching virtual buffer names.")
-
 (defcustom ivy-virtual-abbreviate 'name
   "The mode of abbreviation for virtual buffer names."
   :type '(choice
@@ -2109,7 +2248,7 @@ Don't finish completion."
 
 (defun ivy-reverse-i-search ()
   "Enter a recursive `ivy-read' session using the current history.
-The selected history element will be inserted into the minibufer."
+The selected history element will be inserted into the minibuffer."
   (interactive)
   (let ((enable-recursive-minibuffers t)
         (history (symbol-value (ivy-state-history ivy-last)))
@@ -2147,6 +2286,7 @@ buffer would modify `ivy-last'.")
     (define-key map (kbd "g") 'ivy-occur-press)
     (define-key map (kbd "a") 'ivy-occur-read-action)
     (define-key map (kbd "o") 'ivy-occur-dispatch)
+    (define-key map (kbd "q") 'quit-window)
     map)
   "Keymap for Ivy Occur mode.")
 
@@ -2166,15 +2306,17 @@ buffer would modify `ivy-last'.")
 
 \\{ivy-occur-grep-mode-map}")
 
+(defvar counsel-git-grep-cmd)
+
 (defun ivy-occur ()
   "Stop completion and put the current matches into a new buffer.
 
-The new buffer will also remember the current action(s).
+The new buffer remembers current action(s).
 
-While in the *ivy-occur* buffer, selecting a cadidate with RET or
+While in the *ivy-occur* buffer, selecting a candidate with RET or
 a mouse click will call the appropriate action for that candidate.
 
-It's possible to have an unlimited amount of *ivy-occur* buffers."
+There is no limit on the number of *ivy-occur* buffers."
   (interactive)
   (let ((buffer
          (generate-new-buffer
@@ -2187,7 +2329,14 @@ It's possible to have an unlimited amount of *ivy-occur* buffers."
         (do-grep (eq (ivy-state-caller ivy-last) 'counsel-git-grep)))
     (with-current-buffer buffer
       (if do-grep
-          (ivy-occur-grep-mode)
+          (progn
+            (setq ivy--old-cands
+                  (split-string
+                   (shell-command-to-string
+                    (format counsel-git-grep-cmd ivy--old-re))
+                   "\n"
+                   t))
+            (ivy-occur-grep-mode))
         (ivy-occur-mode))
       (setf (ivy-state-text ivy-last) ivy-text)
       (setq ivy-occur-last ivy-last)