Skip to content

Commit

Permalink
add separate caches for repo branches
Browse files Browse the repository at this point in the history
For VCSes that checkout different branches in the same directory, like git and
hg, it can be nice to have separate caches for different branches so you don't
have to do a full cache refresh everytime you change branches in order to find
the files that are in only one of the branches. I have always got around the
issue by using a long-standing vim process for each branch and using the buffer
search to open windows for the new files in the two branches, but that's
obviously very specific to my personal workflow.

Note that the branch-specific caches are only used if the ProbeFindFileInRepo
command is used. So, ProbeFindFile and ProbeFindFileInRepo might use different
caches, but I don't think it'll be a problem.

In the interests of simplicity I considered having this off by default, but I'm
making it the default since I think it'll will be more intuitive for most
people.
  • Loading branch information
torbiak committed Nov 4, 2012
1 parent 174e03c commit 74d5305
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 30 deletions.
96 changes: 68 additions & 28 deletions autoload/probe/file.vim
@@ -1,20 +1,33 @@
" File caching
" File caching vars
" If g:probe_cache_repo_branches is set repository caches are indexed by root
" directory and VCS branch, while normal (ie. directories without a VCS metadir
" or directories scanned using probe#file#find instead of
" probe#file#find_in_repo) are indexed by path.
let s:file_caches = {}
let s:file_cache_order = []
let s:max_file_caches = 10
let s:hash = ''

function! probe#file#find()
let s:hash = probe#util#rshash(getcwd())
cal probe#open(
\ function('probe#file#scan'),
\ function('probe#file#open'),
\ function('probe#file#refresh'))
endfunction

function! probe#file#find_in_repo()
let repo_root = s:find_repo_root()
if repo_root == ''
cal probe#file#find()
return
endif
let orig_dir = getcwd()
let repo_root = probe#file#find_repo_root()
if repo_root != ''
exe printf('cd %s', repo_root)
exe printf('cd %s', repo_root)
if g:probe_cache_repo_branches
let s:hash = probe#util#rshash(repo_root . s:branch())
else
let s:hash = probe#util#rshash(repo_root)
endif
cal probe#open(
\ function('probe#file#scan'),
Expand All @@ -24,21 +37,20 @@ function! probe#file#find_in_repo()
endfunction

function! probe#file#scan()
let dir = getcwd()
" use cache if possible
if has_key(s:file_caches, dir)
return s:file_caches[dir]
if has_key(s:file_caches, s:hash)
return s:file_caches[s:hash]
endif
let cache_filepath = s:cache_filepath(dir)
let cache_filepath = s:cache_filepath()
if g:probe_cache_dir != '' && filereadable(cache_filepath)
let s:file_caches[dir] = readfile(cache_filepath)
return s:file_caches[dir]
let s:file_caches[s:hash] = readfile(cache_filepath)
return s:file_caches[s:hash]
endif

" init new cache
if !has_key(s:file_caches, dir)
let s:file_caches[dir] = []
cal add(s:file_cache_order, dir)
if !has_key(s:file_caches, s:hash)
let s:file_caches[s:hash] = []
cal add(s:file_cache_order, s:hash)
endif

" pare caches
Expand All @@ -48,14 +60,14 @@ function! probe#file#scan()
endif

" recursively scan for files
let s:file_caches[dir] = s:scan_files(dir, [], 0, {})
let s:file_caches[s:hash] = s:scan_files(getcwd(), [], 0, {})

if g:probe_cache_dir != ''
cal s:save_cache(dir, s:file_caches[dir])
cal s:save_cache(s:cache_filepath(), s:file_caches[s:hash])
endif

cal prompt#render()
return s:file_caches[dir]
return s:file_caches[s:hash]
endfunction

function! probe#file#open(filepath)
Expand All @@ -65,11 +77,10 @@ function! probe#file#open(filepath)
endfunction

function! probe#file#refresh()
let dir = getcwd()
if has_key(s:file_caches, dir)
unlet s:file_caches[dir]
if has_key(s:file_caches, s:hash)
unlet s:file_caches[s:hash]
endif
cal delete(s:cache_filepath(dir))
cal delete(s:cache_filepath())
endfunction


Expand Down Expand Up @@ -114,24 +125,25 @@ function! s:match_some(str, patterns)
return 0
endfunction

function! s:save_cache(dir, files)
function! s:save_cache(filename, files)
if !isdirectory(g:probe_cache_dir)
cal mkdir(g:probe_cache_dir)
endif
cal writefile(a:files, s:cache_filepath(a:dir))
cal writefile(a:files, a:filename)
endfunction

function! s:cache_filepath(dir)
return printf('%s/%x', g:probe_cache_dir, probe#util#rshash(a:dir))
function! s:cache_filepath()
return printf('%s/%s', g:probe_cache_dir, s:hash)
endfunction

function! probe#file#find_repo_root()
let meta_dir_pattern = '\v/\.(git|hg|svn|bzr)\n'
function! s:find_metadir()
let metadir_pattern = '\v/\.(git|hg|svn|bzr)>'
let orig_dir = getcwd()
let dir = orig_dir
while 1
if globpath(dir, '.*', 1) =~ meta_dir_pattern
return dir
let metadir = matchstr(globpath(dir, '.*', 1), metadir_pattern)
if metadir != ''
return dir . metadir
endif
let parent = fnamemodify(dir, ':h')
if parent ==# dir
Expand All @@ -142,3 +154,31 @@ function! probe#file#find_repo_root()
endwhile
return ''
endfunction

function! s:find_repo_root()
let metadir = s:find_metadir()
if metadir == ''
return ''
else
return fnamemodify(metadir, ':h')
endif
endfunction

function! s:branch()
let metadir_name = fnamemodify(s:find_metadir(), ':t')
let branch_cmds = {
\'.git': 'git symbolic-ref -q HEAD',
\'.hg': 'hg branch',
\}
if index(keys(branch_cmds), metadir_name) == -1
return ''
endif

let branch = system(branch_cmds[metadir_name])
if v:shell_error != 0
return ''
endif
" With vim 7.3 on OSX 10.7.4 system() was appending a NUL to the end.
" Haven't figured out why yet.
return substitute(branch, '\%x00', '', 'g')
endfunction
3 changes: 2 additions & 1 deletion autoload/probe/util.vim
Expand Up @@ -3,12 +3,13 @@
" looked attractive.
function! probe#util#rshash(string)
" Robert Sedgwick's hash function from Algorithms in C.
" returns a hexadecimal string
let b = 378551
let a = 63689
let hash = 0
for c in split(a:string, '\zs')
let hash = hash * a + char2nr(c)
let a = a * b
endfor
return hash
return printf('%x', hash)
endfunction
5 changes: 5 additions & 0 deletions doc/probe.txt
Expand Up @@ -133,6 +133,11 @@ OPTIONS *probe-options*
Maximum number of files to scan.
Default: (number) 100000

|g:probe_cache_repo_branches| *g:probe_cache_repo_branches*
If true, maintain separate caches for different branches of a repository.
Works for git and mercurial so far.
Default: (boolean) 0

This comment has been minimized.

Copy link
@campbellr

campbellr Nov 5, 2012

Contributor

It looks like this is actually defaulting to '1'...

This comment has been minimized.

Copy link
@torbiak

torbiak Nov 8, 2012

Author Owner

Yeah, I changed my mind at the last minute and forgot to update the docs.


|g:probe_max_height| *g:probe_max_height*
Maximum height of the match window.
Default: (number) 10
Expand Down
5 changes: 4 additions & 1 deletion plugin/probe.vim
Expand Up @@ -16,11 +16,14 @@ if !exists('g:probe_max_file_cache_size')
let g:probe_max_file_cache_size = 100000
endif

if !exists('g:probe_cache_repo_branches')
let g:probe_cache_repo_branches = 1
endif

if !exists('g:probe_max_height')
let g:probe_max_height = 10
endif

"TODO
if !exists('g:probe_reverse_sort')
let g:probe_reverse_sort = 0
endif
Expand Down

0 comments on commit 74d5305

Please sign in to comment.