solargraph gemのソースコードを読んでいく。
vscodeの方はほぼ何もしておらず、コマンドをサーバーに送信しているだけだった。
solargraphの方では、Host#prepare(directory)でHost#librariesにSolargraph::Librariesを溜めておき、Host#diagnoseでこれに問い合わせている。
Host#diagnoseの実装はLibrary#diagnoseに委譲されていた。更に、Diagnostics::Reporter.reporter(name)に委譲されている。
Diagnostics::Rubocopに辿り着いた。これはReporterの1つで、他にはTypeCheckなどがあるらしい。
lib/solargraph/diagnostics/rubocop.rb を見た。vscode-ruby-lightとやっていることはほぼ同じだった。
Diagnosticsを読むのは終えて、Documentというのを読んでみることに。これはHost#document -> Library#document -> ApiMap#document と委譲されている。
vscode-ruby-lightのおかげで手軽にRubyのソースコードのシンボル情報を得られるようになって、メソッド名で検索するというのがやりやすくなって捗るようになった。
api_map.clip(cursor).complete
でその地点の補完候補を返しているようなので、これを読んでみる。
インライン化すると SourceMap::Clip.new(self, cursor).complete
になる。
# @return [Completion]
def complete
return package_completions([]) if !source_map.source.parsed? || cursor.string?
return package_completions(api_map.get_symbols) if cursor.chain.literal? && cursor.chain.links.last.word == '<Symbol>'
return Completion.new([], cursor.range) if cursor.chain.literal?
if cursor.comment?
tag_complete
else
code_complete
end
end
cursor.chainで使われているChainは、メソッドチェーンなどの一連のトークン列を表すやつ? トークン、と読み替えても差し支えない気がする。chain.linksはtoken.previous_tokens。
そうなると、
return package_completions(api_map.get_symbols) if cursor.chain.literal? && cursor.chain.links.last.word == '<Symbol>'
これは、現在カーソルがSymbolリテラルを指しているときは、Symbol一覧の補完候補を出しましょうということになる。libraryに問い合わせていて、libraryは1つのファイルについての情報のみを持っているはずだから、これは「現在ファイル内のSymbolから補完候補を出す」ということになりそう。
ところで、単純なワードだけを補完するのであれば、VSCodeの標準機能がそれを補完候補に含めてくれるはずなので、実際これは意味があるんだろうか...? 補完候補の優先順位が上がるとかだろうか。
solargraph socket --host 0.0.0.0
とやることでWSL環境でもsolargraphが動いた。これをしないと動かない……デフォルトだと127.0.0.1になってこれがWSLだと動かない (別のもの...Windows側のホスト?に解決される?) のだと推測している。
引数にhoverするとツールチップが表示されて、リンクっぽい文字列をクリックするとwebviewというやつが開くことが確認できた。webviewを使ってドキュメント表示を実現しているらしい。ドキュメントの計算には時間が掛かるから、1ステップ踏ませている、という努力が見られる気がする。
stdioモードにしたら上手く動いた。
vscode-solargraphを見ると、stdioモードの場合は起動時にクライアント側でsolargraph stdioをspawnしている様子が見て取れた。extentionKindがworkspaceなので、当然クライアント側で起動してもOK。
typecheckerは面白いけど、YARD viewerみたいなものがあればそれで十分かなあ。
# @params [Foo::Bar] bar
に対して、Rubyで Foo::Bar
の定義元を調べたりメソッドの情報を調べたりできるともっと便利だけど、これは実行してみないといけないので、適切にrequireしたりする必要があって色々大変かも。
vscode-ruby-lightにYARD Viewer機能をつくってみてもいいかも。できるところまでシグネチャを解析して、ビルドされたYARDのデータベースに一致すればその情報を返すというもの。
あとデフォルトで標準ライブラリについての情報は持っておいてもいいかも。そうなるとYARDに限らない気もするけど。
もうしばらくsolargraphのコードを読んでいく。
Pin, SourceMap, ApiMap辺りの概念を把握する必要がありそう。
コード上のオブジェクトのことをPinと呼ぶようだ。例えば、一つの派生形として、Pin::Methodがある。