我在尝试设置保存某些持久状态的东西时遇到了一些困难,因此我可以在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
和{{1 }}):
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)
替换为:
(set-buffer buf)
这已经设法导致它追加到缓冲区,而不是覆盖它...所以我的if语句似乎确实在某种程度上起作用...但是我没有看到我的 (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?!"))))))
缓冲区中的消息,所以...我不太确定发生了什么。
我想到的一件事我注意到了(尽管我很难确定,因为当这种情况发生时我可能没有积极关注)是这种情况发生在当时不是 - 当时 - 活动缓冲区,而不是我正在编辑的缓冲区。
所以,问题:
欢迎任何其他想法。我正在添加更多*Messages*
表单,希望同时获得更多调试信息。
更新:我发现这只发生在(message)
上。我不知道我的变量是否以某种方式被破坏(并且可能切换到post-gc-hook
和defvar
将解决这个问题?),或者在后gc-hook处理中是否存在某种模糊的错误...通过最新的更改检查复制测试用例。
答案 0 :(得分:2)
您确实可以设置断点,一种简单的方法是将(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)。
答案 1 :(得分:1)
快速回复你所说的一些内容。您的消息永远不会出现,可能是因为您测试with-current-buffer
的缓冲区是否为current-buffer
,它始终是,除非body
更改当前缓冲区。
但您使用with-current-buffer
代替save-excursion
后跟set-buffer
是正确的。
至于其他方式:为什么不将数据放在临时缓冲区中,然后使用write-file
或append-to-file
或write-region
?
FWIW,我简单地尝试了你的代码,没有看到任何问题。但我只是为(prin1 (symbol-function 'my-save-some-data))
尝试了一个简单的body
和文件的常量文件名。我尝试使用预先存在的文件,是否使用预先存在的缓冲区,以及是否使用预先存在的未保存的修改缓冲区。
您是使用解释代码(例如,宏存在)还是字节编译代码进行测试?