aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2025-12-28 22:32:23 -0500
committerStefan Monnier2025-12-28 22:32:23 -0500
commite119514ae8b391f41577d22d4e41cc3fea7ab9eb (patch)
treed1d68551bcf4ae83481731de0ffb93f876dc7b07
parent8f2557844d2f0e7a87b4c94d7a28bc6e4207d9da (diff)
downloademacs-e119514ae8b391f41577d22d4e41cc3fea7ab9eb.tar.gz
emacs-e119514ae8b391f41577d22d4e41cc3fea7ab9eb.zip
track-changes.el (track-changes-undo-only): New var
* lisp/emacs-lisp/track-changes.el (track-changes-undo-only): New var. (track-changes-fetch): Bind it. (track-changes--state): New slot `undo`. (track-changes--after): Set it. * lisp/vc/diff-mode.el (diff--track-changes-function): Use the new var. * doc/lispref/text.texi (Tracking changes): Mention `track-changes-undo-only`.
-rw-r--r--doc/lispref/text.texi13
-rw-r--r--etc/NEWS4
-rw-r--r--lisp/emacs-lisp/track-changes.el36
-rw-r--r--lisp/vc/diff-mode.el3
4 files changed, 52 insertions, 4 deletions
diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi
index c6e3b1bdbec..c1457c49562 100644
--- a/doc/lispref/text.texi
+++ b/doc/lispref/text.texi
@@ -6582,6 +6582,19 @@ risk that the @var{signal} function gets triggered in the middle of it,
6582because the @var{signal} is re-enabled only after @var{func} finishes. 6582because the @var{signal} is re-enabled only after @var{func} finishes.
6583@end defun 6583@end defun
6584 6584
6585@defvar track-changes-undo-only
6586If your code uses @code{track-changes} to perform further modifications
6587to the buffer (for example, to mark the parts of the buffer that have
6588been edited), then you may want to refrain from making those
6589modifications when the changes are the result of an undo (which
6590presumably also undoes the modifications you had applied back when the
6591corresponding edit was made).
6592To that end @code{track-changes-fetch} binds
6593@code{track-changes-undo-only} to non-@code{nil} during calls to
6594@var{func} if the changes were the result of undo.
6595@end defvar
6596
6597
6585@defun track-changes-unregister id 6598@defun track-changes-unregister id
6586This function tells the library that the tracker @var{id} does not need 6599This function tells the library that the tracker @var{id} does not need
6587to know about buffer changes any more. Most clients will never want to 6600to know about buffer changes any more. Most clients will never want to
diff --git a/etc/NEWS b/etc/NEWS
index e8250bfca04..56a9f44ff31 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1119,6 +1119,10 @@ convention. Also, the ':match?' predicate can now take the regexp as
1119either the first or second argument, so it works with both tree-sitter 1119either the first or second argument, so it works with both tree-sitter
1120convention (regexp arg second) and Emacs convention (regexp arg first). 1120convention (regexp arg second) and Emacs convention (regexp arg first).
1121 1121
1122+++
1123** Track-changes
1124*** New variable 'track-changes-undo-only' to distinguish undo changes.
1125
1122** Hideshow 1126** Hideshow
1123 1127
1124+++ 1128+++
diff --git a/lisp/emacs-lisp/track-changes.el b/lisp/emacs-lisp/track-changes.el
index bf899eebbe9..569a04bdcc1 100644
--- a/lisp/emacs-lisp/track-changes.el
+++ b/lisp/emacs-lisp/track-changes.el
@@ -3,7 +3,7 @@
3;; Copyright (C) 2024-2025 Free Software Foundation, Inc. 3;; Copyright (C) 2024-2025 Free Software Foundation, Inc.
4 4
5;; Author: Stefan Monnier <monnier@iro.umontreal.ca> 5;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
6;; Version: 1.4 6;; Version: 1.5
7;; Package-Requires: ((emacs "24")) 7;; Package-Requires: ((emacs "24"))
8 8
9;; This file is part of GNU Emacs. 9;; This file is part of GNU Emacs.
@@ -76,6 +76,11 @@
76 76
77;;; News: 77;;; News:
78 78
79;; v1.5:
80;;
81;; - New variable `track-changes-undo-only' to distinguish undo changes
82;; from others.
83;;
79;; v1.3: 84;; v1.3:
80;; 85;;
81;; - Fix bug#73041. 86;; - Fix bug#73041.
@@ -100,6 +105,19 @@
100;; move t-c--before-beg/end so it scales better when there are 105;; move t-c--before-beg/end so it scales better when there are
101;; many small changes. 106;; many small changes.
102 107
108;;;; Distinguish undo-vs-nonundo
109
110;; In practice, it seems that this distinction matters only for those
111;; clients which make further buffer-changes in response to buffer changes,
112;; (e.g. updating diff chunk headers on the fly, line-centering on the fly,
113;; inserting criticmarkup to keep track of buffer edits, ...).
114;; If all or none of the changes occurred during undo, then it's easy.
115;; If some did and some didn't and we need to merge them into a single change,
116;; there are two options:
117;; - Do the disjoint thing.
118;; - Merge them into a single change that's considered as "nonundo".
119;; We currently don't implement "the disjoint way".
120
103(require 'cl-lib) 121(require 'cl-lib)
104 122
105;;;; Internal types and variables. 123;;;; Internal types and variables.
@@ -130,6 +148,7 @@ state is created."
130 (beg (point-max)) 148 (beg (point-max))
131 (end (point-min)) 149 (end (point-min))
132 (before nil) 150 (before nil)
151 (undo t :type boolean) ;Non-nil until proven otherwise.
133 (next nil)) 152 (next nil))
134 153
135(defvar-local track-changes--trackers () 154(defvar-local track-changes--trackers ()
@@ -190,6 +209,9 @@ Each call is recorded as a (BUFFER-NAME . BACKTRACE).")
190The errors are kept in `track-changes--error-log'. 209The errors are kept in `track-changes--error-log'.
191If set to `trace', then we additionally keep a trace of recent calls to the API.") 210If set to `trace', then we additionally keep a trace of recent calls to the API.")
192 211
212(defvar track-changes-undo-only nil
213 "Bound to non-nil by `track-changes-fetch' if the change was an undo.")
214
193(cl-defun track-changes-register ( signal &key nobefore disjoint immediate) 215(cl-defun track-changes-register ( signal &key nobefore disjoint immediate)
194 "Register a new tracker whose change-tracking function is SIGNAL. 216 "Register a new tracker whose change-tracking function is SIGNAL.
195Return the ID of the new tracker. 217Return the ID of the new tracker.
@@ -281,7 +303,10 @@ This reflects a bug somewhere, so please report it when it happens.
281 303
282If no changes occurred since the last time, it doesn't call FUNC and 304If no changes occurred since the last time, it doesn't call FUNC and
283returns nil, otherwise it returns the value returned by FUNC 305returns nil, otherwise it returns the value returned by FUNC
284and re-enable the TRACKER corresponding to ID." 306and re-enable the TRACKER corresponding to ID.
307
308During the call to FUNC, `track-changes-undo-only' indicates if the changes
309were the result of `undo'."
285 (track-changes--trace) 310 (track-changes--trace)
286 (cl-assert (memq id track-changes--trackers)) 311 (cl-assert (memq id track-changes--trackers))
287 (unless (equal track-changes--buffer-size (buffer-size)) 312 (unless (equal track-changes--buffer-size (buffer-size))
@@ -289,6 +314,7 @@ and re-enable the TRACKER corresponding to ID."
289 `(buffer-size ,track-changes--buffer-size ,(buffer-size)))) 314 `(buffer-size ,track-changes--buffer-size ,(buffer-size))))
290 (let ((beg nil) 315 (let ((beg nil)
291 (end nil) 316 (end nil)
317 (is-undo t)
292 (before t) 318 (before t)
293 (lenbefore 0) 319 (lenbefore 0)
294 (states ())) 320 (states ()))
@@ -316,6 +342,7 @@ and re-enable the TRACKER corresponding to ID."
316 (setq states nil))) 342 (setq states nil)))
317 343
318 (dolist (state states) 344 (dolist (state states)
345 (when is-undo (setq is-undo (track-changes--state-undo state)))
319 (let ((prevbeg (track-changes--state-beg state)) 346 (let ((prevbeg (track-changes--state-beg state))
320 (prevend (track-changes--state-end state)) 347 (prevend (track-changes--state-end state))
321 (prevbefore (track-changes--state-before state))) 348 (prevbefore (track-changes--state-before state)))
@@ -384,7 +411,8 @@ and re-enable the TRACKER corresponding to ID."
384 ;; Update the tracker's state *before* running `func' so we don't risk 411 ;; Update the tracker's state *before* running `func' so we don't risk
385 ;; mistakenly replaying the changes in case `func' exits non-locally. 412 ;; mistakenly replaying the changes in case `func' exits non-locally.
386 (setf (track-changes--tracker-state id) track-changes--state) 413 (setf (track-changes--tracker-state id) track-changes--state)
387 (funcall func beg end (or before lenbefore))) 414 (let ((track-changes-undo-only is-undo))
415 (funcall func beg end (or before lenbefore))))
388 ;; Re-enable the tracker's signal only after running `func', so 416 ;; Re-enable the tracker's signal only after running `func', so
389 ;; as to avoid nested invocations. 417 ;; as to avoid nested invocations.
390 (cl-pushnew id track-changes--clean-trackers)))) 418 (cl-pushnew id track-changes--clean-trackers))))
@@ -629,6 +657,8 @@ Details logged to `track-changes--error-log'")
629 beg end 657 beg end
630 (track-changes--state-end track-changes--state) 658 (track-changes--state-end track-changes--state)
631 track-changes--before-end))))) 659 track-changes--before-end)))))
660 (unless undo-in-progress
661 (setf (track-changes--state-undo track-changes--state) nil))
632 (while track-changes--clean-trackers 662 (while track-changes--clean-trackers
633 (let ((tracker (pop track-changes--clean-trackers))) 663 (let ((tracker (pop track-changes--clean-trackers)))
634 (if (track-changes--tracker-immediate tracker) 664 (if (track-changes--tracker-immediate tracker)
diff --git a/lisp/vc/diff-mode.el b/lisp/vc/diff-mode.el
index 5e634e3bfdb..afd152c9ba1 100644
--- a/lisp/vc/diff-mode.el
+++ b/lisp/vc/diff-mode.el
@@ -1615,7 +1615,8 @@ else cover the whole buffer."
1615 ;; it's safer not to do it on big changes, e.g. when yanking a big 1615 ;; it's safer not to do it on big changes, e.g. when yanking a big
1616 ;; diff, or when the user edits the header, since we might then 1616 ;; diff, or when the user edits the header, since we might then
1617 ;; screw up perfectly correct values. --Stef 1617 ;; screw up perfectly correct values. --Stef
1618 (when (ignore-errors (diff-beginning-of-hunk t)) 1618 (when (and (not track-changes-undo-only)
1619 (ignore-errors (diff-beginning-of-hunk t)))
1619 (let* ((style (if (looking-at "\\*\\*\\*") 'context)) 1620 (let* ((style (if (looking-at "\\*\\*\\*") 'context))
1620 (start (line-beginning-position (if (eq style 'context) 3 2))) 1621 (start (line-beginning-position (if (eq style 'context) 3 2)))
1621 (mid (if (eq style 'context) 1622 (mid (if (eq style 'context)