yasudacloudの日記

札幌に住むソフトウェアエンジニア

JetBrains IDEのプラグイン開発にLSPが組み込まれるらしい

今朝、JetBrainsから届いたメールに気になるトピックがあったのでご紹介します。

blog.jetbrains.com

次のJetBrains IDEの2023.2からプラグイン開発にLSPが組み込まれるというような内容でした。LSPの知識はあまりないのですが、以前興味があって調べていたことがあったので今回取り上げました。

前提

LSPのAPIが使用できるのはIntelliJ Ultimateなどの有料IDEに限られるようです。つまりIntelliJ、PyCharmのコミュニティエディション(CE)では使用できません。公式フォーラムのYouTrackにも記載がありましたが、CEの対応はないと明言されています。

加えてCEだとAPIがそもそもIDEに同梱されないっぽいのでプラグインを取り込めないだけでなく、プラグイン開発を行うこと自体ができないと思われます。

サポートバージョンは2023.2以上が必要らしく、今回は2023.2 Betaで試していきます。

LSPのAPIを試す

せっかくなのでLSP周りのAPIを触ってみます。

1. セットアップ

まず、IntelliJ IDEAのバージョン2023.2 Betaをインストールします。もしJetBrains ToolBoxをお使いの場合はEAP(Early Access Program)を有効にしないとBeta版が表示されないかもしれません。

インストールが終わったら新規プロジェクトでIDE Pluginを選択します。JDKは20だとエラーになったので19にしておきます。

次に、LSPを試すために何かしらのLanguage Serverを用意する必要があります。自分のPCにはterraform-lsがたまたま(?)入っていたのでこちらを使っていきます。Macの場合はbrew install terraform-lsでインストールできます。

ひとまずセットアップは完了。

2. 実装

こちらをベースにしていきます。build.gradle.krsとgradle.propertiesは記載通り設定していけばOKです。

FooLspServerSupportProvider.ktの実装は試行錯誤を重ねてこのようになりました。

gist.github.com

TerraformのLSPなので拡張子をtf、Language IDをterraformとしています。

最後にsrc/main/resources/META-INF/plugin.xmlを編集します。記事本文中には記載がありませんが、FooLspServerSupportProviderはパッケージからフルパスで指定しないとエラーになります。

<idea-plugin>
...省略
<depends>com.intellij.modules.platform</depends>
<depends>com.intellij.modules.ultimate</depends>
<extensions defaultExtensionNs="com.intellij">
<platform.lsp.serverSupportProvider implementation="com.example.demo1.FooLspServerSupportProvider"/>
</extensions>
</idea-plugin>

3. プラグインを動かす

IDE右上のRun Pluginを押すとIDEが新たに起動します。

今回はterraformのLSPなので適当にファイル(hoge.tf)を作成し、補完が効いていることを確認。

↑resまで入力するとresourceという単語が補完されて出ています。加えて上部にメッセージが出ているように、従来のTerraformプラグインが効いているわけではないことが分かります。

トラブルシューティング

com.intellij.platform.lsp以下がインポートできない

build.gradle.ktsの設定を見直します。例えばintellij.typeがIU(IntelliJ Ultimate)に設定されているか。記述がないとIC(コミュニティエディション)がデフォルトになって正しく動きません。

同じくplugins.org.jetbrains.intellijが1.15.0以上になっている必要があります。

設定ファイルが問題ないことを確認したら一度IntelliJを終了し、プロジェクト直下の.gradle以下を削除してから再度IntelliJを起動します。

File Not Foundが出た

自分の場合、当初は拡張子をhclにしていたらFile Not FoundというLSP側のエラーが出ました。(tfにしたら解決しました)

Language Serverの問題かプラグイン側の問題かを切り分けるためにログを吐かせると便利です。例えばterraform-lsの場合はterraform serve -log-file hoge.log のように設定するとファイルにログ出力ができます。

具体的には先ほどのcreateCommandLine()を下記のように変更します。

override fun createCommandLine(): GeneralCommandLine {
val commandLine = GeneralCommandLine()
commandLine.withExePath("terraform-ls")
commandLine.addParameters(
"serve",
"-log-file",
"~/hoge.log"
)
return commandLine
}

まとめ

今回はLanguage Serverとの連携を最低限実現しただけですが、実際にはもっと多くの機能を実装すると思います。例えばTerrafromの場合はAWSやGCPといったProvider毎に補完する情報が異なります。

記事に書いてる通り、コードの補完や宣言元への移動は下記を使って実装するはずですがキャッチアップが追いついていません😇

lspGoToDefinitionSupport
lspCompletionSupport
lspDiagnosticsSupport
lspCodeActionsSupport
lspCommandsSupport

ちなみにTerraform and HCLのプラグインはどうなっているのか気になってjarファイルを開いてみたところ、各ProviderのJSONファイルが大量に入っていました。terraform  providers schema -jsonで出力したようなスキーマが格納されています。

LSPがサポートされることでこの辺りの実装が以前より楽になる、ということですね。

Kotlin関連で最近Ktorが気になっています( ´Д`)y━・~~