Refactor: simplify saving of state for cursors.

This commit is contained in:
Magnar Sveen 2012-06-07 08:20:13 +02:00
parent dfe8a2d1e8
commit 00896cf47f
2 changed files with 46 additions and 39 deletions

View File

@ -110,20 +110,46 @@ highlights the entire width of the window."
(overlay-put overlay 'type 'additional-region) (overlay-put overlay 'type 'additional-region)
overlay)) overlay))
(defun mc/add-cursor-at-point () (defun mc/store-current-state-in-overlay (o)
"Add a fake cursor where point is. (overlay-put o 'point (point))
Also makes a copy of the kill-ring to be used by this cursor." (overlay-put o 'kill-ring kill-ring)
(overlay-put o 'mark (set-marker (make-marker) (mark)))
(overlay-put o 'mark-ring mark-ring)
(overlay-put o 'mark-active mark-active)
(overlay-put o 'er/history er/history)
o)
(defun mc/restore-state-from-overlay (o)
(goto-char (overlay-get o 'point))
(setq kill-ring (overlay-get o 'kill-ring))
(set-marker (mark-marker) (overlay-get o 'mark))
(setq mark-ring (overlay-get o 'mark-ring))
(setq mark-active (overlay-get o 'mark-active))
(setq er/history (overlay-get o 'er/history)))
(defun mc/clean-up-state-overlay (o)
(set-marker (overlay-get o 'mark) nil)
(mc/delete-region-overlay o)
(delete-overlay o))
(defun mc/pop-state-from-overlay (o)
(mc/restore-state-from-overlay o)
(mc/clean-up-state-overlay o))
(defun mc/delete-region-overlay (o)
(ignore-errors
(delete-overlay (overlay-get o 'region-overlay))))
(defun mc/create-fake-cursor-at-point ()
"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))) (let ((overlay (mc/make-cursor-overlay-at-point)))
(overlay-put overlay 'type 'additional-cursor) (overlay-put overlay 'type 'additional-cursor)
(overlay-put overlay 'kill-ring kill-ring) (overlay-put overlay 'priority 100)
(overlay-put overlay 'mark-ring mark-ring) (mc/store-current-state-in-overlay overlay)
(overlay-put overlay 'mark-active mark-active)
(overlay-put overlay 'mark (set-marker (make-marker) (mark)))
(overlay-put overlay 'er/history er/history)
(when (use-region-p) (when (use-region-p)
(overlay-put overlay 'region-overlay (overlay-put overlay 'region-overlay
(mc/make-region-overlay-between-point-and-mark))) (mc/make-region-overlay-between-point-and-mark)))))
(overlay-put overlay 'priority 100)))
(defun mc/execute-command-for-all-fake-cursors (cmd) (defun mc/execute-command-for-all-fake-cursors (cmd)
"Calls CMD interactively for each cursor. "Calls CMD interactively for each cursor.
@ -131,36 +157,19 @@ It works by moving point to the fake cursor, setting
up the proper kill-ring, and then removing the cursor. up the proper kill-ring, and then removing the cursor.
After executing the command, it sets up a new fake After executing the command, it sets up a new fake
cursor with updated info." cursor with updated info."
(let ((current-kill-ring kill-ring) (let ((current-state (mc/store-current-state-in-overlay
(current-mark-ring mark-ring) (make-overlay (point) (point) nil nil t)))
(current-mark-active mark-active)
(current-er/history er/history)
(annoying-arrows-mode nil)) (annoying-arrows-mode nil))
(save-excursion (save-excursion
(mapc #'(lambda (o) (mapc #'(lambda (o)
(when (eq (overlay-get o 'type) 'additional-cursor) (when (eq (overlay-get o 'type) 'additional-cursor)
(goto-char (overlay-start o)) (mc/pop-state-from-overlay o)
(setq kill-ring (overlay-get o 'kill-ring))
(set-marker (mark-marker) (overlay-get o 'mark))
(set-marker (overlay-get o 'mark) nil)
(setq mark-ring (overlay-get o 'mark-ring))
(setq mark-active (overlay-get o 'mark-active))
(setq er/history (overlay-get o 'er/history))
(delete-region-overlay o)
(delete-overlay o)
(ignore-errors (ignore-errors
(call-interactively cmd) (call-interactively cmd)
(when deactivate-mark (deactivate-mark)) (when deactivate-mark (deactivate-mark))
(mc/add-cursor-at-point)))) (mc/create-fake-cursor-at-point))))
(overlays-in (point-min) (point-max)))) (overlays-in (point-min) (point-max))))
(setq kill-ring current-kill-ring) (mc/pop-state-from-overlay current-state)))
(setq mark-ring current-mark-ring)
(setq mark-active current-mark-active)
(setq er/history current-er/history)))
(defun delete-region-overlay (o)
(ignore-errors
(delete-overlay (overlay-get o 'region-overlay))))
(defun mc/execute-this-command-for-all-cursors () (defun mc/execute-this-command-for-all-cursors ()
"Used with post-command-hook to execute supported commands for "Used with post-command-hook to execute supported commands for
@ -183,8 +192,7 @@ Do not use to conclude editing with multiple cursors. For that
you should disable multiple-cursors-mode." you should disable multiple-cursors-mode."
(mapc #'(lambda (o) (mapc #'(lambda (o)
(when (eq (overlay-get o 'type) 'additional-cursor) (when (eq (overlay-get o 'type) 'additional-cursor)
(delete-region-overlay o) (mc/clean-up-state-overlay o)))
(delete-overlay o)))
(overlays-in (point-min) (point-max)))) (overlays-in (point-min) (point-max))))
(defun mc/keyboard-quit () (defun mc/keyboard-quit ()
@ -227,7 +235,7 @@ mark-multiple if point and mark is on different columns."
(navigation-func (if (< point-line mark-line) 'previous-line 'next-line))) (navigation-func (if (< point-line mark-line) 'previous-line 'next-line)))
(deactivate-mark) (deactivate-mark)
(while (not (eq (line-number-at-pos) point-line)) (while (not (eq (line-number-at-pos) point-line))
(mc/add-cursor-at-point) (mc/create-fake-cursor-at-point)
(funcall navigation-func)) (funcall navigation-func))
(multiple-cursors-mode))) (multiple-cursors-mode)))
@ -253,7 +261,7 @@ mark-multiple if point and mark is on different columns."
(save-excursion (save-excursion
(dolist (mirror mm/mirrors) (dolist (mirror mm/mirrors)
(goto-char (+ offset (overlay-start mirror))) (goto-char (+ offset (overlay-start mirror)))
(mc/add-cursor-at-point))) (mc/create-fake-cursor-at-point)))
(mm/clear-all) (mm/clear-all)
(multiple-cursors-mode))) (multiple-cursors-mode)))

View File

@ -1,9 +1,8 @@
* TODO: [3/9] * TODO: [4/9]
** DONE (set-marker MARKER nil) for performance ** DONE (set-marker MARKER nil) for performance
** DONE C-g deactivates regions first, before disabling multiple-cursors ** DONE C-g deactivates regions first, before disabling multiple-cursors
** DONE more state to save per cursor: er/history ** DONE more state to save per cursor: er/history
** TODO refactor ** DONE refactor: an object with all the current state, used for both overlays and current
an object with all the current state, used for both overlays and current
** TODO add tests ** TODO add tests
** TODO collapse cursors at same point ** TODO collapse cursors at same point
** TODO unknown command: (t)ry all or (i)gnore -> (did that work ok? (k)eep doing that or (d)on't) ** TODO unknown command: (t)ry all or (i)gnore -> (did that work ok? (k)eep doing that or (d)on't)