diff --git a/evil-commands.el b/evil-commands.el index 2221ab46..43030c22 100644 --- a/evil-commands.el +++ b/evil-commands.el @@ -2579,20 +2579,26 @@ COUNT is infinite." (evil-define-motion evil-visual-restore () "Restore previous selection." - (let* ((point (point)) - (mark (or (mark t) point)) - (type (evil-visual-type))) - ;; TODO handle swapping selection in visual state... - (unless (evil-visual-state-p) - (cond - ;; No previous selection. - ((or (null evil-visual-selection) - (null evil-visual-mark) - (null evil-visual-point))) - (t - (setq mark evil-visual-mark - point evil-visual-point))) - (evil-visual-make-selection mark point type t)))) + (cond + ;; Called from visual state + ((and (evil-visual-state-p) + evil-prev-visual-mark evil-prev-visual-point evil-prev-visual-selection) + (let ((tmp-visual-mark (marker-position evil-visual-mark)) + (tmp-visual-point (marker-position evil-visual-point)) + (tmp-visual-selection evil-visual-selection)) + (evil-visual-make-selection evil-prev-visual-mark + evil-prev-visual-point + evil-prev-visual-selection + t) + (move-marker evil-prev-visual-mark tmp-visual-mark) + (move-marker evil-prev-visual-point tmp-visual-point) + (setq evil-prev-visual-selection tmp-visual-selection))) + ;; Called from other state + ((and evil-visual-selection evil-visual-mark evil-visual-point) + (evil-visual-make-selection evil-visual-mark + evil-visual-point + (evil-visual-type) + t)))) (evil-define-motion evil-visual-exchange-corners () "Rearrange corners in Visual Block mode. diff --git a/evil-states.el b/evil-states.el index 6b86d9de..26eb844e 100644 --- a/evil-states.el +++ b/evil-states.el @@ -421,7 +421,10 @@ If LATER is non-nil, exit after the current command." (setq deactivate-mark t) (when evil-visual-region-expanded (evil-visual-contract-region)) - (setq evil-this-register nil) + (setq evil-this-register nil + evil-prev-visual-selection evil-visual-selection + evil-prev-visual-mark (copy-marker evil-visual-mark) + evil-prev-visual-point (copy-marker evil-visual-point)) (evil-change-to-previous-state))))) (defun evil-visual-tag (&optional selection) @@ -777,7 +780,8 @@ Default to `evil-visual-make-region'." "Return a Visual selection for TYPE." (catch 'done (dolist (selection evil-visual-alist) - (when (eq (symbol-value (cdr selection)) type) + (when (memq (symbol-value (cdr selection)) + (list type (evil-visual-type type))) (throw 'done (car selection)))))) (defun evil-visual-block-corner (&optional corner point mark) diff --git a/evil-tests.el b/evil-tests.el index 724ea9b9..4699108a 100644 --- a/evil-tests.el +++ b/evil-tests.el @@ -7551,12 +7551,6 @@ otel"))) (ert-deftest evil-test-visual-restore () "Test restoring a previous selection" :tags '(evil visual) - (ert-info ("Start a characterwise selection \ -if no previous selection") - (evil-test-buffer - ";; [T]his buffer is for notes." - ("gv") - ";; <[T]>his buffer is for notes.")) (ert-info ("Restore characterwise selection") (evil-test-buffer ";; <[T]his> buffer is for notes." @@ -7590,7 +7584,34 @@ if no previous selection") echo foxtrot\ngolf hotel" ("2yy" "++" "Vp" "gv") "alpha bravo\ncharlie delta -golf hotel"))) +golf hotel")) + ;; 4 repetitions appears necessary, from manual testing + (ert-info ("Restore previous linewise selection from linewise selection") + (evil-test-buffer + "alpha bravo\nch[a]rlie delta\necho foxtrot\ngolf hotel" + ("V" [escape] "jV") + "alpha bravo\ncharlie delta\ngolf hotel" + ("gv") + "alpha bravo\necho foxtrot\ngolf hotel" + ("gv") + "alpha bravo\ncharlie delta\ngolf hotel" + ("gv") + "alpha bravo\necho foxtrot\ngolf hotel" + ("gv") + "alpha bravo\ncharlie delta\ngolf hotel")) + (ert-info ("Restore between previous charwise selection and linewise selection") + (evil-test-buffer + "alpha bravo\nch[a]rlie delta\necho foxtrot\ngolf hotel" + ("viw" [escape] "jV") + "alpha bravo\ncharlie delta\ngolf hotel" + ("gv") + "alpha bravo\n delta\necho foxtrot\ngolf hotel" + ("gv") + "alpha bravo\ncharlie delta\ngolf hotel" + ("gv") + "alpha bravo\n delta\necho foxtrot\ngolf hotel" + ("gv") + "alpha bravo\ncharlie delta\ngolf hotel"))) (ert-deftest evil-test-visual-redefine () "Test redefining a previous selection" diff --git a/evil-vars.el b/evil-vars.el index aea7eeea..7adbb60c 100644 --- a/evil-vars.el +++ b/evil-vars.el @@ -1740,6 +1740,16 @@ instead of `buffer-undo-list'.") "The kind of Visual selection. This is a selection as defined by `evil-define-visual-selection'.") +(evil-define-local-var evil-prev-visual-point nil + "The previous position of point in Visual state, a marker.") + +(evil-define-local-var evil-prev-visual-mark nil + "The previous position of mark in Visual state, a marker.") + +(evil-define-local-var evil-prev-visual-selection nil + "The previous kind of Visual selection. +This is a selection as defined by `evil-define-visual-selection'.") + ;; we could infer the direction by comparing `evil-visual-mark' ;; and `evil-visual-point', but destructive operations may ;; displace the markers