分享 Emacs 开发 Rails 应用之 --- 自动补全与 snippet 输入

zw963 · 2012年03月22日 · 最后由 xuefuqiao 回复于 2013年07月21日 · 9868 次阅读

应 lgn21st 之邀,写一篇有关Emacs 开发 Rails 应用的 Wiki. 深感任务相当庞大, 好在现在还没有上班,时间相对充裕。虽然已经很晚了,但明天可以睡个懒觉。 立即行动,把这两天的战斗结果记录下来。

这几天突击研究了几天有关 Emacs 中的自动补全 (autocomplete) 以及 snippet 输入。

小有心得,在同一个快捷键之上 (tab), 堪称完美的实现自动补全与 snippet 插入的功能。

赶紧记下来备忘,在这里分享给大家。

我认为针对任何其他编辑器,都应该具有一定的通用性,从此再也不用为了使用什么样的 key 来定义 snippet 发愁了。很爽~~

在 Emacs 下面,自动补全使用的插件叫做 auto-complete, snippet 插件叫做 yasnippet.

你可以在以下 github 找到最新的软件版本: https://github.com/m2ym/auto-complete https://github.com/capitaomorte/yasnippet

首先说下在 Emacs 以上两个插件中存在的提示菜单,总共有三种。

其中两种是自动补全 (autocomplete) 提供的,而另一种是 yasnippet 插件提供的。

自动补全有两个菜单: 一个是光标后面的阴影,会告诉你如果按下 tab 键,会补全为什么单词. 另一个是如果等待 0.8 秒后,什么也没做,弹出一个文本菜单,这个菜单按照一下优先顺序决定扩展:

  • 当前模式对应词典
  • 是否定义对应的 snippet
  • 当前 buffer 上下文

(注意,以上两个菜单,在 Emacs 中,可以设定在输入多少个字符后才允许激活,很明显, 我的设定是 4 个字符,默认情况下,这个选项是 2)

yasnippet 有一个菜单,只有在使用同样的 key, 但是具有不同的 name 的情况下,才会弹出这个菜单. 用于选择同样的 key 下的不同的不同的 snippet.

例如:键入 should, 再次键入 tab, 会弹出一个 snippet 菜单,会有各种 should 的片段注释, 在这里,你可以根据不同的 name, 来选择扩展对应的 snippet.

具体的要求是:

  • 如果键入的字符数量小于等于 3 个,此时,如果存在对应的 snippet key. 例如存 sh 扩展为 should,则扩展该 snippet. (注意,也可以选择这一步直接扩展 snippet, 即,sh => 直接调用所有 should 开头的 snippet 菜单)

  • 如果键入的字符超过 3 个,此时,在光标所在行,会弹出阴影,告诉你按下 tab 后会补全成什么单词. 此时的优先顺序是:当前模式词典 => yasnippet => 当前 buffer 的上下文) 要求此时按下 tab, 应该总是扩展为阴影提示的字符。 例如:你键入 shou, 会看到后面有阴影提示 ld, 此时立即按下 tab 键,应该总是自动完成 should. 但此时又分为两种情况:

    • 如果此时按下 tab 键,会立即从原先的 shou, 补全为 should.
    • 如果此时不按 tab 键,0.8 秒后,光标所在行会自动弹出一个选择菜单。可以通过 M-n, 和 M-p 在所有可能的自动完成中选择。
  • 通过以上两种方式,已经自动补全为 should, 此时再次按下 tab, 会弹出一个 yasnippet 选择菜单 会有各种以 should 开头的 snippet 方案弹出,根据 name 的不同,你可以选择一个,然后扩展它。

