IwamotoBlog

俺に付いて来い

SublimeText3+AllAutoCompleteな環境に、AndyJS2を入れた時の鬱陶しい補完を退治する方法

SublimeのJS補完のためにいままでSublimeCodeIntelやらjQueryにお世話になってたのだけれども、このパッケージ群、補完として弱すぎる。
割と頻繁に駆り出されるappendChild()もgetElementsByClassName()も出してくれない。jQueryをscriptタグに入れたくない我々生JS勢(?)としては非常に辛いものがあります。
そこで何か良いパッケージは無いものかと探していた時にAndyJS2に出会いました。

github.com

数時間使ってみた感想としては「自分の求めていたものだ…」と思わず呟いてしまったほどでした。しかしゆとりプログラマーの僕が使っているAllAutoCompleteというパッケージ。こいつと非常に相性が悪かったのでした。

最高に"""親切"""な補完

AllAutoCompleteはサジェストした瞬間Tabキーを押さずとも補完した関数、変数を叩きだしてくれるパッケージ。
そして恐らくAndyJS2はTabを叩けば全関数が呼び出せるようになっていたのでしょうね。その2つのパッケージが出会った時、悲劇が起こりました。

文末のセミコロンにも
f:id:PEPOipod007:20150831210632p:plain

スペースでも
f:id:PEPOipod007:20150831210650p:plain

さみしがりやな彼はいつでもやって来ます。

邪魔だけどアンインストールするには惜しい

正直超邪魔ですよね。改行のためにescキーを毎回叩く生活にはもううんざりです。しかしアンインストールするにはあまりにも惜しい強力な補完…
そこである一つの結論に至りました。
パッケージのソースを書き換えよう。許されるかどうかはわからないけど個人で使う分だしまあいいでしょう。そうと決まれば早速書き換えに行きましょう。

ソースを書き換えよう

まずはSublimeTextのFile -> Browse Packagesでパッケージのあるフォルダを開きましょう。開けたらAndyJS2というフォルダを開き、末尾が.pyになっているファイルをすべて開きましょう。

f:id:PEPOipod007:20150831212122p:plain

開けたらソースを書き換えましょう。
最下部にあるAndyJSCompletionsとかいう関数が怪しそうですね。chという変数に、恐らく一つ前に入力した文字が入るのでしょうね。
こいつを使って一つ前がセミコロンやスペースの時は何も返さないようにしましょう。

AndyJSCompletions.py

class AndyJSCompletions(sublime_plugin.EventListener):
    def on_query_completions(self, view, prefix, locations):
        global compAll
        if not (view.match_selector(locations[0],
                                    'source.js -string -comment -constant') or
                view.match_selector(locations[0],
                                    'source.ts -string -comment -constant')):
            return []
        completions = []
        pt = locations[0] - len(prefix) - 1
        # get the character before the trigger
        ch = view.substr(sublime.Region(pt, pt + 1)) if pt >= 0 else None
        if ch == '.': pass
        else: pass
        if ch == ';' or ch == ' ': return []
        word = view.word(pt - 1) if pt >= 0 else None
        word = view.substr(word) if word is not None else None
        if word is not None and len(word) > 1:
            pass # could check for window or document
        completions = compAll
        compDefault = [view.extract_completions(prefix)]
        compDefault = [(item + "\tDefault", item) for sublist in compDefault 
            for item in sublist if len(item) > 3]       # flatten
        compDefault = list(set(compDefault))        # make unique
        compFull = list(completions)
        compFull.extend(compDefault)
        compFull.sort()
        return (compFull, sublime.INHIBIT_WORD_COMPLETIONS |
            sublime.INHIBIT_EXPLICIT_COMPLETIONS)

AndyjQueryCompletions.py

class AndyjQueryCompletions(sublime_plugin.EventListener):
    def on_query_completions(self, view, prefix, locations):
        global compAll
        if not view.match_selector(locations[0], \
                'source.js.jquery -string -comment -constant -meta.selector'):
            return []
        completions = []
        pt = locations[0] - len(prefix) - 1
        # get the character before the trigger
        ch = view.substr(sublime.Region(pt, pt + 1)) if pt >= 0 else None
        if ch == '.': pass
        else: pass
        if ch == ';' or ch == ' ': return []
        word = view.word(pt - 1) if pt >= 0 else None
        word = view.substr(word) if word is not None else None
        if word is not None and len(word) > 1:
            pass
        completions = compAll
        compDefault = [view.extract_completions(prefix)]
        compDefault = [(item + "\tDefault", item) for sublist in compDefault 
            for item in sublist if len(item) > 3]       # flatten
        compDefault = list(set(compDefault))        # make unique
        compFull = list(completions)
        compFull.extend(compDefault)
        compFull.sort()
        return (compFull, sublime.INHIBIT_WORD_COMPLETIONS |
            sublime.INHIBIT_EXPLICIT_COMPLETIONS)

この真ん中の方にあるif ch == ';' or ch == ' ': return []がキモです。
;かスペースが来た時にreturn []とすることで補完を出さないようにしています。他に:とかでも出したくないと思った時は、こんな感じで書き足せば同じようなことが実現できます。
これで変更は以上です!思う存分最高の補完を楽しんでください!

おわりに

python、coffeeっぽいなあって思って書いたら動いたしrubyとかあそこら辺の言語は全部こんなかんじなのかなあ。
適当に書いたのでpython強いおじさん達に叩かれないかとても心配です。パッケージ編集で怒られるのも心配です。怖いので怒らないでください。