]> code.delx.au - gnu-emacs-elpa/blobdiff - ivy.el
ivy.el (ivy--insert-prompt): Improve truncation
[gnu-emacs-elpa] / ivy.el
diff --git a/ivy.el b/ivy.el
index 4e646d0c7f7e4f767f7b4ef266e541df47947443..1bb332697d44728e615a62a2a51ec1610b3d1cfc 100644 (file)
--- a/ivy.el
+++ b/ivy.el
   :group 'convenience)
 
 (defface ivy-current-match
   :group 'convenience)
 
 (defface ivy-current-match
-  '((t (:inherit highlight)))
+  '((((class color) (background light))
+     :background "#1a4b77" :foreground "white")
+    (((class color) (background dark))
+     :background "#65a7e2" :foreground "black"))
   "Face used by Ivy for highlighting first match.")
 
 (defface ivy-confirm-face
   "Face used by Ivy for highlighting first match.")
 
 (defface ivy-confirm-face
 
 (defcustom ivy-count-format "%-4d "
   "The style of showing the current candidate count for `ivy-read'.
 
 (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."
-  :type 'string)
+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))
 
 (defcustom ivy-wrap nil
   "Whether to wrap around after the first and last candidate."
   :type 'boolean)
 
 
 (defcustom ivy-wrap nil
   "Whether to wrap around after the first and last candidate."
   :type 'boolean)
 
+(defcustom ivy-display-style nil
+  "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."
+  :type '(choice
+          (const :tag "Plain" nil)
+          (const :tag "Fancy" fancy)))
+
 (defcustom ivy-on-del-error-function 'minibuffer-keyboard-quit
   "The handler for when `ivy-backward-delete-char' throws.
 This is usually meant as a quick exit out of the minibuffer."
 (defcustom ivy-on-del-error-function 'minibuffer-keyboard-quit
   "The handler for when `ivy-backward-delete-char' throws.
 This is usually meant as a quick exit out of the minibuffer."
@@ -90,19 +106,29 @@ Only \"./\" and \"../\" apply here. They appear in reverse order."
   "When non-nil, add `recentf-mode' and bookmarks to the list of buffers."
   :type 'boolean)
 
   "When non-nil, add `recentf-mode' and bookmarks to the list of buffers."
   :type 'boolean)
 
+(defvar ivy--actions-list nil
+  "A list of extra actions per command.")
+
+(defun ivy-set-actions (cmd actions)
+  "Set CMD extra exit points to ACTIONS."
+  (setq ivy--actions-list
+        (plist-put ivy--actions-list cmd actions)))
+
 ;;* Keymap
 (require 'delsel)
 (defvar ivy-minibuffer-map
   (let ((map (make-sparse-keymap)))
     (define-key map (kbd "C-m") 'ivy-done)
 ;;* Keymap
 (require 'delsel)
 (defvar ivy-minibuffer-map
   (let ((map (make-sparse-keymap)))
     (define-key map (kbd "C-m") 'ivy-done)
+    (define-key map (kbd "C-M-m") 'ivy-call)
     (define-key map (kbd "C-j") 'ivy-alt-done)
     (define-key map (kbd "C-j") 'ivy-alt-done)
+    (define-key map (kbd "C-M-j") 'ivy-immediate-done)
     (define-key map (kbd "TAB") 'ivy-partial-or-done)
     (define-key map (kbd "C-n") 'ivy-next-line)
     (define-key map (kbd "C-p") 'ivy-previous-line)
     (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 "TAB") 'ivy-partial-or-done)
     (define-key map (kbd "C-n") 'ivy-next-line)
     (define-key map (kbd "C-p") 'ivy-previous-line)
     (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 "M-DEL") 'ivy-backward-kill-word)
     (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)
@@ -111,8 +137,6 @@ Only \"./\" and \"../\" apply here. They appear in reverse order."
     (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 "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 "<right>") 'ivy-end-of-buffer)
     (define-key map (kbd "M-n") 'ivy-next-history-element)
     (define-key map (kbd "M-p") 'ivy-previous-history-element)
     (define-key map (kbd "C-g") 'minibuffer-keyboard-quit)
     (define-key map (kbd "M-n") 'ivy-next-history-element)
     (define-key map (kbd "M-p") 'ivy-previous-history-element)
     (define-key map (kbd "C-g") 'minibuffer-keyboard-quit)
@@ -122,7 +146,12 @@ Only \"./\" and \"../\" apply here. They appear in reverse order."
     (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 "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-o") 'hydra-ivy/body)
+    (define-key map (kbd "M-o") 'ivy-dispatching-done)
+    (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)
     map)
   "Keymap used in the minibuffer.")
 (autoload 'hydra-ivy/body "ivy-hydra" "" t)
     map)
   "Keymap used in the minibuffer.")
 (autoload 'hydra-ivy/body "ivy-hydra" "" t)
@@ -221,6 +250,13 @@ When non-nil, it should contain one %d.")
                     ,@body))
      (minibuffer-keyboard-quit)))
 
                     ,@body))
      (minibuffer-keyboard-quit)))
 
+(defmacro with-ivy-window (&rest body)
+  "Execute BODY in the window from which `ivy-read' was called."
+  (declare (indent 0)
+           (debug t))
+  `(with-selected-window (ivy-state-window ivy-last)
+     ,@body))
+
 (defun ivy--done (text)
   "Insert TEXT and exit minibuffer."
   (if (and ivy--directory
 (defun ivy--done (text)
   "Insert TEXT and exit minibuffer."
   (if (and ivy--directory
@@ -254,6 +290,34 @@ When non-nil, it should contain one %d.")
          (insert ivy-text)
          (ivy--exhibit))))
 
          (insert ivy-text)
          (ivy--exhibit))))
 
+(defun ivy-dispatching-done ()
+  "Select one of the available actions and call `ivy-done'."
+  (interactive)
+  (let ((actions (ivy-state-action ivy-last)))
+    (if (null (ivy--actionp actions))
+        (ivy-done)
+      (let* ((hint (concat ivy--current
+                           "\n"
+                           (mapconcat
+                            (lambda (x)
+                              (format "%s: %s"
+                                      (propertize
+                                       (car x)
+                                       'face 'font-lock-builtin-face)
+                                      (nth 2 x)))
+                            (cdr actions)
+                            "\n")
+                           "\n"))
+             (key (string (read-key hint)))
+             (action (assoc key (cdr actions))))
+        (cond ((string= key "\a"))
+              ((null action)
+               (error "%s is not bound" key))
+              (t
+               (message "")
+               (ivy-set-action (nth 1 action))
+               (ivy-done)))))))
+
 (defun ivy-build-tramp-name (x)
   "Reconstruct X into a path.
 Is is a cons cell, related to `tramp-get-completion-function'."
 (defun ivy-build-tramp-name (x)
   "Reconstruct X into a path.
 Is is a cons cell, related to `tramp-get-completion-function'."
@@ -270,47 +334,59 @@ Is is a cons cell, related to `tramp-get-completion-function'."
   "Exit the minibuffer with the selected candidate.
 When ARG is t, exit with current text, ignoring the candidates."
   (interactive "P")
   "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))
-            ((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)))
-            ((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."
 
 (defcustom ivy-tab-space nil
   "When non-nil, `ivy-partial-or-done' should insert a space."
@@ -365,6 +441,7 @@ If the text hasn't changed as a result, forward to `ivy-alt-done'."
   (setq ivy-exit 'done)
   (exit-minibuffer))
 
   (setq ivy-exit 'done)
   (exit-minibuffer))
 
+;;;###autoload
 (defun ivy-resume ()
   "Resume the last completion session."
   (interactive)
 (defun ivy-resume ()
   "Resume the last completion session."
   (interactive)
@@ -419,6 +496,20 @@ If the text hasn't changed as a result, forward to `ivy-alt-done'."
   (ivy-set-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")
 (defun ivy-next-line (&optional arg)
   "Move cursor vertically down ARG candidates."
   (interactive "p")
@@ -458,16 +549,62 @@ If the input is empty, select the previous history element instead."
   (ivy-previous-line arg))
 
 (defun ivy-toggle-calling ()
   (ivy-previous-line arg))
 
 (defun ivy-toggle-calling ()
-  "Flip `ivy-calling'"
+  "Flip `ivy-calling'."
   (interactive)
   (when (setq ivy-calling (not ivy-calling))
     (ivy-call)))
 
   (interactive)
   (when (setq ivy-calling (not ivy-calling))
     (ivy-call)))
 
+(defun ivy--get-action (state)
+  "Get the action function from STATE."
+  (let ((action (ivy-state-action state)))
+    (when action
+      (if (functionp action)
+          action
+        (cadr (nth (car action) action))))))
+
+(defun ivy--actionp (x)
+  "Return non-nil when X is a list of actions."
+  (and x (listp x) (not (eq (car x) 'closure))))
+
+(defun ivy-next-action ()
+  "When the current action is a list, scroll it forwards."
+  (interactive)
+  (let ((action (ivy-state-action ivy-last)))
+    (when (ivy--actionp action)
+      (unless (>= (car action) (1- (length action)))
+        (cl-incf (car action))))))
+
+(defun ivy-prev-action ()
+  "When the current action is a list, scroll it backwards."
+  (interactive)
+  (let ((action (ivy-state-action ivy-last)))
+    (when (ivy--actionp action)
+      (unless (<= (car action) 1)
+        (cl-decf (car action))))))
+
+(defun ivy-action-name ()
+  "Return the name associated with the current action."
+  (let ((action (ivy-state-action ivy-last)))
+    (if (ivy--actionp action)
+        (format "[%d/%d] %s"
+                (car action)
+                (1- (length action))
+                (nth 2 (nth (car action) action)))
+      "[1/1] default")))
+
 (defun ivy-call ()
   "Call the current action without exiting completion."
 (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))))
+  (interactive)
+  (let ((action (ivy--get-action ivy-last)))
+    (when action
+      (let* ((collection (ivy-state-collection ivy-last))
+             (x (if (and (consp collection)
+                         (consp (car collection)))
+                    (cdr (assoc ivy--current collection))
+                  (if (equal ivy--current "")
+                      ivy-text
+                    ivy--current))))
+        (funcall action x)))))
 
 (defun ivy-next-line-and-call (&optional arg)
   "Move cursor vertically down ARG candidates.
 
 (defun ivy-next-line-and-call (&optional arg)
   "Move cursor vertically down ARG candidates.
@@ -489,6 +626,7 @@ Call the permanent action if possible."
   "Forward to `previous-history-element' with ARG."
   (interactive "p")
   (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))
 
@@ -496,9 +634,24 @@ Call the permanent action if possible."
   "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
@@ -556,6 +709,13 @@ On error (read-only), call `ivy-on-del-error-function'."
   (unless (= (point) (line-end-position))
     (kill-word arg)))
 
   (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)
 (defun ivy-backward-kill-word ()
   "Forward to `backward-kill-word'."
   (interactive)
@@ -567,7 +727,9 @@ On error (read-only), call `ivy-on-del-error-function'."
                     ivy--directory))))
         (ivy--exhibit))
     (ignore-errors
                     ivy--directory))))
         (ivy--exhibit))
     (ignore-errors
-      (backward-kill-word 1))))
+      (let ((pt (point)))
+        (forward-word -1)
+        (delete-region (point) pt)))))
 
 (defvar ivy--regexp-quote 'regexp-quote
   "Store the regexp quoting state.")
 
 (defvar ivy--regexp-quote 'regexp-quote
   "Store the regexp quoting state.")
@@ -593,9 +755,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
@@ -616,7 +785,13 @@ like.")
 
 (defvar ivy-initial-inputs-alist
   '((org-refile . "^")
 
 (defvar ivy-initial-inputs-alist
   '((org-refile . "^")
-    (counsel-M-x . "^"))
+    (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
   "Command to initial input table.")
 
 (defcustom ivy-sort-max-size 30000
@@ -653,7 +828,8 @@ Directories come first."
 
 PROMPT is a string to prompt with; normally it ends in a colon
 and a space.  When PROMPT contains %d, it will be updated with
 
 PROMPT is a string to prompt with; normally it ends in a colon
 and a space.  When PROMPT contains %d, it will be updated with
-the current number of matching candidates.
+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.
 See also `ivy-count-format'.
 
 COLLECTION is a list of strings.
@@ -680,9 +856,14 @@ MATCHER can completely override matching.
 
 DYNAMIC-COLLECTION is a function to call to update the list of
 candidates with each input."
 
 DYNAMIC-COLLECTION is a function to call to update the list of
 candidates with each input."
-  (unless initial-input
-    (setq initial-input (cdr (assoc this-command
-                                    ivy-initial-inputs-alist))))
+  (let ((extra-actions (plist-get ivy--actions-list this-command)))
+    (when extra-actions
+      (setq action
+            (if (functionp action)
+                `(1
+                  ("o" ,action "default")
+                  ,@extra-actions)
+              (delete-dups (append action extra-actions))))))
   (setq ivy-last
         (make-ivy-state
          :prompt prompt
   (setq ivy-last
         (make-ivy-state
          :prompt prompt
@@ -701,110 +882,159 @@ candidates with each input."
          :re-builder re-builder
          :matcher matcher
          :dynamic-collection dynamic-collection))
          :re-builder re-builder
          :matcher matcher
          :dynamic-collection dynamic-collection))
-  (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-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)
+  (ivy--reset-state ivy-last)
+  (prog1
+      (unwind-protect
+           (minibuffer-with-setup-hook
+               #'ivy--minibuffer-setup
+             (let* ((hist (or history 'ivy-history))
+                    (minibuffer-completion-table collection)
+                    (minibuffer-completion-predicate predicate)
+                    (resize-mini-windows (cond
+                                          ((display-graphic-p) nil)
+                                          ((null resize-mini-windows) 'grow-only)
+                                          (t resize-mini-windows)))
+                    (res (read-from-minibuffer
+                          prompt
+                          (ivy-state-initial-input ivy-last)
+                          (make-composed-keymap keymap ivy-minibuffer-map)
+                          nil
+                          hist)))
+               (when (eq ivy-exit 'done)
+                 (let ((item (if ivy--directory
+                                 ivy--current
+                               ivy-text)))
+                   (unless (equal item "")
+                     (set hist (cons (propertize item 'ivy-index ivy--index)
+                                     (delete item
+                                             (cdr (symbol-value hist)))))))
+                 res)))
+        (remove-hook 'post-command-hook #'ivy--exhibit)
+        (when (setq unwind (ivy-state-unwind ivy-last))
+          (funcall unwind)))
+    (ivy-call)))
+
+(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))
+        (matcher (ivy-state-matcher 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)
+             (when preselect
+               (let ((preselect-directory (file-name-directory preselect)))
+                 (unless (or (null preselect-directory)
+                             (string= preselect-directory
+                                      default-directory))
+                   (setq ivy--directory preselect-directory))
+                 (setq preselect (file-name-nondirectory preselect))))
+             (setq coll (ivy--sorted-files ivy--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)
+                 (byte-code-function-p 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 matcher))
+                        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
           (cond ((string-match "%.*d" prompt)
                  prompt)
     (setq ivy-exit nil)
     (setq ivy--default (or (thing-at-point 'symbol) ""))
     (setq ivy--prompt
           (cond ((string-match "%.*d" prompt)
                  prompt)
+                ((null ivy-count-format)
+                 nil)
+                ((string-match "%d.*%d" ivy-count-format)
+                 (let ((w (length (number-to-string
+                                   (length ivy--all-candidates))))
+                       (s (copy-sequence ivy-count-format)))
+                   (string-match "%d" s)
+                   (match-end 0)
+                   (string-match "%d" s (match-end 0))
+                   (setq s (replace-match (format "%%-%dd" w) nil nil s))
+                   (string-match "%d" s)
+                   (concat (replace-match (format "%%%dd" w) nil nil s)
+                           prompt)))
                 ((string-match "%.*d" ivy-count-format)
                  (concat ivy-count-format prompt))
                 (ivy--directory
                  prompt)
                 (t
                  nil)))
                 ((string-match "%.*d" ivy-count-format)
                  (concat ivy-count-format prompt))
                 (ivy--directory
                  prompt)
                 (t
                  nil)))
-    (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
-                            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 ivy--current)))))
+    (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)
 (defun ivy-completing-read (prompt collection
                             &optional predicate require-match initial-input
                               history def _inherit-input-method)
@@ -823,16 +1053,25 @@ DEF is the default value.
 _INHERIT-INPUT-METHOD is ignored for now.
 
 The history, defaults and input-method arguments are ignored for now."
 _INHERIT-INPUT-METHOD is ignored for now.
 
 The history, defaults and input-method arguments are ignored for now."
-  (ivy-read prompt collection
+  (ivy-read (replace-regexp-in-string "%" "%%" prompt)
+            collection
             :predicate predicate
             :require-match require-match
             :initial-input (if (consp initial-input)
                                (car initial-input)
             :predicate predicate
             :require-match require-match
             :initial-input (if (consp initial-input)
                                (car initial-input)
-                             initial-input)
+                             (if (and (stringp initial-input)
+                                      (string-match "\\+" initial-input))
+                                 (replace-regexp-in-string
+                                  "\\+" "\\\\+" 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
@@ -854,15 +1093,21 @@ Minibuffer bindings:
       (setq completing-read-function 'ivy-completing-read)
     (setq completing-read-function 'completing-read-default)))
 
       (setq completing-read-function 'ivy-completing-read)
     (setq completing-read-function 'completing-read-default)))
 
-(defun ivy--preselect-index (candidates initial-input preselect)
-  "Return the index in CANDIDATES filtered by INITIAL-INPUT for PRESELECT."
-  (when initial-input
-    (setq initial-input (ivy--regex-plus initial-input))
-    (setq candidates
-          (cl-remove-if-not
-           (lambda (x)
-             (string-match initial-input x))
-           candidates)))
+(defun ivy--preselect-index (candidates initial-input preselect matcher)
+  "Return the index in CANDIDATES filtered by INITIAL-INPUT for PRESELECT.
+When MATCHER is non-nil it's used instead of `cl-remove-if-not'."
+  (if initial-input
+      (progn
+        (setq initial-input (ivy--regex-plus initial-input))
+        (setq candidates
+              (if matcher
+                  (funcall matcher initial-input candidates)
+                (cl-remove-if-not
+                 (lambda (x)
+                   (string-match initial-input x))
+                 candidates))))
+    (when matcher
+      (setq candidates (funcall matcher "" candidates))))
   (or (cl-position preselect candidates :test #'equal)
       (cl-position-if
        (lambda (x)
   (or (cl-position preselect candidates :test #'equal)
       (cl-position-if
        (lambda (x)
@@ -914,6 +1159,8 @@ When GREEDY is non-nil, join words in a greedy way."
     (if hashed
         (prog1 (cdr hashed)
           (setq ivy--subexps (car hashed)))
     (if hashed
         (prog1 (cdr hashed)
           (setq ivy--subexps (car hashed)))
+      (when (string-match "\\([^\\]\\|^\\)\\\\$" str)
+        (setq str (substring str 0 -1)))
       (cdr (puthash str
                     (let ((subs (ivy--split str)))
                       (if (= (length subs) 1)
       (cdr (puthash str
                     (let ((subs (ivy--split str)))
                       (if (= (length subs) 1)
@@ -987,6 +1234,8 @@ Insert .* between each char."
   (set (make-local-variable 'minibuffer-default-add-function)
        (lambda ()
          (list ivy--default)))
   (set (make-local-variable 'minibuffer-default-add-function)
        (lambda ()
          (list ivy--default)))
+  (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)
   ;; show completions with empty input
   (setq-local max-mini-window-height ivy-height)
   (add-hook 'post-command-hook #'ivy--exhibit nil t)
   ;; show completions with empty input
@@ -1021,24 +1270,34 @@ Insert .* between each char."
       (let ((inhibit-read-only t)
             (std-props '(front-sticky t rear-nonsticky t field t read-only t))
             (n-str
       (let ((inhibit-read-only t)
             (std-props '(front-sticky t rear-nonsticky t field t read-only t))
             (n-str
-             (format
+             (concat
+              (if (and (bound-and-true-p minibuffer-depth-indicate-mode)
+                       (> (minibuffer-depth) 1))
+                  (format "[%d] " (minibuffer-depth))
+                "")
               (concat
               (concat
-               (if (and (bound-and-true-p minibuffer-depth-indicate-mode)
-                        (> (minibuffer-depth) 1))
-                   (format "[%d] " (minibuffer-depth))
-                 "")
-               head
+               (if (string-match "%d.*%d" ivy-count-format)
+                   (format head
+                           (1+ ivy--index)
+                           (or (and (ivy-state-dynamic-collection ivy-last)
+                                    ivy--full-length)
+                               ivy--length))
+                 (format head
+                         (or (and (ivy-state-dynamic-collection ivy-last)
+                                  ivy--full-length)
+                             ivy--length)))
                ivy--prompt-extra
                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))))
+               tail)
+              (if ivy--directory
+                  (abbreviate-file-name ivy--directory)
+                ""))))
         (save-excursion
           (goto-char (point-min))
           (delete-region (point-min) (minibuffer-prompt-end))
         (save-excursion
           (goto-char (point-min))
           (delete-region (point-min) (minibuffer-prompt-end))
+          (when (> (length n-str) (- (window-width) 35))
+            (setq n-str (concat (substring n-str 0
+                                           (max (- (window-width) 35)
+                                                10)) "... ")))
           (set-text-properties 0 (length n-str)
                                `(face minibuffer-prompt ,@std-props)
                                n-str)
           (set-text-properties 0 (length n-str)
                                `(face minibuffer-prompt ,@std-props)
                                n-str)
@@ -1061,46 +1320,72 @@ Insert .* between each char."
 
 (defvar inhibit-message)
 
 
 (defvar inhibit-message)
 
+(defun ivy--sort-maybe (collection)
+  "Sort COLLECTION if needed."
+  (let ((sort (ivy-state-sort ivy-last))
+        entry)
+    (if (null sort)
+        collection
+      (let ((sort-fn (cond ((functionp sort)
+                            sort)
+                           ((setq entry (assoc (ivy-state-collection ivy-last)
+                                               ivy-sort-functions-alist))
+                            (cdr entry))
+                           (t
+                            (cdr (assoc t ivy-sort-functions-alist))))))
+        (if (functionp sort-fn)
+            (cl-sort (copy-sequence collection) sort-fn)
+          collection)))))
+
 (defun ivy--exhibit ()
   "Insert Ivy completions display.
 Should be run via minibuffer `post-command-hook'."
 (defun ivy--exhibit ()
   "Insert Ivy completions display.
 Should be run via minibuffer `post-command-hook'."
-  (setq ivy-text (ivy--input))
-  (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))
-        (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
-           (if (string-match "/\\'" ivy-text)
-               (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)
-                 (ivy--cd (expand-file-name "~/")))))
-          ((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
-                   (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
-      (ivy--filter ivy-text ivy--all-candidates)))
-    (setq ivy--old-text ivy-text)))
+  (when (memq 'ivy--exhibit post-command-hook)
+    (setq ivy-text (ivy--input))
+    (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))
+          (unless (equal ivy--old-text ivy-text)
+            (while-no-input
+              (setq ivy--all-candidates
+                    (ivy--sort-maybe
+                     (funcall (ivy-state-collection ivy-last) ivy-text)))
+              (setq ivy--old-text ivy-text)))
+          (when ivy--all-candidates
+            (ivy--insert-minibuffer
+             (ivy--format ivy--all-candidates))))
+      (cond (ivy--directory
+             (if (string-match "/\\'" ivy-text)
+                 (if (member ivy-text ivy--all-candidates)
+                     (ivy--cd (expand-file-name ivy-text ivy--directory))
+                   (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 "~/")))))
+            ((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
+                     (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
+        (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."
@@ -1116,7 +1401,23 @@ Should be run via minibuffer `post-command-hook'."
       (let ((buffer-undo-list t))
         (save-excursion
           (forward-line 1)
       (let ((buffer-undo-list t))
         (save-excursion
           (forward-line 1)
-          (insert text))))))
+          (insert text))))
+    (when (display-graphic-p)
+      (ivy--resize-minibuffer-to-fit))))
+
+(defun ivy--resize-minibuffer-to-fit ()
+  "Resize the minibuffer window so it has enough space to display
+all of the text contained in the minibuffer."
+  (with-selected-window (minibuffer-window)
+    (if (fboundp 'window-text-pixel-size)
+        (let ((text-height (cdr (window-text-pixel-size)))
+              (body-height (window-body-height nil t)))
+          (when (> text-height body-height)
+            (window-resize nil (- text-height body-height) nil t t)))
+        (let ((text-height (count-screen-lines))
+              (body-height (window-body-height)))
+          (when (> text-height body-height)
+            (window-resize nil (- text-height body-height) nil t))))))
 
 (declare-function colir-blend-face-background "ext:colir")
 
 
 (declare-function colir-blend-face-background "ext:colir")
 
@@ -1126,7 +1427,15 @@ Should be run via minibuffer `post-command-hook'."
 `propertize' or `add-face-text-property' in this case."
   (require 'colir)
   (condition-case nil
 `propertize' or `add-face-text-property' in this case."
   (require 'colir)
   (condition-case nil
-      (colir-blend-face-background 0 (length str) face str)
+      (progn
+        (colir-blend-face-background 0 (length str) face str)
+        (let ((foreground (face-foreground face)))
+          (when foreground
+            (add-face-text-property
+             0 (length str)
+             `(:foreground ,foreground)
+             nil
+             str))))
     (error
      (ignore-errors
        (font-lock-append-text-property 0 (length str) 'face face str))))
     (error
      (ignore-errors
        (font-lock-append-text-property 0 (length str) 'face face str))))
@@ -1136,7 +1445,9 @@ 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))
+         (re-str (if (listp re) (caar re) re))
          (matcher (ivy-state-matcher ivy-last))
          (matcher (ivy-state-matcher ivy-last))
+         (case-fold-search (string= name (downcase name)))
          (cands (cond
                   (matcher
                    (funcall matcher re candidates))
          (cands (cond
                   (matcher
                    (funcall matcher re candidates))
@@ -1174,15 +1485,18 @@ CANDIDATES are assumed to be static."
                      res))))
          (tail (nthcdr ivy--index ivy--old-cands))
          idx)
                      res))))
          (tail (nthcdr ivy--index ivy--old-cands))
          idx)
-    (when (and tail ivy--old-cands)
-      (unless (and (not (equal re ivy--old-re))
+    (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
                    (or (setq ivy--index
                              (or
-                              (cl-position re cands
-                                           :test #'equal)
+                              (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
                               (and ivy--directory
                                    (cl-position
-                                    (concat re "/") cands
+                                    (concat re-str "/") cands
                                     :test #'equal))))))
         (while (and tail (null idx))
           ;; Compare with eq to handle equal duplicates in cands
                                     :test #'equal))))))
         (while (and tail (null idx))
           ;; Compare with eq to handle equal duplicates in cands
@@ -1193,7 +1507,7 @@ CANDIDATES are assumed to be static."
             (or (cl-position (ivy-state-preselect ivy-last)
                              cands :test #'equal)
                 ivy--index)))
             (or (cl-position (ivy-state-preselect ivy-last)
                              cands :test #'equal)
                 ivy--index)))
-    (setq ivy--old-re (if cands re ""))
+    (setq ivy--old-re (if cands re-str ""))
     (setq ivy--old-cands cands)))
 
 (defvar ivy-format-function 'ivy-format-function-default
     (setq ivy--old-cands cands)))
 
 (defvar ivy-format-function 'ivy-format-function-default
@@ -1202,13 +1516,16 @@ This string will be inserted into the minibuffer.")
 
 (defun ivy-format-function-default (cands)
   "Transform CANDS into a string for 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")))
+  (if (bound-and-true-p truncate-lines)
+      (mapconcat #'identity cands "\n")
+    (let ((ww (- (window-width)
+                 (if (and (boundp 'fringe-mode) (eq fringe-mode 0)) 1 0))))
+      (mapconcat
+       (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."
 
 (defun ivy-format-function-arrow (cands)
   "Transform CANDS into a string for minibuffer."
@@ -1216,11 +1533,53 @@ This string will be inserted into the minibuffer.")
     (mapconcat
      (lambda (s)
        (concat (if (eq (cl-incf i) ivy--index)
     (mapconcat
      (lambda (s)
        (concat (if (eq (cl-incf i) ivy--index)
-                   "==> "
-                 "    ")
+                   "> "
+                 "  ")
                s))
      cands "\n")))
 
                s))
      cands "\n")))
 
+(defcustom swiper-minibuffer-faces
+  '(swiper-minibuffer-match-face-1
+    swiper-minibuffer-match-face-2
+    swiper-minibuffer-match-face-3
+    swiper-minibuffer-match-face-4)
+  "List of `swiper' faces for minibuffer group matches.")
+
+(defun ivy--format-minibuffer-line (str)
+  (let ((start 0)
+        (str (copy-sequence str)))
+    (when (eq ivy-display-style 'fancy)
+      (unless ivy--old-re
+        (setq ivy--old-re (funcall ivy--regex-function ivy-text)))
+      (while (and (string-match ivy--old-re str start)
+                  (> (- (match-end 0) (match-beginning 0)) 0))
+        (setq start (match-end 0))
+        (let ((i 0))
+          (while (<= i ivy--subexps)
+            (let ((face
+                   (cond ((zerop ivy--subexps)
+                          (cadr swiper-minibuffer-faces))
+                         ((zerop i)
+                          (car swiper-minibuffer-faces))
+                         (t
+                          (nth (1+ (mod (+ i 2) (1- (length swiper-minibuffer-faces))))
+                               swiper-minibuffer-faces)))))
+              (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))
+
 (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."
@@ -1232,8 +1591,9 @@ 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)
                               (if (string-match-p "/\\'" x)
       (when ivy--directory
         (setq cands (mapcar (lambda (x)
                               (if (string-match-p "/\\'" x)
@@ -1241,8 +1601,11 @@ CANDS is a list of strings."
                                 x))
                             cands)))
       (setq ivy--current (copy-sequence (nth index cands)))
                                 x))
                             cands)))
       (setq ivy--current (copy-sequence (nth index cands)))
+      (setq cands (mapcar
+                   #'ivy--format-minibuffer-line
+                   cands))
       (setf (nth index cands)
       (setf (nth index cands)
-            (ivy--add-face ivy--current 'ivy-current-match))
+            (ivy--add-face (nth index cands) 'ivy-current-match))
       (let* ((ivy--index index)
              (res (concat "\n" (funcall ivy-format-function cands))))
         (put-text-property 0 (length res) 'read-only nil res)
       (let* ((ivy--index index)
              (res (concat "\n" (funcall ivy-format-function cands))))
         (put-text-property 0 (length res) 'read-only nil res)
@@ -1304,37 +1667,78 @@ When VIRTUAL is non-nil, add virtual buffers."
 
 (defun ivy--switch-buffer-action (buffer)
   "Switch to BUFFER.
 
 (defun ivy--switch-buffer-action (buffer)
   "Switch to BUFFER.
+BUFFER may be a string or nil."
+  (with-ivy-window
+    (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-other-window-action (buffer)
+  "Switch to BUFFER in other window.
 BUFFER may be a string or nil."
   (if (zerop (length buffer))
 BUFFER may be a string or nil."
   (if (zerop (length buffer))
-      (switch-to-buffer
-       ivy-text nil 'force-same-window)
+      (switch-to-buffer-other-window ivy-text)
     (let ((virtual (assoc buffer ivy--virtual-buffers)))
       (if (and virtual
                (not (get-buffer buffer)))
     (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)))))
+          (find-file-other-window (cdr virtual))
+        (switch-to-buffer-other-window buffer)))))
+
+(defun ivy--rename-buffer-action (buffer)
+  "Rename BUFFER."
+  (let ((new-name (read-string "Rename buffer (to new name): ")))
+    (with-current-buffer buffer
+      (rename-buffer new-name))))
+
+(defvar ivy-switch-buffer-map (make-sparse-keymap))
+
+(ivy-set-actions
+ 'ivy-switch-buffer
+ '(("k"
+    (lambda (x)
+      (kill-buffer x)
+      (ivy--reset-state ivy-last))
+    "kill")
+   ("j"
+    ivy--switch-buffer-other-window-action
+    "other")
+   ("r"
+    ivy--rename-buffer-action
+    "rename")))
 
 
+;;;###autoload
 (defun ivy-switch-buffer ()
   "Switch to another buffer."
   (interactive)
   (if (not ivy-mode)
       (call-interactively 'switch-to-buffer)
 (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)))
+    (let ((this-command 'ivy-switch-buffer))
+      (ivy-read "Switch to buffer: " 'internal-complete-buffer
+                :preselect (buffer-name (other-buffer (current-buffer)))
+                :action #'ivy--switch-buffer-action
+                :keymap ivy-switch-buffer-map))))
 
 
+;;;###autoload
 (defun ivy-recentf ()
   "Find a file on `recentf-list'."
   (interactive)
   (ivy-read "Recentf: " recentf-list
 (defun ivy-recentf ()
   "Find a file on `recentf-list'."
   (interactive)
   (ivy-read "Recentf: " recentf-list
-            :action #'find-file))
+            :action
+            (lambda (f)
+              (with-ivy-window
+                (find-file f)))))
 
 (defun ivy-yank-word ()
   "Pull next word from buffer into search string."
   (interactive)
   (let (amend)
 
 (defun ivy-yank-word ()
   "Pull next word from buffer into search string."
   (interactive)
   (let (amend)
-    (with-selected-window (ivy-state-window ivy-last)
+    (with-ivy-window
       (let ((pt (point))
             (le (line-end-position)))
         (forward-word 1)
       (let ((pt (point))
             (le (line-end-position)))
         (forward-word 1)
@@ -1344,6 +1748,59 @@ BUFFER may be a string or nil."
     (when amend
       (insert amend))))
 
     (when amend
       (insert amend))))
 
+(defun ivy-kill-ring-save ()
+  "Store the current candidates into the kill ring.
+If the region is active, forward to `kill-ring-save' instead."
+  (interactive)
+  (if (region-active-p)
+      (call-interactively 'kill-ring-save)
+    (kill-new
+     (mapconcat
+      #'identity
+      ivy--old-cands
+      "\n"))))
+
+(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)))))
+
+(defun ivy-restrict-to-matches ()
+  "Restrict candidates to current matches and erase input."
+  (interactive)
+  (delete-minibuffer-contents)
+  (setq ivy--all-candidates
+        (ivy--filter ivy-text ivy--all-candidates)))
+
 (provide 'ivy)
 
 ;;; ivy.el ends here
 (provide 'ivy)
 
 ;;; ivy.el ends here