在前面我们介绍了 Minor Mode 是如何在mode line中显示的。简单来说就是 mode line 的显示依靠 mode-line-format,默认的format 中存在一个名为 mode-line-modes 的符号,它会解析并显示 minor-mode-alist 的内容。在定义 minor mode 的时候通过关键字 lighter 传入的文字在调用 add-minor-mode 时会被加入 minor-mode-alist 中,在mode处于启用状态时显示。
在 define-derived-mode 中没有这样的关键字,它是直接通过宏参数赋值给 mode-name 进行显示。今天我们来看看背后发生了什么
背景知识
我们以 scratch buffer 为例。在Emacs中可以查到 mode-name 的值为 "Lisp Interaction"。
前面在讨论 mode-line-format 的时候提到过,当前加载mode的信息位于 mode-line-modes 变量中,我们查看该变量找到关键信息(在最开始的位置):
(:propertize (#1="" mode-name)
help-echo "Major mode
mouse-1: Display major mode menu
mouse-2: Show help for major mode
mouse-3: Toggle minor modes"
mouse-face mode-line-highlight
local-map
(keymap ...))根据我们前面介绍的 mode-line-format 格式,#1 是一个引用标记,等价于空字符,所以这部分显示的就单单只是 mode-name 的值
练习
各位读者在配置Emacs或者vim的 lsp 的时候会发现,一些插件会显示lsp 服务器的状态例如显示 lsp[connected] 字样表示已经连接上了lsp服务器。我们来尝试一下利用 mode-line-format 来模拟一下这个状态。
首先我们定义一些模拟函数
(defvar my/lsp-test-status nil
"模拟 LSP 连接状态。取值如 nil、'connected。")
(defun my/test-lsp-connect ()
(interactive)
(setq my/lsp-test-status 'connected)
(force-mode-line-update))
(defun my/test-lsp-disconnect ()
(interactive)
(setq my/lsp-test-status nil)
(force-mode-line-update))然后我们还需要一个根据状态查找显示字符串的函数:
(defun my/test-lsp-status ()
"根据 `my/lsp-test-status' 返回要显示的字符串。"
(pcase my/lsp-test-status
('connected " lsp [connected]")
(_ "")))最后我们定义一个对应的 Major Mode。根据文档,NAME 变量本身应该传入一个字符串,所以我们实际上不能直接在 NAME 字段输入列表作为显示内容,而应该在外部进行修改。
(define-derived-mode my/lsp-test-mode nil "Test"
"演示动态 mode-name。"
(setq mode-name '(:eval (concat "Test" (my/test-lsp-status)))))总结
本节的内容比较简单,实际上读者在阅读并理解了之前分析 minor mode 中显示的文章之后,本节内容差不多能无师自通了。唯一需要注意的是 NAME 参数在文档中已经明确说明是字符串。所以如果想要实现动态更新的话,可能要在后面修改 mode-name 的值。
评论 (0)