Emacs: How to intelligently handle a buffer when changing text properties?

The text property documentation says:

Since text properties are considered part of the contents of the buffer (or string) and can affect the display of the buffer on the screen, any change in the properties of the text buffer places the buffer as changed.

First, I do not understand this policy. Can anyone explain? Text details are not actually saved in the file when the buffer is saved. So why mark the buffer as modified? For me, a buffer change indicates that "some changes have not yet been saved." but understanding politics is just my own entertainment.

More importantly, is there an already established way that in code I can change the properties of the syntax text in the text in the buffer, while retaining the flag modified by the buffer before it was before these changes? I am thinking of something like save-excursion . It would be pretty easy to write, but this seems like a normal case, and I would like to use a standard function if possible.

More about the script - I have a mode that performs a full scan of the text and sets the syntax properties in the text. After opening the buffer, scanning is performed, but as a result, a buffer is created with the modified buffer set to t.

Thanks as always.

+7
emacs
source share
3 answers

Wait! I found this in cc-defs.el

 ;; The following is essentially `save-buffer-state' from lazy-lock.el. ;; It ought to be a standard macro. (defmacro c-save-buffer-state (varlist &rest body) "Bind variables according to VARLIST (in `let*' style) and eval BODY, then restore the buffer state under the assumption that no significant modification has been made in BODY. A change is considered significant if it affects the buffer text in any way that isn't completely restored again. Changes in text properties like `face' or `syntax-table' are considered insignificant. This macro allows text properties to be changed, even in a read-only buffer. This macro should be placed around all calculations which set \"insignificant\" text properties in a buffer, even when the buffer is known to be writeable. That way, these text properties remain set even if the user undoes the command which set them. This macro should ALWAYS be placed around \"temporary\" internal buffer changes \(like adding a newline to calculate a text-property then deleting it again\), so that the user never sees them on his `buffer-undo-list'. See also `c-tentative-buffer-changes'. However, any user-visible changes to the buffer \(like auto-newlines\) must not be within a `c-save-buffer-state', since the user then wouldn't be able to undo them. The return value is the value of the last form in BODY." `(let* ((modified (buffer-modified-p)) (buffer-undo-list t) (inhibit-read-only t) (inhibit-point-motion-hooks t) before-change-functions after-change-functions deactivate-mark buffer-file-name buffer-file-truename ; Prevent primitives checking ; for file modification ,@varlist) (unwind-protect (progn ,@body) (and (not modified) (buffer-modified-p) (set-buffer-modified-p nil))))) 
+3
source share

Newer versions of Emacs include a "with-silent-changes" macro for this:

 Ch f with-silent-modifications ------------------------------------------------------ with-silent-modifications is a Lisp macro in `subr.el'. (with-silent-modifications &rest BODY) Execute BODY, pretending it does not modify the buffer. If BODY performs real modifications to the buffer text, other than cosmetic ones, undo data may become corrupted. Typically used around modifications of text-properties which do not really affect the buffer content. 
+5
source share

Perhaps this is simply because they are considered part of the string ... (as the docs say). Remember that Emacs is buffer-oriented, not file-oriented, so the fact that the contents are stored on disk is somewhat irrelevant (with mental buffering).

In addition, the properties are invalid and, of course, correspond to the fact that the buffer is marked as modified.

I do not know that there is a standard way to save the state modified by the buffer, but I see it in the pabbrev.el library:

 (defmacro pabbrev-save-buffer-modified-p (&rest body) "Eval BODY without affected buffer modification status" `(let ((buffer-modified (buffer-modified-p)) (buffer-undo-list t)) ,@body (set-buffer-modified-p buffer-modified))) 

It does not protect against non-local outputs , so perhaps you need to add an unwind-protect call, for example:

 (defmacro save-buffer-modified-p (&rest body) "Eval BODY without affected buffer modification status" `(let ((buffer-modified (buffer-modified-p)) (buffer-undo-list t)) (unwind-protect ,@body (set-buffer-modified-p buffer-modified)))) 
+1
source share