提到 Emacs,每个程序员应该或多或少听过其大名,毕竟 Emacs已经有将近四十多年的悠久历史。不过由于 Emacs "入道"门槛较高, 导致很多初学者还没领略其精髓就弃之而去。在“熟练”使用Emacs 之前,我也被其虐的体无完肤,因此在使用 Emacs 四年后, 觉得可以把个人经验分享出来,供有兴趣使用Emacs 的读者参考。
本文将分两部分来介绍如何入门 Emacs:
- 核心理念,很多初学者在简单尝试 Emacs 之后就放弃的原因是没了解其设计理念。Emacs 是如此独特,以至于从其他编辑器转过来时有很多不适。 通过了解其理念,读者可以判断 Emacs 是否符合自己的品味,是否值得花精力去掌握它
- 学习建议,笔者在真正把 Emacs 作为主力编辑器前也失败了多次,走了不少弯路,这里就会把我的经验分享给大家;其次会介绍日常使用的扩展。 很多用户选择 Emacs 就是因为某个插件的某个功能,即使现在,我时常也会因为发现某些高级用法而感叹 Emacs 的威力。
虽然本文会用 ELisp 来举例,但读者并不需要学习 ELisp,具备基本编程技能即可。其次本文以现在较为流行的 VSCode 编辑器来对比 Emacs 的特点,换做其他编辑器也是成立的。
Emacs is Emacs. VSCode/Vim/Sublime… is yet just another editor. —– 出处
核心理念
GNU Emacs 官方网站是这么介绍的:
An extensible, customizable, free/libre text editor — and more.
前一部还算直接,"可扩展、可定制、自由的文本编辑器",至于后面的 more 部分,则仁者见仁,智者见智。坊间一度传闻,Emacs 是伪装成编辑器的操作系统。 这一节就来揭开 Emacs 的神秘面纱。
文本编辑
不论 Emacs 的追捧者再怎么神化它,首先 Emacs 是一个文本编辑器,然后才是其他。与 VSCode 不同的是,Emacs 是为纯键盘操作而设计的, 与之类似的编辑器只有 Vi(m)。纯键盘操作无疑比鼠标点击更高效。不过对于初学者来说,使用鼠标点击菜单栏中的功能可能会更方便些。
单就文本编辑而言,Emacs 就提供了很多贴心的功能,这里列两举:备份与撤销。
备份
作为一名成熟的程序员,每时每刻都需要有备份的意识,毕竟错误在所难免。在 Emacs 中主要提供两种备份方式:
- 静态备份,发生在第一次打开文件时,备份的文件名结尾有
~
标示;而且支持多版本备份 - 自动备份(auto saving)。顾名思义,周期性保存当前正在编辑的文件,文件名头尾有
#
标示。 在保存时,自动备份的文件会被删掉,而当因意外原因(如死机)导致 Emacs 崩溃时,文件则会保留,此时可通过 recover-this-file 命令来恢复。
静态备份的文件 !Users!liujiacai!.emacs.d!README.org.~1~ !Users!liujiacai!.emacs.d!README.org.~2~ !Users!liujiacai!.emacs.d!customizations!editing.el.~1~* !Users!liujiacai!.emacs.d!customizations!editing.el.~44~* !Users!liujiacai!.emacs.d!customizations!editing.el.~45~* !Users!liujiacai!.emacs.d!customizations!editing.el.~46~* !Users!liujiacai!.emacs.d!customizations!editing.el.~47~* !Users!liujiacai!.emacs.d!customizations!editing.el.~48~* 自动备份的文件 #!Users!liujiacai!.emacs.d!customizations!misc.org# #!Users!liujiacai!.emacs.d!customizations!navigation.el#* #!Users!liujiacai!.emacs.d!elpa!lsp-java-20201105.1758!lsp-java.el# #!Users!liujiacai!.emacs.d!init.el#
上面是笔者电脑中部分的备份文件,得益于这两个功能,好多次把笔者从崩溃的边缘救回来。
Undo/Redo
在编辑文件时,撤销(Undo)和恢复(Redo)是很重要的功能,传统编辑器这两个操作都是线性的,而在 Emacs 中,则是树状的,这里通过一组文本编辑时的状态图来说明这两者的区别。
- 依次输入 a b c 三个字符,进入到下图中的 current 状态
;; o (initial buffer state) ;; | ;; | ;; o (first edit) ;; | ;; | ;; o (second edit) ;; | ;; | ;; x (current buffer state)
- 此时,撤销两步,回到
first edit
状态(即只输入了字符a
),传统编辑器的此时的状态为
;; o (initial buffer state) ;; | ;; | ;; x (current buffer state) ;; | ;; | ;; o ;; | ;; | ;; o
而 Emacs 则不然,其状态为
;; o (initial buffer state) ;; | ;; | ;; o (first edit) ;; | ;; | ;; o (second edit) ;; | ;; | ;; x (buffer state before undo) ;; | ;; | ;; o (first undo) ;; | ;; | ;; x (second undo)
其状态是追加的,一次撤销意味着返回上次的状态,所以下面的状态图可能更合适些:
;; (initial buffer state) o ;; | ;; | ;; (first edit) o x (second undo) ;; | | ;; | | ;; (second edit) o o (first undo) ;; | / ;; |/ ;; o (buffer state before undo)
- 此时,如果进行一次新的插入(比如字符
d
),此时文本上的字符虽然都为a d
,但编辑器的状态图是不同的,如下所示:
;; Undo/Redo: Emacs' undo ;; ;; o o ;; | | ;; | | ;; o o o ;; .\ | |\ ;; . \ | | \ ;; . x (new edit) o o | ;; (discarded . | / | ;; branch) . |/ | ;; . o | ;; | ;; | ;; x (new edit)
- 此时,如果再进行两次撤销,传统编辑器返回到 initial
状态(无任何字符),而 Emacs 则回到 second 状态(有
a b
两个字符)。
初次接触 Emacs 中的撤销与恢复,十分容易让人迷惑,我时常也被这个搞得晕头转向,不过幸好有 Undo Tree 这个插件来可视化撤销状态,上面的状态图就取自 UndoTree 代码中的注释,感谢其作者的贡献。
扩展、定制
At its core is an interpreter for Emacs Lisp, a dialect of the Lisp programming language with extensions to support text editing.
上面一小节介绍了文本编辑中两个非常实用的基本功能,其实这只是冰山一角,Emacs 可扩展、可定制的特性营造了一个富有创造力的社区,拥有无数功能强大的插件。也许读者会疑问,VSCode 也有丰富的插件市场,那 Emacs 与它们有什么不同呢?这与 Emacs 设计架构有关。
Emacs 本身可以看作是一个虚拟机(Lisp Machine),核心是一个用 C 实现的 ELisp 解释器(interpreter)。除了与操作系统交互的部分使用 C 语言实现外,其余部分均由 ELisp 实现,由核心的 ELisp 解释器解析执行。
在 Emacs 中的所有操作,相当于在解释器中进行函数调用。比如字符输入会调用
self-insert-command
函数。这意味着用户自己定义的代码与 Emacs 的源码(ELisp
部分)是平等的,比如 Emacs 源码里面定义了 foobar
这么一个变量,那么用户自己编写的函数可以直接修改它。
如果读者对 Lisp 不熟悉,可以这么类比,打开 Emacs 的界面对应着在终端输入
python
进入的交互式 REPL,键盘输入、鼠标点击均对应一个个函数调用。
基于核心的 ELisp 解释器,对 Emacs 的扩展变得十分简单(熟悉 ELisp
的前提下),比如在 init.el
中定义下面几行代码即可在 Emacs
中打开浏览器,对指定关键词进行 Google 搜索。
|
|
而 VSCode,即使是个 Hello World 级别的扩展,步骤也复杂的多,可参考:
基于 Emacs 功能完备的 Lisp 解释器,社区开发出了各式各样的插件,让一切都尽可能在 Emacs中完成。 比如听音乐、玩游戏、看EPUB 电子书、聊Telegram,甚至任何应用都能运行在 Emacs 里!
Emacs, "a great operating system, lacking only a decent editor"
自由
提到 Emacs,不得不提的人是 Richard Stallman,江湖人称“教主”。早期的 Emacs 有很多版本,而现在 GNU Emacs 基本上已经统一江湖了。
教主极力推崇自由软件,关于自由软件的定义,可以在 GNU 官方网站上找到,这里不再赘述。读者需要明确的是, GNU 社区中的 free 代表但是自由,而非免费。
自由软件毫无疑问极大促进了软件行业的发展,它让程序员有机会了解所用软件的实现机制,而 Emacs 作为教主早期的作品之一, 毫无疑问继承这种思想。每一个操作都可以追根溯源,喜欢这种自由感觉。
更多 Emacs Hackers 可参考:
- Famous EmacsUsers by Xah Lee
- Ruby Creator Matz on How Emacs Changed My Life by Xah Lee
- Emacs黑客列表 by manateelazycat
- Famous Emacs Users (that are not famous for using Emacs)
入门指南
经验分享
我接触 Emacs 是因为学习 Clojure,作为一门 Lisp,Emacs 毫无疑问是最佳的编辑器。不过由于原生 Emacs 功能“简陋”, 多次尝试不得要领,直到遇到 braveclojure 上 Emacs 教程,把 emacs-for-clojure 的配置 clone 到本地, 这才觉得 Emacs 也没那么“难用”。出于对 Lisp 的热爱,强迫自己尽量在 Emacs 中去编码,大概花了一两个月,度过了最艰难的适应期,以后就离不开它了。
到如今,我的配置文件已经丰富了许多,也有很多自己编写的函数。学习一门新语言之前,会把相关 Emacs 扩展先配置上, 让一切都在 Emacs 中运行。这里我想着重强调一点:
论单个功能来说,Emacs 可能不是最好的,但如何有机的把各个功能组合起来,减少切换,Emacs 无意是最优的。
这里结合自己的踩坑、使用经验,给出下面几条建议:
- 找个成熟的配置先把 Emacs 用起来,一开始不用去纠结细节,等有感觉后再去尝试自己定制。Spacemacs、Doom Emacs 是社区内最流行的两个,建议初学者两个都去尝试下,找最合适自己
- 找一个月重点突击,不要断断续续的使用 Emacs,否则很难适应它,一但过了这一个月,后面就是无限的“春风得意”
在各种插件满足不了自己的需求、有 BUG 时(我大概是在两到三年后),学习 ELisp,毕竟这才是它的精髓。我自己是参考了
- Learn X in Y minutes、
- Xah Lee 的 Practical Emacs Tutorial
- 善用
C-h i
,Emacs 自带的文档,以及 - How do I find out how to do something in Emacs?
- 接触社区,Emacs China 是我见过的质量最高的中文论坛,里面有很多资深的 Emacs Hacker 来解决初学者遇到的各种问题。
- 截止到 2020/11 月初,笔者使用 Emacs 比较追求“原汁原味”,尽量用 Emacs 自己的快捷键(
C-x C-s
之类), 虽然一年前小指就开始疼痛了,当时是把 CAPS 键映射为 Ctrl,这样用了一年左右,问题不能根治。虽然社区有推荐使用 evil (具有 Vim 的操作模式)来解决这个问题,但之前我觉得这不够“忠贞”,就一直没去用,直到最近发现了 viper mode 才意识到这种想法的幼稚,Emacs 的理念就是可以自己根据自身需求来定制,没有所谓的标准答案。对于其他编辑器的优点, Emacs 会吸收过来。于是立刻把 evil 配置上,从此彻底解放了我的小指。用了四年多的时间了,还是能从 Emacs 中学到些人生经验, 估计这是其他软件做不到的。这点也促使我写这篇文章,防止初学者陷入这种思维定势。
当然每个人的学习道路都不一样,读者可根据自身情况来调整,尽读书不如不读书。一些优质的中文学习资料:
- 一年成为Emacs高手 (像神一样使用编辑器) by 陈斌,这里是笔者对陈斌的一次采访
- 21 天掌握 Emacs by 子龙山人,这里是笔者对子龙山人的一次采访
插件推荐
Org-mode
Org-mode 这是很多非程序员选择 Emacs 的主要原因,简单来说它是一种类似 markdown 的标记语言,很多用户用它来记笔记、 管理 GTD,借助于 Emacs 强大的扩展能力,程序员用它来进行文学编程(literate programming),当之无愧的排在插件榜的第一名。🥇
目前我对 org-mode 使用比较简单,只是把它当时 markdown 来用,单就这一点,配合上 Emacs 的快捷键,就已经甩各种 md
编辑器好几条街了,org-mode 对表格的支持也非常棒,比如可以使用 org-table-transpose-table-at-point
命令将表格的行列调换过来。
Magit
Evil
上面在个人经验里面以及提到过 evil,它并不“邪恶”,而是 Extensible VI Layer for Emacs。除了把 Vi 的模态编辑移植过来外,
还增加了 emacs state,用于禁用所有的 vi 功能。由于是在 Emacs 里面,我们完全可以自定义快捷键来覆盖 vi 的默认快捷键,
达到 Emacs/Vi 的最佳融合,可以同时拥有 h j k l
与 C-a, C-e, M-s, M-f, M-b
。 拷贝 7 行的文本,
在 evil 的 normal state 下,只需要
7 yy
而原生 Emacs 则需要
C-a C-SPC C-u 6 C-n C-e M-w
The best editor is neither Emacs nor Vim, it's Emacs with Vim binding! —-出处
Dired
Ivy/Counsel/Swiper
Ivy/Counsel/Swiper 三件套是补全框架,它可以很方便的把当前操作的候选项以交互的方式展示出来,类似 VSCode 中的 Command Palette、 Intellj 中的 Double Shift。
虽然其他编辑器也有类似的功能,但是其功能不是局限,就是与其他功能分割,没有统一的体验。Emacs 则不同,再多的插件也能够有统一的体验, 这一点是非常影响用户体验的。这里通过 ivy-occur + wgrep + evil 批量修改多个文件中的内容来说明 ivy 套件的强大功能。
演示的目录有 1.txt
2.txt
两个文件,内容都是 hello world,这里批量修改为 hello emacs。
操作步骤:
counsel-ag
world 搜索当前目录下搜索含 world 的文件C-c C-o ivy-occur
打开 occur 界面C-x C-q ivy-wgrep-change-to-wgrep-mode
进入编辑模式:%s/world/emacs/g
借助 evil 修改内容C-c C-c wgrep-finish-edit
保存内容
当然,上面操作可以根据自己的习惯定义快捷键,上述五个步骤一气呵成,"挥一挥衣袖,不带走一片云彩"。
LSP
在 LSP 出现之前,没有统一的框架来解决不同语言的高亮、补全等现代 IDE 的基本功能,微软推出的 LSP 无疑已经成为业界标准, 无需使用正则这种既不准又耗自由的方式了。Emacs 中有两个扩展支持 LSP,分别是
目前我使用的是 lsp-mode,初学者可以都去尝试下,然后选择符合自己品味的那一款。
已经叛逃到 eglot 阵营,写 Rust 时还会用业界最快的 lsp-bridge。
More
除了上面介绍的几个扩展外,日常使用的扩展还有如下几个,当然还有很多有趣的扩展等着读者自己去发现。
- company 补全框架,可配合 lsp-mode 使用
- multiple-cursors 多光标点操作
- ace-jump-mode 根据字符,快速移动光标。下图为根据 p 进行快速跳转的示例
- yasnippet 模板系统,通过定义代码片段的缩写来简化输入
- flycheck 语法实时检查
- treemacs 文件目录树导航
- projectile 项目工作空间管理 上面图示展示了如何在一个项目中查找文件、在实现与测试中切换、切换不同的项目
总结
也许 Emacs 的普及程度远远比不上 VSCode,但这也并不算件坏事,比如那些伸手党们就不适合使用 Emacs,让他们进来只会拉低社区的整体水平; 而且 Emacs 是个开放的系统,会借鉴 VSCode 中优秀的设计,Emacs 与其他编辑器并不是互斥的。 之前论坛就有台湾的 Emacs Twitter 账户维护者“叛逃”到 VSCode 的讨论,这类具有争议话题毫无疑问会引起大家的关注, 但是别忘了 Emacs 自由的精神,符合自己的才是最好的,没必要一味沉迷在某个事物中,说到底,Emacs/VSCode 只是些工具而已, 解决实际问题才是最重要的,当然一个舒心的操作系统编辑器,会让这个枯燥的过程变得乐趣无穷。 最后,借 Mastering Emacs 中的一句话结束本文
Your patient mastery of Emacs is well-rewarded. I assure you.
参考资料
- Emacs Beginner's HOWTO
- Emacs As A Lisp Machine
- Ask HN: Is Visual Studio Code the Emacs of 21st century?
- What benefits does emacs offer over vs code
- What are the pros and cons of Vim and Emacs?
- Making Emacs popular again
- Buttery Smooth Emacs
- https://batsov.com/articles/2011/11/19/why-emacs/
- https://github.com/remacs/remacs#why-emacs