(这里需要注意的是:完全可以直接通过 键入 sh => 按下 tab 展开 snippet 菜单,此时必须同时满足以下条件:

  • 键入 should => 按下 tab 展开 snippet 菜单。
  • 键入 sh => 按下 tab, 展开 snippet. 这在 Emacs 的 snippet 插件中,很简单就可以做到。

唧唧歪歪一大堆,最终的效果就是类似这样的:

键入 sh => 按下 tab, 调用跟 should 有关的 Rspec snippet 菜单. 键入 shou => 按下 tab, 展开为 should, 也许你想自己输入自己的 should 定义,此时就不用再次键入 tab 了. 键入 should => 按下 tab, 调用跟 should 有关的 Rspec snippet 菜单,跟 sh 一样。

方案也介绍完了,有人会问,至于费这么大劲儿么?原先自带的不就挺好么?

我要说 我真的是很不喜欢老外的单词首字母简写的那种方案. 我承认这种的确简单,也许会快一点点。

可是就拿 Rspec 当中常见的的 should_not 来说 shnp, shnm, shnre, shnrt, shns, shnb, shkof, shbio, shnbc, shnbr, shne, 这还没完..., 这一大堆东西,你第一次使用,快捷键你记得住吗?你知道是什么意思吗?

而且很明显,这种方式及其容易冲突,有时候你不得不做妥协,例如两个 snippet 的首字母一样,你可能必须 让其中一个稍稍改变一下。这造成的后果是:也许你熟练了,觉得听自然,但是让别人用起来,会很晕。 怎么一会儿这样,一会儿那样啊?的确,使用这种方式,如果 snippet 太多,重复性高,你很难归纳出一个 有共性的东西,

我要的是:以后不管新加多少 snippet, 都可以采用此种方式来推断出你要采用的别名是什么的完整解决方案。

所以,最后的结论是:

所有的 snippet, 都采用完整的激活字符。例如:Ruby 中的 classify 方法,我需要扩展代码块的使用方式, 对应的 key 就是 classify, 只不过,无论你是键入 cla, 或者是键入 class, 在按下 tab, 都会自动补全为 classify, 然后再次 tab, 就自动补全 snippet 了。

针对就有高度相似的 snippet, 使用同样的 key, 例如,跟 render 有关的所有 snippet, 激活 key 都是 render, 在弹出菜单里选择需要的 snippet 就是了。

本论坛,继 vim 之后,lz 要掀起一股 emacs 热了。。。

匿名 #2 2012年03月22日

打个标记慢慢看

楼主传教 Emacs,我可以考虑传教下 Vim,来场“圣战” :)

#2 楼 @ruchee 同为 VIM 党的我精神上支持你

谢谢楼主分享,我也打算玩起来 emacs,根据上次 RubyTuesday @nouse 的说法,要玩 Haskell,得在 Emacs 上玩。 btw,我改天把胡子剃了,呵呵。

之前配了一个 Emacs 的 Rails 环境,不过用了几个星期觉得不爽,又继续用 Vim 了。Emacs 主要是 elisp 写起来很好玩,有兴趣看看: http://github.com/iwinux/emacs-config

匿名 #6 2012年03月22日

@iwinux 看过你分享的配置,其实是直接 copy starter-kit,你要不就 fork 别人的用,要么就自己从头开始改。init.el 的 contributors 历史出卖了你

#4 楼 @lgn21st

开个玩笑。哈哈。

@lgn21st , 嗨~~

我刚刚更新了部分有关 Emacs 的 Wiki, 怎么重新进来,找不到了呢? 索引页面没有自动添加

@lgn21st ,找到了,在目录中.....

#6 楼 @hbin 我只是没在 README 里写而已,目录里那个 starter-kit 是谁都能看到的吧,确实是 copy 的,我也没说是原创的,何来出卖一说……

emacs 24 春季就要 release 了吧,多了大量的 feature,到时候准备进行第 N 次向 emacs 迁移行动...

不过有不少人已经在用 24 了,说是没什么大 bug,不知道@zw963 同学有体验过没?

#11 楼 @willmouse

@没需求啊,短期内不会迁移,至少正式版出来之前,肯定不会。 我不知道有什么 feature, 貌似也就 elpa 啊。这玩意儿,我也就是偶尔上去看看有什么好玩插件, 至于最后安装配置,从来不用 elpa 的. 事实上,我还在用 Emacs 23.1, 虽然 Emacs 我懒得升级,不过我的插件库,可是隔三差五的有空就升级. 多数情况下,我也用不到 Emacs 自带的标准库。因为我自己用的库都在我自己的.emac.d 里面。

自动补全和 snippets 基本是废的,还是不追求的好。等你大脑思考要选哪个的时候,键盘早就敲出来了。

个人觉得 snippet 也就 def, cla, mod, if, do 这些补全 end 的最好用

另外把所有 assertxxx 都改成了 as 触发,所有 validatexxx 都改成 va 触发 ...

#10 楼 @iwinux 我也觉得你是被冤枉了

正适合我用。试试。:)

#16 楼 @foyo99

真的么?哈哈。 难得和我一样的体会. 自从想通了这个规则后,我的效率几何级提高啊。

一边编写代码,一边编写 snippet, 而且不会忘记。

#17 楼 @zw963 有什么好的资源学习 Emacs?自带的 help 么。

#18 楼 @ray

基本上没有中文的。能看到的百度上都能搜出来,都是老掉牙的。而且不涉及什么技术性的东西。

除了自身文档,就是 emacs-wiki.org

