diff --git a/lisp/emacs-lisp/track-changes.el b/lisp/emacs-lisp/track-changes.el index 92d14959763..24df0aac6bb 100644 --- a/lisp/emacs-lisp/track-changes.el +++ b/lisp/emacs-lisp/track-changes.el @@ -213,6 +213,7 @@ track-changes-register that may block, do as little work as possible, ... When IMMEDIATE is non-nil, the SIGNAL should probably not always call `track-changes-fetch', since that would defeat the purpose of this library." + (cl-assert (track-changes--sane-state-p)) (when (and nobefore disjoint) ;; FIXME: Without `before-change-functions', we can discover ;; a disjoint change only after the fact, which is not good enough. @@ -229,6 +230,7 @@ track-changes-register (push tracker track-changes--clean-trackers) (when disjoint (push tracker track-changes--disjoint-trackers)) + (cl-assert (track-changes--sane-state-p)) tracker)) (defun track-changes-unregister (id) @@ -236,6 +238,7 @@ track-changes-unregister Trackers can consume resources (especially if `track-changes-fetch' is not called), so it is good practice to unregister them when you don't need them any more." + (cl-assert (track-changes--sane-state-p)) (unless (memq id track-changes--trackers) (error "Unregistering a non-registered tracker: %S" id)) (setq track-changes--trackers (delq id track-changes--trackers)) @@ -253,7 +256,8 @@ track-changes-unregister track-changes--buffer-size track-changes--before-clean track-changes--state)) - (remove-hook 'after-change-functions #'track-changes--after t))) + (remove-hook 'after-change-functions #'track-changes--after t)) + (cl-assert (track-changes--sane-state-p))) (defun track-changes-fetch (id func) "Fetch the pending changes for tracker ID pass them to FUNC. @@ -372,7 +376,8 @@ track-changes-fetch (funcall func beg end (or before lenbefore))) ;; Re-enable the tracker's signal only after running `func', so ;; as to avoid nested invocations. - (cl-pushnew id track-changes--clean-trackers)))) + (cl-pushnew id track-changes--clean-trackers) + (cl-assert (track-changes--sane-state-p))))) (defun track-changes-inconsistent-state-p () "Return whether the current buffer is in an inconsistent state. @@ -387,6 +392,26 @@ track-changes-inconsistent-state-p ;;;; Auxiliary functions. +(defun track-changes--sane-state-p () + (if (null track-changes--trackers) + (and (zerop track-changes--before-beg) + (zerop track-changes--before-end) + (equal track-changes--before-string "") + (null track-changes--buffer-size) + (eq track-changes--before-clean 'unset) + (null track-changes--state)) + (and (equal track-changes--buffer-size (buffer-size)) + (or track-changes--before-no + (pcase track-changes--before-clean + ('unset t) + ('set (<= track-changes--before-beg track-changes--before-end)) + ('nil + (<= track-changes--before-beg + (track-changes--state-beg track-changes--state) + (track-changes--state-end track-changes--state) + track-changes--before-end)) + (_ nil)))))) + (defun track-changes--clean-state () (cond ((null track-changes--state) @@ -551,7 +576,8 @@ track-changes--before (length track-changes--before-string)))))) (setf track-changes--before-end new-bend) (cl-callf concat track-changes--before-string - (buffer-substring-no-properties old-bend new-bend))))))))) + (buffer-substring-no-properties old-bend new-bend)))))))) + (cl-assert (track-changes--sane-state-p))) (defun track-changes--after (beg end len) (cl-assert track-changes--state) @@ -576,10 +602,26 @@ track-changes--after ;; BEG..END is not covered by previous `before-change-functions'!! (track-changes--recover-from-error `(unexpected-after ,beg ,end ,len)) ;; Note the new changes. + (let ((orig-beg (track-changes--state-beg track-changes--state)) + (orig-end (track-changes--state-end track-changes--state))) (when (< beg (track-changes--state-beg track-changes--state)) (setf (track-changes--state-beg track-changes--state) beg)) (cl-callf (lambda (old-end) (max end (+ old-end offset))) (track-changes--state-end track-changes--state)) + (cl-assert (or track-changes--before-no + (<= track-changes--before-beg + (track-changes--state-beg track-changes--state))) + nil "<=? %S %S (was %S)" + track-changes--before-beg + (track-changes--state-beg track-changes--state) + orig-beg) + (cl-assert (or track-changes--before-no + (<= (track-changes--state-end track-changes--state) + track-changes--before-end)) + nil "<=? %S %S (was %S)" + (track-changes--state-end track-changes--state) + track-changes--before-end + orig-end)) (cl-assert (or track-changes--before-no (<= track-changes--before-beg (track-changes--state-beg track-changes--state) @@ -591,7 +633,8 @@ track-changes--after (if (track-changes--tracker-immediate tracker) (funcall (track-changes--tracker-signal tracker) tracker) (run-with-timer 0 nil #'track-changes--call-signal - (current-buffer) tracker))))) + (current-buffer) tracker)))) + (cl-assert (track-changes--sane-state-p))) (defun track-changes--call-signal (buf tracker) (when (buffer-live-p buf)