]> code.delx.au - gnu-emacs-elpa/blobdiff - ivy.el
Fix Custom menus
[gnu-emacs-elpa] / ivy.el
diff --git a/ivy.el b/ivy.el
index 27df11d49825e9e1c7dffd267a98dc8a140dabf4..3c0f229114fca3ba7e2be02f31d17da6a0985b03 100644 (file)
--- a/ivy.el
+++ b/ivy.el
 
 (defcustom ivy-count-format "%-4d "
   "The style of showing the current candidate count for `ivy-read'.
-Set this to nil 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."
-  :type '(choice (const :tag "Count disabled" nil) string))
+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."
+  :type '(choice
+          (const :tag "Count disabled" "")
+          (const :tag "Count matches" "%-4d ")
+          (const :tag "Count matches and show current match" "(%d/%d) ")
+          string))
 
 (defcustom ivy-wrap nil
   "Whether to wrap around after the first and last candidate."
   :type 'boolean)
 
-(defcustom ivy-display-style nil
+(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.
 
 With the fancy method, the matching parts of the regexp will be
-additionally highlighted, just like `swiper' does it."
+additionally highlighted, just like `swiper' does it.
+
+This setting depends on `add-face-text-property' - a C function
+available as of 24.5. It will behave poorly in earlier Emacs
+versions."
   :type '(choice
           (const :tag "Plain" nil)
           (const :tag "Fancy" fancy)))
@@ -100,10 +108,13 @@ This is usually meant as a quick exit out of the minibuffer."
 (defcustom ivy-extra-directories '("../" "./")
   "Add this to the front of the list when completing file names.
 Only \"./\" and \"../\" apply here. They appear in reverse order."
-  :type 'list)
+  :type '(repeat :tag "Dirs"
+          (choice
+           (const :tag "Parent Directory" "../")
+           (const :tag "Current Directory" "./"))))
 
 (defcustom ivy-use-virtual-buffers nil
-  "When non-nil, add `recentf-mode' and bookmarks to the list of buffers."
+  "When non-nil, add `recentf-mode' and bookmarks to `ivy-switch-buffer'."
   :type 'boolean)
 
 (defvar ivy--actions-list nil
@@ -149,9 +160,11 @@ Only \"./\" and \"../\" apply here. They appear in reverse order."
     (define-key map (kbd "M-i") 'ivy-insert-current)
     (define-key map (kbd "C-o") 'hydra-ivy/body)
     (define-key map (kbd "M-o") 'ivy-dispatching-done)
+    (define-key map (kbd "C-M-o") 'ivy-dispatching-call)
     (define-key map (kbd "C-k") 'ivy-kill-line)
     (define-key map (kbd "S-SPC") 'ivy-restrict-to-matches)
     (define-key map (kbd "M-w") 'ivy-kill-ring-save)
+    (define-key map (kbd "C-'") 'ivy-avy)
     map)
   "Keymap used in the minibuffer.")
 (autoload 'hydra-ivy/body "ivy-hydra" "" t)
@@ -174,10 +187,14 @@ Only \"./\" and \"../\" apply here. They appear in reverse order."
   re-builder
   matcher
   ;; When this is non-nil, call it for each input change to get new candidates
-  dynamic-collection)
+  dynamic-collection
+  caller)
 
 (defvar ivy-last nil
-  "The last parameters passed to `ivy-read'.")
+  "The last parameters passed to `ivy-read'.
+
+This should eventually become a stack so that you could use
+`ivy-read' recursively.")
 
 (defsubst ivy-set-action (action)
   (setf (ivy-state-action ivy-last) action))
@@ -238,6 +255,9 @@ When non-nil, it should contain one %d.")
 (defvar ivy--old-text ""
   "Store old `ivy-text' for dynamic completion.")
 
+(defvar ivy-case-fold-search 'auto
+  "Store the current overriding `case-fold-search'.")
+
 (defvar Info-current-file)
 
 (defmacro ivy-quit-and-run (&rest body)
@@ -290,12 +310,11 @@ When non-nil, it should contain one %d.")
          (insert ivy-text)
          (ivy--exhibit))))
 
-(defun ivy-dispatching-done ()
-  "Select one of the available actions and call `ivy-done'."
+(defun ivy-read-action ()
+  "Change the action to one of the available ones."
   (interactive)
   (let ((actions (ivy-state-action ivy-last)))
-    (if (null (ivy--actionp actions))
-        (ivy-done)
+    (unless (null (ivy--actionp actions))
       (let* ((hint (concat ivy--current
                            "\n"
                            (mapconcat
@@ -309,14 +328,30 @@ When non-nil, it should contain one %d.")
                             "\n")
                            "\n"))
              (key (string (read-key hint)))
-             (action (assoc key (cdr actions))))
+             (action-idx (cl-position-if
+                          (lambda (x) (equal (car x) key))
+                          (cdr actions))))
         (cond ((string= key "\a"))
-              ((null action)
+              ((null action-idx)
                (error "%s is not bound" key))
               (t
                (message "")
-               (ivy-set-action (nth 1 action))
-               (ivy-done)))))))
+               (setcar actions (1+ action-idx))
+               (ivy-set-action actions)))))))
+
+(defun ivy-dispatching-done ()
+  "Select one of the available actions and call `ivy-done'."
+  (interactive)
+  (ivy-read-action)
+  (ivy-done))
+
+(defun ivy-dispatching-call ()
+  "Select one of the available actions and call `ivy-call'."
+  (interactive)
+  (let ((actions (copy-sequence (ivy-state-action ivy-last))))
+    (ivy-read-action)
+    (ivy-call)
+    (ivy-set-action actions)))
 
 (defun ivy-build-tramp-name (x)
   "Reconstruct X into a path.
@@ -419,7 +454,10 @@ If the text hasn't changed as a result, forward to `ivy-alt-done'."
          (new (try-completion (if startp
                                   (substring postfix 1)
                                 postfix)
-                              (mapcar (lambda (str) (substring str (string-match postfix str)))
+                              (mapcar (lambda (str)
+                                        (let ((i (string-match postfix str)))
+                                          (when i
+                                            (substring str i))))
                                       ivy--old-cands))))
     (cond ((eq new t) nil)
           ((string= new ivy-text) nil)
@@ -441,6 +479,7 @@ If the text hasn't changed as a result, forward to `ivy-alt-done'."
   (setq ivy-exit 'done)
   (exit-minibuffer))
 
+;;;###autoload
 (defun ivy-resume ()
   "Resume the last completion session."
   (interactive)
@@ -453,7 +492,7 @@ If the text hasn't changed as a result, forward to `ivy-alt-done'."
    :history (ivy-state-history ivy-last)
    :preselect (unless (eq (ivy-state-collection ivy-last)
                           'read-file-name-internal)
-                (regexp-quote ivy--current))
+                ivy--current)
    :keymap (ivy-state-keymap ivy-last)
    :update-fn (ivy-state-update-fn ivy-last)
    :sort (ivy-state-sort ivy-last)
@@ -461,7 +500,8 @@ If the text hasn't changed as a result, forward to `ivy-alt-done'."
    :unwind (ivy-state-unwind ivy-last)
    :re-builder (ivy-state-re-builder ivy-last)
    :matcher (ivy-state-matcher ivy-last)
-   :dynamic-collection (ivy-state-dynamic-collection ivy-last)))
+   :dynamic-collection (ivy-state-dynamic-collection ivy-last)
+   :caller (ivy-state-caller ivy-last)))
 
 (defvar ivy-calling nil
   "When non-nil, call the current action when `ivy--index' changes.")
@@ -494,6 +534,7 @@ If the text hasn't changed as a result, forward to `ivy-alt-done'."
   (interactive)
   (ivy-set-index (max (- ivy--index ivy-height)
                       0)))
+
 (defun ivy-minibuffer-grow ()
   "Grow the minibuffer window by 1 line."
   (interactive)
@@ -602,7 +643,12 @@ If the input is empty, select the previous history element instead."
                   (if (equal ivy--current "")
                       ivy-text
                     ivy--current))))
