Emacs:如何在设置文本属性时智能地处理缓冲区修改?

时间:2010-04-23 15:34:06

标签: emacs

The documentation on Text Properties说:

  

由于文本属性被视为缓冲区(或字符串)内容的一部分,并且可能影响缓冲区在屏幕上的显示方式,因此缓冲区文本属性的任何更改都会将缓冲区标记为已修改。

首先,我不明白这个政策。谁能解释一下?保存缓冲区时,文本道具实际上不会保存在文件中。为什么要将缓冲区标记为已修改?对我来说,缓冲区修改表示“尚未保存某些更改”。但了解这项政策只是为了我自己的乐趣。

更重要的是,是否有一种已经建立的方式,在代码中,我可以在缓冲区中的文本上更改语法文本属性,同时在这些更改之前将缓冲区修改标志设置为它是什么?我在想save-excursion之类的东西。 编写它会很容易,但这似乎是一种常见的情况,如果可能的话我想使用标准函数。

有关场景的更多信息 - 我有一种模式可以进行全文扫描并在文本上设置语法表属性。打开缓冲区后,扫描会运行,但会产生一个缓冲区已修改设置为t的缓冲区。

一如既往,谢谢。

3 个答案:

答案 0 :(得分:5)

较新版本的Emacs包含宏“with-silent-modification”:

C-h 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's text, other
than cosmetic ones, undo data may become corrupted.
Typically used around modifications of text-properties which do not really
affect the buffer's content.

答案 1 :(得分:3)

等待!我在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)))))

答案 2 :(得分:1)

也许只是因为它们被认为是字符串的一部分......(就像文档所说)。请记住,Emacs是缓冲区中心,而不是以文件为中心的,因此内容在磁盘上保存的事实有点无关紧要(当考虑以缓冲区为中心时)。

此外,属性是可撤消的,并且绝对适合将缓冲区标记为已修改。

我不知道有一种保存缓冲区修改状态的标准方法,但我确实在pabbrev.el库中看到了一个:

(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)))

它无法防范nonlocal exits,因此您可能希望添加对unwind-protect的调用,如下所示:

(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))))