Vim で Python の開発環境を構築する (with language server)

普段は、ほぼバニラ vim を使うことが多いのですが、vim plugin を使って python 開発環境を構築することを目指します。

## Language Server を導入

[vim-lsp-settings](https://github.com/mattn/vim-lsp-settings
) は簡単に language server を導入できるプラグインです。

(注意: vim-lsp は Vim version 8 が必要です。 ([ref](https://github.com/prabirshrestha/vim-lsp)))

[vim-plug](https://github.com/junegunn/vim-plug) を使った install では .vimrc に下記を追記して

```
Plug 'prabirshrestha/vim-lsp'
Plug 'mattn/vim-lsp-settings'
```

`:PlugInstall` します。

今回は python の language server が欲しいです。

現在、 [vim-lsp-settings](https://github.com/mattn/vim-lsp-settings
) がサポートしている python の language server は下記の 4 種類あります ([ref](https://github.com/mattn/vim-lsp-settings#supported-languages))。

- pyls-all: (pyls with dependencies)
-	pyls: (pyls without dependencies)
- pyls-ms (Microsoft Version)
- jedi-language-server

現在、一番 github star の多い pyls を使ってみることにします。

pyls は内部で、下記のツールを利用しています ([ref](https://github.com/palantir/python-language-server))。

- Rope for Completions and renaming
- Pyflakes linter to detect various errors
- McCabe linter for complexity checking
- pycodestyle linter for style checking
- pydocstyle linter for docstring style checking (disabled by - default)
- autopep8 for code formatting
- YAPF for code formatting (preferred over autopep8)

pyls-all では上記すべての依存ツールも同時にインストールされます。

vim で下記コマンドを打って、インストール。

`:LspInstallServer pyls-all`

MacOS/Linux だと下記の箇所に language server がインストールされます ([ref](https://github.com/mattn/vim-lsp-settings#macoslinux))。

`$HOME/.local/share/vim-lsp-settings/servers`

早速 install した pyls-all の中身を確認してみましょう。

```shell
$ ls $HOME/.local/share/vim-lsp-settings/servers/pyls-all/venv/bin/
activate      activate.fish  easy_install      epylint  isort  pip3    pycodestyle  pyflakes  pyls       python   symilar
activate.csh  autopep8       easy_install-3.7  flake8   pip    pip3.7  pydocstyle   pylint    pyreverse  python3  yapf
```

色々インストールされています。

### lint の実行

`:LspDocumentDiagnostics` で実行できます。

下記は、たくさん空行を作って怒られている例です。

![2020-12-06-23-47-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99215/8074555e-7b94-11a2-8562-e73c37f1c181.png)

### status line に linter のメッセージを表示する

.vimrc に下記を設定しておくと、警告がステータスラインに表示されるようになります。

```vim
let g:lsp_diagnostics_echo_cursor = 1
```

![2020-12-07-01-05-10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99215/b83406e5-614c-d23c-12e8-1561bf761ce7.png)

### linter の設定

デフォルトの configuration source は、pycodestyle が使われます。

下記のように設定することで、flake8 の設定値を使うように設定できます。

```vim
let g:lsp_settings = {
\   'pyls-all': {
\     'workspace_config': {
\       'pyls': {
\         'configurationSources': ['flake8']
\       }
\     }
\   },
\}
```

こうすることで、flake8 の設定値を使って pycodestyle と pyflakes を動かすようになるようです (直接 flake8 は使われない) ([ref](https://github.com/palantir/python-language-server/issues/190#issuecomment-344201542))。

### フォーマットを行う

下記のコマンドで、開いているファイルを format (整形) できます。

`:LspDocumentFormat`

![2020-12-07-01-08-39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99215/773bd6d5-008c-49ec-3970-e6d96a7ac645.png)

format 実行後、たくさんあった blank lines が削除されています。

### ファイル保存時に自動で format を行う

以下を .vimrc に記載しておけばよいです。

```
autocmd BufWritePre <buffer> LspDocumentFormatSync
```

format が走るので vim が遅くなるかもしれないとドキュメントに記載あり ([ref](https://github.com/prabirshrestha/vim-lsp/blob/a56304f238f5368ad6c1b3b14b96308edd25a1f9/doc/vim-lsp.txt#L1223))。

### その他 vim-lsp の機能

[vim-lsp コマンド一覧](https://github.com/prabirshrestha/vim-lsp#supported-commands) に記載されているように、定義ジャンプ、関数名の一括変更など他にも色々できます。

よく使うコマンドには、key mapping を設定すると便利です。

下記のプラグインを追加で導入することで、自動補完を使うことも可能です。

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

## vim-sonictemplate で定形コードを瞬時に書く

[vim-sonictemplate](https://github.com/mattn/vim-sonictemplate) を使うことで、main 関数とか、unittest とか、定形のコードのテンプレート/スニペットを瞬時に出すことができます。

.vimrc に下記のように追加して

```
Plug 'mattn/vim-sonictemplate'
```

`:PlugInstall` しましょう。

python の場合、5つのテンプレートが標準で用意されています ([ref](https://github.com/mattn/vim-sonictemplate/tree/master/template/python))。

新規ファイルを vim で開いて `:Template <tab>` を打つと下記のように、class、main、test の候補が表示されます。

![2020-12-07-01-29-50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99215/bcf17546-697f-b9ad-96ab-77dd807cabb9.png)

ここでは test を選んで enter します。

名前を入力して enter すると、下記のように unittest のテンプレートが出現します。

![2020-12-07-01-31-51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99215/c926ab78-0b97-a1b2-30b4-708acba965a1.png)

もっと詳細な使い方を知りたい方は下記を御覧ください。

https://github.com/mattn/vim-sonictemplate/blob/master/doc/sonictemplate.txt

### その他 snippet ツール

いくつか snippet ツールを調べて試した上で vim-sonictemplate を採用したので、せっかくなので他の snippet ツールに関しても記載しておきます。

筆者は vim-sonictemplate が一番シンプルで使いやすいと感じました。

#### ultisnips

スニペット関連の vim plugin で、おそらく一番使われているのが、[ultisnips](https://github.com/SirVer/ultisnips) です。

高機能みたいですが、python 依存があり、vim 本体が python 3 support enabled でないと使えません。

(今回は ultisnips は試していないので使用感はわからないです。)

#### xptemplate

[xptemplate](https://github.com/drmingdrmer/xptemplate) を試してみました。

`<C-\>` の key-binding で自動補完の感覚で snippet を出してくれます。

全然関係ないですが、おそらく iterm の key 設定が原因で `<C-\>` を打つと vertical line `|` が出てくる現象に悩まされ、該当の設定箇所が全然見つからずハマっています (mac 標準の terminal により一時回避)。

## まとめ

Vim で Python 書きましょう！