LoginSignup
3
0

More than 1 year has passed since last update.

Neovim + vim-lsp + solargraph + docker

Posted at

概要

Railsのローカル開発環境をDocker化したら、LSPサーバーもDockerで動かしたくなりました。
記事を漁るとVS CodeNeovim + COCでの設定方法は見つかったのですが、
Neovim + vim-lspでの構成が見つからなかったので試してみました。

やったことポイント

  • Solargraph on Docker :whale:
    • socketモードで起動する(参考)
    • ソースパスがDockerとホストで一致するようにシンボリックリンクを設定(参考)
    • solargraphの起動完了がホスト側で検知できるようにhealthchekを設定する
      (Neovimの起動スクリプトでコンテナを起動+Lsp登録するため)
  • vim-lsp
    • tcpサポートはNeovimでは使えない:cry:(参考)のでnetcat:cat:を使う
      • nvim-lspに乗り換えようかと思ったけどそっちもtcpサポートしてなかった:cry:(参考)
    • Neovim起動時にコンテナを起動して、終了時にコンテナを落とす

やったこと

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
3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0