Partedit で Neovim LSP が起動しない
問題の現象
Markdown やドキュメント類など、部分的に他の言語が混じる文書を Vim で編集する際は thinca/vim-partedit
が便利です。使い方は簡単で、範囲選択した上で :Partedit
コマンドを実行するとその内容が別バッファとして切り出されます。そうすることで、部分的に別のファイルタイプで編集できるというものです。保存操作をすると BufWriteCmd
イベントが発火し、元ファイルに反映されるという仕組みになっています。
Neovim には組み込みの LSP 機能がありますが、上述の Partedit によるバッファ内にて起動してほしい LSP サーバーが起動しないという問題が発生しました。これでは補完などが全く効かず本末転倒です。
環境
- Neovim (v0.11.3)
-
thinca/vim-partedit
(a4ed06ff) - lua-language-server (3.15.0)
- その他設定ファイル
nvim/init.lua
-
nvim/lsp/lua_ls.lua
(nvim-lspconfig
のものと同一)
以下のリポジトリに最小構成を作成しています。Nix がインストールされていれば、クローンしてリポジトリで nix develop . --no-update-lock-file
すれば該当環境に入れます。
再現手順
以下の3ケースに対して該当バッファにアタッチされた LSP サーバーをチェックします。
- 実在する Lua ファイルの編集
- 実在する Lua ファイルを Partedit で開いたもの
- 初期起動時の空バッファのファイルタイプを
lua
にしたもの
アタッチされた LSP サーバーをチェックするコマンドは以下です。
:lua= vim.lsp.get_clients { bufnr = 0 }
Case 1. 実在ファイルの編集
lua-language-server をインストール・セットアップしているので、適当な Lua ファイルを開くと LSP サーバーがアタッチされる筈です。丁度設定ファイルが Lua ファイルなので開いてみましょう。
nvim nvim/init.lua
そして :lua= vim.lsp.get_clients { bufnr = 0 }
でチェック。
きちんと起動していますね。
Case 2. Partedit で起動したバッファ
それではそのまま以下のコマンドでバッファ全体を Partedit にぶち込みましょう。
:%Partedit -filetype lua
そして :lua= vim.lsp.get_clients { bufnr = 0 }
でチェック。
何もアタッチされません。ちなみに、手動で :lua vim.lsp.enable 'lua_ls'
を打ちこんだ後も同様の結果でした。
ft=lua
の空バッファ
Case 3. 気を取り直して、初期起動のバッファに対して :set ft=lua
してチェックしてみましょう。
" 引数なしで nvim した後
:set ft=lua
:lua= vim.lsp.get_clients { bufnr = 0 }
アタッチされていました!
結局原因は何なのか
Case 3. で実在しないバッファに対してもアタッチされていたので、対応するファイルの実在は関係ないようです。
先に結論を言うと、原因は buftype
の値にあります。 Case 2.に対して :set bt=''
をした後に LSP サーバーを再度有効化すると適切にアタッチされます。
" Parteditのバッファでも大丈夫なパターン
:%Partedit -filetype lua
:set bt=''
:lua vim.lsp.enable 'lua_ls'
:lua= vim.lsp.get_clients { bufnr = 0 }
現在の Neovim LSP の実装では以下のように、何故か buftype
が空でないとアタッチされない ようにガードする処理が記載されています。
Only ever attach to buffers that represent an actual file.
とあるように、自動起動処理が各種プラグインの作成したバッファに対して誤爆することを回避するために挿入された処理であるようです。
実際、今回検証した3ケースに対しての buftype
はそれぞれ以下のようになっています。
Case | buftype |
---|---|
Case1. 実在Luaファイル | (空) |
Case2. Parteditバッファ | acwrite |
Case3. 初期空バッファ | (空) |
回避法
暫定的に、自身は thinca/vim-partedit
をフォークさせていただき、バッファに acwrite
を付加しないようにすることで対処しています。
--- a/autoload/partedit.vim
+++ b/autoload/partedit.vim
@@ -77,7 +77,9 @@ function! partedit#start(startline, endline, ...)
let b:partedit__contents = original_contents
let b:partedit__prefix = prefix
let b:partedit__bufhidden = bufhidden
- setlocal buftype=acwrite nomodified bufhidden=wipe noswapfile
+ " NOTE(gw31415): Delete acwrite: because Neovim LSP does not start
+ " Reference: https://github.com/neovim/neovim/blob/d4c8e8df1c80cf195dc1d1b98c1c8429dd3f43ed/runtime/lua/vim/lsp.lua#L535-L537
+ setlocal nomodified bufhidden=wipe noswapfile
command! -buffer -bar ParteditEnd execute b:partedit__bufnr 'buffer'
プラグイン本体に手を加える点でかなり無理矢理な気もしますが、こちらで正常に :Partedit
できるようになりました。
とはいえ、意味論的に acwrite
は外したくありません。恐らく手動で vim.lsp.start()
するのが正攻法ですが、 vim.lsp.enable()
と同様の起動条件を書く羽目になりそうだったので諦めて中断しました。良い対処法があれば教えてください。
Discussion