概要
Railsのローカル開発環境をDocker化したら、LSPサーバーもDockerで動かしたくなりました。
記事を漁るとVS Code
やNeovim + COC
での設定方法は見つかったのですが、
Neovim + vim-lsp
での構成が見つからなかったので試してみました。
やったことポイント
- Solargraph on Docker
- vim-lsp
やったこと
1. Solargraph on Dockerの起動コマンドのイメージ
こんなかんじのコマンドで起動する。
docker run -d --rm -p 7658:7658 -v $PWD:/usr/src/app \
--health-cmd 'ps aux | grep port=7658 | grep -vc grep || exit 1' \
--health-interval=1s --health-timeout=1s --health-retries=10 \
XXXXX/YYYYY:latest \
bash -c "mkdir -p `dirname $PWD` && ln -snf /usr/src/app $PWD && solargraph socket --host=0.0.0.0 --port=7658"
- Dockerコンテナ内のソースパスは
/usr/src/app
です(これは自分のコンテナにあった値を使いましょう) -
-v $PWD:/usr/src/app
でホストのソースパスをコンテナにマウントしてます -
ps aux | grep port=7658 | grep -vc grep || exit 1
でポート7658でsolargraphが起動しているかをhealthチェックで確認してます(ここも自分のコンテナで使えるコマンドでいい感じにしましょう) - solargraphを実行する前に、ホストのソースパス(
$PWD
)と同じパスをコンテナ内に作成して、コンテナ内のソースパスにリンクを貼ってます。(mkdir -p $(dirname $PWD) && ln -snf /usr/src/app $PWD
) - solargraphをsocketモードで起動してコンテナの外から問い合わせできるようにします(
solargraph socket --host=0.0.0.0 --port=7658
)
2. vim-lspでサーバー登録のイメージ
こんなかんじのコマンドで登録する
autocmd User lsp_setup call lsp#register_server({
\ 'name': 'solargraph',
\ 'cmd': {server_info->['nc', '127.0.0.1', "7658"]},
\ 'allowlist': ['ruby'],
\ 'initialization_options': {"logLevel": "debug"},
\})
- netcat(
nc
)でSolargraph on Dockerコンテナとやり取りします - lsp_setupってautocmdで登録します
最終的にこうなりました
Neovim起動時に以下を読み込んで、コンテナ起動、起動が完了するまで待ってからLSP登録、Neovim終了時にコンテナ停止します
let s:solargraph_port = 0
let s:solargraph_docker_id = ""
function! s:setup_solargraph() abort
if s:solargraph_port > 0
return
endif
let s:solargraph_port = 7658
let l:result = system("lsof -i:".s:solargraph_port)
while len(l:result) > 0
let s:solargraph_port = s:solargraph_port + 1
let l:result = system("lsof -i:".s:solargraph_port)
endwhile
let s:solargraph_docker_id = system("docker run -d --rm -p ".s:solargraph_port.":7658 -v $PWD:/usr/src/app --health-cmd 'ps aux | grep port=7658 | grep -vc grep || exit 1' --health-interval=1s --health-timeout=1s --health-retries=10 XXXXX/YYYYY:latest bash -c \"mkdir -p `dirname $PWD` && ln -snf /usr/src/app $PWD && solargraph socket --host=0.0.0.0 --port=7658\"")
let l:health = system("docker inspect -f '{{if eq \"healthy\" .State.Health.Status}}0{{else}}1{{end}}' ".s:solargraph_docker_id)
while l:health == 1
sleep 1
let l:health = system("docker inspect -f '{{if eq \"healthy\" .State.Health.Status}}0{{else}}1{{end}}' ".s:solargraph_docker_id)
endwhile
call lsp#register_server({
\ 'name': 'solargraph',
\ 'cmd': {server_info->['nc', '127.0.0.1', s:solargraph_port]},
\ 'allowlist': ['ruby'],
\ 'initialization_options': {"logLevel": "debug"},
\})
endfunction
function! s:shutdown_solargraph() abort
if len(s:solargraph_docker_id) == 0
return
endif
let l:result = system("docker stop ".s:solargraph_docker_id)
endfunction
augroup solargraph_setup
au!
autocmd User lsp_setup call s:setup_solargraph()
autocmd ExitPre * call s:shutdown_solargraph()
augroup END