玩转Emacs的auto-complete

这两天从另一套很不错的Emacs配置Emacs Live中copy了一段auto-complete和 clojure-mode的配置,用起来很爽,可以通过nREPL来补全Clojure的namespace, class,method等等。不过有一个小小的问题:我的auto-complete是自动触发的, 一般情况下自动触发很好用,速度也很快,但在clojure-mode中补全的时候则会 有卡顿现象。这是因为ac-nrepl是动态发送代码到nREPL中运行以得到补全的候选 列表的,速度必然会相对慢一些,如果是通过快捷键补全可能还好一点,但自动 触发补全时会很影响输入体验。

用了一会很不爽,就开始了改进之旅。

1. 禁用自动补全

第一个选择是禁用自动补全并设定一个触发按键,比如 TAB 。这个很简单,只需 要两行代码:

1
2
(setq ac-auto-start nil)
(ac-set-trigger-key "TAB")

其中 ac-auto-start 还可以被设定为一个指定的数字,这种情况下只有连续 输入了指定数目的字符以后才会开始自动补全。

这么做虽然可以解决卡顿问题,但牺牲了自动触发的便利性。尤其是在补全当前 buffer中已经出现的单词时,自动触发会极大改善输入体验,减少按键次数。所 以这个解决办法有点“因噎废食”的意思,我用了一会就放弃了。

2. 为ac-nrepl单独设定补全按键

翻看了一下auto-complete的文档,发现其中核心的函数 auto-complete 是支 持参数的:

1
(auto-complete &optional SOURCES)

其中 SOURCES 是一个complete source列表,如果没有指定此参数, auto-complete 会使用buffer局部的 ac-sources 变量。一般情况下,我们 都是针对它去做配置。但我想达到的效果是:自动触发的补全,使用速度较快的 sources,而速度较慢的sources,我希望手动触发补全。所以需要做两件事:

  1. 不要 将速度慢的source(比如ac-nrepl的那一堆)放到 ac-sources
  2. 单独写一个补全函数,使用慢速source,并绑定到别的按键上

废话不多说,下面是这部分的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
;; 下面的两行代码要去掉,因为ac-nrepl-setup会将自身
;; 的source加入到ac-sources里
;;(add-hook 'nrepl-mode-hook 'ac-nrepl-setup)
;;(add-hook 'nrepl-interaction-mode-hook 'ac-nrepl-setup)

(defun clojure-complete ()
  (interactive)
  (auto-complete '(ac-source-nrepl-ns
                   ac-source-nrepl-vars
                   ac-source-nrepl-ns-classes
                   ac-source-nrepl-all-classes
                   ac-source-nrepl-java-methods
                   ac-source-nrepl-static-methods)))

(add-hook 'nrepl-mode-hook
          (lambda ()
            (local-set-key (kbd "C-M-/") 'clojure-complete)))
(add-hook 'nrepl-interaction-mode-hook
          (lambda ()
            (local-set-key (kbd "C-M-/") 'clojure-complete)))

很简单,就是新写了个 clojure-complete 函数,里面使用ac-nrepl的source 来调用 auto-complete ,然后将它绑定到nrepl mode的 C-M-/ 上了。原来 的配置里setup的部分 一定要去掉 ,否则 ac-sources 里还是有ac-nrepl的 那些source,问题依旧。

使用这个方案玩了一下,目前感觉良好。有什么好点子也希望读者能评论、分享 一下!

另外我的Emacs配置都在此: https://github.com/moonranger/dotfiles/tree/master/emacs

Happy hacking Emacs! :-)

Comments