Emacs 心路历程(上)

emacs-startup.png

Figure 1: JerryZhang

在使用 Emacs 过程中,从不缺折腾,每次折腾都让人想放弃使用它,但是折腾过后又会觉得很爽。 隔一段时间我都会折腾一次,但是比较大范围的折腾,只有两次。


第一次大范围折腾是在 2014 年,以前 Emacs 只是玩玩,业余时间写写代码、写写文章,并没有作为工作的一部分。 虽然写 C++ 有几年了,但是都只是在 Windows 环境下一直用 VS 系列(VC++6.0,VS2015,VS2010,VS2012 我都很熟)做开发。 2014 年刚换了工作,开始从事游戏服务器开发,虽然依然是在 Windows 下,但是需要远程连到 CentOS 上开发(Xshell)。 心想着总算有 Emacs 的用武之地了,没想到的时候搭建 C++ 开发环境比我想象的要复杂的多。

印象中,有几个月的时间都在与 Emacs 做斗争,尝试各种网上的 Emacs C++ IDE 方案,不断的尝试,然后不断的推翻配置。 当时比较流行的方案有:ECB + CEDET,CEDET 是一个看起来堪称完美的方案,光是看截图都足以让人咽口水。

ecb.png

(btw,现在看到这张图片,依旧很吸引人)

CEDET 其实不是一个插件,而是一堆插件(cedet、eieio、semantic、speedbar 等等),插件之间有版本依赖关系, 还要考虑不支持 GUI 的情况。

忘记当时是因为 Emacs 没有完善的包管理机制(不能轻松的解决版本依赖问题),还是自己不知道这些。但是可以确定的是, 当时的 Github 还没有这么盛行,装插件的方式,还是在 sourceforge 上下载 .el 文件,然后手动 (load-path) 。 配置 C++ 对我帮助比较大的网站有两个:

  1. Emacs 中文网
  2. 曹乐的主页

令人伤心的是,这两个网站现在都已经访问不了了。

当我费劲了力气把 CEDET 搭建好之后,发现太慢了,根本没法用,大部分功能都用不到。

几乎每一个刚开始使用 Emacs 的人,总想着把它配置成一个 IDE,总是想着看他能不能干这个,能不能干那个,却忘了自己到底需要的是什么。

作为一个程序工作者,每天都在写代码,不管是 IDE 还是 Emacs 这样的文本编辑器,常用的功能其实很少,能解决好编辑、复制、 粘贴、查找、保存等基本功能就已经解决了 60% 的问题,再解决代码的语义分析、支持补全、跳转等就可以解决 30% 的问题, 剩下的 10% 是一些调试,重构等工作。所以我们往往在折腾的时候把自己 80% 的精力放在了不足 20% 的功能上,而那些功能只是看起来酷酷的。

后来,我终于明白了, 这样的文本编辑器的优势在于编辑,也就是说它是在解决那 60% 的问题,其编辑效能远不是 VS 这样的 IDE 可以比拟的。而剩下的 40% 则是 IDE 的天下,Emacs 无论装多少插件也比不上 IDE。 所以,我们要做的是权衡:搞定常用的 60%,尽可能的解决剩下的 40%,实在解决不了用其他方法来填充。 比如 gdb 的确可以跟 Emacs 融合做 Debug,但是直接用命令行来做也差不了多少。

最后的配置方案是: xcscope + etags + c++-mode

