]> code.delx.au - gnu-emacs-elpa/blobdiff - ivy.el
Fix Custom menus
[gnu-emacs-elpa] / ivy.el
diff --git a/ivy.el b/ivy.el
index dc6c412fe2aa67581d2c3803fcc1f34a5551b920..3c0f229114fca3ba7e2be02f31d17da6a0985b03 100644 (file)
--- a/ivy.el
+++ b/ivy.el
   :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
 
 (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 \"\" if you don't want the count.  You can also set
+it to e.g. \"(%d/%d) \" if you want to see both the candidate
+index and the candidate count."
+  :type '(choice
+          (const :tag "Count disabled" "")
+          (const :tag "Count matches" "%-4d ")
+          (const :tag "Count matches and show current match" "(%d/%d) ")
+          string))
 
 (defcustom ivy-wrap nil
   "Whether to wrap around after the first and last candidate."
   :type 'boolean)
 
+(defcustom ivy-display-style (unless (version< emacs-version "24.5") 'fancy)
+  "The style for formatting the minibuffer.
+
+By default, the matched strings will be copied as they are.
+
+With the fancy method, the matching parts of the regexp will be
+additionally highlighted, just like `swiper' does it.
+
+This setting depends on `add-face-text-property' - a C function
+available as of 24.5. It will behave poorly in earlier Emacs
+versions."
+  :type '(choice
+          (const :tag "Plain" nil)
+          (const :tag "Fancy" fancy)))
+
 (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."
@@ -84,10 +108,13 @@ This is usually meant as a quick exit out of the minibuffer."
 (defcustom ivy-extra-directories '("../" "./")
   "Add this to the front of the list when completing file names.
 Only \"./\" and \"../\" apply here. They appear in reverse order."
-  :type 'list)
+  :type '(repeat :tag "Dirs"
+          (choice
+           (const :tag "Parent Directory" "../")
+           (const :tag "Current Directory" "./"))))
 
 (defcustom ivy-use-virtual-buffers nil
-  "When non-nil, add `recentf-mode' and bookmarks to the list of buffers."
+  "When non-nil, add `recentf-mode' and bookmarks to `ivy-switch-buffer'."
   :type 'boolean)
 
 (defvar ivy--actions-list nil
@@ -103,7 +130,9 @@ Only \"./\" and \"../\" apply here. They appear in reverse order."
 (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-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)
@@ -119,8 +148,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 "<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)
@@ -132,8 +159,12 @@ Only \"./\" and \"../\" apply here. They appear in reverse order."
     (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 "M-o") 'ivy-dispatching-done)
+    (define-key map (kbd "C-M-o") 'ivy-dispatching-call)
     (define-key map (kbd "C-k") 'ivy-kill-line)
     (define-key map (kbd "S-SPC") 'ivy-restrict-to-matches)
+    (define-key map (kbd "M-w") 'ivy-kill-ring-save)
+    (define-key map (kbd "C-'") 'ivy-avy)
     map)
   "Keymap used in the minibuffer.")
 (autoload 'hydra-ivy/body "ivy-hydra" "" t)
@@ -156,10 +187,14 @@ Only \"./\" and \"../\" apply here. They appear in reverse order."
   re-builder
   matcher
   ;; When this is non-nil, call it for each input change to get new candidates
-  dynamic-collection)
+  dynamic-collection
+  caller)
 
 (defvar ivy-last nil
-  "The last parameters passed to `ivy-read'.")
+  "The last parameters passed to `ivy-read'.
+
+This should eventually become a stack so that you could use
+`ivy-read' recursively.")
 
 (defsubst ivy-set-action (action)
   (setf (ivy-state-action ivy-last) action))
@@ -220,6 +255,9 @@ When non-nil, it should contain one %d.")
 (defvar ivy--old-text ""
   "Store old `ivy-text' for dynamic completion.")
 
+(defvar ivy-case-fold-search 'auto
+  "Store the current overriding `case-fold-search'.")
+
 (defvar Info-current-file)
 
 (defmacro ivy-quit-and-run (&rest body)
@@ -232,6 +270,13 @@ When non-nil, it should contain one %d.")
                     ,@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
@@ -265,6 +310,49 @@ When non-nil, it should contain one %d.")
          (insert ivy-text)
          (ivy--exhibit))))
 
+(defun ivy-read-action ()
+  "Change the action to one of the available ones."
+  (interactive)
+  (let ((actions (ivy-state-action ivy-last)))
+    (unless (null (ivy--actionp actions))
+      (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-idx (cl-position-if
+                          (lambda (x) (equal (car x) key))
+                          (cdr actions))))
+        (cond ((string= key "\a"))
+              ((null action-idx)
+               (error "%s is not bound" key))
+              (t
+               (message "")
+               (setcar actions (1+ action-idx))
+               (ivy-set-action actions)))))))
+
+(defun ivy-dispatching-done ()
+  "Select one of the available actions and call `ivy-done'."
+  (interactive)
+  (ivy-read-action)
+  (ivy-done))
+
+(defun ivy-dispatching-call ()
+  "Select one of the available actions and call `ivy-call'."
+  (interactive)
+  (let ((actions (copy-sequence (ivy-state-action ivy-last))))
+    (ivy-read-action)
+    (ivy-call)
+    (ivy-set-action actions)))
+
 (defun ivy-build-tramp-name (x)
   "Reconstruct X into a path.
 Is is a cons cell, related to `tramp-get-completion-function'."
@@ -366,7 +454,10 @@ If the text hasn't changed as a result, forward to `ivy-alt-done'."
          (new (try-completion (if startp
                                   (substring postfix 1)
                                 postfix)
-                              (mapcar (lambda (str) (substring str (string-match postfix str)))
+                              (mapcar (lambda (str)
+                                        (let ((i (string-match postfix str)))
+                                          (when i
+                                            (substring str i))))
                                       ivy--old-cands))))
     (cond ((eq new t) nil)
           ((string= new ivy-text) nil)
@@ -388,6 +479,7 @@ If the text hasn't changed as a result, forward to `ivy-alt-done'."
   (setq ivy-exit 'done)
   (exit-minibuffer))
 
+;;;###autoload
 (defun ivy-resume ()
   "Resume the last completion session."
   (interactive)
@@ -400,7 +492,7 @@ If the text hasn't changed as a result, forward to `ivy-alt-done'."
    :history (ivy-state-history ivy-last)
    :preselect (unless (eq (ivy-state-collection ivy-last)
                           'read-file-name-internal)
-                (regexp-quote ivy--current))
+                ivy--current)
    :keymap (ivy-state-keymap ivy-last)
    :update-fn (ivy-state-update-fn ivy-last)
    :sort (ivy-state-sort ivy-last)
@@ -408,7 +500,8 @@ If the text hasn't changed as a result, forward to `ivy-alt-done'."
    :unwind (ivy-state-unwind ivy-last)
    :re-builder (ivy-state-re-builder ivy-last)
    :matcher (ivy-state-matcher ivy-last)
-   :dynamic-collection (ivy-state-dynamic-collection ivy-last)))
+   :dynamic-collection (ivy-state-dynamic-collection ivy-last)
+   :caller (ivy-state-caller ivy-last)))
 
 (defvar ivy-calling nil
   "When non-nil, call the current action when `ivy--index' changes.")
@@ -441,8 +534,9 @@ If the text hasn't changed as a result, forward to `ivy-alt-done'."
   (interactive)
   (ivy-set-index (max (- ivy--index ivy-height)
                       0)))
+
 (defun ivy-minibuffer-grow ()
-  "Grow the minibuffer window by 1 line"
+  "Grow the minibuffer window by 1 line."
   (interactive)
   (setq-local max-mini-window-height
               (cl-incf ivy-height)))
@@ -494,7 +588,7 @@ If the input is empty, select the previous history element instead."
   (ivy-previous-line arg))
 
 (defun ivy-toggle-calling ()
-  "Flip `ivy-calling'"
+  "Flip `ivy-calling'."
   (interactive)
   (when (setq ivy-calling (not ivy-calling))
     (ivy-call)))
@@ -534,15 +628,27 @@ If the input is empty, select the previous history element instead."
         (format "[%d/%d] %s"
                 (car action)
                 (1- (length action))
-                (car (nth (car action) action)))
+                (nth 2 (nth (car action) action)))
       "[1/1] default")))
 
 (defun ivy-call ()
   "Call the current action without exiting completion."
+  (interactive)
   (let ((action (ivy--get-action ivy-last)))
     (when action
-      (with-selected-window (ivy-state-window ivy-last)
-        (funcall action ivy--current)))))
+      (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))))
+        (prog1 (funcall action x)
+          (unless (or (eq ivy-exit 'done)
+                      (equal (selected-window)
+                             (active-minibuffer-window))
+                      (null (active-minibuffer-window)))
+            (select-window (active-minibuffer-window))))))))
 
 (defun ivy-next-line-and-call (&optional arg)
   "Move cursor vertically down ARG candidates.
@@ -665,7 +771,9 @@ On error (read-only), call `ivy-on-del-error-function'."
                     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.")
@@ -676,6 +784,52 @@ On error (read-only), call `ivy-on-del-error-function'."
   (setq ivy--old-re nil)
   (cl-rotatef ivy--regex-function ivy--regexp-quote))
 
