在尝试设置保存某些持久状态的内容时遇到一些困难,以便我可以在 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 的评论激励我将它们切换到 devfar
和defcustom
):
; 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*
缓冲区中查看消息,所以...我不太确定发生了什么。
我认为我注意到的一件事(尽管很难确定,因为当这种情况发生时我可能没有积极关注)是这种情况发生在一个非当时-事件缓冲区,而不是我当前正在编辑的缓冲区。
所以,问题是:
- 我在这里做错了什么吗?
- 还有其他/更好的方法吗?
- 是否有我可以使用的以编程方式保存状态的标准方法? (我适本地查了一下,但没有找到任何东西......尽管也许我只是不知道要寻找什么。)
- 我可以做什么来帮助自己找到这个问题? (有什么办法可以设置断点之类的吗?)
- 我可以在这样的代码中使用其他保护措施吗?
欢迎任何其他想法。我添加了更多 (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/