:UniteWithProjectDir
を使うとプロジェクトディレクトリにターゲットを絞れるけれど、カレントディレクトリ(特に変更していない場合はVimを起動したディレクトリ)を起点としてプロジェクトディレクトリを探すので、これをカレントバッファで開いているファイルのディレクトリを起点とするようにしたい。
以下のことができるよう設定する。
- カレントバッファのファイルのディレクトリから、プロジェクトディレクトリを決定する
- VimFilerにいるときは、VimFilerの現在のディレクトリから、プロジェクトディレクトリを決定する
- 自分でプロジェクトディレクトリにマッチするパターンを設定できるようにする
- .gitignoreで設定されたファイルは無視する
まず、カレントバッファのディレクトリは
let buffer_dir = expand('%:p:h')
で、絶対パスで取得できる。一方、VimFilerの現在のパスはVimFilerのコードを見てみるとb:vimfiler.current_dir
というバッファのローカル変数に入っているようなので、これらを使って、現在のバッファのディレクトリを決定する。
if exists('b:vimfiler.current_dir')let buffer_dir =b:vimfiler.current_dir
elselet buffer_dir = expand('%:p:h')endif
次にプロジェクトディレクトリだが、.gitなどを検知してプロジェクトディレクトリをいい感じで返してくれる関数がvital.vimにあるので、vital.vimをインストールしてこれを使う。こんな感じ。
let project_dir = vital#of('vital').import('Prelude').path2project_directory(buffer_dir,1)
第2引数に0以外の数字を与えると、プロジェクトディレクトリが発見できなかった時は空文字を返す。与えないとフルパスを返す(:h Vital.Prelude.path2project_directory()
)。
プロジェクトディレクトリが発見できなかった場合はg:project_dir_pattern
で設定した正規表現にマッチしたディレクトリをプロジェクトディレクトリにする。例えば、
letg:project_dir_pattern ='^/home/tmsanrinsha/project/[^/]\+'
とした場合に、/home/tmsanrinsha/project/hoge
がプロジェクトディレクトリとして認識されるようにする。
最終的に、プロジェクトディレクトリが決定できたらプロジェクトディレクトリを、できなかったらバッファのディレクトリを返すような関数を作る。
function! GetProjectDir() abort " {{{if exists('b:vimfiler.current_dir')letl:buffer_dir =b:vimfiler.current_dir
elseletl:buffer_dir = expand('%:p:h')endifletl:project_dir = vital#of('vital').import('Prelude').path2project_directory(l:buffer_dir,1)if empty(l:project_dir)&& exists('g:project_dir_pattern')letl:project_dir = matchstr(l:buffer_dir,g:project_dir_pattern)endifif empty(l:project_dir)returnl:buffer_dir
elsereturnl:project_dir
endifendfunction" }}}
変数にはl:
をつけて、関数ローカルな変数であること明示した。
次にUnite.vimの設定。以下の設定をすると,fp
でプロジェクト内のファイル一覧でuniteバッファで表示されるようになる1。
nnoremap,fp :<C-u>call<SID>unite_file_project('-start-insert')<CR>function!s:unite_file_project(...)letl:opts =(a:0 ? join(a:000,' ') : '')letl:project_dir = GetProjectDir()
execute 'Unite '.opts.' file_rec/async:'.l:project_dir
endfunction
uniteバッファをinsert modeで始めたくない場合は'-start-insert'
を消す
ただし、このままだと、.gitignoreに設定されているファイルも出てきてしまうので、git ls-files
コマンドを利用したUnite file_rec/git
をgitリポジトリでは使うようにする。:h unite-source-file_rec/git
に書いてあるfile_rec/gitのオプションを参考にして
nnoremap [unite]fp :<C-u>call<SID>unite_file_project('-start-insert')<CR>function!s:unite_file_project(...)letl:opts =(a:0 ? join(a:000,' ') : '')letl:project_dir = GetProjectDir()if isdirectory(l:project_dir.'/.git')
execute 'lcd '.l:project_dir
execute 'Unite '.opts.' file_rec/git:--cached:--others:--exclude-standard'else
execute 'Unite '.opts.' file_rec/async:'.l:project_dir
endifendfunction
とする。ここでfile_rec/gitはカレントディレクトリがgitのリポジトリでないと使えないので、lcdで移動する。file_rec/gitのオプションの--cached
はインデックスにキャッシュされたファイルを出力するオプション、--others
は追跡されてないファイルを出力するオプション、--exlude-standard
は.gitignoreで無視されるファイルは除いて出力するオプション。要するに、.gitignoreで無視されるファイル以外のすべてを出力する。
同様な感じでgrepの方も設定する。
nnoremap,gp :<C-u>call<SID>unite_grep_project('-start-insert')<CR>function!s:unite_grep_project(...)let opts =(a:0 ? join(a:000,' ') : '')letl:project_dir = GetProjectDir()if!executable('ag')&& isdirectory(l:project_dir.'/.git')
execute 'Unite '.opts.' grep/git:/:--untracked'else
execute 'Unite '.opts.' grep:'.l:project_dir
endifendfunction
grepの方はagがあれば、agが.gitignoreにあるファイルを無視してくれるのと、smart-caseを使いたいのでagを使う。
ない場合はgit grep
を利用するgrep/gitを使う。/
でリポジトリのルートディレクトリをディレクトリ対象に指定し、--untracked
で追跡していないファイルも含める。
まとめると最終的に以下のような設定になる。ちょっとuniteの設定を追加した。
" Note: Skip initialization for vim-tiny or vim-small.if0|endifif has('vim_starting')if&compatiblesetnocompatible" Be iMprovedendif " Required:setruntimepath+=~/.vim/bundle/neobundle.vim/endif" Required:call neobundle#begin(expand('~/.vim/bundle/'))" Let NeoBundle manage NeoBundle" Required:
NeoBundleFetch 'Shougo/neobundle.vim'" My Bundles here:" Refer to |:NeoBundle-examples|." Note: You don't set neobundle setting in .gvimrc!
NeoBundle 'Shougo/vimproc.vim', {
\ 'build' : {
\ 'windows' : 'tools\\update-dll-mingw',
\ 'cygwin' : 'make -f make_cygwin.mak',
\ 'mac' : 'make -f make_mac.mak',
\ 'linux' : 'make',
\ 'unix' : 'gmake',
\ },
\ }
NeoBundle 'Shougo/unite.vim'
NeoBundle 'Shougo/vimfiler.vim'
NeoBundle 'vim-jp/vital.vim'call neobundle#end()" Required:filetype plugin indent on" If there are uninstalled bundles found on startup," this will conveniently prompt you to install them.
NeoBundleCheck
" 設定例" let g:project_dir_pattern = '^/home/tmsanrinsha/project/[^/]\+'function! GetProjectDir() abort " {{{if exists('b:vimfiler.current_dir')letl:buffer_dir =b:vimfiler.current_dir
elseletl:buffer_dir = expand('%:p:h')endifletl:project_dir = vital#of('vital').import('Prelude').path2project_directory(l:buffer_dir,1)if empty(l:project_dir)&& exists('g:project_dir_pattern')letl:project_dir = matchstr(l:buffer_dir,g:project_dir_pattern)endifif empty(l:project_dir)returnl:buffer_dir
elsereturnl:project_dir
endifendfunction" }}}nnoremap [unite] <Nop>
nmap , [unite]
call unite#custom#profile('default','context', {
\ 'start_insert': 1,
\ 'winheight': 10,
\ 'auto_resize': 1,
\ })nnoremap [unite]fp :<C-u>call<SID>unite_file_project('-start-insert')<CR>function!s:unite_file_project(...)letl:opts =(a:0 ? join(a:000,' ') : '')letl:project_dir = GetProjectDir()if isdirectory(l:project_dir.'/.git')
execute 'lcd '.l:project_dir
execute 'Unite '.opts.' file_rec/git:--cached:--others:--exclude-standard'else
execute 'Unite '.opts.' file_rec/async:'.l:project_dir
endifendfunctionif executable('ag') " Use ag in unite grep source.letg:unite_source_grep_command ='ag'letg:unite_source_grep_default_opts =
\ '-f --vimgrep --hidden --ignore ' .
\ '''.hg'' --ignore ''.svn'' --ignore ''.git'' --ignore ''.bzr'''letg:unite_source_grep_recursive_opt =''endifnnoremap [unite]gp :<C-u>call<SID>unite_grep_project('-start-insert')<CR>function!s:unite_grep_project(...)let opts =(a:0 ? join(a:000,' ') : '')letl:project_dir = GetProjectDir()if!executable('ag')&& isdirectory(l:project_dir.'/.git')
execute 'Unite '.opts.' grep/git:/:--untracked'else
execute 'Unite '.opts.' grep:'.l:project_dir
endifendfunction