IDEをやめてvim-lspに移行したのでCLI環境を整える

先日メインで使っているマシンを修理にださなければいけなくなり、1週間ほど古いスペックの低いマシンを使うことになりました。
その環境では複数個のIDEを起動しておくのが難しく困っていたところLanguage Server Protocolの存在を思い出し使ってみることにしました。

私はIDE以外で使っているエディタはvimのため、vim-lspを入れました。

LSP

LSPの説明や導入方法は他の記事に譲りますが、IDEが持っている言語に関する機能である

  • 関数や変数の補完、リネーム
  • 定義元や宣言元へのジャンプ
  • エラーやワーニングの表示
  • フォーマット
  • ドキュメントの表示

などがあり、基本的な開発なら問題なく行えます。

実際に開発していると物足りなくなってくる

いざ開発をしてみるとIDEでの開発と比較して不便なところがあります。

  • プロジェクト内を対象としたファイル名とファイル内のテキストに対する検索が簡単にできない
  • おおよその場所しかわからない目当てのファイルを見つけるのが遅い
  • プロジェクト内の特定のファイルを対象にした任意のコマンドの実行が面倒

これらを解決するためにCLI環境を整えたので紹介します。

なお、これから紹介する設定はGitHubで公開しているため、適宜参照してください。

github.com

プロジェクト内の検索

これはIDEで最もよく使うコマンドと言っても過言でないぐらい頻繁に使うものなので、IDEと同じレベルのスムーズさが欲しいところです。

簡単なコマンドで検索を開始してプレビューを見ながら選択し、選んだファイルをエディタで開きたいです。

そこで高速な検索を行えるripgrepとCLIでインクリメンタルに曖昧検索ができるfzfを導入することにしました。CLIで曖昧検索をするツールは他にも存在しますが、fzfはvimから使うことができるのとプレビュー機能があることからfzfにしました。

以下のような設定をするとIDEのような検索が行えます。

Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all' }
Plug 'junegunn/fzf.vim'

command! -bang -nargs=* Rg
  \ call fzf#vim#grep(
  \   'rg --column --line-number --no-heading --color=always --smart-case '.shellescape(<q-args>), 1,
  \   <bang>0 ? fzf#vim#with_preview('up:60%')
  \           : fzf#vim#with_preview('right:50%:hidden', '?'),
  \   <bang>0)

command! -bang -nargs=? -complete=dir Files
  \ call fzf#vim#files(<q-args>, fzf#vim#with_preview(), <bang>0)

nnoremap <Leader>f :Files<CR>
nnoremap <Leader>s :Rg<CR>
nnoremap <Leader>b :Buffer<CR>

f:id:akaimo3:20191219113722p:plain

これでIDEのような検索が行えるようになりました。基本的にはIDEと同等の速度でスムーズに使えますが、プロジェクトが巨大になると検索に時間がかかるようになりCPUの負荷が高まります。これはインデックスされたものから検索しているIDEには敵いません。

vim以外からも使えるようにする

この検索はただのコマンドの組み合わせなのでvimを経由しなくても使うことができます。
以下のようにzshrcに書くと、検索ワードに引っかかったファイルをプレビューで見ながらインクリメンタルに絞り込みできます。

fif() {
  if [ ! "$#" -gt 0 ]; then echo "Need a string to search for!"; return 1; fi
  file=$(rg --files-with-matches --no-messages "$1" | fzf --preview "highlight -O ansi -l {} 2> /dev/null | rg --colors 'match:bg:yellow' --ignore-case --pretty --context 10 '$1' || rg --ignore-case --pretty --context 10 '$1' {}")
  if [ -n "$file" ]; then
    less ${file}
  fi
}

f:id:akaimo3:20191219120409p:plain

このスクリプトだとlessで開いていますが、vimで開くようにするなどカスタマイズ次第では無数のつなげ方ができると思います。

おおよその場所しかわからないファイルを見つける

すべてを把握できていないプロジェクトでは、「名前はわからないけどあそこらへんにあったファイルを見たい」ということが稀にあります。

このようなときのためにツリー表示をすることができるプラグインを入れています。基本的にはfzf経由でファイルを開くためツリーはオフにしておき、困ったときだけトグルでオンにしています。

github.com

特定のファイルを対象にしたコマンドの実行が面倒

IDEでは開いているファイルやツリー上のファイルをクリックして何かしら便利なコマンドが実行できたりします。
当然vimにはそのような機能はなく、新たにプラグインを入れるか別のターミナルから同等のコマンドを実行する必要があります。

機能ごとにプラグインを入れるのも複雑になるため、ターミナルで同等のコマンドを実行することが多くなります。
この場合、目的のファイルが存在するディレクトリが深い場合はそこそこ時間がかかります。

そこでよく使うコマンドはfzfを使って曖昧検索で対象を見つけて実行できるようにします。

今回は個人的によく使うgitの変更ログをみるコマンドを作成しました。

git_history() {
  file=$(rg --files --hidden . | fzf --preview 'cat {}')
  if [ -n "$file" ]; then
    git log -p ${file}
  fi
}

このコマンドを実行するとカレントディレクトリ以下に存在するファイルがfzfにプレビュー付きで表示され、選択するとgitの変更履歴が表示されます。

f:id:akaimo3:20191219142832p:plain f:id:akaimo3:20191219142902p:plain

おわりに

LSPが登場したことでIDE以外でもIDEの主要機能を使って開発することができるようになりました。IDEには主要機能以外にも様々な便利機能が存在しますが、それらはLSPの責務外なため存在しません。しかしコマンドを組み合わせることで同等の機能を作ることはできます。この記事が快適なCLI環境の構築の手助けになれば幸いです。