-        (funcall action x)))))
+        (prog1 (funcall action x)
+          (unless (or (eq ivy-exit 'done)
+                      (equal (selected-window)
+                             (active-minibuffer-window))
+                      (null (active-minibuffer-window)))
+            (select-window (active-minibuffer-window))))))))
 
 (defun ivy-next-line-and-call (&optional arg)
   "Move cursor vertically down ARG candidates.
@@ -738,6 +784,52 @@ On error (read-only), call `ivy-on-del-error-function'."
   (setq ivy--old-re nil)
   (cl-rotatef ivy--regex-function ivy--regexp-quote))
 
+(defvar avy-all-windows)
+(defvar avy-action)
+(defvar avy-keys)
+(defvar avy-keys-alist)
+(defvar avy-style)
+(defvar avy-styles-alist)
+(declare-function avy--process "ext:avy")
+(declare-function avy--style-fn "ext:avy")
+
+(eval-after-load 'avy
+  '(add-to-list 'avy-styles-alist '(ivy-avy . pre)))
+
+(defun ivy-avy ()
+  "Jump to one of the current ivy candidates."
+  (interactive)
+  (unless (require 'avy nil 'noerror)
+    (error "Package avy isn't installed"))
+  (let* ((avy-all-windows nil)
+         (avy-keys (or (cdr (assq 'ivy-avy avy-keys-alist))
+                       avy-keys))
+         (avy-style (or (cdr (assq 'ivy-avy
+                                   avy-styles-alist))
+                        avy-style))
+         (candidate
+          (let ((candidates))
+            (save-excursion
+              (save-restriction
+                (narrow-to-region
+                 (window-start)
+                 (window-end))
+                (goto-char (point-min))
+                (forward-line)
+                (while (< (point) (point-max))
+                  (push
+                   (cons (point)
+                         (selected-window))
+                   candidates)
+                  (forward-line))))
+            (setq avy-action #'identity)
+            (avy--process
+             (nreverse candidates)
+             (avy--style-fn avy-style)))))
+    (ivy-set-index (- (line-number-at-pos candidate) 2))
+    (ivy--exhibit)
+    (ivy-done)))
+
 (defun ivy-sort-file-function-default (x y)
   "Compare two files X and Y.
 Prioritize directories."
@@ -749,7 +841,7 @@ Prioritize directories."
         nil
       (string< x y))))
 
-(defvar ivy-sort-functions-alist
+(defcustom ivy-sort-functions-alist
   '((read-file-name-internal . ivy-sort-file-function-default)
     (internal-complete-buffer . nil)
     (counsel-git-grep-function . nil)
@@ -763,7 +855,27 @@ 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'.
 
-The entry associated to t is used for all fall-through cases.")
+The entry associated to t is used for all fall-through cases."
+  :type
+  '(alist
+    :key-type (choice
+               (const :tag "All other functions" t)
+               (symbol :tag "Function"))
+    :value-type (choice
+                 (const :tag "plain sort" string-lessp)
+                 (const :tag "file sort" ivy-sort-file-function-default)
+                 (const :tag "no sort" nil)))
+  :group 'ivy)
+
+(defvar ivy-index-functions-alist
+  '((swiper . ivy-recompute-index-swiper)
+    (swiper-multi . ivy-recompute-index-swiper)
+    (counsel-git-grep . ivy-recompute-index-swiper)
+    (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.")
 
 (defvar ivy-re-builders-alist
   '((t . ivy--regex-plus))
@@ -821,7 +933,7 @@ Directories come first."
 (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)
+                      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
@@ -830,7 +942,8 @@ the current number of matching candidates.  If % appears elsewhere
 in the PROMPT it should be quoted as %%.
 See also `ivy-count-format'.
 
-COLLECTION is a list of strings.
+COLLECTION is a list of strings, or a function, or an alist, or a
+hash table.
 
 If INITIAL-INPUT is non-nil, insert it in the minibuffer initially.
 
@@ -853,7 +966,11 @@ RE-BUILDER is a lambda that transforms text into a regex.
 MATCHER can completely override matching.
 
 DYNAMIC-COLLECTION is a function to call to update the list of
-candidates with each input."
+candidates with each input.
+
+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."
   (let ((extra-actions (plist-get ivy--actions-list this-command)))
     (when extra-actions
       (setq action
@@ -879,7 +996,8 @@ candidates with each input."
          :unwind unwind
          :re-builder re-builder
          :matcher matcher
-         :dynamic-collection dynamic-collection))
+         :dynamic-collection dynamic-collection
+         :caller caller))
   (ivy--reset-state ivy-last)
   (prog1
       (unwind-protect
@@ -888,6 +1006,10 @@ candidates with each input."
              (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)
@@ -926,6 +1048,7 @@ This is useful for recursive `ivy-read'."
       (setq initial-input (cdr (assoc this-command
                                       ivy-initial-inputs-alist))))
     (setq ivy--directory nil)
+    (setq ivy-case-fold-search 'auto)
     (setq ivy--regex-function
           (or re-builder
               (and (functionp collection)
@@ -956,7 +1079,9 @@ This is useful for recursive `ivy-read'."
                              (string= preselect-directory
                                       default-directory))
                    (setq ivy--directory preselect-directory))
