Emacs - 行者无疆 始于足下 - 行走,思考,在路上

Announcing oh-my-emacs v0.3

Today I'm happy to announce oh-my-emacs v0.3.

It has been three months since I first released oh-my-emacs from my homebrew messy dotemacs project to public. To my suprise, oh-my-emacs has attracted many interests from all over the world.

The v0.3 version of oh-my-emacs contains various improvements, check its CHANGELOG for a condensed feature list.

Several features worth mentioning (v0.1->v0.3):

  • code refactoring:
    • Oh-my-emacs splits all its modules into two levels: core and modules. Files in core are required by default, while files in modules are optional. You can load necessary module when you really need it.
  • ome-org module:
    • Upgrade org-mode to latest 8.x branch. This brings us a more powerful export engine.
  • ome-cc module:
    • Oh-my-emacs support auto-complete for C/C++ macros! Combined with pkg-config, oh-my-emacs cc module can be used as a perfect C/C++ working environment with perfect semantic completion for functions and macros for any installed libs recognizable by pkg-config.
  • ome-java module:
    • Oh-my-emacs provide semantic completion for Java projects via emacs-eclim. Though not perfect(and a little heavy), this is a workable solution now.
  • ome-lisp module:
    • The original ubiquitous ome-lisp module has been split to four modules:
      • ome-emacs-lisp module
      • ome-common-lisp module
      • ome-clojure module
      • ome-scheme module
  • documentation:
    • Add a table to specify the system requirments and el-get packages. Thus you can install necessary system tools to make oh-my-emacs modules work as expected.
  • compatibility:
    • Improve compatibility for Mac OS X.
  • completion:
    • Add semantic completion for scheme (via ac-geiser)
    • Add completion table to show you the currrent semantic completion support for various programming languages.
  • miscs:
    • Basic support for JavaScript, Ruby, OCaml.
    • Move some unstale packages to ome-experimental module, load as you need.

Five months of spare time work, 200 git commits, 120 github stars and 35 github issues, all of the above work forms a less than 50MB tarball, which contains 50 el-get packages, 1000 lines of emacs-lisp code, 4000 lines of documentation, hundreds of reference web links, just download and extract this tarball, you'll get a tuned Emacs OS, and it works almost everywhere.

It's time for new year, and I hope you enjoy this gift. Any feedback will be appreciated. Thanks!

 

Announcing ac-geiser v0.1

由于某位 仁兄 的抬爱,oh-my-emacs 发布之后,在 reddit 上出人意料地受到了很多人的 关注。而我也在一夜之间收获了20多个github star,以及人生的第一个 pull request。突 如其来的关注让我有些欣喜,也让我看到了两个月工作的价值。技术上来讲,oh-my-emacs 根本算不上“高端大气上档次”的项目,无非就是读文档读文档写文档外加el-get package的 整合测试。不过话说回来,这两个月以来真心是写了不少文档啊,要是按照一个el-get package一篇blog来算,平均下来两天就可以有一篇Emacs Tips这种文章了。连我都有些佩 服自己的耐心了。

我想,oh-my-emacs 之所以受到了一些的关注,归根到底,还是 oh-my-emacs 确实解决了 一些现实中的问题吧。上篇博文 中我曾经提到,基于 auto-complete 的语义补全是 oh-my-emacs 最看重的目标之一。

也正是基于这个宏伟的目标,我又花了一个晚上的时间,折腾出 ac-geiser,"an Emacs auto-complete backend for geiser"。

去年学习 SICP 的时候就一直希望能有个类似于 SLIME 般强大方便的工作环境1,几番折 腾之后未能如愿,乖乖用Vim作了一百多道SICP的习题。而我的Scheme经验也就止于这些习 题了,因此ac-geiser 可能目前还不适合工程性的应用2。不过对于单个Scheme文件的程序, 我觉得应该还是值得一试的。还是老样子,放张图吧:

ac-geiser

Enjoy it.

--

Footnotes:

1 如果你不知道SLIME如何强大,可以参考 这里 以及 这里

2 话又说回来,Scheme现在似乎也没有多少工程性的应用吧?各个Scheme实现中也没有遵 循 统一的Module/Package的标准。Scheme本来又是极小核心的语言,因此这使得Scheme非常 适合作为教学语言。但似乎除了教学,Scheme一直都没有走出校园过。以上纯属个人认知, 欢迎指正批评。

Announcing oh-my-emacs v0.1

去年偷闲的时候,挖了好多大坑(这里这里这里),怎奈挖坑容易填坑难……客观原因自然是“认真的写作有如雕刻”云云,主观上嘛,“懒”大概是逃不脱的一个字吧。

Wait,是谁说过,“懒惰是程序员的美德”来着。秉承这种美德,耗了将近两个月的业余时间,尝试了不下50个el-get package,并且认真读了不下10个package的manual,遂成 oh-my-emacs.

一切缘起于两个月前的某一天,我忽然心血来潮,想要整理下那一坨"just works"的.emacd.d。我几乎尝试了所有github上比较流行的.emacs.d,但是没有一个满足我的需求。“因为所以,科学道理”, Reinventing the wheelNot invented here 大概是每个程序员必修的一课吧。索性不管那么多了,代码写的不好,又不输房子不输地,坑 挖的不好,大不了留着自己用就是。

Oh-my-emacs着重解决的问题是(引用自oh-my-emacs的README):

  • Better default settings with various eye candy, powerline, scrollbar, color-theme, fonts, etc.
  • Adopt el-get as the default package manager for Emacs, instead of the default builtin package.el, say goodbay to ./configure; make; make install and explicitly mananully management of load-path. el-get also provides automatic documentation management, customizable user's recipe support, etc.
  • Self-adapted, only install necessary packages when it satisfy the prerequisities. You need to install clang for auto-complete-clang, for example.
  • Modular, only load necessary packages as you need.
  • Literate, each package have comprehensive documentation or even a tiny tutorial with it, together with necessary web links. Say goodbye to old, out-dated emacs lisp code from Google.
  • Work as expected, completion every where when possible, semantic code completion through auto-complete with various ac backend, helm for minibuffer completion, etc.
  • Full-blown, oh-my-emacs is not another starter kit, it is hacker kit.

这其中,补全、文档、自适应性,是我特别看重的三点。补全自不必说,作为上古大牛也 许是不需要补全的,但是对于我这样21st Century成长起来、尝试过Visual Studio强大补全甜头的程序员来讲,补全是最为迫切的需求。而Emacs/Vim作为General Purpose Editor, 其最大的使用不便就是没有代码的语义补全(semantic completion)。Emacs有一个内置的 Semantic, 来源于Emacs社区鼎鼎大名,目标远大的CEDET, 但是Semantic的使用和配置 都很复杂(参考emacser.com的文章),而且很慢,有时会让Emacs卡住。究其原因,我认为 Semantic 的思路是不对的。用性能本就不怎么好的Elisp去实现复杂如C++这类语言的 Parser,其本身就是浩大的工作量。正确的思路是,对于不同的语言,依赖于不同的 backend,然后用Elisp写相应补全的interface。所以我认为, auto-complete 的思路是正确的。oh-my-emacs利用已有的各种auto-complete的backend(如 ac-slime, auto-complete-clang 等)基本上实现了对C/C++,Python,ELisp/Common Lisp/Clojure的语义补全。

第二点是文档,Emacs的世界从来不会缺乏选择, el-get-list-packages ,2500个 package,其中有很多package要么是已经过时,要么是年久失修,要么是语焉不详,看上去 一片繁华的Emacs世界,实则荆棘密布。如果你没有一点Elisp的功底,想开箱即用,那几乎是不可能的。单拿Python来说,Emacs和Python社区就有两套不同的 python.el ,这给很多Python和Emacs的初学者造成了困惑。Google: Python Emacs,其首页的几套解决方案,采用的是不同的 python.el ……你说对于一个好容易学会翻墙,开始习惯用Google搜索技术文档的计算机初学者而言,看完这些文章,不晕菜才怪呢。稍微复杂一些的配置,比如 TeXLive,在比如Common Lisp的各种实现和SLIME,想要得到一个比较舒适的环境,不但要配置好Emacs,还要配置好系统环境,这又是一大难题。oh-my-emacs借助org-mode Babel, 采用Literate的方式1, 将文档和代码写在一起,在文档中尽量给出每个模块所需要的系 统环境;对于有多个选择的情况,文档中尽量给出为什么选用package A而不是package B的理由和权衡过程。有一部分文档甚至可以当作Tutorial来看。Literate方式最大的好处是保 持文档和代码的同步,这样,oh-my-emacs即可以用作是“开箱即用”的.emacs.d,也可以当作是手把手的Emacs配置教程 (统计下来,oh-my-emacs中文档和代码的LOC 比例约为3:1左 右)。另外,操作系统的环境千差万别2, 因此oh-my-emacs基本上在每个相关模块的文档里面都指明了使用这个模块所需的系统环境,这也可以看做是我为了填去年的坑所做的一点努力吧。

