Input中心のブログ

poetryを使った時のVimの開発環境を整える

April 30, 2021

仕事でPythonを書くようになったので、Vimでの開発環境を整えます。 整えると言いつつも基本的にはLSPの設定になります。 目指すことは以下が上手くできるようになることです。

  • 補完
  • lint
  • format

補完

補完にはpyrightというツールを使っていきます。 pyrightはPythonの静的型チェックを行ってくれるツールで、Language Serverの機能も備わっているようです。

インストール

これはvim-lsp-settingsやcoc.vimなどの自動でインストールしてくれる系のツールでは必要ありません。

yarn global add pyright

設定

各々のLSPクライアントの設定してください。 基本的にはこれで動くのですが、poetryを使っていると少し工夫が必要です。 poetryでvirtualenvを使っていると、pyrightでライブラリ等の補完を使うためにvirtualenvの場所を知らせる必要があります。

poetryのvirtualenvの場所は以下方法で調べることが出来ます。

# 様々なvirtualenvの場所があるディレクトリを示す
poetry config virtualenvs.path

# 現在のディレクトリのvirtualenvの名前を示す
poetry env list

これらの変数を使ってpyrightで設定をしてください。 Neovim buildin LSPを使った場合の例を示しておきます。

local virtual_env_path = vim.trim(vim.fn.system('poetry config virtualenvs.path'))
local virtual_env_dirctory = vim.trim(vim.fn.system('poetry env list'))

local python_path = 'python'
-- 現在のディレクトリに対応するvirtualenvがあるかのチェック
if #vim.split(virtual_env_dirctory, '\n') == 1 then
  python_path = string.format("%s/%s/bin/python", virtual_env_path, virtual_env_dirctory)
end
nvim_lsp.pyright.setup{
  settings = {
    python = {
      pythonPath = python_path;
    }
  }
}

これでvirtualenvにインストールされているライブラリを考慮した補完が出来ます。

format & lint

pyrightのLSP機能は残念ながらformatterに対応していません。 Pythonでは独自のformatterやlinterがCLIで提供されているので、これらを使うようにします。 これらを使うにはefm-langserverを使っていきます。

ちなみにcoc.vimはこの辺をうまくやるようにcoc-pyrightにlintとformatを入れているのでcoc.vimの場合はefm-langserverを使う必要はなさそうです

efm-langserverは普通のlinterやformatterをLSPに対応させてくれる便利なツールです。 基本的な使い方は対応リポジトリのREADMEを読んでください。

今回はflake8とyapfを使った例を示します。

version: 2
tools:
  python-flake8: &python-flake8
    lint-command: 'flake8 --stdin-display-name ${INPUT} -'
    lint-stdin: true
    lint-formats:
      - '%f:%l:%c: %m'

  python-yapf: &python-yapf
    format-command: 'yapf --quiet'
    format-stdin: true

languages:
  python:
    - <<: *python-flake8
    - <<: *python-yapf
nvim_lsp.efm.setup{
  filetypes = { 'python' },
  default_config = {
    cmd = { 'efm-langserver', '-c', '/path/to/efm-langserver.yaml' };
  }
}

これでいい感じにlinterとformatterも使えるようになります。

おまけ

neovim builtin LSPで保存時にformatterを実行する場合は以下のように書きます。

augroup lsp_formatting
  au!
  autocmd BufWritePre *.py lua vim.lsp.buf.formatting_sync()
augroup END

しかし、efm-langserverはCLIを通してformatterを使うのでかなり遅いです。 neovim builtin LSPはformatting_syncを100msしか待ってくれないため、保存時のformatterが実行できません。 これをうまくやる場合は以下のように時間を調整することで保存時にformatをしてくれます。

augroup lsp_formatting
  au!
  autocmd BufWritePre *.py lua vim.lsp.buf.formatting_sync({}, 300)
augroup END