尽管 xcscope 比 cedet 差一些,但实际上就这些功能都用的很少,写代码最多就是跳转到定义返回,还有有文件和对应源文件之间的跳转, 我当时绑定了一个快捷键: (global-set-key [(f9)] 'ff-find-other-file)

在 Emacs 下写 C/C++ 是我第一次耗费很大的精力去折腾 Emacs,之后写 Python,写 Golang 都有过折腾,但是都不会那么复杂。为什么呢?

因为 C++ 语法比较复杂,灵活性很强,尤其是模板嵌套的缩进一层好搞,两层就很麻烦了,何况多层。我印象中最后模板的缩进都没有做的特别好。 另外一个原因是没有统一业内的规范,C/C++ 程序员历经了太多的代,主要的两个流派:Linux 和 Microsoft,是完全不同的风格。 我经历过 Windows 下的 C++ 开发,也经历过 Linux 下的 C++ 开发,别说是编码风格了,文化和技术手段都差很多(这个值得我再写一篇文章)。

因为这些导致网上对与 C++ 的配置五花八门,我印象比较深的是 C++ 中函数的括号位置,默认的情况下 Emacs 是这样的:

function()
  {}

因为很多传统的 C++ 程序员,比如说 云风 曾经说过括号放在下面是没有缩进的,相同的言论在代码大全里也说过。 所以 Linux 的风格是这样的(他们认为这样才是有缩进的):

function() {
}

但实际上我们当时用的编码风格需求是这样的:

function()
{
}

最后在 Emacs indent for C++ class method? 找到函数括号缩进的解决方案。

类似的问题还有很多,但为什么 Python 和 Golang 没有那么复杂呢?因为他们都有业内比较权威的编码规范,比如 Python 有 PEP 8, Go 做的更彻底,直接官方提供了代码格式化工具 gofmt。大家都是相同的规范,在社区就很容易就找到配置文件参考。

(实际上由于 Python 依靠空格缩进来定义代码块这种方式为 IDE 和编辑器都带来了很大的困难,因为它没有办法来判断你的下一行是 属于上一个代码块的还是下一个,这会导致每次的缩进都参考上一行,如果想新起代码块总是需要手动调整)

C++ 配置搞定了之后,面对一个终端,在鼠标束手无策的情况下,完全在 Emacs 下工作还是有一定问题。尤其是分屏情况下窗口切换, Emacs 默认情况下的快捷键是 C-x o ,两个窗口还可以,多个窗口的情况下很难准确的定位到自己想要的窗口。

后来找到了 window-numbering.el,使用 Meta + 1/2/3/... 的方式进行窗口切换,对于当时来讲,简直就是救星,太好用了。 但是 Meta + 数组键盘 这种快捷键组合通常会跟终端模拟器的快捷键冲突,比如 Xshell,还有 Linux 的各种终端, 直到用上 MacOS 之后,才解决这个问题(因为 Mac 下是用 Command 作为 Leading-Key 的)。

windows-number.gif

毫不夸张的说,在使用 Emacs 的过程中,我有无数次想要切换到其它的编辑器,比如 Sublime TextAtomVS Code, 甚至我把编程环境都配置好了,最后都是卡在了 Buffer 管理和窗口切换上,Emacs 的多窗口实在太好用了。

helm-grep-ag-persistent.png

另外一个让我真正开始喜欢 Emacs 的插件是 helm,当时应该还没有这个网站,我看的资料是:Emacs mini manual。 看到里面的 gif 图之后惊呆了,没想到 Emacs 还这么用。

Helm 是极大提升 Emacs 效率的一个插件。在此之前我一直用 =ido+smex=,但是 Helm 除了在文件打开和 Buffer 切换这块有极大提升之外,还在本文件和工程搜索,以及书签等。

其中最喜欢的也是最常用的有两个快捷键: helm-occurhelm-show-kill-ring ; 前者用来在本文档中搜索(可替代 C-s ),后者可以显示历史的复制记录。

在 Helm 的基础上扩展了很多使用的插件,比如:helm-is-githelm-projectile。后来 helm 逐渐成了一个体系。

上面这些插件再结合 highlight-symbolauto-completeyasnippetexpant-region.el 等插件,组成了一个堪称完美的编辑器。

后来我整理了一篇文章:Emacs 简易教程,相关的配置在文章中有比较细致的说明。

在后面的四年时间里,所有与编辑工作(C/C++,Python/Django,JS/HTML/CSS/JSX,Go)都在终端 + Emacs上进行, 养成一套自己的工作流,偶尔也会有些问题,但整体还是很爽的。

First created: 2019-06-17 23:17:00
Last updated: 2022-12-11 Sun 12:49
Power by Emacs 27.1 (Org mode 9.4.4)