第三点是自适应性。这又是一个很宽泛的话题。什么叫自适应性?是支持多个操作系统吗? 不是的,至少我没有打算让oh-my-emacs很好的支持Windows,一方面是因为Windows没有一个好的类似于apt-get这种类型的package manager3,oh-my-emacs依赖的很多底层软件如ssh,gcc/clang,TeXLive等在Windows上配置起来都很麻烦,远不如 apt-get/yum/pacman/homebrew这种一条命令来的方便。我这里讲的自适应性,主要包括:

  • 采用el-get, 自动化管理load-path,以及info文档等,say goodbay to git submodule
  • 如果系统环境不满足某个package的要求,就不要安装这个package,免得装完了不能用。 比如 auto-complete-clang 依赖于 clang, 如果系统中没有安装clang,那么oh-my-emacs在启动的时候就不会安装 auto-complete-clang。反之,如果你意识到这个问题并安装了clang,那么可要重启Emacs, auto-complete-clang就应该可用了。
  • 尽量借助工具和代码获取相关配置,而不是在代码中写死。比如,oh-my-emacs大量使用Elisp中的 executable-find ,这需要依赖于操作系统的package manager设置好相关的 $PATH , 这样带来的好处就是oh-my-emacs能够无缝的适应很多环境。
    • 比如 AUCTeX需要PDF阅读器作为LaTeX文档的Viewer, oh-my-emacs采取的策略是优先采用 Okular, 其次是 Evince, 如果操作系统上即没有装Okular也没有装Evince, 那么oh-my-emacs会fallback到 xdg-open, 这样可以用可移植的代码获得最大限度的灵活性和自适应性[4]。
    • 再比如 SLIME 支持多种Common Lisp Implementation, oh-my-emacs采取的策略是同时支持 SBCL/Clozure CL/CLisp ,也就是说,只要你安装了SBCL/Clozure CL/CLisp其中的一个,oh-my-emacs的Common Lisp设置就应该是可以工作的。
    • 针对auto-complete-clang, oh-my-emacs可以利用 pkg-config 检测并设置正确的 ac-clang-flags , 可以对系统中可用的任意C/C++ lib提供语义补全。比如,你可 以用 M-x ome-pkg-config-enable-clang-flag "QtGui" RET 来获得QtGui库的补全 支持,效果可以参考这里

Oh-my-emacs目前已经包含了对C/C++/Python/Common Lisp/Clojure的支持,基本上都提供了较好的语义补全。其他方面,设置了更友好的字体,powerline,color-theme。启用了 一些比较好的内置mode,诸如recentf/savespace/uniquify。对\LaTeX编辑提供了完整的支持,默认采用XeTeX。

Oh-my-emacs的名字来源于 oh-my-zsh, 用意嘛,自然是希望能将oh-my-emacs打造成oh-my-zsh那样。大话止于此,看行动。

最后放张图,更多美照在 这里 。Enjoy emacs, and, your life.

oh-my-emacs

--

Footnotes:

4 这个PDF阅读器的例子主要是在Linux下面测试的,我手头没有Mac的环境,so, patches are always welcome.

1 Literate programming 的 概念来源于祖师爷 Donald Knuth。没记错的话,大名鼎鼎的 \TeX 早期也是用literate的 方式写成的。 Org-babel提供了所谓的"active code in Org-mode",还有专门的Paper论 述Org-babel的workflow。 oh-my-emacs这方面的灵感主要来自于 emacs24-starter-kit

2 也许正是如此,puppet/chef这类工具才会大行其道吧。

3 chocolatey 也许是个不错的选择,但是我没有用过。

 

Emacs as a Python IDE

赋闲脱产的半年里,自己用C++/Java/Lisp胡乱写了几万行的代码,到了现在的公司,给OpenStack项目贴牛皮藓,反倒是Python用得最多。作为公司里面唯一的Emacser(没准也是 公司里JJ最长的吧,),我一直致力于在Emacs平台上折腾出一套顺手的Python开发环境,所幸有些小心得,付诸纸面,以飨大家。

1 Python.el的选择

Emacs的python-mode有两套,一个是Emacs官方提供的python.el,另外一套是Python社区提供的python-mode.el。不过python.el和python-mode.el都有各种各样的小问题,python.el似乎是无法正确处理python的docstring,而python-mode.el的menu项太过繁杂,而且很多menu无法正确工作。这里用到的python.el来自于https://github.com/fgallina/python.el,细节可以参考水木社区的讨论

安装方法可以参考项目主页的README,我自己针对el-get做了一个recipe,这样以后更新装卸都会方便很多,recipe如下:

(:name python
       :website "https://github.com/fgallina/python.el"
       :description "improved python.el from Fabián Ezequiel Gallina"
       :type github
       :pkgname "fgallina/python.el")

不过这个patch并没有被el-get接收,限于时间精力,我没有再去细究el-get撰写recipe的规范。

1.1 ipython集成

