emacs - elisp 代码破坏了缓冲区,而不是保存在其他地方......为什么?

标签 emacs elisp

在尝试设置保存某些持久状态的内容时遇到一些困难,以便我可以在 emacs 调用之间使用数据。

使用 another question 中的一些代码作为起点,我为我想做的事情想出了以下小代码片段:

(defmacro with-output-to-file (path &rest body)
  "record output of commands in body to file"
  `(save-excursion
     (let* ((buf (find-file-noselect ,path))
            (standard-output buf))
       (set-buffer buf)
       (erase-buffer)
       ,@body
       (save-buffer)
       (kill-buffer))))

然后我有一个使用它的函数,例如:

(defun my-save-some-data ()
  (with-output-to-file my-data-save-file
                       (prin1 my-data)))

编辑:它们都遵循如下代码(以前,它们都是 setq 的;感谢 @phils 的评论激励我将它们切换到 devfardefcustom):

; note: my actual variable names (and filename value) are different;
; changed for example sake:
(defvar my-data (make-hash-table :test 'equal) "Data for a thing")
(defcustom my-data-save-file "~/tmp/my-data.el" "File to save my data to")

(注意:我还有一个函数可以读回数据,该函数会在加载时或按需自动发生。)

我已将其设置为在几种情况下运行(也许太多?也许是糟糕的选择?无论如何,这就是我设置的):

(add-hook 'auto-save-hook 'my-save-some-data)
(add-hook 'kill-emacs-hook 'my-save-some-data)
(add-hook 'post-gc-hook 'my-save-some-data)

大多数时候,这都可以正常工作。然而,每隔一段时间,我就会遇到一个问题,数据被写入我之前打开的缓冲区之一(杀死那里所有以前的内容!),然后该缓冲区被杀死,并保存了更改。

可以说,这非常烦人,因为发生这种情况的缓冲区经常位于我一直在做一些工作的地方,但不一定将其 checkin 。

我尝试更改上面的宏,将 (set-buffer buf) 替换为:

       (with-current-buffer buf ; because set-buffer wasn't working??
         (erase-buffer)
         ,@body
         (if (eq buf (current-buffer))
             (progn
               (save-buffer)
               (kill-buffer))
           (message "buffer changed?!"))))))

这以某种方式设法使其追加到缓冲区,而不是覆盖它...所以我的 if 语句似乎在某种程度上起作用...但是我不这样做在我的 *Messages* 缓冲区中查看消息,所以...我不太确定发生了什么。

认为我注意到的一件事(尽管很难确定,因为当这种情况发生时我可能没有积极关注)是这种情况发生在一个非当时-事件缓冲区,而不是我当前正在编辑的缓冲区。

所以,问题是:

  1. 我在这里做错了什么吗?
  2. 还有其他/更好的方法吗?
  3. 是否有我可以使用的以编程方式保存状态的标准方法? (我适本地查了一下,但没有找到任何东西......尽管也许我只是不知道要寻找什么。)
  4. 我可以做什么来帮助自己找到这个问题? (有什么办法可以设置断点之类的吗?)
  5. 我可以在这样的代码中使用其他保护措施吗?

欢迎任何其他想法。我添加了更多 (message) 表单,希望同时获得更多调试信息。

更新:我发现这只发生在 post-gc-hook 上。我不知道我的变量是否以某种方式被破坏(也许切换到 defvar 和 defcustom 可以解决这个问题?),或者是否存在某种模糊的错误post-gc-hook 处理...检查是否使用最新更改重现测试用例。

最佳答案

你确实可以设置断点,一个简单的方法是将(edebug)放在你想要断点的地方。然后您可以使用 n 表示下一步,SPC 表示步骤,使用 e 进行评估。您可以阅读有关 edebug 的更多信息 here .

因此,您可以在调用 (set-buffer) 之前设置条件断点作为保护/警告,如下所示:

(when (get-file-buffer my-data-save-file) 
 (read-from-minibuffer 
   (format "Warning: %s is already being visited by a buffer, contents will be overwritten! Entering edebug" my-data-save-file))
   (edebug))

如果您在某个缓冲区中访问的文件即将被宏覆盖,这将向您发出警告,然后进入调试器,您可以在其中检查正在发生的情况。

这是find-file-no-select的文档字符串的一部分:

Read file FILENAME into a buffer and return the buffer.
If a buffer exists visiting FILENAME, return that one, but
verify that the file has not changed since visited or saved.

我的猜测是 my-data-save-file 已被缓冲区访问,因此这就是返回的缓冲区(随后被覆盖)。但你确实可以通过 (edebug) 找出发生了什么。

关于emacs - elisp 代码破坏了缓冲区,而不是保存在其他地方......为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19260509/

相关文章:

oop - EIEIO 组合(通过自己的槽暴露包含对象的槽)

python - emacs 的正确 flymake 配置是什么? (使用 Python.el)

c++ - 如何将 Emacs 24 配置为 K&R(或 Stroutrup)风格?

emacs - Emacs 是否有允许插入一些文本的只读或查看模式?

Emacs - 计算新窗口开始/结束而不重新显示

emacs - 从代码块的结果创建组织表

linux - 从 Linux 通过 SSH 连接到 Mac OS X(使用 XForwarding)时如何运行 Emacs?

ruby-on-rails-3 - Emacs Ruby 自动完成几乎可以工作

emacs - 为特定函数配置 emacs 变量

javascript - emacs缓冲区中的node.js没有进程——更好的系统在emacs中交互式执行js