Help us understand the problem. What is going on with this article?

neovim/VimでLanguage Server Protocolを利用するための基礎知識と設定方法

この記事ではLanguage Server Protocol(LSP)の基礎知識とneovim/VimでLSPを利用するための設定方法を紹介します。

Language Server Protocol(LSP)とは

Language Server Protocol(LSP)は、エディタや統合開発環境などの開発支援ツールと言語サーバ(Language Server)のコミュニケーションの手順を定めた仕様です。

従来、開発支援ツールが各種のプログラミング支援機能(自動補完や定義ジャンプ)を提供するためにはプログラミング言語ごとに個別の機能を実装する必要がありました。

LSPでは、言語サーバがクライアントに対して一般的なプログラミング支援機能を提供します。その結果、開発支援ツールは単一のLSPクライアント機能を実装するだけで自動的に言語サーバを提供する全てのプログラミング言語のプログラミング支援機能を提供することが可能になります。

neovim/Vimユーザの目線から見ると、これまでプログラミング言語毎に様々なプラグインを導入していたところが、LSPクライアントのプラグインを一つ導入するだけであらゆるプログラミング言語の支援を得られるということになります。

LSPの詳細は以下の公式サイトで確認できます。

LSPの実装

以下の2つのサイトでLSPサーバ/クライアント実装の一覧を確認できます。

一つ目はMicrosoftが運営するLSP公式サイトのImplementationsページです。言語サーバ、開発ツールの一覧が見られるほか、各言語サーバの動作環境を確認できます。

二つ目のLangserver.orgは、Sourcegraphが管理するコミュニティ運営のLSP情報集約サイトです。言語サーバ、開発ツールの一覧とそれぞれのサーバ、クライアントが対応している基本的な機能がまとめられています。

各実装は必ずしもLSPが定める全ての機能を網羅しているわけではなく、一部の機能のみを提供している場合があります。Langserver.orgでは以下の機能について各実装の対応状況がまとめられています。一覧の内容からLSPで提供される機能がなんとなくイメージできます。

  • Code Completion
  • Hover
  • Jump to def
  • Workspace symbols
  • Find references
  • Diagnostics
  • Additional capabilities

主な言語サーバの実装を以下に一覧します。

プログラミング言語 言語サーバ
Ruby Solargraph
Go gopls
Python python-language-server
JavaScript typescript-language-server

neovim/VimのLSP対応プラグイン

neovim/Vimで利用できるLSP対応プラグインで有名なものは、今の所以下の2つのようです。

この記事を書いている時点でGithubのスターの数はLanguageClient-neovimが1,893、vim-lspが801でした。

vim-lsp

この記事ではvim-lspを利用する手順を記載します。

vim-lspはmattnさんが積極的にcommitされている点を個人的に注目しています。

vim-lspのインストール

プラグインマネージャにvim-plugを利用する場合、設定ファイルに以下を記述します。他のプラグインマネージャを使用している人は各自読み替えてください。

Plug 'prabirshrestha/async.vim'
Plug 'prabirshrestha/vim-lsp'
Plug 'prabirshrestha/asyncomplete.vim'
Plug 'prabirshrestha/asyncomplete-lsp.vim'

vim-lspに加えてasync.vimのインストールが必要です。また、自動補完を有効にするためにasyncomplete.vimとasyncomplete-lsp.vimをインストールしています。

vim-lspの設定

設定ファイルに以下を記述します。

let g:lsp_diagnostics_enabled = 0
" debug
let g:lsp_log_verbose = 1
let g:lsp_log_file = expand('~/vim-lsp.log')
let g:asyncomplete_log_file = expand('~/asyncomplete.log')

let g:lsp_diagnostics_enabled = 0はLSPのLint機能を無効にするオプションです。w0rp/aleなど別のLinterプラグインを使用している場合は競合しないよう無効にします。有効にしたい場合は1を設定します。

# debug以下はログ出力用の設定です。LSPの機能が思ったように動作しない場合にログを見て原因を確認します。動作に問題がない場合は設定をコメントアウトして無効にして問題ありません。

