From 0bee4cda881f7db4113cba541b684c334e828c4a Mon Sep 17 00:00:00 2001 From: Lars Ingebrigtsen Date: Tue, 10 May 2022 03:38:01 +0200 Subject: [PATCH] Reimplement recent with-silent-modifications auto-save changes * doc/lispref/buffers.texi (Buffer Modification): Document buffer-modified-p returning `autosaved'. * lisp/subr.el (with-silent-modifications): Use restore-buffer-modified-p instead of altering the buffer modiff (since this has other side effects like not updating after async `display' changes. * src/buffer.c (Fbuffer_modified_p): Allow returning whether the buffer has been autosaved after changes. (Frestore_buffer_modified_p): Allow adjusting whether the buffer has been autosaved after changes. * src/fileio.c (Fdo_auto_save): Refill the doc string. --- doc/lispref/buffers.texi | 10 +++++---- lisp/subr.el | 12 ++++------ src/buffer.c | 47 +++++++++++++++++++++++++++++----------- src/fileio.c | 11 ++++++---- test/src/buffer-tests.el | 35 ++++++++++++++++++++++++++++++ 5 files changed, 86 insertions(+), 29 deletions(-) diff --git a/doc/lispref/buffers.texi b/doc/lispref/buffers.texi index d8cf3d7919b..3e3b0bd9f01 100644 --- a/doc/lispref/buffers.texi +++ b/doc/lispref/buffers.texi @@ -541,10 +541,12 @@ file formerly visited. @ref{Text}. @defun buffer-modified-p &optional buffer -This function returns @code{t} if the buffer @var{buffer} has been modified -since it was last read in from a file or saved, or @code{nil} -otherwise. If @var{buffer} is not supplied, the current buffer -is tested. +This function returns non-@code{nil} if the buffer @var{buffer} has +been modified since it was last read in from a file or saved, or +@code{nil} otherwise. If @var{buffer} has been autosaved after +@var{buffer} was last modified, the symbol @code{autosaved} is +returned. If @var{buffer} is not supplied, the current buffer is +tested. @end defun @defun set-buffer-modified-p flag diff --git a/lisp/subr.el b/lisp/subr.el index 01549cc6f74..54c9f35264d 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -4594,21 +4594,17 @@ like `buffer-modified-p', checking whether the file is locked by someone else, running buffer modification hooks, and other things of that nature." (declare (debug t) (indent 0)) - (let ((modified (make-symbol "modified")) - (tick (make-symbol "tick"))) + (let ((modified (make-symbol "modified"))) `(let* ((,modified (buffer-modified-p)) - (,tick (buffer-modified-tick)) (buffer-undo-list t) (inhibit-read-only t) (inhibit-modification-hooks t)) (unwind-protect (progn ,@body) - ;; We restore the buffer tick count, too, because otherwise - ;; we'll trigger a new auto-save. - (internal--set-buffer-modified-tick ,tick) - (unless ,modified - (restore-buffer-modified-p nil)))))) + (when (or (not ,modified) + (eq ,modified 'autosaved)) + (restore-buffer-modified-p ,modified)))))) (defmacro with-output-to-string (&rest body) "Execute BODY, return the text it sent to `standard-output', as a string." diff --git a/src/buffer.c b/src/buffer.c index 6334e197f0e..f54714675e2 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -1376,12 +1376,23 @@ No argument or nil as argument means use current buffer as BUFFER. */) DEFUN ("buffer-modified-p", Fbuffer_modified_p, Sbuffer_modified_p, 0, 1, 0, - doc: /* Return t if BUFFER was modified since its file was last read or saved. -No argument or nil as argument means use current buffer as BUFFER. */) + doc: /* Return non-nil if BUFFER was modified since its file was last read or saved. +No argument or nil as argument means use current buffer as BUFFER. + +If BUFFER has been autosaved after BUFFER was last modified, the +symbol `autosaved' is returned. */) (Lisp_Object buffer) { struct buffer *buf = decode_buffer (buffer); - return BUF_SAVE_MODIFF (buf) < BUF_MODIFF (buf) ? Qt : Qnil; + if (BUF_SAVE_MODIFF (buf) < BUF_MODIFF (buf)) + { + if (BUF_AUTOSAVE_MODIFF (buf) == BUF_MODIFF (buf)) + return Qautosaved; + else + return Qt; + } + else + return Qnil; } DEFUN ("force-mode-line-update", Fforce_mode_line_update, @@ -1436,6 +1447,11 @@ and `buffer-file-truename' are non-nil. */) DEFUN ("restore-buffer-modified-p", Frestore_buffer_modified_p, Srestore_buffer_modified_p, 1, 1, 0, doc: /* Like `set-buffer-modified-p', but doesn't redisplay buffer's mode line. +A nil FLAG means to mark the buffer as unmodified. A non-nil FLAG +means mark the buffer as modified, except the special value +`autosaved', which will instead mark the buffer as having been +autosaved. + This function also locks or unlocks the file visited by the buffer, if both `buffer-file-truename' and `buffer-file-name' are non-nil. @@ -1475,16 +1491,19 @@ state of the current buffer. Use with care. */) recent-auto-save-p from t to nil. Vice versa, if FLAG is non-nil and SAVE_MODIFF>=auto_save_modified we risk changing recent-auto-save-p from nil to t. */ - SAVE_MODIFF = (NILP (flag) - /* FIXME: This unavoidably sets recent-auto-save-p to nil. */ - ? MODIFF - /* Let's try to preserve recent-auto-save-p. */ - : SAVE_MODIFF < MODIFF ? SAVE_MODIFF - /* If SAVE_MODIFF == auto_save_modified == MODIFF, - we can either decrease SAVE_MODIFF and auto_save_modified - or increase MODIFF. */ - : modiff_incr (&MODIFF)); - + if (NILP (flag)) + /* This unavoidably sets recent-auto-save-p to nil. */ + SAVE_MODIFF = MODIFF; + else + { + if (EQ (flag, Qautosaved)) + BUF_AUTOSAVE_MODIFF (b) = MODIFF; + /* If SAVE_MODIFF == auto_save_modified == MODIFF, we can either + decrease SAVE_MODIFF and auto_save_modified or increase + MODIFF. */ + else if (SAVE_MODIFF >= MODIFF) + SAVE_MODIFF = modiff_incr (&MODIFF); + } return flag; } @@ -6465,5 +6484,7 @@ will run for `clone-indirect-buffer' calls as well. */); defsubr (&Soverlay_put); defsubr (&Srestore_buffer_modified_p); + DEFSYM (Qautosaved, "autosaved"); + Fput (intern_c_string ("erase-buffer"), Qdisabled, Qt); } diff --git a/src/fileio.c b/src/fileio.c index 0610f7235a5..9da14c8f541 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -5972,14 +5972,17 @@ do_auto_save_eh (Lisp_Object ignore) DEFUN ("do-auto-save", Fdo_auto_save, Sdo_auto_save, 0, 2, "", doc: /* Auto-save all buffers that need it. -This is all buffers that have auto-saving enabled -and are changed since last auto-saved. -Auto-saving writes the buffer into a file -so that your editing is not lost if the system crashes. +This is all buffers that have auto-saving enabled and are changed +since last auto-saved. + +Auto-saving writes the buffer into a file so that your editing is not +lost if the system crashes. + This file is not the file you visited; that changes only when you save. Normally, run the normal hook `auto-save-hook' before saving. A non-nil NO-MESSAGE argument means do not print any message if successful. + A non-nil CURRENT-ONLY argument means save only current buffer. */) (Lisp_Object no_message, Lisp_Object current_only) { diff --git a/test/src/buffer-tests.el b/test/src/buffer-tests.el index c1e5d0ebed3..10dac68f9fe 100644 --- a/test/src/buffer-tests.el +++ b/test/src/buffer-tests.el @@ -1482,4 +1482,39 @@ with parameters from the *Messages* buffer modification." (when auto-save (ignore-errors (delete-file auto-save)))))))) +(ert-deftest test-buffer-modifications () + (ert-with-temp-file file + (with-current-buffer (find-file file) + (auto-save-mode 1) + (should-not (buffer-modified-p)) + (insert "foo") + (should (buffer-modified-p)) + (should-not (eq (buffer-modified-p) 'autosaved)) + (do-auto-save nil t) + (should (eq (buffer-modified-p) 'autosaved)) + (with-silent-modifications + (put-text-property 1 3 'face 'bold)) + (should (eq (buffer-modified-p) 'autosaved)) + (save-buffer) + (should-not (buffer-modified-p)) + (with-silent-modifications + (put-text-property 1 3 'face 'italic)) + (should-not (buffer-modified-p))))) + +(ert-deftest test-restore-buffer-modified-p () + (ert-with-temp-file file + (with-current-buffer (find-file file) + (auto-save-mode 1) + (should-not (buffer-modified-p)) + (insert "foo") + (should (buffer-modified-p)) + (restore-buffer-modified-p nil) + (should-not (buffer-modified-p)) + (insert "bar") + (do-auto-save nil t) + (should (eq (buffer-modified-p) 'autosaved)) + (insert "zot") + (restore-buffer-modified-p 'autosaved) + (should (eq (buffer-modified-p) 'autosaved))))) + ;;; buffer-tests.el ends here -- 2.39.2