dotfilesを刷新した(2020-09)
久々に開発環境の dotfiles を刷新したのでやったことのメモ。
きっかけ
メルカリさんの開発ライブ実況に触発された。
【解説】開発ライブ実況 #1 (Vim / Go) 編 by メルペイ Architect チーム Backend エンジニア #mercari_codecast | メルカリエンジニアリング
こういうコンテンツとっても好き。
主に改善したかったところ
- 凝集度が低い
- 例えば Homebrew で入れるツールが
brew.sh
みたいなファイルにまとまっていて、付随する環境変数などの設定は別ファイルにあって…といった感じで凝集度が低いのが気に入らなかった- 現にもう入れていないツールの設定などが残っていたりで良くない状態だった
- 例えば Homebrew で入れるツールが
- 使えていないツールや key bind が多かった
- ノイズになり便利で使うべきだったはずのものが埋もれてしまうので良くない
今回はすべての設定を把握している状態を目指し、定期的に掃除&覚え直しがしやすい設計を目指しました。
方針
- shell は
zsh
fish
も使ってみたいけど文法が違うのを許容するほどのモチベーションは湧いていない
- zsh の設定ベースは prezto
- sorin-ionescu/prezto: The configuration framework for Zsh
- これは引き続き。設定もしやすいし速度も特に困っていないので続投。
- alias や暗黙的な挙動は使いすぎない
- prezto の module も最低限。例えば prezto の git モジュールみたいに大量の alias が設定されてしまうのは許容するけど、実用する alias は基本的に自分で明示的に設定する。
- Vim は Neovim
- Shougoさんの
de*
系ツールは積極利用- たまに互換性を失ったりバグが生じたりすることもあるけど速いし便利なので愛用している
- Shougoさんの
- grep 系ツールを ggreer/the_silver_searcher から BurntSushi/ripgrep に乗り換え。
- 速いらしいので試しに。
やったこと
とりあえず現時点(2020-09-22)でのリポジトリがこちら。
やってよかったことで参考になりそうなところをメモがてら紹介してみます。
凝集度を高めるためにインストール用スクリプトと設定ファイルをツールごとにまとめた
zsh/modules/
以下に欲求ごとにディレクトリを切り、 install.sh
と export.zsh
をそれぞれ置くことで凝集度を高めています。
インストール処理は init.sh
で以下のようにすることで全ツールについて発火。
for f in "$(dirname "${BASH_SOURCE:-$0}")/zsh/modules/"*"/install.sh"
do
echo "Execute installation script ${f}"
zsh -c "${f}"
echo "Finish installation script ${f}"
done
また、 export.zsh
についても zsh/modules/export.zsh
で以下のように設定。
for f in "$(dirname "${BASH_SOURCE:-$0}")/"*"/export.zsh"
do
source "$f"
done
これを prezto の zprofile
から以下のように読み込むことで一括して読み込んでいます。
source "$HOME/.zsh/modules/export.zsh"
凝集度を高めたおかげでどこで何が設定されているのかわからないものが全くなくなり、非常にやってよかったです。
また、環境変数の設定はツールのインストール時にも必要なもの(Go 系ツールをインストールするときの $GOPATH
とか)もありますが、各 install.sh
から各 export.zsh
を読み込むようにすることで安心して実行できるようになりました。
部分実行が気軽にできるようになったので Node.js などのバージョン更新時も対応が楽です。
export.zsh
が分割されていることによる読み込みのパフォーマンスは今のところは気になっていないですが、もし気になり始めたら各 export.zsh
は結合して 1 ファイルにする処理を更新時に叩くフローを検討するつもりです。
Powerlevel9k から Powerlevel10k に変えた
昔も移行しようとして設定移植が面倒でやめたような気がしていたのですが、確認したら設定を変更せずに適用できるようだったので prezto の設定を書き換え。
問題なく動いている上、目に見えて速くなったのでやってよかったです。
vim-go をやめた
vim-go は素晴らしいツールなのですが、LSP (Language Server Protocol) である gopls が充実してきたことで必要性が薄くなったため卒業しました。
vim-go には充実した機能で長らく非常にお世話になっていたのですが、多機能なだけに依存ツールの変更への対応が荒れることもあり LSP の wrapper としての役割も含めてすべてを網羅する巨大ツールとして今後進めていくのは厳しいのかなーと見ています。
今後は、基本的な機能は LSP を活用した上で、LSP にない機能のツールについては特化した小さなプラグインやスクリプトで対応していくのが良いかなーと思っています。
とりあえず今のところは goimports
, gofmt
の自動発火については mattn さんの vim-goimports を使い、テストは vim-test/vim-test を使っています。
その他のツールについては vim-test でも使われている tpope/vim-dispatch で発火しています。
今のところ大きな不満はないですが、vim-test の TestFile
では子パッケージまでテストを走らせてしまうためそこだけ調整しようかと思っています。
追記(2020-09-27): vim-dispatch を直接叩くようにして調整
TestNearest
は引き続き vim-test のものを使っていますが、今いるパッケージのテストは vim-dispatch を直接叩くように変更しました。
ついでに golangci-lint の設定も載せておきます。
let g:dispatch_compilers['go test'] = 'go'
nnoremap <buffer> <Leader>t :<C-u>Dispatch go test %:p:h<CR>
nnoremap <buffer> <Leader>gt :<C-u>Dispatch go test %:p:h/...<CR>
nnoremap <buffer> <Leader>pt :<C-u>Dispatch go test ./...<CR>
let g:dispatch_compilers['golangci-lint run'] = 'go'
nnoremap <buffer> <Leader>l :<C-u>Dispatch golangci-lint run %:p:h<CR>
nnoremap <buffer> <Leader>gl :<C-u>Dispatch golangci-lint run %:p:h/...<CR>
nnoremap <buffer> <Leader>pl :<C-u>Dispatch golangci-lint run ./...<CR>
Neovim の Session 機能を使い始めた
Neovim には Session 機能があり、今開いている画面の構成などの状態を保存して後ほど開き直すことができます。
他のプロジェクト(リポジトリ)をちょっと確認して戻ってきたい、みたいなことが多いので、以下のような要件を満たす設定を整備してみました。
- x-motemen/ghq で他の Git Repository を拾い、 Shougo/denite.nvim などの fuzzy finder 系ツールで検索&移動する
- 移動時に Session 機能を使い、移動元の状態を保存する
- 移動時に Session 機能を使い、移動先の状態を(存在したら)復元する
行って戻ってきたらさっきの状態、また行ったらさっきの状態、って感じで往復できます。便利。
#mercari_codecast に触発されてvimのsession機能を本格的に導入してるのだけどめっちゃ便利だな〜
— hori (@hori_ryota) August 28, 2020
denite.nvimのvim-denite-ghqと組み合わせて、deniteでghq管理のプロジェクトを引いて、custom actionでcdとsessionファイルのload_or_createする感じで設定してみた。
複数リポジトリの開発捗りそう
Denite と ghq での設定が以下。
let s:data_home = empty($XDG_DATA_HOME) ? expand('~/.local/share') : $XDG_DATA_HOME
let s:session_dir = get(g:, 'denite_session_dir', s:data_home . '/nvim/denite_session')
if !isdirectory(s:session_dir)
call mkdir(s:session_dir, 'p')
endif
function! s:session_file_name(target_dir)
return s:session_dir . '/' . trim(substitute(resolve(a:target_dir), '/', '-', 'g'), '-') . '.vim'
endfunction
function! s:save_session(target_dir)
execute 'mksession! ' . s:session_file_name(a:target_dir)
endfunction
function! s:load_or_create_session(target_dir)
let s:file_name = s:session_file_name(a:target_dir)
if filereadable(s:file_name)
execute 'source ' . s:file_name
return
endif
call s:save_session(a:target_dir)
endfunction
function! s:cdsession_action(context)
call s:save_session(getcwd())
let s:target = a:context['targets'][0]
let s:path = s:target['action__path']
execute 'cd ' . s:path
call s:load_or_create_session(s:path)
endfunction
call denite#custom#action('directory', 'cdsession', function('s:cdsession_action'))
current directory ごとに Session を保存し、Denite での移動時に移動元の保存と移動先の復元をしています。
また、廃棄したくなることもあるので以下のような掃除処理も仕込んでいます。
function! s:clean_session(target_dir)
let s:file_name = s:session_file_name(a:target_dir)
if filewritable(s:file_name)
call delete(s:file_name)
endif
endfunction
function! s:clean_session_action(context)
let s:target = a:context['targets'][0]
let s:path = s:target['action__path']
call s:clean_session(s:path)
endfunction
call denite#custom#action('directory', 'clean_session', function('s:clean_session_action'), {'is_quit': 0})
function! s:clean_sessions()
call system('rm ' . s:session_file_name('*'))
endfunction
function! s:clean_sessions_action(context)
call s:clean_sessions()
endfunction
call denite#custom#action('directory', 'clean_allsession', function('s:clean_sessions_action'), {'is_quit': 0})
vimscript 扱い慣れてはいない&自分用なのでしっかりしたデバッグはしていないですが、とりあえず期待通り動いています。
自分は作業の区切りですぐにまっさらな状態に掃除しちゃいたい派なので Neovim 起動時に Session 復元などはしておらず、起動ディレクトリごとに保存先を分けたり命名管理などもせずに気軽に上書きしています。
この辺は好みがあると思うので良きに調整してください。
以上
今回は凝集度アップとスリム化が主目的だったのであまり新しく入れたものは無いのですが、やってよかった感は強かったので良かったことをメモしてみました。
もし参考になれば嬉しいです。また、おすすめの設定などあればぜひ紹介してください。