Preserve marks as well as points (#198)

Marks are processed in almost exactly the same way as point; in
particular going through exactly the same `apheleia--align-point`
function. This works with minimal changes because markers act like
numbers, but also can be passed to `set-marker` to mutate their state.

---------

Co-authored-by: Radon Rosborough <radon@intuitiveexplanations.com>
This commit is contained in:
Sohum Banerjea 2023-11-18 11:53:07 +11:00 committed by GitHub
parent 49701675a8
commit 615b0f5591
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 54 additions and 31 deletions

View file

@ -27,6 +27,8 @@ The format is based on [Keep a Changelog].
* Prettier is now enabled in `svelte-mode`. * Prettier is now enabled in `svelte-mode`.
* More tree-sitter based major modes have been added to * More tree-sitter based major modes have been added to
`apheleia-mode-alist` ([#191]). `apheleia-mode-alist` ([#191]).
* All marks (the current `(mark)`, and the `mark-ring`) are now
adjusted, alongside `(point)` ([#197]).
* Built-in formatters now use a new `"apheleia-npx"` built-in script * Built-in formatters now use a new `"apheleia-npx"` built-in script
instead of the legacy `npx` keyword. The effect of the new script is instead of the legacy `npx` keyword. The effect of the new script is
the same, except that it also works with Yarn PNP projects as well the same, except that it also works with Yarn PNP projects as well
@ -104,6 +106,7 @@ The format is based on [Keep a Changelog].
[#182]: https://github.com/radian-software/apheleia/pull/182 [#182]: https://github.com/radian-software/apheleia/pull/182
[#187]: https://github.com/radian-software/apheleia/pull/187 [#187]: https://github.com/radian-software/apheleia/pull/187
[#196]: https://github.com/radian-software/apheleia/pull/196 [#196]: https://github.com/radian-software/apheleia/pull/196
[#197]: https://github.com/radian-software/apheleia/issues/197
[#208]: https://github.com/radian-software/apheleia/discussions/208 [#208]: https://github.com/radian-software/apheleia/discussions/208
[#209]: https://github.com/radian-software/apheleia/pull/209 [#209]: https://github.com/radian-software/apheleia/pull/209
[#213]: https://github.com/radian-software/apheleia/pull/213 [#213]: https://github.com/radian-software/apheleia/pull/213

View file

@ -120,12 +120,18 @@ contains the patch."
(apheleia--log (apheleia--log
'rcs "Applying RCS patch from %S to %S" patch-buffer content-buffer) 'rcs "Applying RCS patch from %S to %S" patch-buffer content-buffer)
(let ((commands nil) (let ((commands nil)
(point-list nil) (pos-list nil)
(window-line-list nil)) (window-line-list nil))
(with-current-buffer content-buffer (with-current-buffer content-buffer
(push (cons nil (point)) point-list) (push `(:type point :pos ,(point)) pos-list)
(when (marker-position (mark-marker))
(push `(:type marker :pos ,(mark-marker)) pos-list))
(dolist (m mark-ring)
(when (marker-position m)
(push `(:type marker :pos ,m) pos-list)))
(dolist (w (get-buffer-window-list nil nil t)) (dolist (w (get-buffer-window-list nil nil t))
(push (cons w (window-point w)) point-list) (push
`(:type window-point :pos ,(window-point w) :window ,w) pos-list)
(push (cons w (count-lines (window-start w) (point))) (push (cons w (count-lines (window-start w) (point)))
window-line-list))) window-line-list)))
(with-current-buffer patch-buffer (with-current-buffer patch-buffer
@ -173,10 +179,12 @@ contains the patch."
(let ((text-start (alist-get 'marker deletion))) (let ((text-start (alist-get 'marker deletion)))
(forward-line (alist-get 'lines deletion)) (forward-line (alist-get 'lines deletion))
(let ((text-end (point))) (let ((text-end (point)))
(dolist (entry point-list) (dolist (pos-spec pos-list)
;; Check if the (window) point is within the (let ((p (plist-get pos-spec :pos)))
;; replaced region. ;; Check if the point, or marker, or window
(cl-destructuring-bind (w . p) entry ;; point, is within the replaced region.
;; Markers pretend to be numbers, so we can
;; run this in any of the three cases.
(when (and (< text-start p) (when (and (< text-start p)
(< p text-end)) (< p text-end))
(let* ((old-text (buffer-substring-no-properties (let* ((old-text (buffer-substring-no-properties
@ -191,31 +199,43 @@ contains the patch."
(apheleia--align-point (apheleia--align-point
old-text new-text old-relative-point)))) old-text new-text old-relative-point))))
(goto-char text-start) (goto-char text-start)
(push `((marker . ,(point-marker)) (push
(command . set-point) `((command . move-cursor)
(window . ,w) (cursor . ,pos-spec)
(relative-point . ,new-relative-point)) (offset . ,(- new-relative-point
commands)))))))))))))) old-relative-point)))
commands))))))))))))))
(with-current-buffer content-buffer (with-current-buffer content-buffer
(let ((move-to nil)) ;; We run both `goto-char' and `set-window-point' to offset
(save-excursion ;; point and window point, don't want to chance that both
(dolist (command (nreverse commands)) ;; changes will stack on top of each other.
(goto-char (alist-get 'marker command)) (let ((orig-point (point)))
(pcase (alist-get 'command command) (dolist (command (nreverse commands))
(`addition (pcase (alist-get 'command command)
(insert (alist-get 'text command))) (`addition
(`deletion (save-excursion
(let ((text-start (point))) (goto-char (alist-get 'marker command))
(forward-line (alist-get 'lines command)) (insert (alist-get 'text command))))
(delete-region text-start (point)))) (`deletion
(`set-point (save-excursion
(let ((new-point (goto-char (alist-get 'marker command))
(+ (point) (alist-get 'relative-point command)))) (forward-line (alist-get 'lines command))
(if-let ((w (alist-get 'window command))) (delete-region (alist-get 'marker command) (point))))
(set-window-point w new-point) (`move-cursor
(setq move-to new-point))))))) (let ((cursor (alist-get 'cursor command))
(when move-to (offset (alist-get 'offset command)))
(goto-char move-to)))) (pcase (plist-get cursor :type)
(`point
(goto-char
(+ orig-point offset)))
(`marker
(set-marker
(plist-get cursor :pos)
(+ (plist-get cursor :pos) offset)))
(`window-point
(set-window-point
(plist-get cursor :window)
(+ orig-point offset))))))))))
;; Restore the scroll position of each window displaying the ;; Restore the scroll position of each window displaying the
;; buffer. ;; buffer.
(dolist (entry window-line-list) (dolist (entry window-line-list)