🦀

lspmuxでrust-analyzer(あるいは任意のLSPサーバ)の起動を高速化する

に公開

はじめに

rust-analyzerはRustのLSPサーバですが、大規模なプロジェクトの場合、起動にかなり時間がかかることがあります。
例えば現在主に作業している https://github.com/veryl-lang/veryl は20万行ほどのRustコードと600程度の依存関係からなりますが、ビルドキャッシュが存在する状態でもエディタの起動からインデックス作成完了まで15秒程度かかります。
エディタを立ち上げっぱなしにしておく運用であればあまり問題にならないと思われますが、頻繁にエディタの起動と終了を繰り返すスタイルだと15秒の待ち時間は結構気になります。
これを解決するツールとして lspmux というものを見つけたのでご紹介します。

lspmux

lspmux はLSPのためのマルチプレクサで、ワークスペース毎に1つ立ち上げたLSPサーバを複数のエディタから共有することができます。一旦立ち上がったLSPサーバはエディタ終了後も動いたままになるので、次にエディタを起動したときにもその立ち上がったままのLSPサーバに接続されます。そのためエディタ起動時のインデックス作成などの処理が走ることなく、起動した瞬間からLSPサーバの全機能を使用可能になります。

元々はrust-analyzerのためのツールということで ra-multiplex という名前で公開されていましたが、任意のLSPサーバに対応するということで最近名前を変えたようです。また同時に GitHub から Codeberg へリポジトリを移動したようで、最新のリポジトリは以下になります。

https://codeberg.org/p2502/lspmux

設定

微妙に嵌りどころがあったのでセットアップの手順を書いておきます。環境は以下の通りです。

  • OS: AlmaLinux 9
  • エディタ: neovim

インストールは cargo install lsumux で問題ありません。

lspmuxサーバの起動設定

lspmuxのサーバはエディタからの接続を受け付けるため常に起動しておく必要があります。
systemdにはユーザ毎にサービスを起動できる仕組みがあるのでこれを使います。
~/.config/systemd/user/lspmux.service に以下のようなファイルを置きます。

[Unit]
Description=Language server multiplexer server

[Service]
Type=simple
ExecStart=/path/../.cargo/bin/lspmux server
Environment=PATH=/path/../.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

[Install]
WantedBy=default.target

ExecStartには lspmux への絶対パスを書きます。また、lspmuxは内部的にrust-analyzerを起動するため、rust-analyzerへのパスが通っている必要がありますが、systemdのデフォルトでは当然 $HOME/.cargo/bin へのパスは通っていません。そのため PATH 環境変数も明示的に追加しています。

この状態で

$ systemctl --user enable lspmux
$ systemctl --user start lspmux

とすれば lspmux が起動します。起動したかどうかは systemctl --user status lspmux で確認できます。

neovimの設定

neovimでrust-analyzerを使っている場合、 require('lspconfig')['rust_analyzer'].setup というエントリ(neovim 0.11以降では vim.lsp.config('rust_analyzer'かも?)があるのでそこに設定を追加します。
cmdlspMux の2つです。

require('lspconfig')['rust_analyzer'].setup{
    on_attach = on_attach,
    flags = lsp_flags,
    cmd = vim.lsp.rpc.connect("127.0.0.1", 27631),
    settings = {
      ["rust-analyzer"] = {
        lspMux = {
            version = "1",
            method = "connect",
            server = "rust-analyzer",
        },
      }
    }
}

nvim-lspconfigのバージョンが古い場合は lspMuxinit_optionsに書かないといけないかもしれません。

require('lspconfig')['rust_analyzer'].setup{
    ...
    init_options = {
        lspMux = {
            version = "1",
            method = "connect",
            server = "rust-analyzer",
        },
    },
    ...
}

これで設定は完了です。
neovimを起動すればlspmux経由でrust-analyzerに接続されるはずです。

Discussion