-                 (setq preselect (file-name-nondirectory preselect))))
+                 (setf
+                  (ivy-state-preselect state)
+                  (setq preselect (file-name-nondirectory preselect)))))
              (setq coll (ivy--sorted-files ivy--directory))
              (when initial-input
                (unless (or require-match
@@ -969,10 +1094,9 @@ This is useful for recursive `ivy-read'."
             ((or (functionp collection)
                  (byte-code-function-p collection)
                  (vectorp collection)
-                 (listp (car collection)))
+                 (and (consp collection) (listp (car collection)))
+                 (hash-table-p collection))
              (setq coll (all-completions "" collection predicate)))
-            ((hash-table-p collection)
-             (error "Hash table as a collection unsupported"))
             (t
              (setq coll collection)))
       (when sort
@@ -988,7 +1112,7 @@ This is useful for recursive `ivy-read'."
       (when preselect
         (unless (or (and require-match
                          (not (eq collection 'internal-complete-buffer)))
-                    (let ((re (format "\\`%s" (regexp-quote preselect))))
+                    (let ((re (regexp-quote preselect)))
                       (cl-find-if (lambda (x) (string-match re x))
                                   coll)))
           (setq coll (cons preselect coll))))
@@ -1008,7 +1132,8 @@ This is useful for recursive `ivy-read'."
           (cond ((string-match "%.*d" prompt)
                  prompt)
                 ((null ivy-count-format)
-                 nil)
+                 (error
+                  "`ivy-count-format' can't be nil.  Set it to an empty string instead"))
                 ((string-match "%d.*%d" ivy-count-format)
                  (let ((w (length (number-to-string
                                    (length ivy--all-candidates))))
@@ -1028,6 +1153,7 @@ This is useful for recursive `ivy-read'."
                  nil)))
     (setf (ivy-state-initial-input ivy-last) initial-input)))
 
+;;;###autoload
 (defun ivy-completing-read (prompt collection
                             &optional predicate require-match initial-input
                               history def _inherit-input-method)
@@ -1039,7 +1165,7 @@ it 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 considered boolean.  See `completing-read'.
 INITIAL-INPUT is a string that can be inserted into the minibuffer initially.
 _HISTORY is ignored for now.
 DEF is the default value.
@@ -1102,10 +1228,12 @@ When MATCHER is non-nil it's used instead of `cl-remove-if-not'."
     (when matcher
       (setq candidates (funcall matcher "" candidates))))
   (or (cl-position preselect candidates :test #'equal)
-      (cl-position-if
-       (lambda (x)
-         (string-match (regexp-quote preselect) x))
-       candidates)))
+      (and (stringp preselect)
+           (let ((re (regexp-quote preselect)))
+             (cl-position-if
+              (lambda (x)
+                (string-match re x))
+              candidates)))))
 
 ;;* Implementation
 ;;** Regex
@@ -1215,9 +1343,14 @@ Everything after \"!\" should not match."
   "Build a regex sequence from STR.
 Insert .* between each char."
   (if (string-match "\\`\\(\\^?\\)\\(.*?\\)\\(\\$?\\)\\'" str)
-      (concat (match-string 1 str)
-              (mapconcat #'string (string-to-list (match-string 2 str)) ".*")
-              (match-string 3 str))
+      (prog1
+          (concat (match-string 1 str)
+                  (mapconcat
+                   (lambda (x)
+                     (format "\\(%c\\)" x))
+                   (string-to-list (match-string 2 str)) ".*")
+                  (match-string 3 str))
+        (setq ivy--subexps (length (match-string 2 str))))
     str))
 
 ;;** Rest
@@ -1227,7 +1360,7 @@ Insert .* between each char."
   (set (make-local-variable 'minibuffer-default-add-function)
        (lambda ()
          (list ivy--default)))
-  (when (and (display-graphic-p) (= (length (frame-list)) 1))
+  (when (display-graphic-p)
     (setq truncate-lines t))
   (setq-local max-mini-window-height ivy-height)
   (add-hook 'post-command-hook #'ivy--exhibit nil t)
@@ -1280,13 +1413,21 @@ Insert .* between each char."
                                   ivy--full-length)
                              ivy--length)))
                ivy--prompt-extra
-               tail)
-              (if ivy--directory
-                  (abbreviate-file-name ivy--directory)
-                ""))))
+               tail)))
+            (d-str (if ivy--directory
+                       (abbreviate-file-name ivy--directory)
+                     "")))
         (save-excursion
           (goto-char (point-min))
           (delete-region (point-min) (minibuffer-prompt-end))
+          (if (> (+ (mod (+ (length n-str) (length d-str)) (window-width))
+                    (length ivy-text))
+                 (window-width))
+              (setq n-str (concat n-str "\n" d-str))
+            (setq n-str (concat n-str d-str)))
+          (let ((regex (format "\\([^\n]\\{%d\\}\\)[^\n]" (window-width))))
+            (while (string-match regex n-str)
+              (setq n-str (replace-match (concat (match-string 1 n-str) "\n") nil t n-str 1))))
           (set-text-properties 0 (length n-str)
                                `(face minibuffer-prompt ,@std-props)
                                n-str)
@@ -1330,6 +1471,8 @@ Insert .* between each char."
   "Insert Ivy completions display.
 Should be run via minibuffer `post-command-hook'."
   (when (memq 'ivy--exhibit post-command-hook)
+    (let ((inhibit-field-text-motion nil))
+      (constrain-to-field nil (point-max)))
     (setq ivy-text (ivy--input))
     (if (ivy-state-dynamic-collection ivy-last)
         ;; while-no-input would cause annoying
@@ -1403,7 +1546,10 @@ all of the text contained in the minibuffer."
               (body-height (window-body-height nil t)))
           (when (> text-height body-height)
             (window-resize nil (- text-height body-height) nil t t)))
-      (fit-window-to-buffer))))
+        (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")
 
@@ -1427,74 +1573,156 @@ all of the text contained in the minibuffer."
        (font-lock-append-text-property 0 (length str) 'face face str))))
   str)
 
+(declare-function flx-make-string-cache "ext:flx")
+(declare-function flx-score "ext:flx")
+
+(defvar ivy--flx-cache nil)
+
+(eval-after-load 'flx
+  '(setq ivy--flx-cache (flx-make-string-cache)))
+
+(defun ivy-toggle-case-fold ()
+  "Toggle the case folding between nil and auto.
+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.
+
+You can toggle this to make `case-fold-search' nil regardless of input."
+  (interactive)
+  (setq ivy-case-fold-search
+        (if ivy-case-fold-search
+            nil
+          'auto))
+  ;; reset cache so that the candidate list updates
+  (setq ivy--old-re nil))
+
 (defun ivy--filter (name candidates)
   "Return all items that match NAME in CANDIDATES.
 CANDIDATES are assumed to be static."
-  (let* ((re (funcall ivy--regex-function name))
-         (re-str (if (listp re) (caar re) re))
-         (matcher (ivy-state-matcher ivy-last))
-         (case-fold-search (string= name (downcase name)))
-         (cands (cond
-                  (matcher
-                   (funcall matcher re candidates))
-                  ((and (equal re ivy--old-re)
-                        ivy--old-cands)
-                   ivy--old-cands)
-                  ((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)
-                              '(0 2)))
-                   (ignore-errors
-                     (cl-remove-if-not
-                      (lambda (x) (string-match re x))
-                      ivy--old-cands)))
-                  (t
-                   (let ((re-list (if (stringp re) (list (cons re t)) re))
-                         (res candidates))
-                     (dolist (re re-list)
-                       (setq res
-                             (ignore-errors
-                               (funcall
-                                (if (cdr re)
-                                    #'cl-remove-if-not
-                                  #'cl-remove-if)
-                                (let ((re (car re)))
-                                  (lambda (x) (string-match re x)))
-                                res))))
-                     res))))
-         (tail (nthcdr ivy--index ivy--old-cands))
-         idx)
-    (when (and tail ivy--old-cands (not (equal "^" ivy--old-re)))
-      (unless (and (not (equal re-str ivy--old-re))
-                   (or (setq ivy--index
-                             (or
-                              (cl-position (if (and (> (length re-str) 0)
-                                                    (eq ?^ (aref re-str 0)))
-                                               (substring re-str 1)
-                                             re-str) cands
-                                             :test #'equal)
-                              (and ivy--directory
-                                   (cl-position
-                                    (concat re-str "/") cands
-                                    :test #'equal))))))
-        (while (and tail (null idx))
-          ;; Compare with eq to handle equal duplicates in cands
-          (setq idx (cl-position (pop tail) cands)))
-        (setq ivy--index (or idx 0))))
-    (when (and (string= name "") (not (equal ivy--old-re "")))
+  (let ((re (funcall ivy--regex-function name)))
+    (if (and (equal re ivy--old-re)
+             ivy--old-cands)
+        ;; quick caching for "C-n", "C-p" etc.
+        ivy--old-cands
+      (let* ((re-str (if (listp re) (caar re) re))
+             (matcher (ivy-state-matcher ivy-last))
+             (case-fold-search
+              (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)
+                                       (substring ivy--old-re 0 -2)
+                                     ivy--old-re)
+                                   re)
+                                  '(0 2)))
+                       (ignore-errors
+                         (cl-remove-if-not
+                          (lambda (x) (string-match re x))
+                          ivy--old-cands)))
+                      (t
+                       (let ((re-list (if (stringp re) (list (cons re t)) re))
+                             (res candidates))
+                         (dolist (re re-list)
+                           (setq res
+                                 (ignore-errors
+                                   (funcall
+                                    (if (cdr re)
+                                        #'cl-remove-if-not
+                                      #'cl-remove-if)
+                                    (let ((re-str (car re)))
+                                      (lambda (x) (string-match re-str x)))
+                                    res))))
+                         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)))))
+
+(defun ivy--recompute-index (name re-str cands)
+  (let* ((caller (ivy-state-caller ivy-last))
+         (func (or (and caller (cdr (assoc caller ivy-index-functions-alist)))
+                   (cdr (assoc t ivy-index-functions-alist))
+                   #'ivy-recompute-index-zero)))
+    (setq ivy--index
+          (or
+           (cl-position (if (and (> (length re-str) 0)
+                                 (eq ?^ (aref re-str 0)))
+                            (substring re-str 1)
+                          re-str) cands
+                          :test #'equal)
+           (and ivy--directory
+                (cl-position
+                 (concat re-str "/") cands
+                 :test #'equal))
+           (and (not (string= name ""))
+                (not (and (require 'flx nil 'noerror)
+                          (eq ivy--regex-function 'ivy--regex-fuzzy)
+                          (< (length cands) 200)))
+
+                (cl-position (nth ivy--index ivy--old-cands)
+                             cands))
+           (funcall func re-str cands)))
+    (when (and (or (string= name "")
+                   (string= name "^"))
+               (not (equal ivy--old-re "")))
       (setq ivy--index
-            (or (cl-position (ivy-state-preselect ivy-last)
-                             cands :test #'equal)
-                ivy--index)))
-    (setq ivy--old-re (if cands re-str ""))
-    (setq ivy--old-cands cands)))
+            (or (ivy--preselect-index
+                 cands
+                 nil
+                 (ivy-state-preselect ivy-last)
+                 nil)
+                ivy--index)))))
+
+(defun ivy-recompute-index-swiper (_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 eq to handle equal duplicates in cands
+            (setq idx (cl-position (pop tail) cands)))
+          (or idx 0))
+      ivy--index)))
+
+(defun ivy-recompute-index-zero (_re-str _cands)
+  0)
+
+(defun ivy--flx-sort (name cands)
+  "Sort according to closeness to string NAME the string list CANDS."
+  (condition-case nil
+      (if (and cands
+               (< (length cands) 200))
+          (let* ((flx-name (if (string-match "^\\^" name)
+                               (substring name 1)
+                             name))
+                 (cands-with-score
+                  (delq nil
+                        (mapcar
+                         (lambda (x)
+                           (let ((score (car (flx-score x flx-name ivy--flx-cache))))
+                             (and score
+                                  (cons score x))))
+                         cands))))
+            (if cands-with-score
+                (mapcar #'cdr
+                        (sort cands-with-score
+                              (lambda (x y)
+                                (> (car x) (car y)))))
+              cands))
+        cands)
+    (error
+     cands)))
 
 (defvar ivy-format-function 'ivy-format-function-default
   "Function to transform the list of candidates into a string.
@@ -1507,10 +1735,12 @@ This string will be inserted into the minibuffer.")
     (let ((ww (- (window-width)
                  (if (and (boundp 'fringe-mode) (eq fringe-mode 0)) 1 0))))
       (mapconcat
-       (lambda (s)
-         (if (> (length s) ww)
-             (concat (substring s 0 (- ww 3)) "...")
-           s))
+       (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)
@@ -1550,12 +1780,19 @@ This string will be inserted into the minibuffer.")
                          (t
                           (nth (1+ (mod (+ i 2) (1- (length swiper-minibuffer-faces))))
                                swiper-minibuffer-faces)))))
-              (add-face-text-property
-               (match-beginning i)
-               (match-end i)
-               face
-               nil
-               str))
+              (if (fboundp 'add-face-text-property)
+                  (add-face-text-property
+                   (match-beginning i)
+                   (match-end i)
+                   face
+                   nil
+                   str)
+                (font-lock-append-text-property
+                 (match-beginning i)
+                 (match-end i)
+                 'face
+                 face
+                 str)))
             (cl-incf i)))))
     str))
 
@@ -1598,6 +1835,14 @@ CANDS is a list of strings."
 (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
+          (const :tag "Only name" name)
+          (const :tag "Full path" full)
+          ;; eventually, uniquify
+          ))
+
 (defun ivy--virtual-buffers ()
   "Adapted from `ido-add-virtual-buffers-to-list'."
   (unless recentf-mode
@@ -1611,7 +1856,10 @@ CANDS is a list of strings."
                            (delq nil (mapcar (lambda (bookmark)
                                                (cdr (assoc 'filename bookmark)))
                                              bookmarks)))))
-      (setq name (file-name-nondirectory head))
+      (setq name
+            (if (eq ivy-virtual-abbreviate 'name)
+                (file-name-nondirectory head)
+              (expand-file-name head)))
       (when (equal name "")
         (setq name (file-name-nondirectory (directory-file-name head))))
       (when (equal name "")
@@ -1691,6 +1939,7 @@ BUFFER may be a string or nil."
     ivy--rename-buffer-action
     "rename")))
 
+;;;###autoload
 (defun ivy-switch-buffer ()
   "Switch to another buffer."
   (interactive)
@@ -1702,6 +1951,7 @@ BUFFER may be a string or nil."
                 :action #'ivy--switch-buffer-action
                 :keymap ivy-switch-buffer-map))))
 
+;;;###autoload
 (defun ivy-recentf ()
   "Find a file on `recentf-list'."
   (interactive)
@@ -1723,7 +1973,7 @@ BUFFER may be a string or nil."
             (goto-char pt)
           (setq amend (buffer-substring-no-properties pt (point))))))
     (when amend
-      (insert amend))))
+      (insert (replace-regexp-in-string "  +" " " amend)))))
 
 (defun ivy-kill-ring-save ()
   "Store the current candidates into the kill ring.