Emacs 导学
如果你打算学习 Emacs,可从本文了解以下内容:
- Emacs 是什么
- Emacs 能做什么
- Emacs 使用收益
- Emacs 学习难点
1. Emacs 是什么
现代的 Emacs 是一个编辑器家族,GNU Emacs (后简称 Emacs)是其中最主要的版本。
本文编写时,最新版本是即将发布的 Emacs 29.0。
Emacs 是 自由软件基金会 的自由软件,它最初是由自由软件运动领袖 Richard Matthew Stallman(自称 RMS) 在 1974 至 1976 年在 MIT 人工智能实验室的不兼容分时系统(ITS)上开始编写,它其实是一堆由一种不完备的语言 TECO(Tape/Text Editor & Corrector)宏;现在的 GNU Emacs(Editor MACroS)源自 1984 年重写的版本。
Emacs 也是一种“宗教”,“教主”就是 Stallman,他是自由软件运动的创始人和斗士,他个人非常有性格,在其认定的事情上坚持原则,知行合一,是一个对自由软件有信仰又极有天赋的黑客。
在 Emacs 诞生时,最值得称道的部分是可在运行时扩展的实时显示编辑器。
当时的计算机交互界面是由字符组成的,界面的刷新频率并不是很高,视觉上每次也只刷新一屏字符(现在是刷新一屏像素),实时显示是说,当在输入设备(如键盘或鼠标)上完成输入后,计算机将编辑的内存(缓冲区)立即地输出在输出设备(屏幕)上,实时刷新这点已成为了现代文本编辑器的最基础的实现。
运行时扩展是指,用户可以在不退出编辑器的情况下,能增加新功能和修改旧功能,在 Emacs 初具雏形时,它使用了当时时髦的解释型语言 Lisp 来实现此特性。Lisp 在现在看来也是足够快的语言,用户可以使用 Emacs Lisp 立即为 Emacs 定义一个新功能,并立即解释执行它,来对已有功能进行重加载,然后就可以使用这个新增加的功能。这样做的优点是编辑器的实现者不固化和限制用户的使用偏好和习惯,让用户可以自由的修改 Emacs,以实现用户所需。
维护多年软件产品的作者都会了解到,软件的版本计划中,功能优先级取舍是非常困难的。很多功能的设计决策是包含在主程序中还是留给用户扩展很难取舍。而 Emacs 不存在这样的决策,因为它把此类需求的决策权充分给到用户。用户可以充分的探索和实验,并把满足价值的功能点扩展好,在每次启动 Emacs 时装载它,用户还可以在开源社区分享和发布这些扩展库,有突出的,会合入核心功能。
这种机制让 Emacs 生态具备了生命的特征,任何人只要通过简单的复制粘贴,就能方便地分享和吸收其它人的代码,相比可定制性不高的文本编辑器,Emacs 更能适应时代和文本编辑需求的变化。为让用户更好的尝试和探索 Emacs,它内置了非常完善的文档,包含在每一份发布版中。
另外,模式编辑,可以让 Emacs 在文本编辑任务的上下文中更懂用户意图,比如向后移动操作,在不同的模式中,代表不同的预期,在文本编辑时,可快速移到下一字符、单词、句子、段落;在编程时,可快速移到下一行、函数、类;在大纲视图中,同样的操作又可以移动到下一条标题、下一记录。这些不同场景的移动逻辑,都抽象为高一致性的快捷键。n
代表 next,p
代表 previous,f
代表 forward,b
代表 backword,这些就和 Vim 中命令模式的 h
j
k
l
c
d
一样,让其在模式中变得更 meaningful & sensitive;编写程序,可以语法高亮,智能提示,格式化代码,代码质量检测,自动编译,测试;大型程序也可以桥接语言服务器的支持。和各种更大型的编辑软件相比,写作系统、个人信息管理、集成开发环境,都能高效的实现,Emacs 一个应用程序就做到了。
Emacs 还在不断生长、演变,和它使用者一起进化,成为他/她们心中想象的样子。
设计灵感
GNU Emacs 设计灵感是来自 Stallman 的同事,他们发现非专业用户也可编写了 Lisp 代码来扩充软件的功能。于是定下使用 C 实现最基础和稳定的功能,再用开放的 Lisp 方言实现功能的可扩展性和跨平台。
1981年,Stallman 实现最早的 Emacs 时,其定位是自带文档的可扩展编辑器,其中使用了 Java 之父 Gosling 公开的 C 语言编写的的代码,但 Gosling 实现的 MockLisp 却是不完备的,而 80 年代 Gosling 又把他的 Gosling Emacs 代码卖给了 UniPress 公司(一个创业公司)推出为商业版本,Stallman 被要求停止分发他的自由软件版本的 Emacs,他 也因此创造了 GPL 协议。
由于 Gosling Emacs 中实现了很复杂却很有效率的字符串到字符串最小编辑距离算法(动态规划),他在注释上标记上一段 ASCII Art——一个警告的骷髅头,以告诉任何想改进这块代码的程序员:“这里的实现代码是难以置信的扭曲,如果认为自己已弄懂了代码的工作原理时,其实是你并没有懂,请谨慎行事,请再读一遍。”
这句话一定是对的,据多年后 Stallman 回答提问时说,他也没有直接修改这些代码,而是用新算法重写。它修改的最后一部分 Gosmacs 的带骷髅头的毒代码是终端滚动显示代码,但他却没有直接修改 Gosmacs 的代码,而是思考几个小时后,创造了一个更简单的算法,而最后的代码实现的却更短、更高效、更清晰且更具可扩展性。替换掉 Gosling 的代码后,他发现屏幕刷新变得更有效率了。直至 1986 年 Stallman 和社区完成了 GNU Emacs 版本,重写替换了 Gosling 的所有代码。
关于这一段 Stallman 和 Gosling 的口述版本是不同的,真相很难考证,但好在可在 Github 上找到这些代码,有兴趣探索代码的人可以自行推理。
如今的 GUN Emacs 必然经过了许多年的工作和许多天才的投入和贡献,是黑客文化中具有传奇色彩的自由软件之一。虽然从时代上看,它是一个“上古软件”,但它和 GCC、GDB 一起都是自由软件世界的基石,而这些软件也是现代软件世界最重要的部分。
虽然从自由软件分枝出的开源软件大行其道,赢得了商业世界的认可,但我相信历史会记得自由软件的价值和远见,以及其中所蕴含的智慧;如果你还不清楚 Free Software / Freeware / Open Source Software 三者的区别,则可以参看 RMS 有关自由和免费的论文。
有兴趣 STRING-TO-STRING CORRECTION 问题,可以继续了解我在算法模块中的字符串的最小编辑距离问题。
-
例一,源字符串"abd",目标字符串"abc",则修改替换字符串最后字符 'd' 为 'c'。
-
例二,源字符串"abdc",目标字符串"bacd",则修改步骤是交换 'a' 和 'b' 位置,再交换 'c' 和 'd'
最小编辑距离问题是计算机本科毕业因达到的水平,但为更好解决它所使用的动态规划算法属硕士研究生级别。
def edit_dist_dp(str1, str2):
len1 = len(str1)
len2 = len(str2)
DP = [[0 for i in range(len1 + 1)] for j in range(2)]
for i in range(0, len1 + 1):
DP[0][i] = i
for i in range(1, len2 + 1):
for j in range(0, len1 + 1):
if (j == 0):
DP[i % 2][j] = i
elif(str1[j - 1] == str2[i-1]):
DP[i % 2][j] = DP[(i - 1) % 2][j - 1]
else:
DP[i % 2][j] = (1 + min(DP[(i - 1) % 2][j], min(DP[i % 2][j - 1], DP[(i - 1) % 2][j - 1])))
print(DP[len2 % 2][len1], "")
目前 GNU Emacs 已更新至 29 预览版,原生支持 Eglot、Tree-sitter、VSCode 如 LSP,以及 Org mode 9.6 等强大功能。
Emacs 的其他版本还有 Unipress、JOVE、MicroEmacs、Freemacs、MG、Epsilon、CCA 等,比如 Linus Torvalds 使用的版本是 uemacs,u = μ = Micro,Torvalds 亲自修改自 MicroEmacs 的某个版本。
Emacs 能做什么
每隔一些年,市面上总有新的文本编辑器被发明出来,Emacs 并不是市面上最新的文本编辑工具,在某类文本编辑领域内也不是最好的,但它可能是你能找到对你最有用的编辑工具。
对我来说,Emacs 代表着一种经年的智慧,性能和扩展性,功能的权衡和取舍。从中透露出早年的黑客程序员们对文本编辑的理解和从编程视角出发的独立思考精神,它透露着一种天然的长期主义哲学。
Emacs 有着很多的赞誉,比如,Emacs 是“神的编辑器”和“伪装成文本编辑器的操作系统”。确实,Emacs 除了纯文本编辑,还它可以做很多事:
- 编程:支持 C、Lisp 等几乎所有的编程语言,创造编程语言的人很可能也使用 Emacs
- 写作:记笔记、写小说、写论文
- 网络:发邮件、浏览网页、发布博客、管理书签
- 项目管理:日历、时间管理、日程管理
- 文件管理:能集成管理文件和目录
- 玩游戏:例如俄罗斯方块 M-x tetris
- 煮咖啡
- 变为其他任何你想象的软件
谁适合学习 Emacs?
有效的教育都是自我教育。
适合学习 Emacs 的人:
- 秉承长期主义哲学的人;
- 需要做一些个人项目管理和轻度笔记但不想购买商业软件的人;
- 重度跨各种操作系统工作的人;
- 想涉猎 Lisp 但又没有机会,还打算学 Scheme、Common Lisp、Racket 的学生;
- 真程序员,计划把 Emacs 改造成适合他/她所偏 好的编程语言 IDE;
- 认同并支持自由软件的人;
学习 Emacs 的收益也是明显的,这个答案一直就在它的名字中:
- 首先,你最终会拥有一个免费的、任何平台可移植的、行为统一的、可定制的文本编辑器;
- 其次,你会学会 Lisp 并尝试改造它,在改造的过程中,你会加深对计算机程序设计和 Lisp 语言的理解;
- 最终,Emacs = Editor + Macros,所有的场景化编辑,都可以沉淀为一个你自己定义的函数,并绑定一个快捷键实现操作的复用;
学习使用 Emacs 有难度吗?
你可能见过类似学习曲线的描述:
或者你见过你的同事第一次使用 Emacs 时代样子:
是的,虽然 Emacs 学习曲线不至于成为半条羊角螺旋线,但使用 Emacs 至少有三个阶段:
- 第一阶段:先破后立。需要先破除已习得的文本编辑的习惯认知,让思维熟悉 Emacs 的设计和概念,做到能在 Emacs 操作习惯和旧编辑习惯间平滑切换;
- 第二阶段:博采众长。在未 完全熟悉命令和掌握 Emacs Lisp 之前,需要囫囵吞枣,对所需的配置代码,先用为敬;
- 第三阶段:融汇贯通。精通的前提是需学会 Emacs Lisp 编程,然后按个人哲学开宗立派。
虽然都是文本编辑器,但 Emacs 和你使用的其他文本编辑器不同,它有着相对陡峭的学习曲线,基本需要用学习普通文本编辑器三倍以上的决心和心智投入,才可能坚持学习它直到融会贯通。在我看来,它的学习难度在于:
-
不同的基本概念和不同的快捷键
它穿越时代而来,带有着独特的设计和有历史感的命名,以及不同的快捷键,这些都可能影响你理解基本概念,但一旦你熟悉起来,会发现它经过了精心设计,尤其是一些基本的快捷键,也是在 Unix/Linux/Mac 上通用。
-
整合第三方定制的 Lisp。
它提供给你基础版,把功能定制的能力交给用户,基于 Emacs Lisp 的能力,你可以对它进行按需配置、扩展和 DIY。
-
它需要日常坚持使用它。
要理解 Emacs 的哲学,你需要 Live with it。
-
最终需要学习 Emacs Lisp 语言
Emacs 最终就是在使用 C + Emacs Lisp 语言,一旦你掌握和熟练 Emacs Lisp,你就对整个文本编辑过程就有了一种随心所欲的定制力。
所以,了解这些后,你不要指望在几天之内学会它,但你可以花几个月,甚至是几年时间学会它。
Emacs 的学习路径
- 学习基本概念。
- 学习基本操作:Emacs 默认快捷键和 Windows 的快捷键有很大差异,但其实加以理解和练习,你也可以学会它, 等熟悉后,还可以依据个人的需求进行定制快捷键。
- 学习常见命令:Emacs 几乎所有的操作都对应一个命令,但并不需要死记硬背,它自带完善的文档和源代码供查询。
- 学习 Emacs Lisp 并定制功能:学习 Emacs Lisp 后将常见的操作定义为快捷键,使用越久,快捷键沉淀越多,编辑越高效。
- 源码阅读:Emacs 发行版都自带源码,可以在 Emacs 中阅读 Emacs 源代码。