vim-lspとddc.vimのおすすめ?設定
発端
たまには一般の役に立つ内容を書こうと思ったので..(しかしAI coding全盛の今,この記事は役に立つのか?)
vim-lsp
LSPとは
LSPはlanguage server protcolの略で,2016年にMicrosoftが発表した,プログラミング言語とエディタを繋ぐプロトコルです。従来はエディタ毎に各言語のサポート機能を実装していたところを,エディタと言語を繋ぐ統一規格を作ることで,サポート機能とエディタを分離しつつ画一化するものです。
LSPは発表からすでに時間が経っており調べると様々な情報が出てくるため,ここでは詳細は省略します[1]。
Vim-LSPとは
VimでLSPを簡単に使う選択肢として,vim-lsp があります。こちらは(自分の認識が正しければ)Microsoftの社員でもあるPrabir Shresthaさんが開発したプラグインになります。
vim-lspを使用してlanguage server (LS) を呼び出すにはLS毎に設定が必要ですが,この設定を自動で行うvim-lsp-settingsというものがあります。面白いことに,こちらはmattnさんの開発したプラグインになります。これらをふたつともインストールし,
" vim-plug の場合
Plug 'prabirshrestha/vim-lsp'
Plug 'mattn/vim-lsp-settings'
vim-lsp-settingsでサポートされた言語のファイルを開き,以下のコマンドを叩くことでVim上でLSPを使用することが出来ます。
:LspInstallServer
おすすめ?設定
以下では自分の設定を示していきます。なお,最新版はここにあります。(ただし,基本の設定を書いたのは数年前なので,今のvim-lspでは状況は変わっているかも...)
まず,表示設定です。デフォルトだとdiagnosticsの表示がやかましいので,それをoffにしつつsign行にwarning/errorを表示しています。
let g:lsp_diagnostics_enabled = 1
let g:lsp_diagnostics_highlights_enabled = 0
let g:lsp_diagnostics_signs_enabled = 1
let g:lsp_diagnostics_signs_insert_mode_enabled = 1
let g:lsp_diagnostics_virtual_text_enabled = 0
warningなどのfloatingでの表示も微妙だったのでoffにして,その代わりにechoで表示するようにしています。
let g:lsp_diagnostics_echo_cursor = 1
let g:lsp_diagnostics_float_cursor = 0 " disgnosticsのfloatは挙動が難しい..
let g:lsp_diagnostics_float_delay = 1500
見映えについては,nerdfontを使ってちょっと良い感じにしています
let g:lsp_diagnostics_signs_warning = {'text': nr2char(0xf071)}
let g:lsp_diagnostics_signs_error = {'text': nr2char(0xf068c)}
let g:lsp_diagnostics_signs_hint = {'text': nr2char(0xf12a)}
その他,<c-]>や<c-p>をそれっぽくマッピングしていますが,設定はかなり煩雑なので省略します。基本的にはファイルのチェックを行うLspDocumentDiagnosticsや関数/変数の定義へジャンプするLspDefinition,ヘルプを表示してくれるLspHoverあたりにマップ(ショートカット)を設定して使っています。
ddc.vim
ddc.vimとは
ddc.vimとは,皆さんご存知の暗黒美夢王 (Shougo) さんが作成した"Dark deno-powered completion framework"(入力補完プラグイン)です。
ddc.vimの特徴として,あらゆる機能が別のプラグインとして分離されていることがあります。そのためddc.vimのみを入れただけでは動きませんが,一方で第三者が機能を追加しやすかったり,自分の好きな機能のみに絞って動かすことができます。
設定方法については,ベータ版の記事なので詳細は異なりますが,御本人の記事が参考になると思います。
おすすめ?設定
再度,自分の設定を晒していきます。最新の設定はこちらです。
まず,使用するプラグインをインストールします。
" source
Plug 'Shougo/ddc-around'
Plug 'LumaKernel/ddc-file'
Plug 'LumaKernel/ddc-tabnine'
Plug 'shun/ddc-vim-lsp'
Plug 'Shougo/neco-vim'
" matcher
Plug 'Shougo/ddc-matcher_head'
" sorter
Plug 'Shougo/ddc-sorter_rank'
" converter
Plug 'Shougo/ddc-converter_remove_overlap'
" UI
Plug 'Shougo/ddc-ui-native'
Plug 'Shougo/ddc.vim'
普段遣いとしてvim-lsp(上のvim-lspを用いた補完候補の取得),around(入力済みの単語から補完候補を取得),file(ファイルパスから補完候補を取得)を使いつつ,vim scriptではneco-vim, pythonやC言語ではtabnineを有効にしています。
" set UI
call ddc#custom#patch_global('ui', 'native')
" add sources
call ddc#custom#patch_global('sources', ['vim-lsp', 'around', 'file'])
" set basic options
call ddc#custom#patch_global(
\ 'sourceOptions', {
\ '_': {
\ 'matchers': ['matcher_head'],
\ 'sorters': ['sorter_rank'],
\ 'converters': ['converter_remove_overlap'],
\ },
\ })
" set sorce-specific options
call ddc#custom#patch_global(
\ 'sourceOptions', {
\ 'around': {
\ 'mark': 'A',
\ },
\ 'file': {
\ 'mark': 'F',
\ 'isVolatile': v:true,
\ 'forceCompletionPattern': '\S/\S*',
\ },
\ 'tabnine': {
\ 'mark': 'TN',
\ 'maxItems': 5,
\ 'isVolatile': v:true,
\ },
\ 'vim-lsp': {
\ 'mark': 'lsp',
\ },
\ })
call ddc#custom#patch_global(
\ 'sourceParams', {
\ 'tabnine': {
\ 'maxNumResults': 10,
\ },
\ }
\ )
" set filetype-specific options
call ddc#custom#patch_filetype(['ps1', 'dosbatch', 'autohotkey', 'registry'], {
\ 'sourceOptions': {
\ 'file': {
\ 'forceCompletionPattern': '\S\\\S*',
\ },
\ },
\ 'sourceParams': {
\ 'file': {
\ 'mode': 'win32',
\ },
\ }
\ })
call ddc#custom#patch_filetype(['vim'], {
\ 'sources': ['necovim', 'around', 'file'],
\ 'sourceOptions': {
\ 'necovim': {
\ 'mark': 'vim',
\ 'maxItems': 5,
\},
\}
\ })
let ft_sources = []
call add(ft_sources, 'vim-lsp')
call add(ft_sources, 'around')
call add(ft_sources, 'tabnine')
call add(ft_sources, 'file')
call ddc#custom#patch_filetype(['python', 'c', 'cpp'], {
\ 'sources': ft_sources,
\ })
" Mappings
" <TAB>: completion.
inoremap <silent><expr> <TAB>
\ pumvisible() ? '<C-n>' :
\ (col('.') <= 1 <Bar><Bar> getline('.')[col('.') - 2] =~# '\s') ?
\ '<TAB>' : ddc#map#manual_complete()
" <S-TAB>: completion back.
inoremap <expr><S-TAB> pumvisible() ? '<C-p>' : '<C-h>'
" automatically close preview window.
autocmd PlugLocal CompleteDone * silent! pclose!
" on.
call ddc#enable()
おまけ
ちなみに,自分は現在copilot.vimも併用しています。そのまま使うとタブキーが衝突するため,
imap <silent><script><expr> <C-T> copilot#Accept("\<CR>")
let g:copilot_no_tab_map = v:true
としてctrl-tでcopilotの補完が動くようにしています。
終わりに
ざっくりとvim-lspとddc.vimの設定について説明しました。これらのプラグインが使えるようになると,VScodeなど最近のエディタやIDEにも劣らない開発環境を作れるのではないでしょうか。また,どちらもかなり奥深いプラグインなので,この記事をとっかかりとしてその深淵に踏み込んでもらえると嬉しいです。
Discussion