+(defvar avy-all-windows)
+(defvar avy-action)
+(defvar avy-keys)
+(defvar avy-keys-alist)
+(defvar avy-style)
+(defvar avy-styles-alist)
+(declare-function avy--process "ext:avy")
+(declare-function avy--style-fn "ext:avy")
+
+(eval-after-load 'avy
+  '(add-to-list 'avy-styles-alist '(ivy-avy . pre)))
+
+(defun ivy-avy ()
+  "Jump to one of the current ivy candidates."
+  (interactive)
+  (unless (require 'avy nil 'noerror)
+    (error "Package avy isn't installed"))
+  (let* ((avy-all-windows nil)
+         (avy-keys (or (cdr (assq 'ivy-avy avy-keys-alist))
+                       avy-keys))
+         (avy-style (or (cdr (assq 'ivy-avy
+                                   avy-styles-alist))
+                        avy-style))
+         (candidate
+          (let ((candidates))
+            (save-excursion
+              (save-restriction
+                (narrow-to-region
+                 (window-start)
+                 (window-end))
+                (goto-char (point-min))
+                (forward-line)
+                (while (< (point) (point-max))
+                  (push
+                   (cons (point)
+                         (selected-window))
+                   candidates)
+                  (forward-line))))
+            (setq avy-action #'identity)
+            (avy--process
+             (nreverse candidates)
+             (avy--style-fn avy-style)))))
+    (ivy-set-index (- (line-number-at-pos candidate) 2))
+    (ivy--exhibit)
+    (ivy-done)))
+
 (defun ivy-sort-file-function-default (x y)
   "Compare two files X and Y.
 Prioritize directories."
@@ -687,7 +841,7 @@ Prioritize directories."
         nil
       (string< x y))))
 
-(defvar ivy-sort-functions-alist
+(defcustom ivy-sort-functions-alist
   '((read-file-name-internal . ivy-sort-file-function-default)
     (internal-complete-buffer . nil)
     (counsel-git-grep-function . nil)
@@ -697,11 +851,31 @@ Prioritize directories."
   "An alist of sorting functions for each collection function.
 Interactive functions that call completion fit in here as well.
 
-For each entry, nil means no sorting. It's very useful to turn
+For each entry, nil means no sorting.  It's very useful to turn
 off the sorting for functions that have candidates in the natural
 buffer order, like `org-refile' or `Man-goto-section'.
 
-The entry associated to t is used for all fall-through cases.")
+The entry associated to t is used for all fall-through cases."
+  :type
+  '(alist
+    :key-type (choice
+               (const :tag "All other functions" t)
+               (symbol :tag "Function"))
+    :value-type (choice
+                 (const :tag "plain sort" string-lessp)
+                 (const :tag "file sort" ivy-sort-file-function-default)
+                 (const :tag "no sort" nil)))
+  :group 'ivy)
+
+(defvar ivy-index-functions-alist
+  '((swiper . ivy-recompute-index-swiper)
+    (swiper-multi . ivy-recompute-index-swiper)
+    (counsel-git-grep . ivy-recompute-index-swiper)
+    (t . ivy-recompute-index-zero))
+  "An alist of index recomputing functions for each collection function.
+When the input changes, calling the appropriate function will
+return an integer - the index of the matched candidate that
+should be selected.")
 
 (defvar ivy-re-builders-alist
   '((t . ivy--regex-plus))
@@ -759,15 +933,17 @@ Directories come first."
 (cl-defun ivy-read (prompt collection
                     &key predicate require-match initial-input
                       history preselect keymap update-fn sort
-                      action unwind re-builder matcher dynamic-collection)
+                      action unwind re-builder matcher dynamic-collection caller)
   "Read a string in the minibuffer, with completion.
 
 PROMPT is a string to prompt with; normally it ends in a colon
 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.
+COLLECTION is a list of strings, or a function, or an alist, or a
+hash table.
 
 If INITIAL-INPUT is non-nil, insert it in the minibuffer initially.
 
@@ -790,13 +966,19 @@ RE-BUILDER is a lambda that transforms text into a regex.
 MATCHER can completely override matching.
 
 DYNAMIC-COLLECTION is a function to call to update the list of
-candidates with each input."
+candidates with each input.
+
+CALLER is a symbol to uniquely identify the caller to `ivy-read'.
+It's used in conjunction with COLLECTION to indentify which
+customizations should apply to the current completion session."
   (let ((extra-actions (plist-get ivy--actions-list this-command)))
     (when extra-actions
       (setq action
-            `(1
-              ("default" ,action)
-              ,@extra-actions))))
+            (if (functionp action)
+                `(1
+                  ("o" ,action "default")
+                  ,@extra-actions)
+              (delete-dups (append action extra-actions))))))
   (setq ivy-last
         (make-ivy-state
          :prompt prompt
@@ -814,7 +996,8 @@ candidates with each input."
          :unwind unwind
          :re-builder re-builder
          :matcher matcher
-         :dynamic-collection dynamic-collection))
+         :dynamic-collection dynamic-collection
+         :caller caller))
   (ivy--reset-state ivy-last)
   (prog1
       (unwind-protect
@@ -823,6 +1006,10 @@ candidates with each input."
              (let* ((hist (or history 'ivy-history))
                     (minibuffer-completion-table collection)
                     (minibuffer-completion-predicate predicate)
+                    (resize-mini-windows (cond
+                                           ((display-graphic-p) nil)
+                                           ((null resize-mini-windows) 'grow-only)
+                                           (t resize-mini-windows)))
                     (res (read-from-minibuffer
                           prompt
                           (ivy-state-initial-input ivy-last)
@@ -841,8 +1028,7 @@ candidates with each input."
         (remove-hook 'post-command-hook #'ivy--exhibit)
         (when (setq unwind (ivy-state-unwind ivy-last))
           (funcall unwind)))
-    (when (setq action (ivy--get-action ivy-last))
-      (funcall action ivy--current))))
+    (ivy-call)))
 
 (defun ivy--reset-state (state)
   "Reset the ivy to STATE.
@@ -856,11 +1042,13 @@ This is useful for recursive `ivy-read'."
         (re-builder (ivy-state-re-builder state))
         (dynamic-collection (ivy-state-dynamic-collection state))
         (initial-input (ivy-state-initial-input state))
-        (require-match (ivy-state-require-match state)))
+        (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-case-fold-search 'auto)
     (setq ivy--regex-function
           (or re-builder
               (and (functionp collection)
@@ -891,7 +1079,9 @@ This is useful for recursive `ivy-read'."
                              (string= preselect-directory
                                       default-directory))
                    (setq ivy--directory preselect-directory))
-                 (setq preselect (file-name-nondirectory preselect))))
+                 (setf
+                  (ivy-state-preselect state)
+                  (setq preselect (file-name-nondirectory preselect)))))
              (setq coll (ivy--sorted-files ivy--directory))
              (when initial-input
                (unless (or require-match
@@ -902,11 +1092,11 @@ This is useful for recursive `ivy-read'."
             ((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)))
+                 (and (consp collection) (listp (car collection)))
+                 (hash-table-p collection))
              (setq coll (all-completions "" collection predicate)))
-            ((hash-table-p collection)
-             (error "Hash table as a collection unsupported"))
             (t
              (setq coll collection)))
       (when sort
@@ -922,7 +1112,7 @@ This is useful for recursive `ivy-read'."
       (when preselect
         (unless (or (and require-match
                          (not (eq collection 'internal-complete-buffer)))
-                    (let ((re (format "\\`%s" (regexp-quote preselect))))
+                    (let ((re (regexp-quote preselect)))
                       (cl-find-if (lambda (x) (string-match re x))
                                   coll)))
           (setq coll (cons preselect coll))))
