皈依Emacs

这应该算第三次使用Emacs了。第一次是在2009年,NOI 2009酱油后下决心好好学习Linux,Philip Xu前辈我指引了两天,发现Linux这个未知世界竟然有这么多好玩的软件。编辑器之神Vim用了一阵子了,NOIP 2009前若干天开始探索神的编辑器Emacs,使用Emacs Lisp配置,实现与Vim相似的设定效果需要多出好多代码,因此不久又回到Vim。大概2010下半年又用起Emacs,这次好好折腾了一把。当时Vim的插件生态还围绕vim.org(现在逐步转战GitHub了),Emacs倒是有个http://www.emacswiki.org,尝试了Mew、ERC、AUCTeX、haskell-mode、org-mode等好多东西。很多文件类型的解析、自动缩进支持比Vim对应物好不少,插件质量感觉也稍高。

Emacs有时被人诟病为一个缺乏好的编辑器的操作系统。诚然,收邮件、上IRC、内置终端模拟器、各种网站客户端,网上能找到很多插件赋予它做各式各样任务的能力。我2012年第二次弃用Emacs是因为我认为作为“操作系统”的Emacs扮演了很多窗口管理器的角色,我已经配置好了xmonad,这些任务应该交给xmonad。Emacs扮演的窗口管理器提供了不错的REPL能力,buffer间通信的方便程度不是不同进程间通信可比的。

Emacs的很多major mode会与外部程序通信,提供快捷键把代码传递给inferior process执行,再把结果传输回来,并用适当形式在Emacs中显示。如haskell-mode、tuareg-mode、erlang-mode等,这些major mode往往都提供REPL功能,而且词法高亮、缩进也都优于Vim下的对应物。另外minor mode的设计着实高明,功能模块可以方便地载入和卸载,比Vim使用autocommand和filetype检测方便。Emacs能作为操作系统的竞争力来自于它是个优秀的Lisp交互式编程环境,活着的Lisp Machine。求值光标前的代码、查询快捷键绑定、查阅函数文档,有相当多功能通过Vim的插件很难做好。

下图是j-mode,使用快捷键把当前行传输给inferior process (jconsole)并获取执行结果。
j-mode

下图是Proof General,theorem prover的界面,录色底色部分为已经执行过的命令,阶段性结果显示在下方buffer中。Proof General提供了快捷键执行下一条命令或者撤销上一条命令。
Proof General

web-mode可以在一个buffer中同时支持HTML、CSS、JavaScript等多种词法高亮,根据当前major mode提供的菜单也非常方便。
web-mode

感谢最近的awesome-*系列项目,全方位介绍各种领域的插件,通过https://github.com/emacs-tw/awesome-emacs,发现Emacs的插件生态还挺好的。这是再次皈依Emacs的重要原因,另一方面是感觉Emacs固有的设计优于Vim。GTK+的Emacs是个富文本编辑器,每个字符都可以有不同的样式,而GVim的字符大小是统一的,在UI表现能力上弱于Emacs。AUCTeX就充分利用了Emacs的这个优势,解析TeX中粗体、斜体、大字号、小字号等标记,用相应的样式显示,一目了然。Google Images中搜索AUCTeX有很多图片例子。另外Emacs也可以内嵌图片,公式片段作为图片渲染,这可是个杀手级特性。再譬如prettify-symbols-mode,Vim也有conceal,但是由于字体显示的缺陷,不能很好发挥。

自package.el诞生以来Emacs的包管理生态也逐渐好转。第二次放弃Emacs时还有很多插件散落在网上各地,如今逐步被ELPA等仓库收纳。现在包管理的选择太多,el-getcaskquelpa……选择太多有些时候不是好事。

Evil

Vim的modal editing非常方便,我认为Vim胜过Emacs的最主要的地方在于normal mode下的一些操作,特别是光标移动和operator-pending mode。Emacs默认的光标移动快捷键主要有C-fC-bC-pC-nM-fM-b等,使用频率很高,但却需要两个键,令人恼火。优于缺少模式,Emacs默认提供的很多快捷键使用了很长的key sequence,比如C-x r j映射为jump-to-register,后面跟字符a就类似于Vim的`a,但是太不方便了。

所幸插件evil-mode可以在Emacs里模拟Vim,使Emacs具备modal editing的功能。为了更好的一致性,我不使用insert mode中的Vim特有快捷键,只用Emacs默认的:

1
2
3
(setcdr evil-insert-state-map nil)
(define-key evil-insert-state-map (read-kbd-macro evil-toggle-key) 'evil-normal-state)
(define-key evil-insert-state-map [escape] 'evil-normal-state)

Evil另外附带了一些Vim中以插件形式提供的功能。下图是Evil整合的ace-jump(Vim的easymotion),跳转到指定字符或以指定字符开头的单词、行等:
evil-ace-jump

Helm

和Vim的Unite类似但强大得多的必备插件,参见http://tuhdo.github.io/helm-intro.html

helm-ag,在当前目录下用ag搜索,显示匹配项。
helm-ag

helm-imenuImenu的增量搜索版:
helm-imenu

helm-swoop,增量搜索匹配行,类似于helm-occur,但会即时显示匹配的部分。
helm-swoop

Global的前端helm-gtags

helm-gtags,Global的前端。helm-gtags-dwimhelm-gtags-find-rtag很有用,值得为之绑定简单的快捷键。
helm-gtags

Org-mode

一款日程安排、项目管理、literate programming、笔记软件,神器。参考http://doc.norang.ca/org-mode.html

键绑定与冲突

fcitx默认以C-SPC为输入法切换键,与Emacs默认的set-mark-command冲突,我把切换键改为C-S-SPC

fcitx默认绑定了C-M-h用于拼写检查,与Emacs默认的mark-defun冲突,我删除了fcitx的绑定:Configure-Input Method,双击Keyboard,点击Toggle to word hint,按ESC。

其他

  • M-x winner-mode,内置,global minor mode。可以用C-c leftC-c right在撤销或重做对窗格布局的变更。
  • M-x ansi-term,内置,可显示颜色的终端模拟器。
  • dired,内置的文件管理器。
  • expand-region,基于语义单位增量式选择区域。视频http://emacsrocks.com/e09.html
  • neotree,树状文件管理器,类似Vim的NERD Tree
  • flycheck,即时语法检查,类似Vim的syntastic。
  • projectile,提供一些以项目为单位的实用功能。
  • smartparens,处理广义括号的minor mode。
  • which-key-mode,在弹出的buffer中显示当前按下的前缀键的所有可能绑定。
    which-key-mode

目前采用的GIF录制方法:

xwininfo获取Emacs窗口位置大小信息,用byzanz-record -x 1 -y 33 -w 960 -h 640 -d 10 a.gif录制GIF动画,再用gifsicle --scale 0.75 --delete '#33-' a.gif > b.gif裁剪开头部分。

我的配置

https://github.com/MaskRay/Config/tree/master/home/.emacs.d

进一步了解

Vim到Emacs的迁移:

聚合、Wiki:

一些配置: