flow + auto-complete.el で JavaScript のコードを補完する
Posted on June 20, 2016
flow の自動補完機能を使って Emacs 上でJavaScript のコードを補完できるようにしようという話。 flow の自動補完機能は最近になってずいぶん改善され、ほぼ問題なくコード補完できるようになったのだけど、肝心のクライアント実装がまだしょぼいため自作する必要があった。自分は普段 auto-complete.el を使っているので以下に挙げるのは主に auto-complete.el 向けの設定だけど、company-mode に移植するのはさほど難しくないと思う。
(require 'auto-complete)
(require 'json)
(defvar flow-program "flow")
(defun flow--get-completions ()
(assoc-default
'result
(json-read-from-string
(with-output-to-string
(let ((line (line-number-at-pos))
(col (1+ (current-column))))
(call-process-region
(point-min) (point-max) flow-program nil standard-output nil
"autocomplete"
"--json"
(number-to-string line)
(number-to-string col)))))))
(defun flow--ac-prefix ()
(when (re-search-backward "\\(?:\\.\\)\\(\\(?:[a-zA-Z0-9][_a-zA-Z0-9]*\\)?\\)\\=" nil t)
(match-beginning 1)))
(defun flow--ac-candidates ()
(mapcar
(lambda (c)
(popup-make-item
(assoc-default 'name c)
:summary (assoc-default 'type c)))
(flow--get-completions)))
(ac-define-source flow
'((candidates . flow--ac-candidates)
(prefix . flow--ac-prefix)
(requires . 0))))
これで M-x ac-complete-flow
で補完ができるようになる。(.flowconfig
を作ることを忘れないように)
コード補完のイメージ
自分は C-c TAB
にこのコマンドを割り当てている。なお、補完のたびに外部コマンドを起動するため、 ac-sources
に ac-source-flow
を追加することはおすすめしない。
JS や JSX の編集に web-mode を使っている場合は少しトリッキーな設定を追加する必要がある。
(defvar my-web-mode-complete-triggered nil)
(defun my-web-mode-setup-complete ()
(setq web-mode-ignore-ac-start-advice my-web-mode-complete-triggered))
(defun my-web-mode-complete ()
(interactive)
(let ((my-web-mode-complete-triggered t))
(call-interactively 'ac-complete-flow)))
(add-hook 'web-mode-before-auto-complete-hooks 'my-web-mode-setup-complete)
(define-key web-mode-map (kbd "C-c TAB") 'my-web-mode-complete))
web-mode が web-mode-ac-sources-alist
に基づいて(強引に)ac-sources
を書き換えるため、たとえ手動でコード補完を呼び出したとしても、それを防ぐ必要があるようだ。1
ちなみに、自分で言うのもなんだが auto-complete.el の API やドキュメントの不備にはイライラさせられた。 company-mode を使う気にはなれないし、この状況は本当になんとかしたい。
web-mode の問題だけど修正するのが面倒くさい↩