7

在 emacs 中,我有时会错误地调用 call-last-kbd-macro。撤消时,我希望撤消以原子方式撤消键盘宏的整个效果,但这不会发生。相反,我发现自己必须一次撤消宏的每一步。如何让emacs在执行宏之前返回到缓冲区状态?

4

2 回答 2

3

恐怕您不能仅使用内置'undo机制来做到这一点。Emacs 中的宏系统实际上会像用户实际键入击键(或鼠标事件)一样回放事物,因此撤消历史记录( buffer-undo-list) 会正常更新。

这里有一个关于如何扩展当前undo机制来做你想做的事情的建议。

  1. 扩展'undo以了解撤消列表中的新条目、macro-begin标记和macro-end元素

  2. 建议/更改宏播放以在宏播放的开头/结尾插入标记

  3. undo代码将两个标记之间的所有撤消事件视为一个单元并将它们全部撤消(并在撤消历史记录的末尾添加适当的标记,因此当您进行redo操作时,它们仍被视为单个块)

注意事项:

  • 这仅适用于在单个缓冲区中运行的宏,如果您的宏切换缓冲区(或在其他缓冲区中有副作用),则这些更改不会被视为块。
  • 如果您的宏在与开始时不同的缓冲区中结束,那么您必须干净地处理它 - 您不希望撤消列表中出现“不平衡”macro-beginmacro-end标记。

不用说,这是一项复杂的工作。祝你好运。

于 2010-10-28T03:54:14.960 回答
1

这可以很容易地通过覆盖undo-boundary例如noflet包来完成。

给定一个宏定义(由 生成insert-kbd-macro)如下:

(fset 'my-macro
   [... keys ...])

或者:

(fset 'my-macro
   (lambda (&optional arg) "Keyboard macro." (interactive "p") (kmacro-exec-ring-item (quote ([...keys...] 0 "%d")) arg)))

像这样编辑它:

(require 'noflet)

(fset 'my-macro
      (lambda (&optional arg) "Keyboard macro." (interactive "p")
        (undo-boundary)
        (noflet ((undo-boundary ()))
          (kmacro-exec-ring-item (quote ([...keys...] 0 "%d")) arg))
        (undo-boundary)))

如果您不想编辑所有宏定义,您也可以添加一个包装器,该包装器调用作为参数给出的宏,同时如上所述创建/抑制撤消边界。

于 2019-01-10T21:39:59.800 回答