要使用 Edebug 调试 Lisp 代码,必须先对代码 插桩(instrument)。 插桩会在代码中插入额外逻辑,以便在合适位置调用 Edebug。
在函数定义上使用前缀参数执行 C-M-x(eval-defun),
会在求值前先对定义进行插桩。(这不会修改源码本身。)
如果变量 edebug-all-defs 为非nil,则反转前缀参数的含义:
此时 C-M-x 默认会插桩, 除非 带有前缀参数。
edebug-all-defs 默认值为 nil。
命令 M-x edebug-all-defs 可切换该变量的值。
如果 edebug-all-defs 为非nil,
则 eval-region 和 eval-buffer 在求值时也会对定义插桩。
类似地,edebug-all-forms 控制 eval-region 是否对 所有 表达式插桩,包括非定义表达式。
这不适用于加载或迷你缓冲区中的求值。
命令 M-x edebug-all-forms 可切换该选项。
另一个命令 M-x edebug-eval-top-level-form
可对任意顶层表达式插桩,不受 edebug-all-defs 和 edebug-all-forms 影响。
edebug-defun 是 edebug-eval-top-level-form 的别名。
当 Edebug 处于激活状态时,命令 I(edebug-instrument-callee)
可对光标所在列表表达式调用的函数或宏进行插桩(如果尚未插桩)。
这仅在 Edebug 能找到该函数源码时有效;
因此,加载 Edebug 后,eval-region 会记录它所求值的每个定义的位置,即使没有插桩。
另见命令 i(see 跳转),它会在插桩后直接进入该调用。
Edebug 知道如何对所有标准特殊形式、带表达式参数的 interactive 形式、
匿名 lambda 表达式以及其他定义形式进行插桩。
但 Edebug 无法自行判断用户定义宏会如何处理宏调用的参数,
因此你必须通过 Edebug 规范提供相关信息;详情见 see Edebug 和 宏。
当 Edebug 在会话中第一次准备插桩代码时,会运行钩子 edebug-setup-hook,
然后将其设为 nil。
你可以用它来加载与你正在使用的包相关的 Edebug 规范,且只在使用 Edebug 时加载。
如果 Edebug 在插桩时检测到语法错误,会将光标停在出错代码处并抛出 invalid-read-syntax 错误。
例如:
error→ Invalid read syntax: "Expected lambda expression"
插桩失败的一个可能原因是:某些宏定义 Emacs 尚未加载。 解决方法是先加载定义了待插桩函数的文件。
要移除定义上的插桩,只需以**不插桩**的方式重新求值该定义。
有两种求值方式永远不会插桩:
使用 load 从文件加载,以及使用迷你缓冲区的 eval-expression(M-:)。
另一种移除插桩的方法是使用命令 edebug-remove-instrumentation。
它也可以移除所有已插桩代码的插桩状态。
更多 Edebug 内部可用的求值函数见 See 表达式求值。