前面我们介绍了 define-minor-mode 中的init-value、global、keymap、lighter 关键字,了解了它对于开关变量、快捷键和 mode line 显示上的管理。现在我们进入关于 define-minor-mode 的最后一个步骤,看看如何利用body管理minor mode 中自定义的资源
背景知识
我们来编写一个简单的测试代码
(define-minor-mode my/focus-mode
""
:lighter "My focus"
(message "welcome to my focus mode"))展开之后,我们发现它被包裹在开关函数之中,无条件的被执行。根据我们前面介绍的该宏的几个核心动作,它位于维护 local-minor-modes 之后,但是在执行 hook 变量之前。所以我们在编写这部分代码时通常要先判断当前mode是处于卸载还是加载的状态。
一个良好的 Minor Mode 应该不影响其他buffer,关闭和开启时也没有残留,所以我们这部分代码一定要重视资管的管理。Emacs中主要的资源有变量、hook、定时器、以及一些ui特效。对于它们的管理一般的规范如下:
- 对于变量,尽量使用
setq-local避免污染全局,同时在退出时记得将它还原成原来的值 - 对于 hook 来说,add-hook 时尽量使用 buffer local 的 hook,在关闭当前mode时要记得卸载hook
- 对于timer 来说, 定义也应该使用
setq-local,关闭时记得关闭 - 在UI上面,开启时应该保存原值之后再修改,关闭时恢复原始模样
练习
本节的内容比较简单,因此我们的练习也比较简单,我们定义个简单的mode,用于改变当前buffer的一些UI特性,我这里简单的将它的特性定义为:
- 显示行号,并且显示相对行号
- 调整光标样式为一条细竖线
- 标记光标所在行
我们需要管理这些属性,以便退出mode 时它能正常恢复
(define-minor-mode my/normal-notepad-mode
"修改Emacs的显示效果"
:lighter " LD"
(if my/normal-notepad-mode
(progn
;; 保存当前值(buffer-local 保存)
(setq-local my-line-display--saved-line-numbers
(if (bound-and-true-p display-line-numbers)
display-line-numbers-type
'off))
(setq-local my-line-display--saved-hl-line
(if (boundp' hl-line-mode) hl-line-mode global-hl-line-mode))
(setq-local my-line-display--saved-cursor-type
(if (boundp 'cursor-type) cursor-type t))
;; 应用新设置
(setq-local display-line-numbers-type 'relative)
(display-line-numbers-mode 1)
(hl-line-mode 1)
(setq-local cursor-type 'bar))
(progn
;; 恢复行号
(if (eq my-line-display--saved-line-numbers 'off)
(display-line-numbers-mode -1)
(setq-local display-line-numbers-type
my-line-display--saved-line-numbers)
(display-line-numbers-mode 1))
;; 恢复高亮行
(unless my-line-display--saved-hl-line
(hl-line-mode -1))
;; 恢复光标
(setq-local cursor-type my-line-display--saved-cursor-type))))上面的套路非常简单,先判断当前状态,如果处于开启状态下,我们可以先保存原始值,再进行覆盖。如果关闭我们使用原来保存的值进行恢复。需要注意的是,因为我们仅仅关注当前buffer的显示,所以这里我们应该使用 setq-local 定义局部缓冲区变量。另外要保存未启用时的原始值,我们只能在开启状态,设置这些属性之前进行处理,否则我们取到的就不是原始值。
小结
本篇我们的内容非常简单,我们主要提供一个代码为大家演示了如何正确获取原始值并在关闭mode的时候恢复原始状态。
评论 (0)