]> code.delx.au - gnu-emacs-elpa/blobdiff - packages/swiper/ivy.el
Merge commit '494c421bfa6f1b72b577267cb3841b0eff262250' from js2-mode
[gnu-emacs-elpa] / packages / swiper / ivy.el
index 47b47f2d56f3b1a7c266ffc4d534160ac925a3c6..f64782cb940acf76ac32332e21f8e9784c22dca2 100644 (file)
@@ -4,7 +4,6 @@
 
 ;; Author: Oleh Krehel <ohwoeowho@gmail.com>
 ;; URL: https://github.com/abo-abo/swiper
 
 ;; Author: Oleh Krehel <ohwoeowho@gmail.com>
 ;; URL: https://github.com/abo-abo/swiper
-;; Version: 0.2.3
 ;; Package-Requires: ((emacs "24.1"))
 ;; Keywords: matching
 
 ;; Package-Requires: ((emacs "24.1"))
 ;; Keywords: matching
 
@@ -36,8 +35,6 @@
 ;; re-building it into a regex.
 ;; So "for example" is transformed into "\\(for\\).*\\(example\\)".
 
 ;; re-building it into a regex.
 ;; So "for example" is transformed into "\\(for\\).*\\(example\\)".
 
-(require 'cl-lib)
-
 ;;; Code:
 (require 'cl-lib)
 
 ;;; Code:
 (require 'cl-lib)
 
@@ -89,6 +86,10 @@ This is usually meant as a quick exit out of the minibuffer."
 Only \"./\" and \"../\" apply here. They appear in reverse order."
   :type 'list)
 
 Only \"./\" and \"../\" apply here. They appear in reverse order."
   :type 'list)
 
+(defcustom ivy-use-virtual-buffers nil
+  "When non-nil, add `recentf-mode' and bookmarks to the list of buffers."
+  :type 'boolean)
+
 ;;* Keymap
 (require 'delsel)
 (defvar ivy-minibuffer-map
 ;;* Keymap
 (require 'delsel)
 (defvar ivy-minibuffer-map
@@ -101,9 +102,13 @@ Only \"./\" and \"../\" apply here. They appear in reverse order."
     (define-key map (kbd "<down>") 'ivy-next-line)
     (define-key map (kbd "<up>") 'ivy-previous-line)
     (define-key map (kbd "C-s") 'ivy-next-line-or-history)
     (define-key map (kbd "<down>") 'ivy-next-line)
     (define-key map (kbd "<up>") 'ivy-previous-line)
     (define-key map (kbd "C-s") 'ivy-next-line-or-history)
-    (define-key map (kbd "C-r") 'ivy-previous-line-or-history)
+    (define-key map (kbd "C-r") 'ivy-reverse-i-search)
     (define-key map (kbd "SPC") 'self-insert-command)
     (define-key map (kbd "DEL") 'ivy-backward-delete-char)
     (define-key map (kbd "SPC") 'self-insert-command)
     (define-key map (kbd "DEL") 'ivy-backward-delete-char)
+    (define-key map (kbd "M-DEL") 'ivy-backward-kill-word)
+    (define-key map (kbd "C-d") 'ivy-delete-char)
+    (define-key map (kbd "C-f") 'ivy-forward-char)
+    (define-key map (kbd "M-d") 'ivy-kill-word)
     (define-key map (kbd "M-<") 'ivy-beginning-of-buffer)
     (define-key map (kbd "M->") 'ivy-end-of-buffer)
     (define-key map (kbd "<left>") 'ivy-beginning-of-buffer)
     (define-key map (kbd "M-<") 'ivy-beginning-of-buffer)
     (define-key map (kbd "M->") 'ivy-end-of-buffer)
     (define-key map (kbd "<left>") 'ivy-beginning-of-buffer)
@@ -116,8 +121,19 @@ Only \"./\" and \"../\" apply here. They appear in reverse order."
     (define-key map (kbd "C-M-n") 'ivy-next-line-and-call)
     (define-key map (kbd "C-M-p") 'ivy-previous-line-and-call)
     (define-key map (kbd "M-q") 'ivy-toggle-regexp-quote)
     (define-key map (kbd "C-M-n") 'ivy-next-line-and-call)
     (define-key map (kbd "C-M-p") 'ivy-previous-line-and-call)
     (define-key map (kbd "M-q") 'ivy-toggle-regexp-quote)
+    (define-key map (kbd "M-j") 'ivy-yank-word)
+    (define-key map (kbd "M-i") 'ivy-insert-current)
+    (define-key map (kbd "C-o") 'hydra-ivy/body)
+    (define-key map (kbd "C-k") 'ivy-kill-line)
     map)
   "Keymap used in the minibuffer.")
     map)
   "Keymap used in the minibuffer.")
+(autoload 'hydra-ivy/body "ivy-hydra" "" t)
+
+(defvar ivy-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map [remap switch-to-buffer] 'ivy-switch-buffer)
+    map)
+  "Keymap for `ivy-mode'.")
 
 ;;* Globals
 (cl-defstruct ivy-state
 
 ;;* Globals
 (cl-defstruct ivy-state
@@ -127,7 +143,11 @@ Only \"./\" and \"../\" apply here. They appear in reverse order."
   ;; The window in which `ivy-read' was called
   window
   action
   ;; The window in which `ivy-read' was called
   window
   action
-  unwind)
+  unwind
+  re-builder
+  matcher
+  ;; When this is non-nil, call it for each input change to get new candidates
+  dynamic-collection)
 
 (defvar ivy-last nil
   "The last parameters passed to `ivy-read'.")
 
 (defvar ivy-last nil
   "The last parameters passed to `ivy-read'.")
@@ -166,9 +186,6 @@ Otherwise, store nil.")
 (defvar ivy--default nil
   "Default initial input.")
 
 (defvar ivy--default nil
   "Default initial input.")
 
-(defvar ivy--update-fn nil
-  "Current function to call when current candidate(s) update.")
-
 (defvar ivy--prompt nil
   "Store the format-style prompt.
 When non-nil, it should contain one %d.")
 (defvar ivy--prompt nil
   "Store the format-style prompt.
 When non-nil, it should contain one %d.")
@@ -185,46 +202,59 @@ When non-nil, it should contain one %d.")
 (defvar ivy--regex-function 'ivy--regex
   "Current function for building a regex.")
 
 (defvar ivy--regex-function 'ivy--regex
   "Current function for building a regex.")
 
-(defvar ivy--collection nil
-  "Store the current collection function.")
+(defvar ivy--subexps 0
+  "Number of groups in the current `ivy--regex'.")
+
+(defvar ivy--full-length nil
+  "When :dynamic-collection is non-nil, this can be the total amount of candidates.")
+
+(defvar ivy--old-text ""
+  "Store old `ivy-text' for dynamic completion.")
 
 (defvar Info-current-file)
 
 
 (defvar Info-current-file)
 
+(defmacro ivy-quit-and-run (&rest body)
+  "Quit the minibuffer and run BODY afterwards."
+  `(progn
+     (put 'quit 'error-message "")
+     (run-at-time nil nil
+                  (lambda ()
+                    (put 'quit 'error-message "Quit")
+                    ,@body))
+     (minibuffer-keyboard-quit)))
+
+(defun ivy--done (text)
+  "Insert TEXT and exit minibuffer."
+  (if (and ivy--directory
+           (not (eq (ivy-state-history ivy-last) 'grep-files-history)))
+      (insert (setq ivy--current (expand-file-name
+                                  text ivy--directory)))
+    (insert (setq ivy--current text)))
+  (setq ivy-exit 'done)
+  (exit-minibuffer))
+
 ;;* Commands
 (defun ivy-done ()
   "Exit the minibuffer with the selected candidate."
   (interactive)
   (delete-minibuffer-contents)
 ;;* Commands
 (defun ivy-done ()
   "Exit the minibuffer with the selected candidate."
   (interactive)
   (delete-minibuffer-contents)
-  (when (cond (ivy--directory
-               (if (zerop ivy--length)
-                   (if (or (not (eq confirm-nonexistent-file-or-buffer t))
-                           (equal " (confirm)" ivy--prompt-extra))
-                       (progn
-                         (insert
-                          (expand-file-name ivy-text ivy--directory))
-                         (setq ivy-exit 'done))
-                     (setq ivy--prompt-extra " (confirm)")
-                     (insert ivy-text)
-                     (ivy--exhibit)
-                     nil)
-                 (insert
-                  (expand-file-name
-                   ivy--current ivy--directory))
-                 (setq ivy-exit 'done)))
-              ((zerop ivy--length)
-               (if (memq (ivy-state-require-match ivy-last)
-                         '(nil confirm confirm-after-completion))
-                   (progn
-                     (insert ivy-text)
-                     (setq ivy-exit 'done))
-                 (setq ivy--prompt-extra " (match required)")
-                 (insert ivy-text)
-                 (ivy--exhibit)
-                 nil))
-              (t
-               (insert ivy--current)
-               (setq ivy-exit 'done)))
-    (exit-minibuffer)))
+  (cond ((> ivy--length 0)
+         (ivy--done ivy--current))
+        ((memq (ivy-state-collection ivy-last)
+               '(read-file-name-internal internal-complete-buffer))
+         (if (or (not (eq confirm-nonexistent-file-or-buffer t))
+                 (equal " (confirm)" ivy--prompt-extra))
+             (ivy--done ivy-text)
+           (setq ivy--prompt-extra " (confirm)")
+           (insert ivy-text)
+           (ivy--exhibit)))
+        ((memq (ivy-state-require-match ivy-last)
+               '(nil confirm confirm-after-completion))
+         (ivy--done ivy-text))
+        (t
+         (setq ivy--prompt-extra " (match required)")
+         (insert ivy-text)
+         (ivy--exhibit))))
 
 (defun ivy-build-tramp-name (x)
   "Reconstruct X into a path.
 
 (defun ivy-build-tramp-name (x)
   "Reconstruct X into a path.
@@ -235,67 +265,117 @@ Is is a cons cell, related to `tramp-get-completion-function'."
         (concat user "@" domain)
       domain)))
 
         (concat user "@" domain)
       domain)))
 
+(declare-function tramp-get-completion-function "tramp")
+(declare-function Info-find-node "info")
+
 (defun ivy-alt-done (&optional arg)
   "Exit the minibuffer with the selected candidate.
 When ARG is t, exit with current text, ignoring the candidates."
   (interactive "P")
 (defun ivy-alt-done (&optional arg)
   "Exit the minibuffer with the selected candidate.
 When ARG is t, exit with current text, ignoring the candidates."
   (interactive "P")
-  (if arg
-      (ivy-immediate-done)
-    (let (dir)
-      (cond ((and ivy--directory
-                  (or
-                   (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))
-            ((string-match "^/\\([^/]+?\\):\\(?:\\(.*\\)@\\)?" ivy-text)
-             (let ((method (match-string 1 ivy-text))
-                   (user (match-string 2 ivy-text))
-                   res)
-               (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 ((host (ivy-read "Find File: "
-                                     (mapcar #'ivy-build-tramp-name res))))
-                 (when host
-                   (setq ivy--directory "/")
-                   (ivy--cd (concat "/" method ":" host ":"))))))
-            (t
-             (ivy-done))))))
+  (let (dir)
+    (cond (arg
+           (ivy-immediate-done))
+          ((and ivy--directory
+                (or
+                 (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)))))
+
+(defcustom ivy-tab-space nil
+  "When non-nil, `ivy-partial-or-done' should insert a space."
+  :type 'boolean)
 
 (defun ivy-partial-or-done ()
   "Complete the minibuffer text as much as possible.
 
 (defun ivy-partial-or-done ()
   "Complete the minibuffer text as much as possible.
-When called twice in a row, exit the minibuffer with the current
-candidate."
+If the text hasn't changed as a result, forward to `ivy-alt-done'."
   (interactive)
   (interactive)
-  (if (eq this-command last-command)
-      (progn
-        (delete-minibuffer-contents)
-        (insert ivy--current)
-        (setq ivy-exit 'done)
-        (exit-minibuffer))
-    (let* ((parts (split-string ivy-text " " t))
-           (postfix (car (last parts)))
-           (new (try-completion postfix
-                                (mapcar (lambda (str) (substring str (string-match postfix str)))
-                                        ivy--old-cands))))
-      (delete-region (minibuffer-prompt-end) (point-max))
-      (setcar (last parts) new)
-      (insert (mapconcat #'identity parts " ") " "))))
+  (if (and (eq (ivy-state-collection ivy-last) #'read-file-name-internal)
+           (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))))
+    (or (ivy-partial)
+        (when (or (eq this-command last-command)
+                  (eq ivy--length 1))
+          (ivy-alt-done)))))
+
+(defun ivy-partial ()
+  "Complete the minibuffer text as much as possible."
+  (interactive)
+  (let* ((parts (or (split-string ivy-text " " t) (list "")))
+         (postfix (car (last parts)))
+         (completion-ignore-case t)
+         (startp (string-match "^\\^" postfix))
+         (new (try-completion (if startp
+                                  (substring postfix 1)
+                                postfix)
+                              (mapcar (lambda (str) (substring str (string-match postfix str)))
+                                      ivy--old-cands))))
+    (cond ((eq new t) nil)
+          ((string= new ivy-text) nil)
+          (new
+           (delete-region (minibuffer-prompt-end) (point-max))
+           (setcar (last parts)
+                   (if startp
+                       (concat "^" new)
+                     new))
+           (insert (mapconcat #'identity parts " ")
+                   (if ivy-tab-space " " ""))
+           t))))
 
 (defun ivy-immediate-done ()
   "Exit the minibuffer with the current input."
   (interactive)
   (delete-minibuffer-contents)
 
 (defun ivy-immediate-done ()
   "Exit the minibuffer with the current input."
   (interactive)
   (delete-minibuffer-contents)
-  (insert ivy-text)
+  (insert (setq ivy--current ivy-text))
   (setq ivy-exit 'done)
   (exit-minibuffer))
 
   (setq ivy-exit 'done)
   (exit-minibuffer))
 
@@ -309,44 +389,73 @@ candidate."
    :require-match (ivy-state-require-match ivy-last)
    :initial-input ivy-text
    :history (ivy-state-history ivy-last)
    :require-match (ivy-state-require-match ivy-last)
    :initial-input ivy-text
    :history (ivy-state-history ivy-last)
-   :preselect (regexp-quote ivy--current)
+   :preselect (unless (eq (ivy-state-collection ivy-last)
+                          'read-file-name-internal)
+                (regexp-quote ivy--current))
    :keymap (ivy-state-keymap ivy-last)
    :update-fn (ivy-state-update-fn ivy-last)
    :sort (ivy-state-sort ivy-last)
    :action (ivy-state-action ivy-last)
    :keymap (ivy-state-keymap ivy-last)
    :update-fn (ivy-state-update-fn ivy-last)
    :sort (ivy-state-sort ivy-last)
    :action (ivy-state-action ivy-last)
-   :unwind (ivy-state-unwind ivy-last)))
+   :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)))
+
+(defvar ivy-calling nil
+  "When non-nil, call the current action when `ivy--index' changes.")
+
+(defun ivy-set-index (index)
+  "Set `ivy--index' to INDEX."
+  (setq ivy--index index)
+  (when ivy-calling
+    (ivy--exhibit)
+    (ivy-call)))
 
 (defun ivy-beginning-of-buffer ()
   "Select the first completion candidate."
   (interactive)
 
 (defun ivy-beginning-of-buffer ()
   "Select the first completion candidate."
   (interactive)
-  (setq ivy--index 0))
+  (ivy-set-index 0))
 
 (defun ivy-end-of-buffer ()
   "Select the last completion candidate."
   (interactive)
 
 (defun ivy-end-of-buffer ()
   "Select the last completion candidate."
   (interactive)
-  (setq ivy--index (1- ivy--length)))
+  (ivy-set-index (1- ivy--length)))
 
 (defun ivy-scroll-up-command ()
   "Scroll the candidates upward by the minibuffer height."
   (interactive)
 
 (defun ivy-scroll-up-command ()
   "Scroll the candidates upward by the minibuffer height."
   (interactive)
-  (setq ivy--index (min (+ ivy--index ivy-height)
-                        (1- ivy--length))))
+  (ivy-set-index (min (+ ivy--index ivy-height)
+                      (1- ivy--length))))
 
 (defun ivy-scroll-down-command ()
   "Scroll the candidates downward by the minibuffer height."
   (interactive)
 
 (defun ivy-scroll-down-command ()
   "Scroll the candidates downward by the minibuffer height."
   (interactive)
-  (setq ivy--index (max (- ivy--index ivy-height)
-                        0)))
+  (ivy-set-index (max (- ivy--index ivy-height)
+                      0)))
+(defun ivy-minibuffer-grow ()
+  "Grow the minibuffer window by 1 line"
+  (interactive)
+  (setq-local max-mini-window-height
+              (cl-incf ivy-height)))
+
+(defun ivy-minibuffer-shrink ()
+  "Shrink the minibuffer window by 1 line."
+  (interactive)
+  (unless (<= ivy-height 2)
+    (setq-local max-mini-window-height
+                (cl-decf ivy-height))
+    (window-resize (selected-window) -1)))
 
 (defun ivy-next-line (&optional arg)
   "Move cursor vertically down ARG candidates."
   (interactive "p")
   (setq arg (or arg 1))
 
 (defun ivy-next-line (&optional arg)
   "Move cursor vertically down ARG candidates."
   (interactive "p")
   (setq arg (or arg 1))
-  (cl-incf ivy--index arg)
-  (when (>= ivy--index (1- ivy--length))
-    (if ivy-wrap
-        (ivy-beginning-of-buffer)
-      (setq ivy--index (1- ivy--length)))))
+  (let ((index (+ ivy--index arg)))
+    (if (> index (1- ivy--length))
+        (if ivy-wrap
+            (ivy-beginning-of-buffer)
+          (ivy-set-index (1- ivy--length)))
+      (ivy-set-index index))))
 
 (defun ivy-next-line-or-history (&optional arg)
   "Move cursor vertically down ARG candidates.
 
 (defun ivy-next-line-or-history (&optional arg)
   "Move cursor vertically down ARG candidates.
@@ -360,11 +469,12 @@ If the input is empty, select the previous history element instead."
   "Move cursor vertically up ARG candidates."
   (interactive "p")
   (setq arg (or arg 1))
   "Move cursor vertically up ARG candidates."
   (interactive "p")
   (setq arg (or arg 1))
-  (cl-decf ivy--index arg)
-  (when (< ivy--index 0)
-    (if ivy-wrap
-        (ivy-end-of-buffer)
-      (setq ivy--index 0))))
+  (let ((index (- ivy--index arg)))
+    (if (< index 0)
+        (if ivy-wrap
+            (ivy-end-of-buffer)
+          (ivy-set-index 0))
+      (ivy-set-index index))))
 
 (defun ivy-previous-line-or-history (arg)
   "Move cursor vertically up ARG candidates.
 
 (defun ivy-previous-line-or-history (arg)
   "Move cursor vertically up ARG candidates.
@@ -374,26 +484,39 @@ If the input is empty, select the previous history element instead."
     (ivy-previous-history-element 1))
   (ivy-previous-line arg))
 
     (ivy-previous-history-element 1))
   (ivy-previous-line arg))
 
+(defun ivy-toggle-calling ()
+  "Flip `ivy-calling'"
+  (interactive)
+  (when (setq ivy-calling (not ivy-calling))
+    (ivy-call)))
+
+(defun ivy-call ()
+  "Call the current action without exiting completion."
+  (when (ivy-state-action ivy-last)
+    (with-selected-window (ivy-state-window ivy-last)
+      (funcall (ivy-state-action ivy-last) ivy--current))))
+
 (defun ivy-next-line-and-call (&optional arg)
 (defun ivy-next-line-and-call (&optional arg)
-  "Move cursor vertically down ARG candidates."
+  "Move cursor vertically down ARG candidates.
+Call the permanent action if possible."
   (interactive "p")
   (ivy-next-line arg)
   (ivy--exhibit)
   (interactive "p")
   (ivy-next-line arg)
   (ivy--exhibit)
-  (with-selected-window (ivy-state-window ivy-last)
-    (funcall (ivy-state-action ivy-last))))
+  (ivy-call))
 
 (defun ivy-previous-line-and-call (&optional arg)
 
 (defun ivy-previous-line-and-call (&optional arg)
-  "Move cursor vertically down ARG candidates."
+  "Move cursor vertically down ARG candidates.
+Call the permanent action if possible."
   (interactive "p")
   (ivy-previous-line arg)
   (ivy--exhibit)
   (interactive "p")
   (ivy-previous-line arg)
   (ivy--exhibit)
-  (with-selected-window (ivy-state-window ivy-last)
-    (funcall (ivy-state-action ivy-last))))
+  (ivy-call))
 
 (defun ivy-previous-history-element (arg)
   "Forward to `previous-history-element' with ARG."
   (interactive "p")
   (previous-history-element arg)
 
 (defun ivy-previous-history-element (arg)
   "Forward to `previous-history-element' with ARG."
   (interactive "p")
   (previous-history-element arg)
+  (ivy--cd-maybe)
   (move-end-of-line 1)
   (ivy--maybe-scroll-history))
 
   (move-end-of-line 1)
   (ivy--maybe-scroll-history))
 
@@ -401,9 +524,24 @@ If the input is empty, select the previous history element instead."
   "Forward to `next-history-element' with ARG."
   (interactive "p")
   (next-history-element arg)
   "Forward to `next-history-element' with ARG."
   (interactive "p")
   (next-history-element arg)
+  (ivy--cd-maybe)
   (move-end-of-line 1)
   (ivy--maybe-scroll-history))
 
   (move-end-of-line 1)
   (ivy--maybe-scroll-history))
 
+(defun ivy--cd-maybe ()
+  "Check if the current input points to a different directory.
+If so, move to that directory, while keeping only the file name."
+  (when ivy--directory
+    (let* ((input (expand-file-name (ivy--input)))
+           (file (file-name-nondirectory input))
+           (dir (expand-file-name (file-name-directory input))))
+      (if (string= dir ivy--directory)
+          (progn
+            (delete-minibuffer-contents)
+            (insert file))
+        (ivy--cd dir)
+        (insert file)))))
+
 (defun ivy--maybe-scroll-history ()
   "If the selected history element has an index, scroll there."
   (let ((idx (ignore-errors
 (defun ivy--maybe-scroll-history ()
   "If the selected history element has an index, scroll there."
   (let ((idx (ignore-errors
@@ -443,6 +581,44 @@ On error (read-only), call `ivy-on-del-error-function'."
        (when ivy-on-del-error-function
          (funcall ivy-on-del-error-function))))))
 
        (when ivy-on-del-error-function
          (funcall ivy-on-del-error-function))))))
 
+(defun ivy-delete-char (arg)
+  "Forward to `delete-char' ARG."
+  (interactive "p")
+  (unless (= (point) (line-end-position))
+    (delete-char arg)))
+
+(defun ivy-forward-char (arg)
+  "Forward to `forward-char' ARG."
+  (interactive "p")
+  (unless (= (point) (line-end-position))
+    (forward-char arg)))
+
+(defun ivy-kill-word (arg)
+  "Forward to `kill-word' ARG."
+  (interactive "p")
+  (unless (= (point) (line-end-position))
+    (kill-word arg)))
+
+(defun ivy-kill-line ()
+  "Forward to `kill-line'."
+  (interactive)
+  (if (eolp)
+      (kill-region (minibuffer-prompt-end) (point))
+    (kill-line)))
+
+(defun ivy-backward-kill-word ()
+  "Forward to `backward-kill-word'."
+  (interactive)
+  (if (and ivy--directory (= (minibuffer-prompt-end) (point)))
+      (progn
+        (ivy--cd (file-name-directory
+                  (directory-file-name
+                   (expand-file-name
+                    ivy--directory))))
+        (ivy--exhibit))
+    (ignore-errors
+      (backward-kill-word 1))))
+
 (defvar ivy--regexp-quote 'regexp-quote
   "Store the regexp quoting state.")
 
 (defvar ivy--regexp-quote 'regexp-quote
   "Store the regexp quoting state.")
 
@@ -467,9 +643,16 @@ Prioritize directories."
   '((read-file-name-internal . ivy-sort-file-function-default)
     (internal-complete-buffer . nil)
     (counsel-git-grep-function . nil)
   '((read-file-name-internal . ivy-sort-file-function-default)
     (internal-complete-buffer . nil)
     (counsel-git-grep-function . nil)
+    (Man-goto-section . nil)
+    (org-refile . nil)
     (t . string-lessp))
   "An alist of sorting functions for each collection function.
     (t . string-lessp))
   "An alist of sorting functions for each collection function.
-For each entry, nil means no sorting.
+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'.
+
 The entry associated to t is used for all fall-through cases.")
 
 (defvar ivy-re-builders-alist
 The entry associated to t is used for all fall-through cases.")
 
 (defvar ivy-re-builders-alist
@@ -488,6 +671,17 @@ The matches will be filtered in a sequence, you can mix the
 regexps that should match and that should not match as you
 like.")
 
 regexps that should match and that should not match as you
 like.")
 
+(defvar ivy-initial-inputs-alist
+  '((org-refile . "^")
+    (org-agenda-refile . "^")
+    (org-capture-refile . "^")
+    (counsel-M-x . "^")
+    (counsel-describe-function . "^")
+    (counsel-describe-variable . "^")
+    (man . "^")
+    (woman . "^"))
+  "Command to initial input table.")
+
 (defcustom ivy-sort-max-size 30000
   "Sorting won't be done for collections larger than this."
   :type 'integer)
 (defcustom ivy-sort-max-size 30000
   "Sorting won't be done for collections larger than this."
   :type 'integer)
@@ -503,9 +697,9 @@ Directories come first."
       (setq seq (delete "./" (delete "../" seq)))
       (when (eq (setq sort-fn (cdr (assoc 'read-file-name-internal
                                           ivy-sort-functions-alist)))
       (setq seq (delete "./" (delete "../" seq)))
       (when (eq (setq sort-fn (cdr (assoc 'read-file-name-internal
                                           ivy-sort-functions-alist)))
-                'ivy-sort-file-function-default)
+                #'ivy-sort-file-function-default)
         (setq seq (mapcar (lambda (x)
         (setq seq (mapcar (lambda (x)
-                            (propertize x 'dirp (string-match-p "/$" x)))
+                            (propertize x 'dirp (string-match-p "/\\'" x)))
                           seq)))
       (when sort-fn
         (setq seq (cl-sort seq sort-fn)))
                           seq)))
       (when sort-fn
         (setq seq (cl-sort seq sort-fn)))
@@ -517,7 +711,7 @@ Directories come first."
 (cl-defun ivy-read (prompt collection
                     &key predicate require-match initial-input
                       history preselect keymap update-fn sort
 (cl-defun ivy-read (prompt collection
                     &key predicate require-match initial-input
                       history preselect keymap update-fn sort
-                      action unwind)
+                      action unwind re-builder matcher dynamic-collection)
   "Read a string in the minibuffer, with completion.
 
 PROMPT is a string to prompt with; normally it ends in a colon
   "Read a string in the minibuffer, with completion.
 
 PROMPT is a string to prompt with; normally it ends in a colon
@@ -538,9 +732,17 @@ 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, refer to `ivy-sort-functions-alist' for sorting.
 
-ACTION is a lambda to call after a result was selected.
+ACTION is a lambda to call after a result was selected. It should
+take a single argument, usually a string.
+
+UNWIND is a lambda to call before exiting.
+
+RE-BUILDER is a lambda that transforms text into a regex.
 
 
-UNWIND is a lambda to call before exiting."
+MATCHER can completely override matching.
+
+DYNAMIC-COLLECTION is a function to call to update the list of
+candidates with each input."
   (setq ivy-last
         (make-ivy-state
          :prompt prompt
   (setq ivy-last
         (make-ivy-state
          :prompt prompt
@@ -555,79 +757,124 @@ UNWIND is a lambda to call before exiting."
          :sort sort
          :action action
          :window (selected-window)
          :sort sort
          :action action
          :window (selected-window)
-         :unwind unwind))
-  (setq ivy--directory nil)
-  (setq ivy--regex-function
-        (or (and (functionp collection)
-                 (cdr (assoc collection ivy-re-builders-alist)))
-            (cdr (assoc t ivy-re-builders-alist))
-            'ivy--regex))
-  (setq ivy--subexps 0)
-  (setq ivy--regexp-quote 'regexp-quote)
-  (setq ivy--collection (and (functionp collection)
-                             collection))
-  (setq ivy--old-text "")
-  (setq ivy-text "")
-  (let (coll sort-fn)
-    (cond ((eq collection 'Info-read-node-name-1)
-           (if (equal Info-current-file "dir")
-               (setq coll
-                     (mapcar (lambda (x) (format "(%s)" x))
-                             (cl-delete-duplicates
-                              (all-completions "(" collection predicate)
-                              :test 'equal)))
-             (setq coll (all-completions "" collection predicate))))
-          ((eq collection 'read-file-name-internal)
-           (setq ivy--directory default-directory)
-           (setq coll
-                 (ivy--sorted-files default-directory))
-           (when initial-input
-             (unless (or require-match
-                         (equal initial-input default-directory))
-               (setq coll (cons initial-input coll)))
-             (setq initial-input nil)))
-          ((eq collection 'internal-complete-buffer)
-           (setq coll
-                 (mapcar (lambda (x)
-                           (if (with-current-buffer x
-                                 (file-remote-p
-                                  (abbreviate-file-name default-directory)))
-                               (propertize x 'face 'ivy-remote)
-                             x))
-                         (all-completions "" collection predicate))))
-          ((or (functionp collection)
-               (vectorp collection)
-               (listp (car collection)))
-           (setq coll (all-completions "" collection predicate)))
-          ((hash-table-p collection)
-           (error "Hash table as a collection unsupported"))
-          (t
-           (setq coll collection)))
-    (when sort
-      (if (and (functionp collection)
-               (setq sort-fn (assoc collection ivy-sort-functions-alist)))
-          (when (and (setq sort-fn (cdr sort-fn))
-                     (not (eq collection 'read-file-name-internal)))
-            (setq coll (cl-sort coll sort-fn)))
-        (unless (eq history 'org-refile-history)
-          (if (and (setq sort-fn (cdr (assoc t ivy-sort-functions-alist)))
-                   (<= (length coll) ivy-sort-max-size))
-              (setq coll (cl-sort (copy-sequence coll) sort-fn))))))
-    (when preselect
-      (unless (or require-match
-                  (cl-find-if `(lambda (x)
-                                 (string-match ,(format "^%s" preselect) x))
-                              coll))
-        (setq coll (cons preselect coll))))
-    (setq ivy--index (or
-                      (and preselect
-                           (ivy--preselect-index
-                            coll initial-input preselect))
-                      0))
-    (setq ivy--old-re nil)
-    (setq ivy--old-cands nil)
-    (setq ivy--all-candidates coll)
-    (setq ivy--update-fn update-fn)
+         :unwind unwind
+         :re-builder re-builder
+         :matcher matcher
+         :dynamic-collection dynamic-collection))
+  (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)
+                    (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)))
+                   (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)))
+    (when (setq action (ivy-state-action ivy-last))
+      (funcall action ivy--current))))
+
+(defun ivy--reset-state (state)
+  "Reset the ivy to STATE.
+This is useful for recursive `ivy-read'."
+  (let ((prompt (ivy-state-prompt state))
+        (collection (ivy-state-collection state))
+        (predicate (ivy-state-predicate state))
+        (history (ivy-state-history state))
+        (preselect (ivy-state-preselect state))
+        (sort (ivy-state-sort state))
+        (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)))
+    (unless initial-input
+      (setq initial-input (cdr (assoc this-command
+                                      ivy-initial-inputs-alist))))
+    (setq ivy--directory nil)
+    (setq ivy--regex-function
+          (or re-builder
+              (and (functionp collection)
+                   (cdr (assoc collection ivy-re-builders-alist)))
+              (cdr (assoc t ivy-re-builders-alist))
+              'ivy--regex))
+    (setq ivy--subexps 0)
+    (setq ivy--regexp-quote 'regexp-quote)
+    (setq ivy--old-text "")
+    (setq ivy--full-length nil)
+    (setq ivy-text "")
+    (setq ivy-calling nil)
+    (let (coll sort-fn)
+      (cond ((eq collection 'Info-read-node-name-1)
+             (if (equal Info-current-file "dir")
+                 (setq coll
+                       (mapcar (lambda (x) (format "(%s)" x))
+                               (cl-delete-duplicates
+                                (all-completions "(" collection predicate)
+                                :test #'equal)))
+               (setq coll (all-completions "" collection predicate))))
+            ((eq collection 'read-file-name-internal)
+             (setq ivy--directory default-directory)
+             (require 'dired)
+             (setq coll
+                   (ivy--sorted-files default-directory))
+             (when initial-input
+               (unless (or require-match
+                           (equal initial-input default-directory)
+                           (equal initial-input ""))
+                 (setq coll (cons initial-input coll)))
+               (setq initial-input nil)))
+            ((eq collection 'internal-complete-buffer)
+             (setq coll (ivy--buffer-list "" ivy-use-virtual-buffers)))
+            ((or (functionp collection)
+                 (vectorp collection)
+                 (listp (car collection)))
+             (setq coll (all-completions "" collection predicate)))
+            ((hash-table-p collection)
+             (error "Hash table as a collection unsupported"))
+            (t
+             (setq coll collection)))
+      (when sort
+        (if (and (functionp collection)
+                 (setq sort-fn (assoc collection ivy-sort-functions-alist)))
+            (when (and (setq sort-fn (cdr sort-fn))
+                       (not (eq collection 'read-file-name-internal)))
+              (setq coll (cl-sort coll sort-fn)))
+          (unless (eq history 'org-refile-history)
+            (if (and (setq sort-fn (cdr (assoc t ivy-sort-functions-alist)))
+                     (<= (length coll) ivy-sort-max-size))
+                (setq coll (cl-sort (copy-sequence coll) sort-fn))))))
+      (when preselect
+        (unless (or (and require-match
+                         (not (eq collection 'internal-complete-buffer)))
+                    (let ((re (format "\\`%s" (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))
+                        0))
+      (setq ivy--old-re nil)
+      (setq ivy--old-cands nil)
+      (setq ivy--all-candidates coll))
     (setq ivy-exit nil)
     (setq ivy--default (or (thing-at-point 'symbol) ""))
     (setq ivy--prompt
     (setq ivy-exit nil)
     (setq ivy--default (or (thing-at-point 'symbol) ""))
     (setq ivy--prompt
@@ -639,27 +886,7 @@ UNWIND is a lambda to call before exiting."
                  prompt)
                 (t
                  nil)))
                  prompt)
                 (t
                  nil)))
-    (prog1
-        (unwind-protect
-             (minibuffer-with-setup-hook
-                 #'ivy--minibuffer-setup
-               (let* ((hist (or history 'ivy-history))
-                      (res (read-from-minibuffer
-                            prompt
-                            initial-input
-                            (make-composed-keymap keymap ivy-minibuffer-map)
-                            nil
-                            hist)))
-                 (when (eq ivy-exit 'done)
-                   (set hist (cons (propertize ivy-text 'ivy-index ivy--index)
-                                   (delete ivy-text
-                                           (cdr (symbol-value hist)))))
-                   res)))
-          (remove-hook 'post-command-hook #'ivy--exhibit)
-          (when (setq unwind (ivy-state-unwind ivy-last))
-            (funcall unwind)))
-      (when (setq action (ivy-state-action ivy-last))
-        (funcall action)))))
+    (setf (ivy-state-initial-input ivy-last) initial-input)))
 
 (defun ivy-completing-read (prompt collection
                             &optional predicate require-match initial-input
 
 (defun ivy-completing-read (prompt collection
                             &optional predicate require-match initial-input
@@ -682,22 +909,33 @@ The history, defaults and input-method arguments are ignored for now."
   (ivy-read prompt collection
             :predicate predicate
             :require-match require-match
   (ivy-read prompt collection
             :predicate predicate
             :require-match require-match
-            :initial-input initial-input
+            :initial-input (if (consp initial-input)
+                               (car initial-input)
+                             initial-input)
             :preselect (if (listp def) (car def) def)
             :history history
             :keymap nil
             :preselect (if (listp def) (car def) def)
             :history history
             :keymap nil
-            :sort t))
+            :sort
+            (let ((sort (assoc this-command ivy-sort-functions-alist)))
+              (if sort
+                  (cdr sort)
+                t))))
 
 ;;;###autoload
 (define-minor-mode ivy-mode
 
 ;;;###autoload
 (define-minor-mode ivy-mode
-    "Toggle Ivy mode on or off.
+  "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
 `ivy-completing-read'.
 
 With ARG, turn Ivy mode on if arg is positive, off otherwise.
 Turning on Ivy mode will set `completing-read-function' to
 `ivy-completing-read'.
 
+Global bindings:
+\\{ivy-mode-map}
+
+Minibuffer bindings:
 \\{ivy-minibuffer-map}"
   :group 'ivy
   :global t
 \\{ivy-minibuffer-map}"
   :group 'ivy
   :global t
+  :keymap ivy-mode-map
   :lighter " ivy"
   (if ivy-mode
       (setq completing-read-function 'ivy-completing-read)
   :lighter " ivy"
   (if ivy-mode
       (setq completing-read-function 'ivy-completing-read)
@@ -712,19 +950,16 @@ Turning on Ivy mode will set `completing-read-function' to
            (lambda (x)
              (string-match initial-input x))
            candidates)))
            (lambda (x)
              (string-match initial-input x))
            candidates)))
-  (or (cl-position preselect candidates :test 'equal)
+  (or (cl-position preselect candidates :test #'equal)
       (cl-position-if
        (lambda (x)
       (cl-position-if
        (lambda (x)
-         (string-match preselect x))
+         (string-match (regexp-quote preselect) x))
        candidates)))
 
 ;;* Implementation
 ;;** Regex
        candidates)))
 
 ;;* Implementation
 ;;** Regex
-(defvar ivy--subexps 0
-  "Number of groups in the current `ivy--regex'.")
-
 (defvar ivy--regex-hash
 (defvar ivy--regex-hash
-  (make-hash-table :test 'equal)
+  (make-hash-table :test #'equal)
   "Store pre-computed regex.")
 
 (defun ivy--split (str)
   "Store pre-computed regex.")
 
 (defun ivy--split (str)
@@ -732,17 +967,30 @@ Turning on Ivy mode will set `completing-read-function' to
 The remaining spaces stick to their left.
 This allows to \"quote\" N spaces by inputting N+1 spaces."
   (let ((len (length str))
 The remaining spaces stick to their left.
 This allows to \"quote\" N spaces by inputting N+1 spaces."
   (let ((len (length str))
-        (start 0)
-        res s)
-    (while (and (string-match " +" str start)
-                (< start len))
-      (setq s (substring str start (1- (match-end 0))))
+        start0
+        (start1 0)
+        res s
+        match-len)
+    (while (and (string-match " +" str start1)
+                (< start1 len))
+      (setq match-len (- (match-end 0) (match-beginning 0)))
+      (if (= match-len 1)
+          (progn
+            (when start0
+              (setq start1 start0)
+              (setq start0 nil))
+            (push (substring str start1 (match-beginning 0)) res)
+            (setq start1 (match-end 0)))
+        (setq str (replace-match
+                   (make-string (1- match-len) ?\ )
+                   nil nil str))
+        (setq start0 (or start0 start1))
+        (setq start1 (1- (match-end 0)))))
+    (if start0
+        (push (substring str start0) res)
+      (setq s (substring str start1))
       (unless (= (length s) 0)
       (unless (= (length s) 0)
-        (push s res))
-      (setq start (match-end 0)))
-    (setq s (substring str start))
-    (unless (= (length s) 0)
-      (push s res))
+        (push s res)))
     (nreverse res)))
 
 (defun ivy--regex (str &optional greedy)
     (nreverse res)))
 
 (defun ivy--regex (str &optional greedy)
@@ -763,7 +1011,7 @@ When GREEDY is non-nil, join words in a greedy way."
                          (setq ivy--subexps (length subs))
                          (mapconcat
                           (lambda (x)
                          (setq ivy--subexps (length subs))
                          (mapconcat
                           (lambda (x)
-                            (if (string-match "^\\\\(.*\\\\)$" x)
+                            (if (string-match "\\`\\\\(.*\\\\)\\'" x)
                                 x
                               (format "\\(%s\\)" x)))
                           subs
                                 x
                               (format "\\(%s\\)" x)))
                           subs
@@ -772,6 +1020,26 @@ When GREEDY is non-nil, join words in a greedy way."
                             ".*?")))))
                     ivy--regex-hash)))))
 
                             ".*?")))))
                     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."
+  (let* ((subs (split-string str " +" t))
+         (len (length subs)))
+    (cl-case len
+      (1
+       (setq ivy--subexps 0)
+       (car subs))
+      (t
+       (setq ivy--subexps len)
+       (let ((all (mapconcat #'identity subs "\\|")))
+         (mapconcat
+          (lambda (x)
+            (if (string-match "\\`\\\\(.*\\\\)\\'" x)
+                x
+              (format "\\(%s\\)" x)))
+          (make-list len all)
+          ".*?"))))))
+
 (defun ivy--regex-plus (str)
   "Build a regex sequence from STR.
 Spaces are wild, everything before \"!\" should match.
 (defun ivy--regex-plus (str)
   "Build a regex sequence from STR.
 Spaces are wild, everything before \"!\" should match.
@@ -790,6 +1058,15 @@ Everything after \"!\" should not match."
                res)))
       (t (error "Unexpected: use only one !")))))
 
                res)))
       (t (error "Unexpected: use only one !")))))
 
+(defun ivy--regex-fuzzy (str)
+  "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))
+    str))
+
 ;;** Rest
 (defun ivy--minibuffer-setup ()
   "Setup ivy completion in the minibuffer."
 ;;** Rest
 (defun ivy--minibuffer-setup ()
   "Setup ivy completion in the minibuffer."
@@ -815,15 +1092,6 @@ Everything after \"!\" should not match."
     (goto-char (minibuffer-prompt-end))
     (delete-region (line-end-position) (point-max))))
 
     (goto-char (minibuffer-prompt-end))
     (delete-region (line-end-position) (point-max))))
 
-(defvar ivy--dynamic-function nil
-  "When this is non-nil, call it for each input change to get new candidates.")
-
-(defvar ivy--full-length nil
-  "When `ivy--dynamic-function' is non-nil, this can be the total amount of candidates.")
-
-(defvar ivy--old-text ""
-  "Store old `ivy-text' for dynamic completion.")
-
 (defun ivy--insert-prompt ()
   "Update the prompt according to `ivy--prompt'."
   (when ivy--prompt
 (defun ivy--insert-prompt ()
   "Update the prompt according to `ivy--prompt'."
   (when ivy--prompt
@@ -831,7 +1099,7 @@ Everything after \"!\" should not match."
                                  counsel-find-symbol))
       (setq ivy--prompt-extra ""))
     (let (head tail)
                                  counsel-find-symbol))
       (setq ivy--prompt-extra ""))
     (let (head tail)
-      (if (string-match "\\(.*\\): $" ivy--prompt)
+      (if (string-match "\\(.*\\): \\'" ivy--prompt)
           (progn
             (setq head (match-string 1 ivy--prompt))
             (setq tail ": "))
           (progn
             (setq head (match-string 1 ivy--prompt))
             (setq tail ": "))
@@ -841,13 +1109,18 @@ Everything after \"!\" should not match."
             (std-props '(front-sticky t rear-nonsticky t field t read-only t))
             (n-str
              (format
             (std-props '(front-sticky t rear-nonsticky t field t read-only t))
             (n-str
              (format
-              (concat head
-                      ivy--prompt-extra
-                      tail
-                      (if ivy--directory
-                          (abbreviate-file-name ivy--directory)
-                        ""))
-              (or (and ivy--dynamic-function
+              (concat
+               (if (and (bound-and-true-p minibuffer-depth-indicate-mode)
+                        (> (minibuffer-depth) 1))
+                   (format "[%d] " (minibuffer-depth))
+                 "")
+               head
+               ivy--prompt-extra
+               tail
+               (if ivy--directory
+                   (abbreviate-file-name ivy--directory)
+                 ""))
+              (or (and (ivy-state-dynamic-collection ivy-last)
                        ivy--full-length)
                   ivy--length))))
         (save-excursion
                        ivy--full-length)
                   ivy--length))))
         (save-excursion
@@ -879,56 +1152,67 @@ Everything after \"!\" should not match."
   "Insert Ivy completions display.
 Should be run via minibuffer `post-command-hook'."
   (setq ivy-text (ivy--input))
   "Insert Ivy completions display.
 Should be run via minibuffer `post-command-hook'."
   (setq ivy-text (ivy--input))
-  (if ivy--dynamic-function
+  (if (ivy-state-dynamic-collection ivy-last)
       ;; while-no-input would cause annoying
       ;; "Waiting for process to die...done" message interruptions
       (let ((inhibit-message t))
       ;; while-no-input would cause annoying
       ;; "Waiting for process to die...done" message interruptions
       (let ((inhibit-message t))
-        (while-no-input
-          (unless (equal ivy--old-text ivy-text)
-            (let ((store ivy--dynamic-function)
-                  (ivy--dynamic-function nil))
-              (setq ivy--all-candidates (funcall store ivy-text))))
-          (ivy--insert-minibuffer (ivy--format ivy--all-candidates))))
+        (unless (equal ivy--old-text ivy-text)
+          (while-no-input
+            ;; dynamic collection should take care of everything
+            (funcall (ivy-state-dynamic-collection ivy-last) ivy-text)
+            (setq ivy--old-text ivy-text)))
+        (unless (eq ivy--full-length -1)
+          (ivy--insert-minibuffer
+           (ivy--format ivy--all-candidates))))
     (cond (ivy--directory
     (cond (ivy--directory
-           (if (string-match "/$" ivy-text)
+           (if (string-match "/\\'" ivy-text)
                (if (member ivy-text ivy--all-candidates)
                    (ivy--cd (expand-file-name ivy-text ivy--directory))
                (if (member ivy-text ivy--all-candidates)
                    (ivy--cd (expand-file-name ivy-text ivy--directory))
-                 (when (string-match "//$" ivy-text)
-                   (ivy--cd "/")))
-             (if (string-match "~$" ivy-text)
+                 (when (string-match "//\\'" ivy-text)
+                  (if (and default-directory
+                           (string-match "\\`[[:alpha:]]:/" default-directory))
+                      (ivy--cd (match-string 0 default-directory))
+                    (ivy--cd "/")))
+                (when (string-match "[[:alpha:]]:/" ivy-text)
+                  (let ((drive-root (match-string 0 ivy-text)))
+                    (when (file-exists-p drive-root)
+                      (ivy--cd drive-root)))))
+             (if (string-match "\\`~\\'" ivy-text)
                  (ivy--cd (expand-file-name "~/")))))
                  (ivy--cd (expand-file-name "~/")))))
-          ((eq ivy--collection 'internal-complete-buffer)
-           (when (or (and (string-match "^ " ivy-text)
-                          (not (string-match "^ " ivy--old-text)))
-                     (and (string-match "^ " ivy--old-text)
-                          (not (string-match "^ " ivy-text))))
+          ((eq (ivy-state-collection ivy-last) 'internal-complete-buffer)
+           (when (or (and (string-match "\\` " ivy-text)
+                          (not (string-match "\\` " ivy--old-text)))
+                     (and (string-match "\\` " ivy--old-text)
+                          (not (string-match "\\` " ivy-text))))
              (setq ivy--all-candidates
              (setq ivy--all-candidates
-                   (all-completions
-                    (if (and (> (length ivy-text) 0)
-                             (eq (aref ivy-text 0)
-                                 ?\ ))
-                        " "
-                      "")
-                    'internal-complete-buffer))
+                   (if (and (> (length ivy-text) 0)
+                            (eq (aref ivy-text 0)
+                                ?\ ))
+                       (ivy--buffer-list " ")
+                     (ivy--buffer-list "" ivy-use-virtual-buffers)))
              (setq ivy--old-re nil))))
     (ivy--insert-minibuffer
      (ivy--format
              (setq ivy--old-re nil))))
     (ivy--insert-minibuffer
      (ivy--format
-      (ivy--filter ivy-text ivy--all-candidates))))
-  (setq ivy--old-text ivy-text))
+      (ivy--filter ivy-text ivy--all-candidates)))
+    (setq ivy--old-text ivy-text)))
 
 (defun ivy--insert-minibuffer (text)
   "Insert TEXT into minibuffer with appropriate cleanup."
 
 (defun ivy--insert-minibuffer (text)
   "Insert TEXT into minibuffer with appropriate cleanup."
-  (ivy--cleanup)
-  (let ((buffer-undo-list t)
+  (let ((resize-mini-windows nil)
+        (update-fn (ivy-state-update-fn ivy-last))
         deactivate-mark)
         deactivate-mark)
-    (when ivy--update-fn
-      (funcall ivy--update-fn))
+    (ivy--cleanup)
+    (when update-fn
+      (funcall update-fn))
     (ivy--insert-prompt)
     ;; Do nothing if while-no-input was aborted.
     (when (stringp text)
     (ivy--insert-prompt)
     ;; Do nothing if while-no-input was aborted.
     (when (stringp text)
-      (save-excursion
-        (forward-line 1)
-        (insert text)))))
+      (let ((buffer-undo-list t))
+        (save-excursion
+          (forward-line 1)
+          (insert text))))))
+
+(declare-function colir-blend-face-background "ext:colir")
 
 (defun ivy--add-face (str face)
   "Propertize STR with FACE.
 
 (defun ivy--add-face (str face)
   "Propertize STR with FACE.
@@ -946,48 +1230,54 @@ Should be run via minibuffer `post-command-hook'."
   "Return all items that match NAME in CANDIDATES.
 CANDIDATES are assumed to be static."
   (let* ((re (funcall ivy--regex-function name))
   "Return all items that match NAME in CANDIDATES.
 CANDIDATES are assumed to be static."
   (let* ((re (funcall ivy--regex-function name))
-         (cands (cond ((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)
-                                    `(lambda (x) (string-match ,(car re) x))
-                                    res))))
-                         res))))
+         (matcher (ivy-state-matcher ivy-last))
+         (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)
          (tail (nthcdr ivy--index ivy--old-cands))
          idx)
-    (when (and tail ivy--old-cands)
+    (when (and tail ivy--old-cands (not (equal "^" ivy--old-re)))
       (unless (and (not (equal re ivy--old-re))
                    (or (setq ivy--index
                              (or
                               (cl-position re cands
       (unless (and (not (equal re ivy--old-re))
                    (or (setq ivy--index
                              (or
                               (cl-position re cands
-                                           :test 'equal)
+                                           :test #'equal)
                               (and ivy--directory
                                    (cl-position
                                     (concat re "/") cands
                               (and ivy--directory
                                    (cl-position
                                     (concat re "/") cands
-                                    :test 'equal))))))
+                                    :test #'equal))))))
         (while (and tail (null idx))
           ;; Compare with eq to handle equal duplicates in cands
           (setq idx (cl-position (pop tail) cands)))
         (while (and tail (null idx))
           ;; Compare with eq to handle equal duplicates in cands
           (setq idx (cl-position (pop tail) cands)))
@@ -995,11 +1285,36 @@ CANDIDATES are assumed to be static."
     (when (and (string= name "") (not (equal ivy--old-re "")))
       (setq ivy--index
             (or (cl-position (ivy-state-preselect ivy-last)
     (when (and (string= name "") (not (equal ivy--old-re "")))
       (setq ivy--index
             (or (cl-position (ivy-state-preselect ivy-last)
-                             cands :test 'equal)
+                             cands :test #'equal)
                 ivy--index)))
                 ivy--index)))
-    (setq ivy--old-re re)
+    (setq ivy--old-re (if cands re ""))
     (setq ivy--old-cands cands)))
 
     (setq ivy--old-cands cands)))
 
+(defvar 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."
+  (let ((ww (window-width)))
+    (mapconcat
+     (lambda (s)
+       (if (> (length s) ww)
+           (concat (substring s 0 (- ww 3)) "...")
+         s))
+     cands "\n")))
+
+(defun ivy-format-function-arrow (cands)
+  "Transform CANDS into a string for minibuffer."
+  (let ((i -1))
+    (mapconcat
+     (lambda (s)
+       (concat (if (eq (cl-incf i) ivy--index)
+                   "> "
+                 "  ")
+               s))
+     cands "\n")))
+
 (defun ivy--format (cands)
   "Return a string for CANDS suitable for display in the minibuffer.
 CANDS is a list of strings."
 (defun ivy--format (cands)
   "Return a string for CANDS suitable for display in the minibuffer.
 CANDS is a list of strings."
@@ -1011,27 +1326,163 @@ CANDS is a list of strings."
     (let* ((half-height (/ ivy-height 2))
            (start (max 0 (- ivy--index half-height)))
            (end (min (+ start (1- ivy-height)) ivy--length))
     (let* ((half-height (/ ivy-height 2))
            (start (max 0 (- ivy--index half-height)))
            (end (min (+ start (1- ivy-height)) ivy--length))
+           (start (max 0 (min start (- end (1- ivy-height)))))
            (cands (cl-subseq cands start end))
            (cands (cl-subseq cands start end))
-           (index (min ivy--index half-height (1- (length cands)))))
+           (index (- ivy--index start)))
       (when ivy--directory
         (setq cands (mapcar (lambda (x)
       (when ivy--directory
         (setq cands (mapcar (lambda (x)
-                              (if (string-match-p "/$" x)
+                              (if (string-match-p "/\\'" x)
                                   (propertize x 'face 'ivy-subdir)
                                 x))
                             cands)))
       (setq ivy--current (copy-sequence (nth index cands)))
       (setf (nth index cands)
             (ivy--add-face ivy--current 'ivy-current-match))
                                   (propertize x 'face 'ivy-subdir)
                                 x))
                             cands)))
       (setq ivy--current (copy-sequence (nth index cands)))
       (setf (nth index cands)
             (ivy--add-face ivy--current 'ivy-current-match))
-      (let* ((ww (window-width))
-             (res (concat "\n" (mapconcat
-                                (lambda (s)
-                                  (if (> (length s) ww)
-                                      (concat (substring s 0 (- ww 3)) "...")
-                                    s))
-                                cands "\n"))))
+      (setq cands (mapcar
+                   (lambda (s)
+                     (let ((s (copy-sequence s)))
+                       (when (fboundp 'add-face-text-property)
+                         (add-face-text-property
+                          0 (length s)
+                          `(:height ,(face-attribute 'default :height)
+                                    :overline nil) nil s))
+                       s))
+                   cands))
+      (let* ((ivy--index index)
+             (res (concat "\n" (funcall ivy-format-function cands))))
         (put-text-property 0 (length res) 'read-only nil res)
         res))))
 
         (put-text-property 0 (length res) 'read-only nil res)
         res))))
 
+(defvar ivy--virtual-buffers nil
+  "Store the virtual buffers alist.")
+
+(defvar recentf-list)
+
+(defface ivy-virtual '((t :inherit font-lock-builtin-face))
+  "Face used by Ivy for matching virtual buffer names.")
+
+(defun ivy--virtual-buffers ()
+  "Adapted from `ido-add-virtual-buffers-to-list'."
+  (unless recentf-mode
+    (recentf-mode 1))
+  (let ((bookmarks (and (boundp 'bookmark-alist)
+                        bookmark-alist))
+        virtual-buffers name)
+    (dolist (head (append
+                   recentf-list
+                   (delete "   - no file -"
+                           (delq nil (mapcar (lambda (bookmark)
+                                               (cdr (assoc 'filename bookmark)))
+                                             bookmarks)))))
+      (setq name (file-name-nondirectory head))
+      (when (equal name "")
+        (setq name (file-name-nondirectory (directory-file-name head))))
+      (when (equal name "")
+        (setq name head))
+      (and (not (equal name ""))
+           (null (get-file-buffer head))
+           (not (assoc name virtual-buffers))
+           (push (cons name head) virtual-buffers)))
+    (when virtual-buffers
+      (dolist (comp virtual-buffers)
+        (put-text-property 0 (length (car comp))
+                           'face 'ivy-virtual
+                           (car comp)))
+      (setq ivy--virtual-buffers (nreverse virtual-buffers))
+      (mapcar #'car ivy--virtual-buffers))))
+
+(defun ivy--buffer-list (str &optional virtual)
+  "Return the buffers that match STR.
+When VIRTUAL is non-nil, add virtual buffers."
+  (delete-dups
+   (append
+    (mapcar
+     (lambda (x)
+       (if (with-current-buffer x
+             (file-remote-p
+              (abbreviate-file-name default-directory)))
+           (propertize x 'face 'ivy-remote)
+         x))
+     (all-completions str 'internal-complete-buffer))
+    (and virtual
+         (ivy--virtual-buffers)))))
+
+(defun ivy--switch-buffer-action (buffer)
+  "Switch to BUFFER.
+BUFFER may be a string or nil."
+  (if (zerop (length buffer))
+      (switch-to-buffer
+       ivy-text nil 'force-same-window)
+    (let ((virtual (assoc buffer ivy--virtual-buffers)))
+      (if (and virtual
+               (not (get-buffer buffer)))
+          (find-file (cdr virtual))
+        (switch-to-buffer
+         buffer nil 'force-same-window)))))
+
+(defun ivy-switch-buffer ()
+  "Switch to another buffer."
+  (interactive)
+  (if (not ivy-mode)
+      (call-interactively 'switch-to-buffer)
+    (ivy-read "Switch to buffer: " 'internal-complete-buffer
+              :preselect (buffer-name (other-buffer (current-buffer)))
+              :action #'ivy--switch-buffer-action)))
+
+(defun ivy-recentf ()
+  "Find a file on `recentf-list'."
+  (interactive)
+  (ivy-read "Recentf: " recentf-list
+            :action #'find-file))
+
+(defun ivy-yank-word ()
+  "Pull next word from buffer into search string."
+  (interactive)
+  (let (amend)
+    (with-selected-window (ivy-state-window ivy-last)
+      (let ((pt (point))
+            (le (line-end-position)))
+        (forward-word 1)
+        (if (> (point) le)
+            (goto-char pt)
+          (setq amend (buffer-substring-no-properties pt (point))))))
+    (when amend
+      (insert amend))))
+
+(defun ivy-insert-current ()
+  "Make the current candidate into current input.
+Don't finish completion."
+  (interactive)
+  (delete-minibuffer-contents)
+  (if (and ivy--directory
+           (string-match "/$" ivy--current))
+      (insert (substring ivy--current 0 -1))
+    (insert ivy--current)))
+
+(defun ivy-toggle-fuzzy ()
+  "Toggle the re builder between `ivy--regex-fuzzy' and `ivy--regex-plus'."
+  (interactive)
+  (setq ivy--old-re nil)
+  (if (eq ivy--regex-function 'ivy--regex-fuzzy)
+      (setq ivy--regex-function 'ivy--regex-plus)
+    (setq ivy--regex-function 'ivy--regex-fuzzy)))
+
+(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."
+  (interactive)
+  (let ((enable-recursive-minibuffers t)
+        (history (symbol-value (ivy-state-history ivy-last)))
+        (old-last ivy-last))
+    (ivy-read "Reverse-i-search: "
+              history
+              :action (lambda (x)
+                        (ivy--reset-state
+                         (setq ivy-last old-last))
+                        (delete-minibuffer-contents)
+                        (insert (substring-no-properties x))
+                        (ivy--cd-maybe)))))
+
 (provide 'ivy)
 
 ;;; ivy.el ends here
 (provide 'ivy)
 
 ;;; ivy.el ends here