vim-lspでは以下のコマンドが提供されます。必要に応じてキーのマッピングを設定します。各コマンドの詳細は:help vim-lspで確認してください。

  • :LspCodeAction
  • :LspDocumentDiagnostics
  • :LspDeclaration
  • :LspDefinition
  • :LspDocumentFormat
  • :LspDocumentFormatSync
  • :LspDocumentRangeFormat
  • :LspDocumentSymbol
  • :LspHover
  • :LspNextError
  • :LspPreviousError
  • :LspImplementation
  • :LspReferences
  • :LspRename
  • :LspTypeDefinition
  • :LspWorkspaceSymbol

プログラミング言語ごとの設定

利用するプログラミング言語ごとに設定を行います。

Ruby

Solargraphをインストールします。Rubyのgemとして提供されます。

$ gem install solargraph

設定ファイルに以下を記述します。

if executable('solargraph')
    " gem install solargraph
    au User lsp_setup call lsp#register_server({
        \ 'name': 'solargraph',
        \ 'cmd': {server_info->[&shell, &shellcmdflag, 'solargraph stdio']},
        \ 'initialization_options': {"diagnostics": "true"},
        \ 'whitelist': ['ruby'],
        \ })
endif

Go

goplsをインストールします。golang公式のツールとして提供されています。

$ go get golang.org/x/tools/cmd/gopls

設定ファイルに以下を記述します。

if executable('gopls')
    au User lsp_setup call lsp#register_server({
        \ 'name': 'gopls',
        \ 'cmd': {server_info->['gopls', '-mode', 'stdio']},
        \ 'whitelist': ['go'],
        \ })
endif

goplsを動かすためには編集対象のファイルがGOPATH以下にあるなど、開発の作法がgolangの基本にしたがっている必要があるようです。GOPATH外でファイルを編集した場合はgoplsが例外で落ちてしまい機能しません。

Python

python-language-serverをインストールします。pipモジュールとして提供されます。

$ pip install python-language-server

設定ファイルに以下を記述します。

if executable('pyls')
    au User lsp_setup call lsp#register_server({
        \ 'name': 'pyls',
        \ 'cmd': {server_info->['pyls']},
        \ 'whitelist': ['python'],
        \ })
endif

JavaScript

typescript-language-serverをインストールします。npmパッケージとして提供されます。名前が示しているようにTypeScriptの言語サーバですが、JavaScriptにも対応しています。

$ npm install -g typescript typescript-language-server

.gitディレクトリ、package.jsonのいずれかが存在するディレクトリをプロジェクトのルートディレクトリとして指定します。

.gitをルートにする場合は設定ファイルに以下を記述します。

if executable('typescript-language-server')
    au User lsp_setup call lsp#register_server({
      \ 'name': 'javascript support using typescript-language-server',
      \ 'cmd': { server_info->[&shell, &shellcmdflag, 'typescript-language-server --stdio']},
      \ 'root_uri': { server_info->lsp#utils#path_to_uri(lsp#utils#find_nearest_parent_directory(lsp#utils#get_buffer_path(), '.git/..'))},
      \ 'whitelist': ['javascript', 'javascript.jsx']
      \ })
endif

package.jsonをルートにする場合は設定ファイルに以下を記述します。

if executable('typescript-language-server')
  au User lsp_setup call lsp#register_server({
    \ 'name': 'javascript support using typescript-language-server',
    \ 'cmd': {server_info->[&shell, &shellcmdflag, 'typescript-language-server --stdio']},
    \ 'root_uri':{server_info->lsp#utils#path_to_uri(lsp#utils#find_nearest_parent_file_directory(lsp#utils#get_buffer_path(), 'package.json'))},
    \ 'whitelist': ['javascript', 'javascript.jsx'],
    \ })
endif

その他の言語

vim-lspのwikiにその他いくつかの言語の設定方法が記載されています。

終わりに

Language Server Protocolは筋の良い取り組みだと感じているので、より一層普及して利用環境が整っていくことを望んでいます。将来的にはneovim本体でLSPをサポートしようという動きもあるようです。

参考URL

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away