branch: externals/ivy-hydra
commit c0dc909cb22614357e265718e31091f07d158ad9
Author: Kien Nguyen <[email protected]>
Commit: Oleh Krehel <[email protected]>

    ivy.el (ivy-resume): Support multiple ivy sessions
    
    Fixes #2557
---
 ivy-test.el |  22 ++++++++++++
 ivy.el      | 117 +++++++++++++++++++++++++++++++++++++++---------------------
 2 files changed, 99 insertions(+), 40 deletions(-)

diff --git a/ivy-test.el b/ivy-test.el
index 182b613..02c8b3f 100644
--- a/ivy-test.el
+++ b/ivy-test.el
@@ -1576,6 +1576,28 @@ a buffer visiting a file."
   (should (eql (ivy--preselect-index "a+" '("a")) 0))
   (should (eql (ivy--preselect-index "a+" '("b" "a")) 1)))
 
+(ert-deftest ivy-multi-resume ()
+  (let ((ivy-last ivy-last)
+        ivy-text ivy--all-candidates ivy--sessions)
+    (ivy-with '(ivy-read "A: " '(a123 b456 c789) :caller 'test-a :action 
#'ignore)
+              "b4 RET")
+    (ivy-with '(ivy-read "A: " '(d123 e456 f789) :caller 'test-b)
+              "d1 RET")
+    (ivy-with '(ivy-read "A: " '(g123 h456 k789) :action #'ignore
+                         :extra-props '(:session test-c))
+              "k7 RET")
+    (should (equal ivy-text "k7"))
+    (should (equal (mapcar #'car ivy--sessions) '(test-c test-a)))
+    (should (equal (ivy-with '(let ((current-prefix-arg '(4)))
+                               (ivy-resume))
+                             "test-a RET RET")
+                   "b456"))
+    (should (equal ivy-text "b4"))
+
+    (should (equal (ivy-with '(ivy-resume 'test-c) "RET")
+                   "k789"))
+    (should (equal ivy-text "k7"))))
+
 (defun ivy-test-run-tests ()
   (let ((test-sets
          '(
diff --git a/ivy.el b/ivy.el
index 6a319ba..e49a371 100644
--- a/ivy.el
+++ b/ivy.el
@@ -513,6 +513,9 @@ action functions.")
 This should eventually become a stack so that you could use
 `ivy-read' recursively.")
 
+(defvar ivy--sessions nil
+  "Alist mapping session symbols to `ivy-state' objects.")
+
 (defvar ivy-recursive-last nil)
 
 (defvar ivy-recursive-restore t
@@ -1266,15 +1269,39 @@ If the text hasn't changed as a result, forward to 
`ivy-alt-done'."
   (setq ivy-exit 'done)
   (exit-minibuffer))
 
+(defun ivy--restore-session (&optional session)
+  "Resume a recorded completion SESSION, if any exists."
+  (when ivy--sessions
+    (unless session
+      (setq session (intern
+                     (let ((ivy-last ivy-last)
+                           ivy--all-candidates
+                           ivy-text)
+                       (ivy-read "Choose ivy session: "
+                                 ivy--sessions
+                                 :require-match t)))))
+    (setq ivy-last (or (cdr (assq session ivy--sessions))
+                       ivy-last)))
+  (let ((data (plist-get (ivy-state-extra-props ivy-last) :ivy-data)))
+    (when data
+      (setq ivy--all-candidates (plist-get data :all-candidates))
+      (setq ivy-text (plist-get data :text)))))
+
 ;;;###autoload
-(defun ivy-resume ()
-  "Resume the last completion session."
+(defun ivy-resume (&optional session)
+  "Resume the last completion session, or SESSION if non-nil.
+With a prefix arg, try to restore a recorded completion session,
+if one exists."
   (interactive)
+  (when (or current-prefix-arg session)
+    (ivy--restore-session session))
+
   (if (or (null (ivy-state-action ivy-last))
-          (eq (ivy--get-action ivy-last) 'identity))
+          (eq (ivy--get-action ivy-last) #'identity))
       (user-error "The last session isn't compatible with `ivy-resume'")
     (when (memq (ivy-state-caller ivy-last)
-                '(swiper swiper-isearch swiper-backward
+                '(swiper
+                  swiper-isearch swiper-backward
                   swiper-isearch-backward
                   counsel-grep))
       (switch-to-buffer (ivy-state-buffer ivy-last)))
@@ -2154,14 +2181,14 @@ found, it falls back to the key t."
 ;;** Entry Point
 ;;;###autoload
 (cl-defun ivy-read (prompt collection
-                           &key
-                           predicate require-match initial-input
-                           history preselect def keymap update-fn sort
-                           action multi-action
-                           unwind re-builder matcher
-                           dynamic-collection
-                           extra-props
-                           caller)
+                    &key
+                      predicate require-match initial-input
+                      history preselect def keymap update-fn sort
+                      action multi-action
+                      unwind re-builder matcher
+                      dynamic-collection
+                      extra-props
+                      caller)
   "Read a string in the minibuffer, with completion.
 
 PROMPT is a string, normally ending in a colon and a space.
@@ -2277,33 +2304,43 @@ customizations apply to the current completion session."
            :def def))
     (ivy--reset-state ivy-last)
     (unwind-protect
-        (minibuffer-with-setup-hook
-            #'ivy--minibuffer-setup
-          (let* ((hist (or history 'ivy-history))
-                 (minibuffer-completion-table collection)
-                 (minibuffer-completion-predicate predicate)
-                 (ivy-height (ivy--height caller))
-                 (resize-mini-windows (unless (display-graphic-p)
-                                        'grow-only)))
-            (if (and ivy-auto-select-single-candidate
-                     ivy--all-candidates
-                     (null (cdr ivy--all-candidates)))
-                (progn
-                  (setf (ivy-state-current ivy-last)
-                        (car ivy--all-candidates))
-                  (setq ivy-exit 'done))
-              (condition-case err
-                  (read-from-minibuffer
-                   prompt
-                   (ivy-state-initial-input ivy-last)
-                   (make-composed-keymap keymap ivy-minibuffer-map)
-                   nil
-                   hist)
-                (error
-                 (unless (equal err '(error "Selecting deleted buffer"))
-                   (signal (car err) (cdr err))))))
-            (when (eq ivy-exit 'done)
-              (ivy--update-history hist))))
+         (minibuffer-with-setup-hook
+             #'ivy--minibuffer-setup
+           (let* ((hist (or history 'ivy-history))
+                  (minibuffer-completion-table collection)
+                  (minibuffer-completion-predicate predicate)
+                  (ivy-height (ivy--height caller))
+                  (resize-mini-windows (unless (display-graphic-p)
+                                         'grow-only)))
+             (if (and ivy-auto-select-single-candidate
+                      ivy--all-candidates
+                      (null (cdr ivy--all-candidates)))
+                 (progn
+                   (setf (ivy-state-current ivy-last)
+                         (car ivy--all-candidates))
+                   (setq ivy-exit 'done))
+               (condition-case err
+                   (read-from-minibuffer
+                    prompt
+                    (ivy-state-initial-input ivy-last)
+                    (make-composed-keymap keymap ivy-minibuffer-map)
+                    nil
+                    hist)
+                 (error
+                  (unless (equal err '(error "Selecting deleted buffer"))
+                    (signal (car err) (cdr err))))))
+             (when (eq ivy-exit 'done)
+               (ivy--update-history hist))))
+      (let ((session (or (plist-get extra-props :session)
+                         (unless (or (minibufferp)
+                                     (null (ivy-state-action ivy-last))
+                                     (eq (ivy--get-action ivy-last) 
#'identity))
+                           caller))))
+        (when session
+          (setf (ivy-state-extra-props ivy-last)
+                (plist-put extra-props :ivy-data `(:all-candidates 
,ivy--all-candidates
+                                                   :text ,ivy-text)))
+          (ivy--alist-set 'ivy--sessions session ivy-last)))
       (ivy--cleanup))
     (ivy-call)))
 
@@ -2443,7 +2480,7 @@ This is useful for recursive `ivy-read'."
                            (equal initial-input ""))
                  (setq coll (cons initial-input coll)))
                (when (or (not (ivy-state-action ivy-last))
-                         (equal (ivy--get-action ivy-last) 'identity))
+                         (equal (ivy--get-action ivy-last) #'identity))
                  (setq initial-input nil))))
             ((eq collection #'internal-complete-buffer)
              (setq coll (ivy--buffer-list

Reply via email to