tags:

views:

47

answers:

2

The documentation on Text Properties says:

Since text properties are considered part of the contents of the buffer (or string), and can affect how a buffer looks on the screen, any change in buffer text properties marks the buffer as modified.

First, I don't understand that policy. Can anyone explain? The text props are not actually saved in the file, when the buffer is saved. So why mark the buffer as modified? For me, buffer-modified indicates "some changes have not yet been saved." but understanding the policy is just for my own amusement.

More importantly, is there an already-established way that, in code, I can change syntax text properties on the text in a buffer, while keeping the buffer-modified flag set to whatever it was, prior to those changes? I'm thinking of something like save-excursion. It would be pretty easy to write, but this seems like a common case and I'd like to use the standard function, if possible.

For more on the scenario - I have a mode that does a full text scan and sets syntax-table properties on the text. After opening a buffer, the scan runs, but it results in a buffer with buffer-modified set to t .

As always, thanks.

+1  A: 

Perhaps it is simply because they are considered a part of the string... (like the docs say). Remember, Emacs is buffer-centric, not file-centric, so the fact that the contents get saved out on disk is somewhat irrelevant (when thinking buffer-centric).

Also, the properties are undo-able, and that definitely fits with having the buffer marked as modified.

I don't know that there is a standard way of saving the buffer-modified state, but I do see one 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 doesn't protect against nonlocal exits, so perhaps you'd want to add a call to unwind-protect, like so:

(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))))
Trey Jackson
Excellent, thank you. I had got the `set-buffer-modified-p` part, but not the `buffer-undo-list` thing.
Cheeso
But wait! This is still helpful, but look at my answer.
Cheeso
+2  A: 

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)))))
Cheeso
Nice, I didn't see that one. A little more complete than the one in pabbrev.
Trey Jackson