@@ -931,7 +1121,7 @@ This is useful for recursive `ivy-read'."
                              ivy--index)
                         (and preselect
                              (ivy--preselect-index
-                              coll initial-input preselect))
+                              coll initial-input preselect matcher))
                         0))
       (setq ivy--old-re nil)
       (setq ivy--old-cands nil)
@@ -941,6 +1131,9 @@ This is useful for recursive `ivy-read'."
     (setq ivy--prompt
           (cond ((string-match "%.*d" prompt)
                  prompt)
+                ((null ivy-count-format)
+                 (error
+                  "`ivy-count-format' can't be nil.  Set it to an empty string instead"))
                 ((string-match "%d.*%d" ivy-count-format)
                  (let ((w (length (number-to-string
                                    (length ivy--all-candidates))))
@@ -960,6 +1153,7 @@ This is useful for recursive `ivy-read'."
                  nil)))
     (setf (ivy-state-initial-input ivy-last) initial-input)))
 
+;;;###autoload
 (defun ivy-completing-read (prompt collection
                             &optional predicate require-match initial-input
                               history def _inherit-input-method)
@@ -971,19 +1165,24 @@ it can be used for `completing-read-function'.
 PROMPT is a string to prompt with; normally it ends in a colon and a space.
 COLLECTION can be a list of strings, an alist, an obarray or a hash table.
 PREDICATE limits completion to a subset of COLLECTION.
-REQUIRE-MATCH is considered boolean. See `completing-read'.
+REQUIRE-MATCH is considered boolean.  See `completing-read'.
 INITIAL-INPUT is a string that can be inserted into the minibuffer initially.
 _HISTORY is ignored for now.
 DEF is the default value.
 _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)
-                             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
@@ -1013,20 +1212,28 @@ Minibuffer bindings:
       (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)
-         (string-match (regexp-quote preselect) x))
-       candidates)))
+      (and (stringp preselect)
+           (let ((re (regexp-quote preselect)))
+             (cl-position-if
+              (lambda (x)
+                (string-match re x))
+              candidates)))))
 
 ;;* Implementation
 ;;** Regex