匿名 #20 2012年03月23日

#18 楼 @ray 可以先看 Emacs 自带的 tutorial,有中文;国内还有一个网站叫 Emacser 中文网,有些文章还是很不错的,不过版主很久没有更新。

@zw963 这....头像,我觉得老毛比 gnu 的野牛看上去让人更印象深刻

#18 楼 @ray #20 楼 @hbin

对了,Emacs 最权威的资料还是 Emacs Manual, Emacs 安装就自带的 pdf 文档,我挑着读了大概不到一半。就已经很熟了。不过全英文哦,在读书之前,还是先用用,零陵散散的看点中文配置资料啥的吧。

#21 楼 @willmouse

靠~~ 呵呵,你怎么老咬着不放吶 ??

不错~~ 我真怀疑,这坛子里一多半人不知道这牛是干嘛的。

#23 楼 @zw963 错了,一半人看不出这是头牛

#19 楼 @zw963 你说的这些我都有看,用 Emacs 也用过一段时间,感觉配置什么的花的时间比较多。PS:我用 Emacs 24。

#24 楼 @willmouse

事实上,这也不是牛... 只是看着像牛而已,自身就是一个四不像,就像 GNU 的双关语一样。

你用英文词典,查一下 GNU, 就知道是什么玩意了。

#20 楼 @hbin 看过 Emacser 的文章,好像国外现在用 Emacs 的人真的也不多,Vim 的插件满天飞,Emacs 好像没怎么看到。不过毕竟 Emacs 难度大一些。

匿名 #28 2012年03月24日

#27 楼 @ray 不要想当然,google trends 一下就知道了。看来在 @zw963 的鼓吹下,Emacs 在坛子里小有气候了。

#27 楼 @ray #28 楼 @hbin

我刚写了一篇帖子发牢骚,就说这事儿。

别说欧美,日本用 Emacs 一抓一大把 , 你有空看看 Emacs 当中的标准库有多少是日本人写的。包括 Ruby 标准库,那些写 Ruby 代码的日本人,我估计十有八九都是用 Emacs, 事实上 Emacs 自带的库里面,里面你能见到大把的 Ruby 名人,好些个人就是 Ruby 核心开发组的,看邮箱就知道。

事实上,标准的 Ruby-mode, matz 写的。你随便打开一个日本人写的 Ruby 库,在这个 mode 下面,你运行 format-buffer 命令,再另存,会提示你文件根本没有任何变化,这虽然不见肯定,但是有很大可能对方就是 Emacs 编写的 Ruby 库。

#28 楼 @hbin 哈,刚刚 google trends 了一下,发现 vim 和 emacs 总体趋势都在下降,不过 vim 下降得不明显,所以现在 emacs 已经低于 vim 了,不过日本确实比较特别,与其他地区不一样,emacs 是压倒性的多

很奇怪,我 auto-complete 配置按照官方的写 (add-to-list 'ac-dictionary-directories "~/.emacs.d/ac-dict"),但是提示错误说:Symbol's value as variable is void: ac-dictionary-directories

#31 楼 @ghosTM55 你有~/.emacs.d/ac-dict 这个目录吗?

不过,即使没有,也不应该是这个错误吧。

我怀疑你根本没有加载 auto-complete 的 config 库。

(require 'auto-complete-config)

#32 楼 @zw963 我是完整的根据官方的配置来的,之前我用过 auto-complete,也没有遇到这个错误

(add-to-list 'load-path "~/.emacs.d/plugins/auto-complete") (add-to-list 'ac-dictionary-directories "~/.emacs.d/ac-dict") (require 'auto-complete-config) (ac-config-default)

这样的

ac-dictionary-directories 这个变量在 auto-complete.el 中被定义,auto-complete.el 又被 auto-complete-config.el 混入,所以正常情况下不可能提示变量不存在。

你有没有吧 auto-complete.el 和 auto-complete-config.el 放在你的 load-path 之内? 例如:~/.emacs.d/plugins/auto-complete

#30 楼 @neutralevil

Emacs 从来就没高过 Vim.

#33 楼 @ghosTM55 我猜你应该是 byte compile 以后找不到变量声明,用 eval after load 加载配置或者自己声明下变量 (defvar ac-dictionary-directories nil)

不错,回家尝试一下

配好了并且用了一段日子了,不过仍然有一些不够“人性化”的地方,明天找@zw963 大哥现场请教下!

#19 楼 @zw963 Typo fix: http://emacswiki.org

BTW 这些地方也很不错:

#28 楼 @Guest Eclipse IDE 也在下降。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号