推荐一下……理解 Emacs 的模式

Lobsters Hottest 新闻

摘要

文章解释了 Emacs 的架构模式,重点介绍了通用缓冲区数据模型和增量补全读取(ICR),并将其比作玫瑰的根与花瓣。文章强调了 Emacs 如何统一界面并通过 Elisp 实现可扩展性。

<p><a href="https://lobste.rs/s/rnpigi/may_i_recommend_understanding_emacs_s">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/05/14 02:25

# 容我推荐...理解Emacs的范式 来源:https://www.chiply.dev/post-emacs-carnival-may 想象一朵玫瑰,如果你愿意的话,选一朵紫色的(毕竟我们在聊Emacs)。 玫瑰的一端是根系,通过复杂且不断生长的须根网络汲取养分和氧化二氢。另一端则是玫瑰美丽绽放的花瓣:这是整株玫瑰生长的成果,吸引着欣赏的目光,也是通过授粉繁衍的基础。从架构上看,Emacs的范式让我想起这种绽放——我们能发现,Emacs的扇入(fan-in)与扇出(fan-out),正如这朵紫色玫瑰的根系与花瓣,以同样美妙而富有生命力的方式运作。 想想缓冲区(buffer)吧。你在Emacs里看到的任何东西(不用枚举,我的意思是**一切**)都是一个承载着字符与文本属性的缓冲区。我稍微简化了一点,但大致如此。这种标准化就是核心数据模型,其他一切皆由此生发。 玫瑰的根系,无论从黏土、土壤还是沙地中汲取矿物质(最终都不过是水与离子),看起来都大同小异。在Emacs中,**任何**东西都被抽象为缓冲区中的字符与属性(扇入)。其推论是:你学到的每一个编辑基本操作——搜索、删除、标记、窄化、替换、撤销等等——都能作用于你在Emacs里看到的**每一**块内容,因为相对于这个数据模型,没有任何特殊之处,也不会出现例外。字符+文本属性就是那个统一概念,而承载它们的缓冲区提供了一套通用词汇表,让你可以用Emacs随心所欲地表达你的愿望,朱丽叶 😉。 在这套词汇之上是Elisp,而在Elisp之上则是各种应用。但凡你能想到的东西(邮件、RSS、日历、版本控制、文件管理、IRC、音乐、财务账本、终端等等),无外乎是一个小小的Elisp程序,将文本放入缓冲区(通常带有专门的major-mode),并将按键绑定到能转换和导航这些文本的命令上。 像[Magit](https://magit.vc/)这样复杂的东西,与我自己写的一个在弹出缓冲区中绘制ASCII玫瑰的简单模式,在语言层面上并没有根本区别。驱动这些模式的Elisp实体处于同一命名空间,共享相同的API,并遵循同样的Emacsen与Elispien惯例。这便是“界面统一”的深层含义:你不仅仅是通过一个界面来查看不同事物(这本身已有价值),而是**通过这一个界面**来构建、扩展和重构它们。如果某个用例还没有应用,构建一个也很容易,因为你拥有Elisp的全部力量。 下一个范式位于输入层,令人联想到许多“触手可及”的比喻。当Emacs让你选择某物(文件、缓冲区、命令,或者任何上下文中的候选项)时,它并不会要求你逐字记住你要找的东西。**渐进式补全读取**(Incremental Completing Read, ICR)极大地减轻了在Emacs内搜索任何东西时的回忆负担;而像[Orderless](https://github.com/oantolin/orderless)这样提供灵活筛选的包,使得最终候选集足够小且具体,以至于识别通常轻而易举。 Emacs中的ICR可以获取当前所有的候选集合,并在你键入时实时过滤,根据最近使用和[频率](https://en.wikipedia.org/wiki/Frecency)排序、模糊匹配、按相关性重新排序等等。当你按下M-x(来运行命令)时,你不需要知道确切命令名;你只需知道——或者更准确地说“凭直觉感知”——它的大致形态,从而缩小范围。由于Emacs中的每个域最终都会通过同一个minibuffer机制暴露其候选对象,整个“你可能需要的事物宇宙”都通过一个单一、极其熟悉的选择器来拉取(扇入)。在运行时,你可以凭借自己脑中那个微小而模糊的对目标的印象,来具体化并搜索这个宇宙(扇出)。这种召回功能不仅使Emacs强大,而且在认知上非常符合人体工程学。就像缓冲区+文本+属性一样,一段时间后你会发现,Emacs的绝大部分使用都汇聚到这个统一的minibuffer补全界面中。 ICR只是故事的一部分。选出候选后,你还能用它做什么?Emacs狡猾地回答“什么不能做!”,然后更贴心地补充道“让我**准确**告诉你都能做什么”。这源于一种我称之为**识别-分发**(recognize-dispatch)模式的实现。 在大多数软件中,“我能对屏幕上这个东西做什么”的答案被硬编码为一个单一的默认操作:文件打开对话框用来打开文件,联系人选择器用于选择联系人,等等。像[Embark](https://github.com/oantolin/embark)和[Hyperbole](https://www.gnu.org/software/hyperbole/)这样的包则在这里改变了数量关系,使之更优。 任何“东西”(在Emacs的世界里,这个词很有意思)——只要你能将光标放在上面(文件路径、URL、符号、区域等等)——都有一个类型,并且该类型关联着一个操作菜单。由于类型和操作都是可扩展的,Embark提供了将特定类型(或一组特定类型)分配给Emacs中出现的**任何**东西(扇入)的能力,并允许你对那个东西执行**任何**操作(扇出)。 这样一来,例如,一个符号是一个你可以描述、跳转、出现搜索、重命名、在网络搜索、交给LLM等等的对象……一个文件是一个你可以打开、差异化、复制路径、重命名、附加到邮件等等的对象……“等等”这个词非常字面化,特别是考虑到你可以将任何带参数的命令用作Embark操作(不限于定义好的菜单中的内容)。这样,随着你不断扩展Emacs,操作会不断累积。当你安装一个新包(扇入)时,你所有的现有名词或类型突然获得了新的动词或操作(扇出)。 另外,考虑一下如何用Emacs实现与Unix shell相似的管道范式。在精神上,这复现了90年代[CLIM(Common Lisp Interface Manager)](https://en.wikipedia.org/wiki/Common_Lisp_Interface_Manager)中演示类型(presentation-types)的实现:Emacs中某个命令的输出可以通过这个识别-分发系统成为另一个命令的输入。蛇咬住了自己的尾巴,但不知怎么地并不是自我吞噬的方式,就像全能的Unix shell一样。 通过这种方式添加的一组特别强大的操作来自Emacs中的语言服务器。几十年来,“转到定义”、“查找引用”和“重命名符号”都是IDE的专有特权——那些IDE是为特定语言手工编写(并标价)的。[语言服务器协议(Language Server Protocol, LSP)](https://microsoft.github.io/language-server-protocol/)将这种内省功能外部化到每个语言专用的服务器中,该服务器使用通用格式通信。Emacs(通过[eglot](https://github.com/joaotavora/eglot)或[lsp-mode](https://emacs-lsp.github.io/lsp-mode/))与服务器对话,服务器报告类型和位置,Emacs将结果渲染到缓冲区中。结果是,Emacs现有的类型化事物机制继承了语言服务器的内省能力,每种有对应服务器的语言(扇入)都适用。学习新语言的成本骤降(对我而言好极了!),因为编辑器不需要学习任何新东西;只有服务器(或服务器的实现者)需要。这样,你就可以使用相同使用模式,轻松地以任何语言导航、编码和执行(扇出)。 这个范式中蕴含着巨大的力量:识别名词,分发动词。将所有实例汇入单一通道(扇入);再以你安装过的所有扩展的全部力量,从这个通道辐射出去(扇出)。 这种扇入、扇出也发生在应用层面。拿[elfeed](https://github.com/skeeto/elfeed)来说,它是Emacs中领先的RSS阅读器。你所订阅的任何新闻源的各种琐碎细节,都将新项目汇入elfeed-search缓冲区中的一个扁平列表(扇入);而在浏览和消费这些新闻源时,所有Emacs中适用于其他模式的功能对你也是可用的(扇出)。再比如[mu4e](https://www.djcbsoftware.nl/code/mu/mu4e.html),一个流行的Emacs邮件包。来自你所有邮箱的邮件,再次被汇入一个单一扁平列表(扇入),而你可以利用Emacs的全部能力来导航邮件、阅读和回复(扇出)。 玫瑰之所以有这样的结构,是因为它有效;多年的进化赋予了它美丽的形式与功能。 绽放: 广泛地拉取,狭窄地推送;狭窄地拉取,广泛地推送。 借助**识别-分发**:广泛地拉取一切到文本缓冲区,狭窄地推送到可操作的类型系统;从这个稀疏的类型化事物集合中狭窄地拉取,广泛地推送到任何可以想象的操作。 在此期间任何需要的搜索或选择,都由ICR变得毫不费力——顺便说一句,类型和操作仍然可用(多亏了Embark)。广泛地拉取任何候选源进入Emacs,狭窄地推送到minibuffer的ICR系统;从过滤后的候选集中狭窄地拉取,广泛地推送到你所选对象上的任何可想象操作。 你甚至可以看到这两种模式优雅地协同工作:假设要为某个泛化目标调度一个巨大的操作菜单。你不想手动扫描which-key缓冲区来选择那个操作,那么你可以使用embark-help来启动ICR,用这种方式选择你的操作。太美了! Emacs的范式并非偶然。它们更像是每个有抱负的通用工具最终都会问的一个问题的正确答案,这个问题是:“如何用一个界面代表多个,同时不丢失任何特定性?”

相似文章

我可以推荐 Emacs 的创新 UI——eww 吗?

Lobsters Hottest

文章推荐使用 Emacs 的 eww 网页浏览器,强调其缺少 JavaScript 的特性改善了许多网站的体验,并指出 Emacs 提供了独特的 UI 创新,如逐张图片调整大小和键盘导航。

Emacs 的更多内置功能

Lobsters Hottest

一篇博客文章,介绍了Emacs中不太为人所知但实用的内置功能,延续了一个旨在提高原版Emacs功能可发现性的系列。

还有人用 Emacs 吗?

Lobsters Hottest

作者对与 Emacs 数十年关系的个人反思,包括转向 VSCode 和 IntelliJ,最终因其独特功能回归 Emacs。

软件界的Emacs化

Hacker News Top

作者讲述了在终端中阅读 Markdown 的烦恼,并描述了如何使用 Claude 快速构建一个自定义的 macOS Markdown 查看器(MDV.app),展示了 AI 如何让人能够迅速创建个人软件工具。