首页
归档
友情链接
关于
Search
1
在wsl2中安装archlinux
295 阅读
2
从零开始配置 vim(15)——状态栏配置
174 阅读
3
nvim番外之将配置的插件管理器更新为lazy
162 阅读
4
2018总结与2019规划
150 阅读
5
PDF标准详解(五)——图形状态
127 阅读
软件与环境配置
读书笔记
编程
Thinking
FIRE
菜谱
翻译
登录
Search
标签搜索
c++
c
emacs
学习笔记
elisp
windows
文本操作术
编辑器
NeoVim
Vim
win32
读书笔记
VimScript
linux
文本编辑器
投资理财
Java
反汇编
OLEDB
数据库编程
Masimaro
累计撰写
456
篇文章
累计收到
33
条评论
首页
栏目
软件与环境配置
读书笔记
编程
Thinking
FIRE
菜谱
翻译
页面
归档
友情链接
关于
搜索到
1
篇与
的结果
2026-10-18
《elisp 每日一练》——mode hook
在前面,我们分析minor mode 和 major mode 时忽略了hook相关的内容,一笔带过了。现在我们有了hook相关的知识,今天带着这些知识在回过头来看mode中的hook是如何被定义和调用的背景知识minor mode我们先从 minor mode 开始, 下面是我使用最基本的 define-minor-mode 得到的部分内容。在mode 的开关变量中我们发现下面几处与 hook 相关的内容(run-hooks 'my/focus-mode-hook (if my/focus-mode 'my/focus-mode-on-hook 'my/focus-mode-off-hook))run-hooks 后面可以接入多个hooks变量,它会依次执行变量中保存的hook函数。所以从这段代码中我们可以知道,不管当前是准备开启或者关闭minor mode,都会无条件的执行 my/focus-mode-hook。然后根据开启或者关闭的状态执行 my/focus-mode-on-hook 或者 my/focus-mode-off-hook在开关函数定义结束之后,还有下面的代码(defvar my/focus-mode-hook nil) (unless (get 'my/focus-mode-hook 'variable-documentation) (put 'my/focus-mode-hook 'variable-documentation "Hook run after entering or leaving `my/focus-mode'.\nNo problems result if this variable is not bound.\n`add-hook' automatically binds it. (This is true for all hook variables.)")) (put 'my/focus-mode-hook 'custom-type 'hook) (put 'my/focus-mode-hook 'standard-value (list nil))我们可以看到这里它采用 defvar 定义hook变量,但是后面又调用了 (put 'my/focus-mode-hook 'custom-type 'hook) 设置它在 customize 界面中的type。又设置了 standard-value 属性,这个也是 customize 变量的属性。实际上这里是将一个由 defvar 定义的普通变量转化成了 customize 类型的变量。也就是说Emacs区分变量是否是 customize 变量并不是根据是否调用 defcusom 定义,而是根据变量属性中是否有对应的属性。至于这里为什么不采用 defcustom 来定义,我也不太清楚,如果有了解的读者可以在评论区留言讨论。当然我们也可以在外部使用 defcustom 或者 defvar 定义同名的hook变量。后面的这些属性可以保证它被正确归类到 customize 变量中的 hook 类型。我们只看到了 define-minor-mode 定义 my/focus-mode-hook 变量,而没有定义 my/focus-mode-on-hook 和 my/focus-mode-off-hook。这意味着,开启和关闭的事件交由设计者自行处理,如果设计时需要关心开启或者关闭事件可以定义这两个变量,否则可以忽略。major modemajor mode 中我们已继承的模板进行展开,观察一下它里面有关hook的代码首先我们可以看到,启动函数中,大部分的代码被包裹在 delay-mode-hooks 中,它可以保证所有hook 在代码运行之后在运行。所以在它里面调用父类的mode启动函数并不会执行函数中定义的hook。此时父类的hook在 delay-mode-hooks 执行的最后被调用。而关于hook 的定义,我们可以找到(defvar my/foucs-mode-hook nil) (unless (get 'my/foucs-mode-hook 'variable-documentation) (put 'my/foucs-mode-hook 'variable-documentation "Hook run after entering `my/foucs-mode'.\nNo problems result if this variable is not bound.\n`add-hook' automatically binds it. (This is true for all hook variables.)"))也就是说在major mode中,它不再帮我们管理 hook 的定义,强行将它变为 customize 类型。或者换一个角度思考,对于 major mode中的hook,Emacs的设计者似乎更愿意使用 defvar 形式的普通变量。我们发现最终调用 hook时不再使用 run-hooks 而是调用 (run-mode-hooks 'my/foucs-mode-hook)。它与普通的 run-hooks 有什么区别呢?run-hook 会立即调用,但是 run-mode-hooks 更加复杂一点,我们这里不详细分析它的代码,我们只需要知道它配合 delay-mode-hooks 使用时,如果在 delay-mode-hooks 内部,它会将所有的hook暂时保存起来,在下一次调用 run-mode-hooks 时再调用。所以在这个基础上,我们可以这么理解调用hook的流程:调用父类的mode函数,最后会调用父类的 run-mode-hooks但是它父类的mode函数被放置在 delay-mode-hooks 内部,此时它会暂存需要执行的父类hookdelay-mode-hooks 内部开始执行子类的初始化代码子类的初始化代码执行完毕,此时跳出 delay-mode-hooks 宏在 delay-mode-hooks 宏外部,子类调用 run-mode-hooks此时会先调用之前被暂存的hook,然后调用子类的hook总结到此我们详细分析了major mode 和minor mode中有关hook的处理。现在总结如下:minor mode 中推荐使用 customize 类型的hook 变量,并且我们只要定义同名的hook变量,它会自动帮我们进行一些处理。调用hook的过程为,每次切换mode状态都会无条件的调用普通hook,但是如果我们关系开启和关闭状态,它还额外有调用off-hook 和 on-hook的机制major mode 中推荐使用 defvar 定义普通的hook变量,我们可以在外界定义同名的 customize 变量进行覆盖。在执行顺序上虽然会首先调用父类的mode函数,但是delay-mode-hooks 和最后调用的 run-mode-hooks 会保证在所有初始化都完成之后先调用 父类的hook、再调用子类hook
2026年10月18日
1 阅读
0 评论
0 点赞