@@ -1073,6 +1280,8 @@ When GREEDY is non-nil, join words in a greedy way."
     (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)
@@ -1134,9 +1343,14 @@ Everything after \"!\" should not match."
   "Build a regex sequence from STR.
 Insert .* between each char."
   (if (string-match "\\`\\(\\^?\\)\\(.*?\\)\\(\\$?\\)\\'" str)
-      (concat (match-string 1 str)
-              (mapconcat #'string (string-to-list (match-string 2 str)) ".*")
-              (match-string 3 str))
+      (prog1
+          (concat (match-string 1 str)
+                  (mapconcat
+                   (lambda (x)
+                     (format "\\(%c\\)" x))
+                   (string-to-list (match-string 2 str)) ".*")
+                  (match-string 3 str))
+        (setq ivy--subexps (length (match-string 2 str))))
     str))
 
 ;;** Rest
@@ -1146,6 +1360,8 @@ Insert .* between each char."
   (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
@@ -1197,13 +1413,21 @@ Insert .* between each char."
                                   ivy--full-length)
                              ivy--length)))
                ivy--prompt-extra
-               tail)
-              (if ivy--directory
-                  (abbreviate-file-name ivy--directory)
-                ""))))
+               tail)))
+            (d-str (if ivy--directory
+                       (abbreviate-file-name ivy--directory)
+                     "")))
         (save-excursion
           (goto-char (point-min))
           (delete-region (point-min) (minibuffer-prompt-end))
+          (if (> (+ (mod (+ (length n-str) (length d-str)) (window-width))
+                    (length ivy-text))
+                 (window-width))
+              (setq n-str (concat n-str "\n" d-str))
+            (setq n-str (concat n-str d-str)))
+          (let ((regex (format "\\([^\n]\\{%d\\}\\)[^\n]" (window-width))))
+            (while (string-match regex n-str)
+              (setq n-str (replace-match (concat (match-string 1 n-str) "\n") nil t n-str 1))))
           (set-text-properties 0 (length n-str)
                                `(face minibuffer-prompt ,@std-props)
                                n-str)
@@ -1226,53 +1450,74 @@ Insert .* between each char."
 
 (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'."
-  (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)
-                  (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)))
+  (when (memq 'ivy--exhibit post-command-hook)
+    (let ((inhibit-field-text-motion nil))
+      (constrain-to-field nil (point-max)))
+    (setq ivy-text (ivy--input))
+    (if (ivy-state-dynamic-collection ivy-last)
+        ;; while-no-input would cause annoying
+        ;; "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."
@@ -1288,7 +1533,23 @@ Should be run via minibuffer `post-command-hook'."
       (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")
 
@@ -1298,76 +1559,170 @@ Should be run via minibuffer `post-command-hook'."
 `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))))
   str)
 
