在 emacs-rime 中的断言(pyim 中称为探针)是相当实用的功能,配置的好的话可以在输入过程中做到完全自动切换中英文。
我希望在配置中不同的 mode 中能有不同的断言,因此写了个判断函数,根据不同的mode 计算不同的断言函数的值,然后集中返回;另外还自定义了几种自己需要的断言,如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| (defun +rime-predicate-button-at-point-p ()
"Determines whether the point is a button.
\"Button\" means that positon is not editable."
(button-at (point)))
(defun +rime-predicate-beancount-p ()
"Predicate input state in `beancount-mode.'
Determines whether current buffer's `major-mode' is
`beancount-mode', and the cursor is at the beginning of the
line."
(when (derived-mode-p 'beancount-mode)
(not (or (nth 3 (syntax-ppss))
(nth 4 (syntax-ppss))))))
(defun +rime-predicate-multi-mode-english-p()
"Using different predicates in different modes."
(if (derived-mode-p 'telega-chat-mode
'text-mode)
(rime-predicate-auto-english-p)
(or (rime-predicate-after-alphabet-char-p)
(rime-predicate-prog-in-code-p)
(+rime-predicate-beancount-p))))
(setq rime-disable-predicates '(rime-predicate-evil-mode-p
+rime-predicate-button-at-point-p
rime-predicate-punctuation-line-begin-p
+rime-predicate-multi-mode-english-p))
|
从中可以看到对 `telega-chat-mode` 和 `text-mode` 两种模式使用了不同的断言逻辑,实际应用满足了我的需求。
如果使用的 mode 很多,每种 mode 又需要不同的断言组合,那就需要对判断函数增加逻辑。可以预想,很有可能会发展成类似于
(if 条件1 (逻辑1) (if 条件2 (逻辑2) (if 条件3 (逻辑3) (……))))
的形式。
恰好这时在 Emacs China 论坛 上看到关于 buffer-local 变量的帖子,以前对 `setq-default` 和 `setq-local` 一头雾水,这次经过回帖的解释,总算明白了 buffer-local 变量的用处。
对于我用断言的情况,不正是 buffer-local 变量的使用场景吗?把之前配置里 17 行以后的代码修改一下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| (setq-default rime-disable-predicates
'(+rime-predicate-button-at-point-p
rime-predicate-evil-mode-p
rime-predicate-punctuation-line-begin-p
rime-predicate-after-alphabet-char-p
rime-predicate-prog-in-code-p
+rime-predicate-beancount-p))
(add-hook 'telega-chat-mode-hook
(lambda() (setq-local rime-disable-predicates
'(+rime-predicate-button-at-point-p
rime-predicate-evil-mode-p
rime-predicate-punctuation-line-begin-p
rime-predicate-auto-english-p))))
(add-hook 'text-mode-hook
(lambda() (setq-local rime-disable-predicates
'(+rime-predicate-button-at-point-p
rime-predicate-evil-mode-p
rime-predicate-punctuation-line-begin-p
rime-predicate-auto-english-p))))
|
也就是先用 `setq-default` 设置一个大部分 mode 都用的默认断言组合,其次对需要单独设置的 mode 用 `setq-local` 设置 buffer-local 断言组合,通过 `add-hook` 使其在进入对应 mode 时设置生效。
这种方式配置代码行数可能会增多,但是逻辑简单,无论多少个不同需求的 mode ,只需要依此类推逐个 `setq-loca` 设置就好了,不容易出错。
最后安利一下 `doom-emacs` ,提供了很多简化代码的宏,如上述两个 `setq-loca` 在 `doom-emacs` 里就可以写为:
1
2
3
4
5
6
| (add-hook! (telega-chat-mode text-mode)
(setq-local rime-disable-predicates
'(+rime-predicate-button-at-point-p
rime-predicate-evil-mode-p
rime-predicate-punctuation-line-begin-p
rime-predicate-auto-english-p)))
|
搞定,简单吧?
注: 最新的断言配置在 github仓库 ,里面的逻辑稍微复杂点,谨供参考。