commit 825aea2c01e1fe750a92d9963ffbd72981263a17
parent 2c69574f80c328706119227788dbb5bb31c8672b
Author: Wojciech Siewierski <wojciech@siewierski.eu>
Date: Thu, 13 Apr 2023 17:28:49 +0200
Refactor the live previews
Diffstat:
| M | kmacro-x-mc.el | | | 96 | ++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------- |
1 file changed, 63 insertions(+), 33 deletions(-)
diff --git a/kmacro-x-mc.el b/kmacro-x-mc.el
@@ -67,6 +67,13 @@ Example, with | being the point and ^ being the mark:
"Functions to run after applying the recorded keyboard macro to cursors."
:type 'hook)
+(defcustom kmacro-x-mc-live-preview nil
+ "Experimental live previews of the edits performed within the cursors.
+
+Changes performed outside of the cursors are not displayed, but
+will be replicated as usual."
+ :type 'boolean)
+
(defvar-local kmacro-x-mc-regexp nil
"A regexp matching the intended cursor positions.")
@@ -84,6 +91,58 @@ cursors use `kmacro-x-mc-cursor-face' instead.")
Duplicated from `kmacro-x-mc-cursors' so it can be accessed at
all times without searching through this list.")
+
+(defun kmacro-x-mc--modification-hook-live-preview
+ (ov after-p _beg _end &optional _length)
+ "Overlay modification-hook updating all the other overlays."
+ (when after-p
+ (dolist (cursor kmacro-x-mc-cursors)
+ (unless (kmacro-x-mc--main-cursor-p cursor)
+ (overlay-put cursor 'display
+ (buffer-substring (overlay-start ov)
+ (overlay-end ov)))))))
+
+(defun kmacro-x-mc--make-main-cursor (beg end)
+ "Create an overlay representing the main cursor from BEG to END."
+
+ ;; With `kmacro-x-mc-live-preview' inverting the *-advance arguments
+ ;; of `make-overlay' it's possible to use the overlay
+ ;; modification-hooks to capture the edits at the cursor boundaries.
+ ;; With `kmacro-x-mc-live-preview' being nil, the difference is only
+ ;; visual and this setting here is subjectively the most visually
+ ;; pleasing one (according to the author).
+ (let* ((front-advance (not kmacro-x-mc-live-preview))
+ (rear-advance kmacro-x-mc-live-preview)
+ (ov (make-overlay beg end nil front-advance rear-advance)))
+ (overlay-put ov 'face 'kmacro-x-mc-main-cursor-face)
+ (overlay-put ov 'offsets (cons (- (point) beg)
+ (- (mark) end)))
+ (when kmacro-x-mc-live-preview
+ (let ((hooks (list #'kmacro-x-mc--modification-hook-live-preview)))
+ (overlay-put ov 'modification-hooks hooks)
+ (overlay-put ov 'insert-in-front-hooks hooks)
+ (overlay-put ov 'insert-behind-hooks hooks)))
+ ov))
+
+(defun kmacro-x-mc--make-cursor (beg end)
+ "Create an overlay representing a fake cursor from BEG to END."
+ (let ((ov (make-overlay beg end nil t nil)))
+ (overlay-put ov 'face 'kmacro-x-mc-cursor-face)
+
+ ;; Store the offsets per cursor as mouse-created cursors
+ ;; have different offsets.
+ (overlay-put ov 'offsets
+ (overlay-get kmacro-x-mc-main-cursor 'offsets))
+
+ ;; Store whether the region should be active for this
+ ;; cursor. This allows to properly replicate the
+ ;; region-sensitive commands such as using `DEL' to delete
+ ;; the whole region without affecting the `kill-ring' (like
+ ;; `C-w' would).
+ (overlay-put ov 'region-active (region-active-p))
+
+ ov))
+
(defun kmacro-x-mc--mark (prefix &optional backwards)
"Create a new fake cursor for `kmacro-x-mc-mode'.
@@ -145,23 +204,8 @@ Otherwise searches forward."
(if backwards
(search-backward-regexp kmacro-x-mc-regexp nil 'noerror)
(search-forward-regexp kmacro-x-mc-regexp nil 'noerror)))
- (let ((ov (make-overlay (match-beginning 0)
- (match-end 0)
- nil t nil)))
- (overlay-put ov 'face 'kmacro-x-mc-cursor-face)
-
- ;; Store the offsets per cursor as mouse-created cursors
- ;; have different offsets.
- (overlay-put ov 'offsets
- (overlay-get kmacro-x-mc-main-cursor 'offsets))
-
- ;; Store whether the region should be active for this
- ;; cursor. This allows to properly replicate the
- ;; region-sensitive commands such as using `DEL' to delete
- ;; the whole region without affecting the `kill-ring' (like
- ;; `C-w' would).
- (overlay-put ov 'region-active (region-active-p))
-
+ (let ((ov (kmacro-x-mc--make-cursor (match-beginning 0)
+ (match-end 0))))
(if prefix
;; Replace the first or last cursor with the new one.
(let ((old-cursor (if backwards
@@ -318,22 +362,8 @@ user directory.
;; position it was before.
(push-mark (cdr bounds))))
- (let ((ov (make-overlay (car bounds) (cdr bounds)
- nil t nil)))
- (overlay-put ov 'face 'kmacro-x-mc-main-cursor-face)
- (overlay-put ov 'offsets (cons (- (point)
- (car bounds))
- (- (mark)
- (car bounds))))
- (overlay-put ov 'modification-hooks
- (list
- (lambda (main-cursor after-p _beg _end &optional _length)
- (when after-p
- (dolist (cursor kmacro-x-mc-cursors)
- (unless (kmacro-x-mc--main-cursor-p cursor)
- (overlay-put cursor 'display
- (buffer-substring (overlay-start main-cursor)
- (overlay-end main-cursor)))))))))
+ (let ((ov (kmacro-x-mc--make-main-cursor (car bounds)
+ (cdr bounds))))
(setq-local kmacro-x-mc-main-cursor ov)
(setq-local kmacro-x-mc-cursors (list ov)))