交互式的开发是python/ruby/lisp这类动态语言的重要特性,它让程序员从“编码-编译-运行-调试“的程序开发工程链中解放出来,从老旧的批处理是开发过渡到现代的交互式开发。如果你用过slime,你就会知道,交互式的开发不仅仅是一种开发模式,slime也不仅仅是一种工具,而是一种编程的革命。Emacs集成ipython,虽然没有slime那么强大,但是对于提高开发效率还是有莫大的帮助的。幸运的是,fgalling/python.el是支持ipython的。关于fgalling/python.el的参考设置如下:

(add-to-list 'load-path (expand-file-name                                                                        
                         "~/.emacs.d/el-get/python"))                                                            
(require 'python)                                                                                                
(add-to-list 'auto-mode-alist '("\\.py\\'" . python-mode))                                                       
(setq                                                                                                            
 python-shell-interpreter "ipython2"                                                                             
 python-shell-interpreter-args ""                                                                                
 python-shell-prompt-regexp "In \\[[0-9]+\\]: "                                                                  
 python-shell-prompt-output-regexp "Out\\[[0-9]+\\]: "                                                           
 python-shell-completion-setup-code                                                                              
 "from IPython.core.completerlib import module_completion"                                                       
 python-shell-completion-module-string-code                                                                      
 "';'.join(module_completion('''%s'''))\n"                                                                       
 python-shell-completion-string-code                                                                             
 "';'.join(get_ipython().Completer.all_completions('''%s'''))\n")

常用快捷键:

  • C-c C-z: (python-shell-switch-to-shell),切换至ipython解释器
  • C-c C-c: (python-shell-send-buffer &optional ARG),发送整个buffer内容到ipython解释器运行

2 Emacs补全:Pymacs和Ropemacs

语言补全一直是Vim/Emacs这类上古"IDE"的弱项,每种语言都有自己的补全插件、配置方法和版本差异,而网上资料、特别是中文资料,或是陈旧潦草,或是语焉不详,常常让初学者们不知所措。本文所载内容恐怕两年左右就会过时,诸位看官高贤注意鉴别……

Emacs下的通用补全插件大概就是auto-completeyasnippet了,前者可以做出基于buffer分词的补全,后者可以基于特定编程语言语法结构的补全。不过基于语义的补全,Emacs+Python下用的是pymacs和ropemacs。需要安装的有

  • pymacs
  • rope
  • ropemacs
  • ropemode

以上均可通过el-get安装。如若使用过程中出现莫名问题,不要纠缠,有可能是版本问题,无妨试验下用apt-get/pacman/yum安装。我本机上的配置如下:

;;; pymacs, rope and ropemacs
(add-to-list 'load-path "~/.emacs.d/el-get/pymacs")
(require 'pymacs)

(setq pymacs-load-path '("~/.emacs.d/el-get/rope"
                         "~/.emacs.d/el-get/ropemacs"))

;; Initialize Pymacs
(autoload 'pymacs-apply "pymacs")
(autoload 'pymacs-call "pymacs")
(autoload 'pymacs-eval "pymacs" nil t)
(autoload 'pymacs-exec "pymacs" nil t)
(autoload 'pymacs-load "pymacs" nil t)
;; Initialize Rope                                                                                             
(pymacs-load "ropemacs" "rope-")
(setq ropemacs-enable-autoimport t)

3 virtualenv

virtualenv是Python的sandbox(沙盒)。那么什么是sandbox呢?

在日常开发中我们常常碰到这样的场景:

  • 需要针对不同的python library做测试(兼容性、性能等)
  • 需要多人共享一台开发机

可是:

  • 并不是所有人都有向系统PYTHONPATH安装python library的权限
  • 我们常常需要同时安装多个不同版本的python library

而virtualenv通过一些脚本,通过软连接和修改环境变量的方式,提供了一个轻量级的虚拟python环境,在这里面个人可以按照自己意愿任意装卸配置library,也可以针对不同版本的library创建不同的virtualenv,方便的很。

3.1 virtualenvwrapper

virtualenv默认是在当前目录下建立一个.venv目录,但是这样有一个问题,就是virtualenv本身的管理很不方便,因为需要记忆不同的.venv的存放位置、具体用途等等。virtualenvwrapper则通过一些python和shell脚本,在virtualenv的基础上建立了一层抽象,实现了对virtualenv本身的统一管理。virtualenvwrapper会默认在$HOME/.virtualenvs目录下创建所有的virtualenv。

virtualenv和virtualenvwrapper均可以通过python pip安装:

pip install virtualenv virtualenvwrapper

常用命令:

  • mkvirtualenv venv_name: 建立一个新的virtualenv,
  • workon venv_name: 切换到venv_name这个virtualenv

3.2 virtualenv.el

virtualenv.el可以配合Emacs集成virtualenv,可以通过el-get安装。virtualenv.el需要virtualenv和virtualenvwrapper。

配置:

;; virtualenv support
(add-to-list 'load-path (expand-file-name
                         "~/.emacs.d/el-get/virtualenv"))
(require 'virtualenv)

常用命令:

  • M-x virtualenv-workon: 切换virtualenv

4 Miscs

一些hook设置:

(add-hook 'python-mode-hook
          (lambda ()
            (ropemacs-mode)
            (global-set-key (kbd "RET") 'newline-and-indent)
            (auto-fill-mode 1)
            (virtualenv-minor-mode 1)))

除了以上,Emacs中和Python开发有关的插件还可以有pylint、pep8、pyflakes等,参考文章:

以上,抛砖引玉,希望能够对刚刚接触Linux/Python/Emacs的朋友有些许帮助。

走进Lisp的世界——兼谈Emacs下Lisp的开发环境(上)

1 磨刀不误砍柴工

”工欲善其行,必先利其器“,工具的强是无敌的。 而判断一个工具是否值得学习,需要理性的分析学习成本和收益。简单地讲,如果学习一个工具的时间远远超出你使用这个工具的时间,那么这个工具就是不值得你去学的。注意, 我并没有说这个工具本身不值得学,而是说它不值得你学 。同在互联网行业的人,你不可能建议UI设计师去学习Emacs/Vim,也不太可能去要求码农去学习Photoshop。

编程几乎是一种纯脑力劳动,更确切的说,编程是人脑的一种思维运作。 高效的编程必然伴随着顺畅的思维运作,任何使你在编程中感觉到思维运作受阻的东西,都是你需要不断改进的东西,包括但不限于编程语言、算法和编程工具。 我在前面的的文章《少即是多——兼谈对SNS的看法》 也曾经写到:“深入的思考是容不得别人打扰的,一旦中断,思考的大厦就会崩塌,重建的过程往往循环往复、困难重重。这就是为什么聪明人只想和更聪明,至少是和自己一样聪明的人一起工作的原因,资深的Hacker更是如此,他们才没有耐心告诉你Apache该怎么配置呢。”

简单的例子,作为码农,如果你不能流畅的阅读英文技术资料,那么你需要去提高下英文能力,考个TOFEL/GRE或许是个一劳永逸的办法;如果你的电脑配置不能顺畅的运行你需要用到的开发工具,那么攒钱换电脑或者增强配置吧, 时间就是金钱,将珍贵的时间耗费在等待软件启动的过程中,这是对生命的一种亵渎 ;如果你不能顺畅的实现各种基本数据结构和算法乃至于无法深入看一些技术书籍和自我学习深造,那么找本算法书吧,认认真真的将所有代码从头敲一遍,最好再做一些习题;如果你觉得C++的各种特性杂糅使你不堪重负,使得你在解决问题的时候不断地需要脱离问题本身而去关心实现细节的,那么你应该考虑下去学习几门新的编程语言,跳出语言的框架去寻找解决方案1

除了以上种种,最常见也最容易被广大码农忽略的,就是高效的文本编辑。很多人对此不以为然,鼓吹能力是最重要的,工具是次要的,甚至举出某某牛人用记事本编出某某牛软件的例子来自我麻醉,为自己的懒惰和不思进取提供理论支撑和YY的对象。后面我会说明,语言和工具对于编程工作而言起着至关重要的作用,如果将来有朝一日我去招人,我第一件事肯定问他是Emacs/Vim用得是否熟练,对于Emacs/Vim都没有听说过的人,我肯定是坚决不会要的。

为什么高效的文本编辑如此重要?因为对于码农而言,最重要的工作就是写代码, 而写代码本身可以看成是一种特化的文本编辑工作 ,因此找一款看着舒心、用着称心的编辑器是很有必要的。我不止一次的想起,大三时光,某个实验室的角落,某某同学滚着鼠标寻找码海里的某个函数定义。他的滚轮每滚一格,我的心就咯噔一下;每次他滚了一大段又往回滚的时候,我的心就咯噔咯噔跳个不停。何必呢?即使你不知道emacs/vim,不知道source insight这样的工具,但你至少应该会Edit->Find吧。《卓有成效的程序员》 里面有几条非常重要的原则:

  • Using the mouse less.
  • Prefer typing over mousing.
  • Typing is faster than navigation.

总结起来,这三条原则的核心要旨就是快,快速定位到你想要到的地方,随心所欲,不为外物所阻。毕竟,“天下武功,无坚不破,唯快不破“。只有快,才能让思维的高速列车略偏方向而迅速纠偏,不至于偏离车道,走向“车毁人亡”的不归路。具体说来,我们编程是为了解决问题(思维的高速列车),但是很多时候我们不得不花时间和精力去处理诸如代码缩进、括号配对等非常琐碎的工作(偏离方向),而这些琐碎工作不仅会严重影响我们思维的顺畅性,更有甚者,它有时候会让我们忘了我们最初需要解决的问题(“车毁人亡”了)。这里有一段yasnippet的demo视频, 是一个极佳的高效文本编辑的例子。比如我们写html代码,我们真正关心的问题应该是到底选用那个标签,至于这个标签该怎么缩进怎么配对怎么符合xhtml标准都不是也完全不应该是我们需要分心解决的问题;日常工作中诸如此类的例子还有很多很多。所有琐碎的小问题加起来,足以碎化你的思维,让你举步维艰。“没有NFS、Java和其他的技术还能活;但是如果没有Vi,简直没法活了”2,可见一个高效文本编辑器在优秀程序员心中的地位。

废话好像有点多,接下来主要谈谈Emacs下Lisp开发环境的配置,几天的折腾碰到了很多大大小小的issue,一并记录下来,希望后来者能够少走点弯路。

最后的最后,主流文本编辑器学习曲线, 博君一笑。

2 Emacs

  • ”Emacs是伪装成操作系统的编辑器3(emacs isn't a text editor but more of an operating system that incidentally happens to include a text editor.)“。
  • 没错,Emacs就是一个操作系统,只是这个操作系统本身缺少类似于Vim这样高效的编辑器4。如果你去看下Emacs和Elisp合起来将近2000页的手册,你就会发现,emacs这货真不是一个编辑器这么简单,实在是一个以编辑器为核心构建起来的操作系统,有自己的编程语言(elisp),API,API文档,window、frame……
  • 很多人说Emacs反Unix哲学的,因为Unix的哲学是提供简明的接口(这个接口主要是文本流),透过小工具的组合完成所有的工作。但Emacs似乎野心太大,妄图以一己之力完成从编程、上网、邮件、听音乐等所有的工作5。从某种意义上而言,这种说法是正确的。但是换一个角度,如果我们真的将Emacs看成一个类似于Unix这样的操作系统的话,那么Elisp之于Emacs就相当于C之于Unix;Emacs的各种插件扩展就相当于Unix下的各种小工具;Unix通过Shell管道将各种小工具粘合起来完成复杂的工作,而Emacs通过自己的Elisp环境将各种扩展插件整合起来,让他们完美合作,完成各种各样对编辑器而言几乎不可能的工作。从这个意义上而言,如果你真的把Emacs当做一种平台而不仅仅是一个编辑器的话,那么Unix的哲学和Emacs是不冲突的。因为Unix的哲学针对的是工具,而不是工具底层的平台,不是吗?
  • 可能你会问,Emacs到底能干些什么?Easy,除了Adobe能干的,Emacs都能干。具体而言,Emacs不擅长做图形图像视频音频方面的工作,这方面是Adobe CS系列软件的天下。而除了这些基于图形图像的工作, 其余 基于文本流的工作,Emacs都能干的不错 6
  • 如果你想看看Emacs到底长什么样,emacser.com一定会让你大开眼界。
  • Ruby语言的创始人松本行弘在LibrePlanet 2012 conference上讲述了"how emacs changed mylife"。
  • 当然,Emacs并不是完美的,体型巨大、启动速度慢、Elispe的性能、多线程支持还有统一的扩展管理,这些一直被人诟病。
  • 关于启动速度,最常见的优化方法有三种:
    • 将el文件编译成elc文件,
    • 将许多插件由load转换成autoload。
    • 在Emacs首次启动时开启M-x server-mode,然后以后启动Emacs只需要emacsclient即可。我还做了几个懒人专用的alias:
      • ecc='emacsclient -c'
      • ecd='emacs –daemon'
      • ect='emacsclient -nw'
      • emacs='LC_CTYPE=zh_CN.UTF-8 emacs'7
  • Emacs作为一个老牌自由软件,以无限的可扩展性作为核心竞争力,但直到近年来才出现了一些比较好的扩展管理工具,细节可以参考ELPA: Emacs Lisp Package ArchiveGNU Emacs的终极扩展管理工具。在此强烈推荐下el-get,结合eshell,让我在Emacs身上闻到了一丝Lisp Machine的味道。
    • eshell是可以直接调用Elisp函数的(这是我无意间发现的,惭愧),结合el-get,使得emacs扩展的安装可以像debian的apt-get一般简单。比如说,你可以通过如下的elisp代码“一键安装”auctex、auto-complete、cdlatex-mode、slime、yasnippet8
(let ((softs '(auctex auto-complete cdlatex-mode slime yasnippet)))
  (dolist (obj softs)
    (el-get-install obj)))

3 Slime

  • 学习计算机四年有余,用过的编程工具IDE环境没有上百也有一打,但从来没有任何一种编程环境,能够像Slime那样,让我印象深刻,彻底颠覆我的编程方法学和世界观。
  • 这种颠覆型的编程模型就是slime的交互式编程。
  • 多数人都已经对C/C++/Java这种编译型语言的构建模型见怪不怪了,对于C++ Template这种扭曲的所谓元编程模型和超长的编译时间也学会了忍耐,大不了去上个厕所、抽一颗烟,要么就去泡杯咖啡呗。可是很少有人去深入思考过,为什么我们要忍受冗长的编译过程?为什么我们只是随便更改几句代码,就要重新做一次完整的编译?如果你从来没有思考过这些问题,那么请尝试下Slime吧,或者python/ruby也好的,交互式的编程会颠覆你的编程理念。
  • Paul Graham在它的《Ansi Common Lisp》用这样一段话来描述Lisp中的编程模型:"In purely functional code, you can test each function as you write it. If it returns the values you expect, you can be confident that it is correct. The added confidence, in the aggregate, makes a huge difference. You have instant turnaround when you make changes anywhere in a program. And this instant turnaround enables a whole new style of programming, much as the telephone, as compared to letters, enabled a new style of communication"
    • 我认为这段话强调的关键之处在于"instant turnaround", 即快速的修改和反馈,更加生动和详细的描述可以参考Paul Graham的另一本Lisp广告书《黑客与画家》。
    • 想快速构建一个链表一棵树?没问题,在lisp中这些都可以用大一统的list来表示的。Alan J. Perlis在SICP的序言中曾写到:"It is better to have 100 functions operate on one data structure than 10 functions on 10 data structures"。如果你认真用C/C++/Java实现过链表和二叉树,你会发现两者的数据节点声明是一样的,都是一个data域和两个指针域。为什么会这样?很少有人深入想过这个问题。后续我会写文章,从Lisp的角度上探讨下这个问题。
    • 想快速测试某个函数的正确性和性能?没问题,开启slime然后C-c C-c即可,你再也不用像Java那样,先建立一个类、然后声明一个static function,最后在写JUnit测试,然后编译、运行(架屋叠床的设计9,OOP的风格也许并没有声称的那么美好)。Alan J. Perlis在SICP的序言中还写到:"Pascal is for building pyramids—imposing, breathtaking, static structures built by armies pushing heavy blocks into place. Lisp is for building organisms—imposing, breathtaking, dynamic structures built by squads fitting fluctuating myriads of simpler organisms into place."
  • 关于Slime配置,如果你直到什么叫load-path、major-mode、mode-hook这些elisp概念的话,还是比较容易的。要么就只能照抄网上配置碰运气了。Understanding SLIME (Using Emacs and Lisp Cooperatively)是一篇极好的Slime资源,Quick Intro to Live Programming with Overtone令人印象深刻,极为震撼。
  • python/ruby这类动态语言可以用Slime吗?这点我没有找到太好的资料,slime的contrib目录里面有一个ruby文件,但是我目前还不会ruby,所以没有做过尝试;google上搜到的一些资料说python由于语言本身的限制并不能采用Slime的编程模式10,不过要彻底理解这些,恐怕要涉及到对各种编程语言的深入探讨,目前的我功力有限,恳请高手不吝赐教。
    • 不过像python/ruby/octave这类语言,在Emacs里面开个文件同时开个解释器边写边测也是可以的,关键字:comint-mode

4 Common Lisp

  • 和c语言不同,Common Lisp的实现有很多11,我主要用的是SBCLCCL ,ArchLinux下的安装都比较简单,不再赘述。
  • Quicklisp 是推荐的Lisp库管理工具,Quicklisp之于Common Lisp相当于cpan之于Perl.
  • 在Emacs中装好Slime后(推荐用el-get),将下列代码放入SBCL的初始化文件.sbclrc或者CCL的初始化文件ccl-init.lisp中。启动SBCL或者CCL开启swank,然后在Emacs slime中用M-x slime-connect连接即可(swank可以是远程机器)。
;;; The following lines added by ql:add-to-init-file:
#-quicklisp
(let ((quicklisp-init (merge-pathnames "quicklisp/setup.lisp"
                                       (user-homedir-pathname))))
  (when (probe-file quicklisp-init)
    (load quicklisp-init)))

;;; swank for emacs slime to connect
(load "~/.emacs.d/el-get/slime/swank-loader.lisp")
(swank-loader:init)
(swank:create-server :port 4005 :dont-close t)
  • LispWorks公司为Common Lisp提供有一份非常详尽的HyperSpec 文档,在ArchLinux中,你可以通过AUR来安装(yaourt -S cl-hyperspec)。
  • Slime对HyperSpec提供了良好的支持:slime-hyperspec-lookup。配置好Emacs-w3m,就可以在Emacs通过w3m查询Common Lisp语言文档的,很方便。我的配置片段如下:
(add-to-list 'load-path "~/.emacs.d/el-get/emacs-w3m")
(require 'w3m-load)
(setq browse-url-browser-function 'w3m)

;; view common lisp hyperspec documentation
(global-set-key "\C-ch" 'slime-hyperspec-lookup)
(setq common-lisp-hyperspec-root "file:/usr/share/doc/HyperSpec/")
  • M-x slime-connect之后,几个常用的功能:
    • C-c C-c: slime-compile-defun,编译当前光标所在处的表达式
    • C-x C-e: slime-eval-last-expression,对last-expression进行求值
    • M-.: slime-edit-definition,这条命令可以看到Common Lisp中的各种语言结构诸如defun、and、progn的源码,代码取决于你所用的Lisp实现,非常强大,是深入理解Lisp底层的良师益友。
  • 绝大多数Lisp实现均支持trace函数,可以用来跟踪递归过程,形象化地展示递归的运行机理,是深入学习理解递归的良好工具。比如下面的SBCL的REPL中的代码展示:
CL-USER> (defun just-return (n) (if (zerop n) 0 (+ 1 (just-return (- n 1)))))

JUST-RETURN
CL-USER> (trace just-return)

(JUST-RETURN)
CL-USER> (just-return 5)
  0: (JUST-RETURN 5)
    1: (JUST-RETURN 4)
      2: (JUST-RETURN 3)
        3: (JUST-RETURN 2)
          4: (JUST-RETURN 1)
            5: (JUST-RETURN 0)
            5: JUST-RETURN returned 0
          4: JUST-RETURN returned 1
        3: JUST-RETURN returned 2
      2: JUST-RETURN returned 3
    1: JUST-RETURN returned 4
  0: JUST-RETURN returned 5
5
CL-USER> 
  • 书的话,伞哥的博客 已经给出了很好的建议,我再加一本Paul Graham的《Ansi Common Lisp》,一本一本的看吧。“LISP is worth learning for a different reason — the profound enlightenment experience you will have when you finally get it. That experience will make you a better programmer for the rest of your days, even if you never actually use LISP itself a lot”12

差不多了,今天就写到这里,从早到晚写了一天了,累坏了,再写下去我估计读者也坚持不下来了。信息量太大,因此临时决定将文章拆成上下两篇,下篇我会谈谈Scheme/Clojure这两种Lisp方言开发环境的建立,并顺手谈谈Emacs和Maxima的集成。虽然Maxima本身并不是Lisp,但是其基于Lisp实现的事实,也让其与Emacs的联姻充满了浪漫主义的色彩,最近在深入学习算法分析,常常用到Maxima和LaTeX,十分快乐。敬请期待。

--

Footnotes:

1The Joy of Clojure》有这样一段 话:”Writing code is often a constant struggle against distraction, and every time a language requires you to think about syntax, operator precedence, or inheritance hierarchies, it exacerbates the problem. “任何反紧凑的语言,其繁杂的 语言特性往往会使得人们在解决问题的过程中脱离问题本身而陷入语言细节的泥沼,要么是 像C++那样到处是坑到处是禁忌到处是编程规范,要么是像Java那样到处是架屋叠床的类。 问题域和实现域是我最近常常思考的问题,其深度超越于编程语言的范畴,后续我会再写文 章深入探讨下这个主题。

2 http://www.techcn.com.cn/index.php?doc-view-132647.html

3 "The only thing the emacs OS lacks is a really good editor",更多的八卦, 这里

4 坦白的讲,如果以击键次数为标准,单单比较文本编辑的效率,我认为Vim的效率确实比 Emacs强很多。考虑可扩展性的话,我认为Emacs的elisp还是要比Vim的vimscript强很多的。

5 Living in Emacs, 这篇Emacs之所以如此出名,完全在于它起了一个好名字,简明扼要的给出了这篇教程的终 极目标。

6 不擅长干并不代表不能干,比如 这里这里、 还有 这里

7 这个主要是解决Emacs中文输入法的问题,细节可以参考 解决ibus在gVim/Emacs下不能使用的问题、还有 输入法 环境变量的故事

8 鉴于天朝网络的奇葩性,如果某些扩展无法安装,无妨追查下是否是网络问题。解决方案关 键字:ssh && proxychains。

9 架屋叠床这么有创造力的词来源于 function/bind的救赎, “尽 管如此,Java还是沾染上了“面向类设计”的癌症,基础类库里就有很多架床叠屋的设计……”

10 Why there is no SLIME for Python (or Ruby or…)?

11 All Common Lisp Implementations,伞哥的博客有很多关于Lisp极有价值的文章,他对Lisp的执着和 不断学习的精神也让我很是景仰。

12 How to Become a Hacker

 




Host by is-Programmer.com | Power by Chito 1.3.3 beta | © 2007 LinuxGem | Design by Matthew "Agent Spork" McGee