[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/multiple-cursors 7ab8a8c 067/434: Better support for undo.
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/multiple-cursors 7ab8a8c 067/434: Better support for undo. |
Date: |
Sat, 7 Aug 2021 09:19:56 -0400 (EDT) |
branch: elpa/multiple-cursors
commit 7ab8a8c9774a2bafe76d6fe8f3fb19561db91155
Author: Magnar Sveen <magnars@gmail.com>
Commit: Magnar Sveen <magnars@gmail.com>
Better support for undo.
---
features/multiple-cursors-core.feature | 8 ++++
multiple-cursors-core.el | 76 ++++++++++++++++++++++++++++------
2 files changed, 71 insertions(+), 13 deletions(-)
diff --git a/features/multiple-cursors-core.feature
b/features/multiple-cursors-core.feature
index 62ebccf..cf0121a 100644
--- a/features/multiple-cursors-core.feature
+++ b/features/multiple-cursors-core.feature
@@ -57,6 +57,14 @@ Feature: Multiple cursors core
And I press "C-!"
Then I should see "This aatext contains the word text twice"
+ Scenario: Undo
+ Given I have cursors at "text" in "This text contains the word text twice"
+ When I press "M-f"
+ And I press "M-DEL"
+ And I press "C-_"
+ And I type "!"
+ Then I should see "This text! contains the word text! twice"
+
Scenario: Setting and popping mark
Given I have cursors at "text" in "This text contains the word text twice"
And I press "C-SPC"
diff --git a/multiple-cursors-core.el b/multiple-cursors-core.el
index 2893637..d70b22a 100644
--- a/multiple-cursors-core.el
+++ b/multiple-cursors-core.el
@@ -1,3 +1,5 @@
+(eval-when-compile (require 'cl))
+
(defface mc/cursor-face
'((t (:inverse-video t)))
"The face used for fake cursors"
@@ -77,10 +79,18 @@ highlights the entire width of the window."
(ignore-errors
(delete-overlay (overlay-get o 'region-overlay))))
-(defun mc/create-fake-cursor-at-point ()
+(defvar mc--current-cursor-id 0
+ "Var to store increasing id of fake cursors, used to keep track of them for
undo.")
+
+(defun mc/create-cursor-id ()
+ "Returns a unique cursor id"
+ (incf mc--current-cursor-id))
+
+(defun mc/create-fake-cursor-at-point (&optional id)
"Add a fake cursor and possibly a fake active region overlay based on point
and mark.
Saves the current state in the overlay to be restored later."
(let ((overlay (mc/make-cursor-overlay-at-point)))
+ (overlay-put overlay 'mc-id (or id (mc/create-cursor-id)))
(overlay-put overlay 'type 'additional-cursor)
(overlay-put overlay 'priority 100)
(mc/store-current-state-in-overlay overlay)
@@ -88,23 +98,62 @@ Saves the current state in the overlay to be restored
later."
(overlay-put overlay 'region-overlay
(mc/make-region-overlay-between-point-and-mark)))))
+(defun mc/execute-command (cmd)
+ "Run command, simulating the parts of the command loop that makes sense for
fake cursors."
+ (setq this-command cmd)
+ (run-hooks 'pre-command-hook)
+ (unless (eq this-command 'ignore)
+ (call-interactively cmd))
+ (when deactivate-mark (deactivate-mark)))
+
(defun mc/execute-command-for-all-fake-cursors (cmd)
"Calls CMD interactively for each cursor.
It works by moving point to the fake cursor, setting
-up the proper kill-ring, and then removing the cursor.
+up the proper environment, and then removing the cursor.
After executing the command, it sets up a new fake
cursor with updated info."
- (let ((annoying-arrows-mode nil))
- (mc/save-excursion
- (mc/for-each-fake-cursor
- (mc/pop-state-from-overlay cursor)
- (ignore-errors
- (setq this-command cmd)
- (run-hooks 'pre-command-hook)
- (unless (eq this-command 'ignore)
- (call-interactively cmd))
- (when deactivate-mark (deactivate-mark))
- (mc/create-fake-cursor-at-point))))))
+ (mc/save-excursion
+ (mc/for-each-fake-cursor
+ (let ((id (overlay-get cursor 'mc-id))
+ (annoying-arrows-mode nil))
+ (mc/add-fake-cursor-to-undo-list
+ (mc/pop-state-from-overlay cursor)
+ (ignore-errors
+ (mc/execute-command cmd)
+ (mc/create-fake-cursor-at-point id)))))))
+
+(defmacro mc/add-fake-cursor-to-undo-list (&rest forms)
+ "Make sure point is in the right place when undoing"
+ `(let ((undo-cleaner (cons 'apply (cons 'deactivate-cursor-after-undo (list
id)))))
+ (setq buffer-undo-list (cons undo-cleaner buffer-undo-list))
+ ,@forms
+ (if (eq undo-cleaner (car buffer-undo-list)) ;; if nothing has been added
to the undo-list
+ (setq buffer-undo-list (cdr buffer-undo-list)) ;; then pop the
cleaner right off again
+ (setq buffer-undo-list ;; otherwise add a function to activate this
cursor
+ (cons (cons 'apply (cons 'activate-cursor-for-undo (list id)))
buffer-undo-list)))))
+
+(defun mc/cursor-with-id (id)
+ "Find the first cursor with the given id, or nil"
+ (find-if #'(lambda (o) (= id (overlay-get o 'mc-id)))
+ (overlays-in (point-min) (point-max))))
+
+(defvar mc--stored-state-for-undo nil
+ "Variable to keep the state of the real cursor while undoing a fake one")
+
+(defun activate-cursor-for-undo (id)
+ "Called when undoing to temporarily activate the fake cursor which action is
being undone."
+ (let ((cursor (mc/cursor-with-id id)))
+ (when cursor
+ (setq mc--stored-state-for-undo (mc/store-current-state-in-overlay
+ (make-overlay (point) (point) nil nil
t)))
+ (mc/pop-state-from-overlay cursor))))
+
+(defun deactivate-cursor-after-undo (id)
+ "Called when undoing to reinstate the real cursor after undoing a fake one."
+ (when mc--stored-state-for-undo
+ (mc/create-fake-cursor-at-point id)
+ (mc/pop-state-from-overlay mc--stored-state-for-undo)
+ (setq mc--stored-state-for-undo nil)))
(defmacro mc/for-each-fake-cursor (&rest forms)
"Runs the body for each fake cursor, bound to the name cursor"
@@ -122,6 +171,7 @@ cursor with updated info."
(mc/pop-state-from-overlay current-state)))
(defun mc/prompt-for-inclusion-in-whitelist (original-command)
+ "Asks the user, then adds the command either to the once-list or the
all-list."
(if (y-or-n-p (format "Do %S for all cursors?" original-command))
(add-to-list 'mc--cmds original-command)
(add-to-list 'mc--cmds-run-once original-command)
- [nongnu] elpa/multiple-cursors ddbe3ae 396/434: Merge pull request #278 from shlomme/master, (continued)
- [nongnu] elpa/multiple-cursors ddbe3ae 396/434: Merge pull request #278 from shlomme/master, ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors d2766bc 400/434: tips and tricks: add note about <return> and newlines; if it is not default, let it at least be more discoverable, ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors 0e49fec 410/434: Merge pull request #326 from pstray/issue325, ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors 1075270 407/434: Added mc/interactive-repeating-commands (#303), ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors 038815b 414/434: Make "no more matches found." user-error, fix #218, ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors d27870d 421/434: Load mc/list-file as late as possible, ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors fc6a6a7 422/434: Merge pull request #355 from flatwhatson/lazy-list-file, ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors 7763f4f 429/434: Load mc-cycle-cursors and mc-hide-unmatched-lines-mode after loading multiple-cursors-core, ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors a9d7764 431/434: Add option to disable bar-style fake cursors (#367), ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors 616fbdd 434/434: Document existing functions in Readme, ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors 7ab8a8c 067/434: Better support for undo.,
ELPA Syncer <=
- [nongnu] elpa/multiple-cursors 608ceb4 069/434: Disable multiple-cursors-mode if there's only one cursor (the real one)., ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors 61280ae 100/434: autoload integration for package.el compatibility, ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors d82e252 106/434: Don't let fake cursors scroll the buffer, ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors dc22766 108/434: Macros must be defined before they are used to be expanded properly, ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors 7a655b0 117/434: Disable emacs-snapshot tests until it is in order., ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors 067063a 118/434: Split multiline kill-ring entry over cursors when num lines match, ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors bdc4d9a 124/434: Add some more commands to default run-once/run-for-all lists., ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors 0f54f98 133/434: Bump to 1.1.1 for bugfix, ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors a0f771f 151/434: Include interactive commands for deselecting prev/next, ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors 8a12e97 148/434: Mention region-bindings-mode in README, ELPA Syncer, 2021/08/07