首页
归档
友情链接
关于
Search
1
在wsl2中安装archlinux
301 阅读
2
从零开始配置 vim(15)——状态栏配置
176 阅读
3
nvim番外之将配置的插件管理器更新为lazy
165 阅读
4
2018总结与2019规划
154 阅读
5
PDF标准详解(五)——图形状态
131 阅读
软件与环境配置
读书笔记
编程
Thinking
FIRE
菜谱
翻译
登录
Search
标签搜索
c++
c
emacs
elisp
学习笔记
windows
文本操作术
编辑器
NeoVim
Vim
win32
读书笔记
VimScript
linux
文本编辑器
投资理财
Java
反汇编
OLEDB
数据库编程
Masimaro
累计撰写
469
篇文章
累计收到
33
条评论
首页
栏目
软件与环境配置
读书笔记
编程
Thinking
FIRE
菜谱
翻译
页面
归档
友情链接
关于
搜索到
2
篇与
的结果
2026-09-20
《elisp 每日一练》—— Major Mode 管理 abbrev-table
在前一篇博文中,我们讨论了Emacs中 abbrev-table 的基础用法,现在我们来看看 define-derived-mode 是如何管理 abbrev-table 资源的背景知识我们先来回顾一下之前默认展开时它是如何处理 abbrev-table(progn (defvar my/code-mode-abbrev-table) (unless (boundp 'my/code-mode-abbrev-table) (put 'my/code-mode-abbrev-table 'definition-name 'my/code-mode) (defvar my/code-mode-abbrev-table (progn (define-abbrev-table 'my/code-mode-abbrev-table nil) my/code-mode-abbrev-table))) (unless (get 'my/code-mode-abbrev-table 'variable-documentation) (put 'my/code-mode-abbrev-table 'variable-documentation (purecopy "Abbrev table for `my/code-mode'."))))首先通过 defvar 定义了一个以 mode 名称加上 -abbrev-table 形式的变量名。根据 defvar 的性质,如果我们在外部有这么一个名称的变量,那么它会使用我们定义的变量作为 Major Mode 的 abbrev-table 进行管理。后续利用 boundp 如果发现该变量名没有绑定值,那么它会自己使用我们在上一节中介绍的函数 define-abbrev-table 定义一个。另外的一些代码就是设置一些属性用于给对应的交互式工具展示信息。在mode函数中,主要的代码如下:(unless (or (abbrev-table-get my/code-mode-abbrev-table :parents) (eq my/code-mode-abbrev-table local-abbrev-table)) (abbrev-table-put my/code-mode-abbrev-table :parents (list local-abbrev-table)))这段代码仅仅通过我们前面介绍的 PROP属性中的 :parents 设置了继承关系。根据上面的代码,我们可以得出结论,默认情况下,它是以 mode 名称加上 -abbrev-table 形式的变量名 作为当前Major Mode 的 abbrev-table 进行管理,并且如果在定义时设置了继承关系,那么它会通过 :parents 属性设置 abbrev-table 的继承关系。实际上,define-derived-mode 也支持通过 :abbrev-table 关键字来进行abbrev-table 的管理,我们同样的以一个例子来展开讨论:(define-derived-mode my/code-mode prog-mode "MyCode" "继承自 prog-mode 的代码主模式" :abbrev-table (defvar major-mode-abbrev-table (define-abbrev-table 'majro-mode-abbrev-table nil "自定义 Major Mode 的 abbrev-table")))我们展开之后会发现,原来有关 abbrev-table 的一切代码都消失了,仅仅留下了(setq local-abbrev-table (defvar major-mode-abbrev-table (define-abbrev-table 'majro-mode-abbrev-table nil "自定义 Major Mode 的 abbrev-table")))我觉得可能是开发者觉得既然我们已经通过 :abbrev-table 指定了外部的 abbrev-table,那么对于继承和创建一定有自己的理解,就不需要我接管了。所以这里仅仅帮我们把当前 local-abbrev-table 变量指向了我们自己定义的 abbrev-table。所以这就给我们提了一个醒,使用 :abbrev-table 实际上是比较危险的行为,作为一个菜鸟,在不具备深入理解 abbrev-table 机制的情况下贸然使用 :abbrev-table 关键字可能会带来意想不到的问题。所以在处理 abbrev-table 的时候,最好的办法就是定义一个类似名称 abbrev-table 变量,我们只关心要往里面加入哪些对应的映射关系,而不考虑其他,其他内容由 define-derived-mode 自己处理。小结本节我们总结了 define-derived-mode 是如何管理 abbrev-table 的。如果不指定 :abbrev-table 关键字,它会默认将 mode 名称 + -abbrev-table 名称的变量作为当前Major Mode 的 abbrev-table 进行管理,主要操作是:设置文档属性,方便后续用户通过交互式窗口查看它的相关信息如果没有定义,默认定义一个空表设置 :parents 的继承关系更新当前 local-abbrev-table 设置而如果我们使用了 :abbrev-table 关键,它只会更新 local-abbrev-table 设置。也就意味着一切由我们自己处理,一切问题自己承担。所以在处理 abbrev-table 最好的办法是不使用 :abbrev-table 关键字,我们只关系表中的映射关系,其余的交给 define-derived-mode 处理。结合我们昨天提到的 edit-abbrevs 编辑方式,我们完全可以放心的把 abbrev-table 交由 define-derived-mode 自己处理
2026年09月20日
7 阅读
0 评论
0 点赞
2026-09-19
《elisp 每日一练》——abbrev table
一般,定义Major Mode 的时候需要管理 hook、mode-class、mode-name、keymap、abbrev-table、syntax-table这么六种资源。我们在前面介绍buffer 相关内容的时候我们跳过了 abbrev-table 的介绍,仅仅简单介绍了 syntax-table。在正式探索Major Mode 管理 abbrev-table 的秘密之前,需要先讨论一下 abbrev-table 的基础以及基本的使用方法基础知识所谓的 abbrev-table 它的全称是 Abbreviation Table 缩写表。读者如果对我之前写的vim script 教程有映像的话应该了解,abbrev 可以做到根据我们输入的简短的几个字母或者单词帮助我们扩展出想要的内容。例如我们输入 fn 按下 回车或者空格或者其他能表示输入关键字结束的按键,它会自动帮助我们将 fn 替换为 function一般来讲,一个 Abbrev Table 就是一个专门用来存储“缩写词 --> 展开词”映射关系的哈希表/查找表。与变量类似,Emacs中也有两种类型:buffer local 和 global 全局。buffer local 中的 abbrev-table 变量名称为 local-abbrev-table,而 全局的 abbrev-table 名称为 global-abbrev-table。定义并启用 abbrev-table我们可以通过 define-abbrev-table 定义一个缩写表。它的函数签名如下:(define-abbrev-table TABLENAME DEFINITIONS &optional DOCSTRING &rest PROPS)TABLENAME 是当前表的名称,它是一个符号DEFINITIONS 是一组定义好的映射关系,它是一个列表,列表的每一项都是一组 (key value) 形式的映射DOCSTRING 是当前列表的文档PROPS 是一个属性的列表。与 keymap 类似,它也支持继承机制,我们可以通过 PROPS 中的 :parents 定义父表。例如我们可以在 scratch buffer 中定义如下的 abbrev-table(define-abbrev-table 'my/list-abbrev-table '(("df" "(defun ()\n)") ("dm" "(defmacro ())")))我们可以通过开启buffer 的 abbrev-mode 来启用 abbrev-table,Emacs会根据输入的内容自动触发缩写,也可以调用 expand-abbrev 手动通知Emacs触发。在触发的时候Emacs会根据事先定义的 abbrev-table,按照优先查找 local-abbrev-table 然后查找 global-abbrev-table 的顺序。所以如果我们希望我们定义的 abbrev-table 能启用,可以使用 setq 将我们定义的变量绑定到 local-abbrev-table。因此我们如果要启用自定义的 abbrev-table,完整的代码应该如下:(define-abbrev-table 'my/list-abbrev-table '(("df" "(defun ()\n)") ("dm" "(defmacro ())"))) (setq local-abbrev-table my/list-abbrev-table) (abbrev-mode 1) ;; 也可以不启用,手动使用 expand-abbrev 主动触发abbrev table 的编辑Emacs 中并没有定义类似的 inert 或者 delete 这样的函数来修改某一项的映射关系,如果要修改某一项或者插入,都是通过 define-abbrev 来进行。删除操作我们只需要将对应项设置为 nil,而修改只需要对某项重新赋值即可。插入的话新定义一项原来没有的就可以了。例如对于lisp mode,我们加入快速定义交互式函数的项(define-abbrev my/list-abbrev-table "dfi" "(defun()\n(interactive))")如果想要一次性清空可以使用 clear-abbrev-table。Emacs还提供了一个交互式的修改方案,可以使用 edit-abbrevs 命令。该命令会打开一个新的窗口显示当前启用的 abbrev 项,我们可以直接进行修改,最后执行 C-c C-c 保存。持久化保存对于 abbrev-table 数据来说,我们并不会经常改动,可以说它适合作为外部的配置文件。Emacs当然有提供的手段。缩写默认定义在 ~/.emacs.d/abbrev_defs 中,我们可以修改 abbrev-file-name 变量来修改默认保存的位置。因此我们可以采用更合理的方式,例如:将 C/C++ 语言的数据保存在 ~/.emacs.d/abbrevs/c将 elisp 语言的数据保存在 ~/.emacs.d/abbrevs/elisp将 python 语言的数据保存在 ~/.emacs.d/abbrevs/py对于加载过来的数据,我们对于不合理的项可以使用上面提到的 define-abbrev 和 edit-abbrevs 进行编辑和修改,虽然在 edit-abbrevs 模式下,执行 C-c C-c 会默认执行 save-abbrevs 将内容保存到 abbrev-file-name 所指定的文件中,但是我们同样可以在关闭Emacs之前可以使用 write-abbrev-file 将当前buffer中的 abbrev 写入到指定文件保存。例如在scratch buffer中,我们使用 (write-abbrev-file (expand-file-name "~/.emacs.d/abbrevs/elisp")) 进行保存。对于保存的内容,我们可以通过 (quietly-read-abbrev-file &optional filename) 来读取。练习今天的练习我们就涉及Major Mode 了,我们根据上文使用 write-abbrev-file 保存的文件。编写一段加载指定 abbrev-file 并启用的代码(defun my/load-abbrev-file (filename) (interactive "fAbbrev File: ") (if (file-exists-p filename) (progn (quietly-read-abbrev-file filename) (setq local-abbrev-table my/list-abbrev-table) (abbrev-mode t))))上述代码非常简单。如果我们查看保存的内容会发现,它将我们通过 define-abbrev-table 的整个表达式都拷贝到对应的文件中,所以使用 quietly-read-abbrev-file 读取并执行代码之后会生成一个对应名称的变量,后面我只需要设置当前的 local-abbrev-table 为当前变量即可。总结本篇我们入门了 abbrev-table 的基础概念以及基本的操作API,本节涉及到的函数有:define-abbrev-tabledefine-abbrevwrite-abbrev-filequietly-read-abbrev-file
2026年09月19日
6 阅读
0 评论
0 点赞