読者です 読者をやめる 読者になる 読者になる

Google Apps Scriptを補完するためのTernのプラグインを作りました

Tern Google Apps Script Emacs

これは何?

Google Apps Scriptを使ってやりたいことがあったので開発環境について調べると、
Google Apps Scriptの入力補完ができるのは、Webブラウザ上のScriptEditorか、Eclipseだけのようでした。
しかし私は、コーディングするならEmacs! な人間であり、
5文字以上の単語入力でタイプミスり、3歩歩けば覚えたリファレンスが忘却の彼方に消え去る人間なので、
どうしてもEmacsGoogle Apps Scriptの入力補完をしたくて、
Google Apps Scriptの型情報を追加するTernプラグインを作りました。

このプラグインを使うことで、TernでGoogle Apps Scriptの補完が効くようになります。

インストール/設定など

以下にまとめました。
https://github.com/aki2o/tern-gas

未対応な部分

https://developers.google.com/apps-script/ の Advanced Google Services 配下にリストされている機能は補完できません。

Emacsでauto-complete.elと連携させて使う場合

Tern補完専用コマンド

Ternのマニュアルにある設定だと、"."を入力した時しかTernの補完を使いません。
そのため、Google Apps Scriptのルート要素(Loggerとか)の補完ができません。
これは ac-source-tern-completion が ac-sources に追加されるのが上記タイミングのみのためで、
例えば以下のようにすれば常にTernの補完が効くようになります。

(add-hook 'js2-mode-hook '(lambda () (tern-mode 1) (add-to-list 'ac-sources 'ac-source-tern-completion)))

ただ、TernはJavascriptの組み込みキーワード(forとかwhileとか)は補完してくれないようで、
常時有効だと使い勝手が悪かったです。
Ternの補完を有効にする専用コマンドが提供されているので、
私は補完開始はC-SPCに設定していますが、以下のように別のコマンドでTernの補完を開始するようにしました。

(define-key tern-mode-keymap (kbd "M-RET") 'tern-ac-complete)

大文字小文字の区別

auto-complete.elは ac-ignore-case を有効にすることで、
文字の大小の違いは無視して補完候補を表示してくれます。
しかし、Ternから提供されているtern-auto-complete.elは、
現状だと、この違いを無視してくれず、例えば、"logg"と入力しても"Logger"は補完されません。
ただ、Tern側には、 caseInsensitive というオプションがあり、
それを有効にすれば補完されるようになるので、その修正を本家に出しています。

実装について

このプラグインの作成にあたって採用した実装について、
あんまり良い方法ではないんじゃないかなと思っていて、その辺の経緯をまとめておきます。

まず、このプラグインにはGoogle Apps Scriptの型情報をハードコードしており、
それらは https://developers.google.com/apps-script/reference からスクレイピングしたものです。
インストールのリンク先でも言及していますが、contribフォルダ配下のスクリプトを使ってプラグインの更新ができます。

最初、Webブラウザで入力した時に呼ばれる機能をNode.jsから呼び出すことができるんじゃないかと、
Webブラウザ上のScriptEditorのソースを見始めたんですが、難読化に阻まれ把握できず...
実装にはCodeMirrorが使われていて、 Ternと同じ作者で、
コメントにもその方が関わっている記述があったので、解析を頑張れば上手いこと移植できるかもしれません。
でしたが私は挫折しました。

次に、Eclipseプラグイン Google Plugin for Eclipse のソースを観てみると、
型情報を定義したテキストファイルを内部に持っていて、そこから補完しているようでした。
そのテキストファイルを同じように利用すれば、Google Apps Scriptの仕様変更にも追随できそうでしたが、
内部ファイルだしフォーマットが変わらない保証はなく、ヘルプ情報も定義されていなかったので、
却下しました。

で、結局、これという方法が見つからず、Webのリファレンスからスクレイピングすれは良いやっという妥協。
なので、仕様変更があった時、サイト構造が変わっててスクリプト動かないってことがありえます。

Enjoy!!!