+(declare-function flx-make-string-cache "ext:flx")
+(declare-function flx-score "ext:flx")
+
+(defvar ivy--flx-cache nil)
+
+(eval-after-load 'flx
+  '(setq ivy--flx-cache (flx-make-string-cache)))
+
+(defun ivy-toggle-case-fold ()
+  "Toggle the case folding between nil and auto.
+In any completion session, the case folding starts in auto:
+
+- when the input is all lower case, `case-fold-search' is t
+- otherwise it's nil.
+
+You can toggle this to make `case-fold-search' nil regardless of input."
+  (interactive)
+  (setq ivy-case-fold-search
+        (if ivy-case-fold-search
+            nil
+          'auto))
+  ;; reset cache so that the candidate list updates
+  (setq ivy--old-re nil))
+
 (defun ivy--filter (name candidates)
   "Return all items that match NAME in CANDIDATES.
 CANDIDATES are assumed to be static."
-  (let* ((re (funcall ivy--regex-function name))
-         (matcher (ivy-state-matcher ivy-last))
-         (case-fold-search (string= name (downcase name)))
-         (cands (cond
-                  (matcher
-                   (funcall matcher re candidates))
-                  ((and (equal re ivy--old-re)
-                        ivy--old-cands)
-                   ivy--old-cands)
-                  ((and ivy--old-re
-                        (stringp re)
-                        (stringp ivy--old-re)
-                        (not (string-match "\\\\" ivy--old-re))
-                        (not (equal ivy--old-re ""))
-                        (memq (cl-search
-                               (if (string-match "\\\\)\\'" ivy--old-re)
-                                   (substring ivy--old-re 0 -2)
-                                 ivy--old-re)
-                               re)
-                              '(0 2)))
-                   (ignore-errors
-                     (cl-remove-if-not
-                      (lambda (x) (string-match re x))
-                      ivy--old-cands)))
-                  (t
-                   (let ((re-list (if (stringp re) (list (cons re t)) re))
-                         (res candidates))
-                     (dolist (re re-list)
-                       (setq res
-                             (ignore-errors
-                               (funcall
-                                (if (cdr re)
-                                    #'cl-remove-if-not
-                                  #'cl-remove-if)
-                                (let ((re (car re)))
-                                  (lambda (x) (string-match re x)))
-                                res))))
-                     res))))
-         (tail (nthcdr ivy--index ivy--old-cands))
-         idx)
-    (when (and tail ivy--old-cands (not (equal "^" ivy--old-re)))
-      (unless (and (not (equal re ivy--old-re))
-                   (or (setq ivy--index
-                             (or
-                              (cl-position re cands
-                                           :test #'equal)
-                              (and ivy--directory
-                                   (cl-position
-                                    (concat re "/") cands
-                                    :test #'equal))))))
-        (while (and tail (null idx))
-          ;; Compare with eq to handle equal duplicates in cands
-          (setq idx (cl-position (pop tail) cands)))
-        (setq ivy--index (or idx 0))))
-    (when (and (string= name "") (not (equal ivy--old-re "")))
+  (let ((re (funcall ivy--regex-function name)))
+    (if (and (equal re ivy--old-re)
+             ivy--old-cands)
+        ;; quick caching for "C-n", "C-p" etc.
+        ivy--old-cands
+      (let* ((re-str (if (listp re) (caar re) re))
+             (matcher (ivy-state-matcher ivy-last))
+             (case-fold-search
+              (and ivy-case-fold-search
+                   (string= name (downcase name))))
+             (cands (cond
+                      (matcher
+                       (funcall matcher re candidates))
+                      ((and ivy--old-re
+                            (stringp re)
+                            (stringp ivy--old-re)
+                            (not (string-match "\\\\" ivy--old-re))
+                            (not (equal ivy--old-re ""))
+                            (memq (cl-search
+                                   (if (string-match "\\\\)\\'" ivy--old-re)
+                                       (substring ivy--old-re 0 -2)
+                                     ivy--old-re)
+                                   re)
+                                  '(0 2)))
+                       (ignore-errors
+                         (cl-remove-if-not
+                          (lambda (x) (string-match re x))
+                          ivy--old-cands)))
+                      (t
+                       (let ((re-list (if (stringp re) (list (cons re t)) re))
+                             (res candidates))
+                         (dolist (re re-list)
+                           (setq res
+                                 (ignore-errors
+                                   (funcall
+                                    (if (cdr re)
+                                        #'cl-remove-if-not
+                                      #'cl-remove-if)
+                                    (let ((re-str (car re)))
+                                      (lambda (x) (string-match re-str x)))
+                                    res))))
+                         res)))))
+        (ivy--recompute-index name re-str cands)
+        (setq ivy--old-re (if cands re-str ""))
+        (when (and (require 'flx nil 'noerror)
+                   (eq ivy--regex-function 'ivy--regex-fuzzy))
+          (setq cands (ivy--flx-sort name cands)))
+        (setq ivy--old-cands cands)))))
+
+(defun ivy--recompute-index (name re-str cands)
+  (let* ((caller (ivy-state-caller ivy-last))
+         (func (or (and caller (cdr (assoc caller ivy-index-functions-alist)))
+                   (cdr (assoc t ivy-index-functions-alist))
+                   #'ivy-recompute-index-zero)))
+    (setq ivy--index
+          (or
+           (cl-position (if (and (> (length re-str) 0)
+                                 (eq ?^ (aref re-str 0)))
+                            (substring re-str 1)
+                          re-str) cands
+                          :test #'equal)
+           (and ivy--directory
+                (cl-position
+                 (concat re-str "/") cands
+                 :test #'equal))
+           (and (not (string= name ""))
+                (not (and (require 'flx nil 'noerror)
+                          (eq ivy--regex-function 'ivy--regex-fuzzy)
+                          (< (length cands) 200)))
+
+                (cl-position (nth ivy--index ivy--old-cands)
+                             cands))
+           (funcall func re-str cands)))
+    (when (and (or (string= name "")
+                   (string= name "^"))
+               (not (equal ivy--old-re "")))
       (setq ivy--index
-            (or (cl-position (ivy-state-preselect ivy-last)
-                             cands :test #'equal)
-                ivy--index)))
-    (setq ivy--old-re (if cands re ""))
-    (setq ivy--old-cands cands)))
+            (or (ivy--preselect-index
+                 cands
+                 nil
+                 (ivy-state-preselect ivy-last)
+                 nil)
+                ivy--index)))))
+
+(defun ivy-recompute-index-swiper (_re-str cands)
+  (let ((tail (nthcdr ivy--index ivy--old-cands))
+        idx)
+    (if (and tail ivy--old-cands (not (equal "^" ivy--old-re)))
+        (progn
+          (while (and tail (null idx))
+            ;; Compare with eq to handle equal duplicates in cands
+            (setq idx (cl-position (pop tail) cands)))
+          (or idx 0))
+      ivy--index)))
+
+(defun ivy-recompute-index-zero (_re-str _cands)
+  0)
+
+(defun ivy--flx-sort (name cands)
+  "Sort according to closeness to string NAME the string list CANDS."
+  (condition-case nil
+      (if (and cands
+               (< (length cands) 200))
+          (let* ((flx-name (if (string-match "^\\^" name)
+                               (substring name 1)
+                             name))
+                 (cands-with-score
+                  (delq nil
+                        (mapcar
+                         (lambda (x)
+                           (let ((score (car (flx-score x flx-name ivy--flx-cache))))
+                             (and score
+                                  (cons score x))))
+                         cands))))
+            (if cands-with-score
+                (mapcar #'cdr
+                        (sort cands-with-score
+                              (lambda (x y)
+                                (> (car x) (car y)))))
+              cands))
+        cands)
+    (error
+     cands)))
 
 (defvar ivy-format-function 'ivy-format-function-default
   "Function to transform the list of candidates into a string.
@@ -1375,13 +1730,18 @@ 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")))
+  (if (bound-and-true-p truncate-lines)
+      (mapconcat #'identity cands "\n")
+    (let ((ww (- (window-width)
+                 (if (and (boundp 'fringe-mode) (eq fringe-mode 0)) 1 0))))
+      (mapconcat
+       (if truncate-lines
+           (lambda (s)
+             (if (> (length s) ww)
+                 (concat (substring s 0 (- ww 3)) "...")
+               s))
+         #'identity)
+       cands "\n"))))
 
 (defun ivy-format-function-arrow (cands)
   "Transform CANDS into a string for minibuffer."
@@ -1394,6 +1754,48 @@ This string will be inserted into the minibuffer.")
                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."
@@ -1415,18 +1817,11 @@ CANDS is a list of strings."
                                 x))
                             cands)))
       (setq ivy--current (copy-sequence (nth index cands)))
-      (setf (nth index cands)
-            (ivy--add-face ivy--current 'ivy-current-match))
       (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))
+                   #'ivy--format-minibuffer-line
                    cands))
+      (setf (nth index cands)
+            (ivy--add-face (nth index cands) 'ivy-current-match))
       (let* ((ivy--index index)
              (res (concat "\n" (funcall ivy-format-function cands))))
         (put-text-property 0 (length res) 'read-only nil res)
@@ -1440,6 +1835,14 @@ CANDS is a list of strings."
 (defface ivy-virtual '((t :inherit font-lock-builtin-face))
   "Face used by Ivy for matching virtual buffer names.")
 
+(defcustom ivy-virtual-abbreviate 'name
+  "The mode of abbreviation for virtual buffer names."
+  :type '(choice
+          (const :tag "Only name" name)
+          (const :tag "Full path" full)
+          ;; eventually, uniquify
+          ))
+
 (defun ivy--virtual-buffers ()
   "Adapted from `ido-add-virtual-buffers-to-list'."
   (unless recentf-mode
@@ -1453,7 +1856,10 @@ CANDS is a list of strings."
                            (delq nil (mapcar (lambda (bookmark)
                                                (cdr (assoc 'filename bookmark)))
                                              bookmarks)))))
-      (setq name (file-name-nondirectory head))
+      (setq name
+            (if (eq ivy-virtual-abbreviate 'name)
+                (file-name-nondirectory head)
+              (expand-file-name head)))
       (when (equal name "")
         (setq name (file-name-nondirectory (directory-file-name head))))
       (when (equal name "")
@@ -1488,26 +1894,52 @@ When VIRTUAL is non-nil, add virtual buffers."
 
 (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))
-      (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)))
-          (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
- '(("kill"
+ '(("k"
     (lambda (x)
       (kill-buffer x)
-      (ivy--reset-state ivy-last)))))
+      (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)
@@ -1519,17 +1951,21 @@ BUFFER may be a string or nil."
                 :action #'ivy--switch-buffer-action
                 :keymap ivy-switch-buffer-map))))
 
+;;;###autoload
 (defun ivy-recentf ()
   "Find a file on `recentf-list'."
   (interactive)
   (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)
-    (with-selected-window (ivy-state-window ivy-last)
+    (with-ivy-window
       (let ((pt (point))
             (le (line-end-position)))
         (forward-word 1)
@@ -1537,7 +1973,19 @@ BUFFER may be a string or nil."
             (goto-char pt)
           (setq amend (buffer-substring-no-properties pt (point))))))
     (when amend
-      (insert amend))))
+      (insert (replace-regexp-in-string "  +" " " amend)))))
+
+(defun ivy-kill-ring-save ()
+  "Store the current candidates into the kill ring.
+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.