diff --git a/autoload/fugitive.vim b/autoload/fugitive.vim index d000561..cf34ca6 100644 --- a/autoload/fugitive.vim +++ b/autoload/fugitive.vim @@ -2162,14 +2162,57 @@ function! s:TreeInfo(dir, commit) abort return [{}, -1] endfunction +let s:index_info = {} +function! s:IndexInfo(dir, commit_stage, path) abort + let cache_key = 'cache://' . a:dir . '//' . a:path + let index = get(s:index_info, cache_key, []) + let newftime = getftime(fugitive#Find('.git/index', a:dir)) + + if get(index, 0, -1) == newftime + return get(get(index, 1, {}), a:commit_stage, []) + endif + + let indexes = {'0': [], '1': [], '2': [], '3': []} + let s:index_info[cache_key] = [newftime, indexes] + + let result = fugitive#Execute(['--literal-pathspecs', 'ls-files', '--stage', '--', a:path]) + if result.exit_status + return [] + endif + for line in result.stdout[:2] + " Inspect up to the first three lines to find the correct stage + if empty(line) + break + endif + let [info, filename] = split(line, "\t") + let [mode, sha, stage] = split(info, '\s\+') + if filename ==# a:path + let indexes[stage] = [newftime, mode, 'blob', sha, -2] + else + " Only support stage '0' for tree objects + let indexes['0'] = [newftime, '040000', 'tree', '', 0] + endif + endfor + return get(indexes, a:commit_stage, []) +endfunction + function! s:PathInfo(url) abort let [dir, commit, file] = s:DirCommitFile(a:url) if empty(dir) || !get(g:, 'fugitive_file_api', 1) return [-1, '000000', '', '', -1] endif let path = substitute(file[1:-1], '/*$', '', '') - let [tree, ftime] = s:TreeInfo(dir, commit) - let entry = empty(path) ? [ftime, '040000', 'tree', '', -1] : get(tree, path, []) + + if empty(path) + let [_, ftime] = s:TreeInfo(dir, commit) + let entry = [ftime, '040000', 'tree', '', -1] + elseif commit =~# '^:\=[0-3]$' + let entry = s:IndexInfo(dir, commit[-1:-1], path) + else + let [tree, ftime] = s:TreeInfo(dir, commit) + let entry = get(tree, path, []) + endif + if empty(entry) || file =~# '/$' && entry[2] !=# 'tree' return [-1, '000000', '', '', -1] else