🏡
Vimの起動時にpwdをgitルートへ移動する
ファイルツリーやfuzzy-finder系のプラグインを使っていて、常にプロジェクトルートからファイルを探したかったので作りました。
以下を設定ファイルに記載してください。
.vimrc or init.vim
" {{{ ensure_git_root
function! s:ensure_git_root() abort
let cmd = 'git rev-parse --show-superproject-working-tree --show-toplevel 2>/dev/null | head -1'
let root = system(cmd)->trim()->expand()
if isdirectory(root) && root != getcwd()
execute 'cd' root
endif
endfunction
autocmd VimEnter * ++once call s:ensure_git_root()
" }}}
以下のようなディレクトリ構成のプロジェクトで、dir
内でVimを開いたときに、pwdがmy_project
に移動するようになります。
my_project/
├─ .git/
├─ dir1/
│ ├─ file-inner1
│ └─ file-inner2
├─ file-outer1
└─ file-outer2
参考
追記 非同期実行バージョン
function! s:ensure_git_root() abort
function! s:cd_to_root() abort
let root = get(s:, 'git_root', '')
if isdirectory(root) && root != getcwd()
execute 'cd' root
endif
endfunction
if exists('s:git_root')
call s:cd_to_root()
return
endif
function! s:on_stdout(_, msg, ...) abort
if exists('s:git_root')
" set once
return
endif
" a:msg is list in neovim, string in vim
let s:git_root = type(a:msg) == v:t_list ? a:msg[0] : a:msg
call s:cd_to_root()
endfunction
let cmd = 'git rev-parse --show-superproject-working-tree --show-toplevel'
if exists('*jobstart')
" neovim-async
call jobstart(split(cmd), { 'on_stdout': function('s:on_stdout') })
elseif exists('*job_start')
" vim-async
call job_start(split(cmd), { 'out_cb': function('s:on_stdout') })
else
" sequential run
let s:git_root = trim(systemlist(cmd)[0])
call s:cd_to_root()
endif
endfunction
vimとneovimでコールバック関数の仕様が異なるので、可変長引数をいれたりタイプチェックを噛ませたりして差分を吸収しています。
Discussion