neovimとLSPでRust開発環境をつくったら最高だった話

2019年1月27日 engineering

背景

Rust の開発環境をつくろうとしてたら、いつのまにか vim から nvim に移行して、LSP で補完ができるようにしていました。 完全に「ヤクの毛刈り」ですが、ある程度動くようになって結構かきやすくなったので設定周りを紹介します。

成果物

先に成果物を。

コード補完

フォーマット

手順

インストール系

Rust はインストールされているものとして話を進めます。

neovim のインストール

$ brew install neovim

pip で neovim をインストール

$ pip install neovim
$ pip3 install neovim

rust の LSP サーバーや補完用のものをインストール

$ rustup update
$ rustup component add rls-preview --toolchain nightly
$ rustup component add rust-analysis --toolchain nightly
$ rustup component add rust-src --toolchain nightly

設定ファイル

設定ファイルは以下のディレクトリ配下にいれています。

$HOME/.config/nvim/
├── colors
│   └── iceberg.vim
├── dein.toml
├── dein_lazy.toml
├── init.vim
├── plugins
│   ├── LanguageClient-neovim.rc.vim
│   ├── NERDTree.rc.vim
│   ├── deoplete.rc.vim
│   ├── fzf.rc.vim
│   ├── neosnippet.rc.vim
│   ├── rust.rc.vim
│   └── vim-fugitive.rc.vim
└── syntax
    └── html.vim

init.vim に nvim 初期化用のスクリプトをいれています。 今回に関係するところでいうとまず、nit.vim のプラグイン周りは以下のようになっています。 パッケージマネージャは dein を用いています。

プラグイン周りの設定は以下のような感じ

init.vim

" ===========
" Plugins
" ===========

augroup PluginInstall
    autocmd!
    autocmd VimEnter * if dein#check_install() | call dein#install() | endif
augroup END
command! -nargs=0 PluginUpdate call dein#update()

let s:dein_dir = expand('$DATA/dein')

if &runtimepath !~# '/dein.vim'
    let s:dein_repo_dir = s:dein_dir . '/repos/github.com/Shougo.dein.vim'

    if !isdirectory(s:dein_repo_dir)
        execute printf('!git clone %s %s', 'https://github.com/Shougo/dein.vim', s:dein_repo_dir)
    endif

    execute 'set runtimepath^=' . s:dein_repo_dir
endif

let g:dein#install_pax_processed = 48

let s:toml_file = '~/.config/nvim/dein.toml'
let s:toml_lazy_file = '~/.config/nvim/dein_lazy.toml'
if dein#load_state(s:dein_dir)
    call dein#begin(s:dein_dir)

    call dein#load_toml(s:toml_file, {'lazy': 0})
    call dein#load_toml(s:toml_lazy_file, {'lazy': 1})

    call dein#end()
    call dein#save_state()
endif

filetype plugin indent on

dein.toml は以下のような感じ、LSP に関係しそうなところのみ抜き出してますが最低限このくらいで大丈夫なはずです。

dein.toml


[[plugins]]
repo = 'Shougo/context_filetype.vim'

[[plugins]]
repo = 'Shougo/neosnippet.vim'
on_event = 'InsertCharPre'
on_ft = 'snippet'
depends = 'context_filetype.vim'
hook_add = '''
source ~/.config/nvim/plugins/neosnippet.rc.vim
'''

[[plugins]]
repo = 'Shougo/neosnippet-snippets'

[[plugins]]
repo = 'Shougo/deoplete.nvim'
depends = 'context_filetype.vim'
on_event = "InsertEnter"
hook_add = '''
source ~/.config/nvim/plugins/deoplete.rc.vim
'''

[[plugins]]
repo = 'autozimu/LanguageClient-neovim'
rev = 'next'
build = 'bash install.sh'
hook_add = '''
source ~/.config/nvim/plugins/LanguageClient-neovim.rc.vim
'''

[[plugins]]
repo = 'rust-lang/rust.vim'
on_ft = 'rust'
hook_add = '''
source ~/.config/nvim/plugins/rust.rc.vim
'''

rust.rc.vim

let g:rustfmt_autosave = 1

deoplete.rc.vim

" options
let g:deoplete#enable_at_startup = 1
let g:deoplete#auto_complete_delay = 0
let g:deoplete#auto_complete_start_length = 1
let g:deoplete#enable_camel_case = 0
let g:deoplete#enable_ignore_case = 0
let g:deoplete#enable_refresh_always = 0
let g:deoplete#enable_smart_case = 1
let g:deoplete#file#enable_buffer_path = 1
let g:deoplete#max_list = 10000

neosnippet.rc.vim

let g:neosnippet#snippets_directory = '~/.config/nvim/snippets'
let g:neosnippet#enable_snipmate_compatibility = 1

imap <C-k> <Plug>(neosnippet_expand_or_jump)
smap <C-k> <Plug>(neosnippet_expand_or_jump)
xmap <C-k> <Plug>(neosnippet_expand_target)
if has('conceal')
    set conceallevel=2 concealcursor=niv
endif

LanguageClient-neovim.rc.vim

以下のように設定しています。

  • Space + lh でドキュメント
  • Space + ld で定義ジャンプ
  • Space + lr でリネーム
  • Space + lf でフォーマット
set hidden

" settings for languages
let g:LanguageClient_serverCommands = {
            \ 'cpp': ['clangd'],
            \ 'rust': ['rustup', 'run', 'nightly', 'rls'],
            \ }

augroup LanguageClient_config
    autocmd!
    autocmd User LanguageClientStarted setlocal signcolumn=yes
    autocmd User LanguageClientStopped setlocal signcolumn=auto
augroup END

let g:LanguageClient_autoStart = 1
nnoremap <silent> <Space>lh :call LanguageClient_textDocument_hover()<CR>
nnoremap <silent> <Space>ld :call LanguageClient_textDocument_definition()<CR>
nnoremap <silent> <Space>lr :call LanguageClient_textDocument_rename()<CR>
nnoremap <silent> <Space>lf :call LanguageClient_textDocument_formatting()<CR>

まとめ

とりあえず、neovim で Rust の補完・定義ジャンプ・ドキュメント参照・リネーム・フォーマットができるようになりました。これで開発がはかどるはずです。

今回は設定ファイルなどをただ列挙しているだけなので、もしわからないこと等あればお気軽に聞いていただければと思います。 @kz_morita

参考サイト

http://wheson-prog.hatenablog.jp/entry/2018/06/05/141730 https://muunyblue.github.io/48dd34fa4a5fc8e0045aba1952e1818e.html

この記事をシェア