diff --git a/autoload/gitgutter.vim b/autoload/gitgutter.vim index 659d952..5eb2cb0 100644 --- a/autoload/gitgutter.vim +++ b/autoload/gitgutter.vim @@ -195,6 +195,7 @@ function! s:clear(bufnr) call gitgutter#hunk#reset(a:bufnr) call s:reset_tick(a:bufnr) call gitgutter#utility#setbufvar(a:bufnr, 'path', '') + call gitgutter#utility#setbufvar(a:bufnr, 'basepath', '') endfunction diff --git a/autoload/gitgutter/diff.vim b/autoload/gitgutter/diff.vim index 010a17b..328cfaa 100644 --- a/autoload/gitgutter/diff.vim +++ b/autoload/gitgutter/diff.vim @@ -123,7 +123,7 @@ function! gitgutter#diff#run_diff(bufnr, from, preserve_full_diff) abort endif " Write file from index to temporary file. - let index_name = gitgutter#utility#get_diff_base(a:bufnr).':'.gitgutter#utility#repo_path(a:bufnr, 1) + let index_name = gitgutter#utility#get_diff_base(a:bufnr).':'.s:base_path(a:bufnr) let cmd .= gitgutter#git().' --no-pager show --textconv '.index_name.' > '.from_file.' || exit 0) && (' elseif a:from ==# 'working_tree' @@ -425,3 +425,65 @@ endfunction function! s:save_last_seen_change(bufnr) abort call gitgutter#utility#setbufvar(a:bufnr, 'tick', getbufvar(a:bufnr, 'changedtick')) endfunction + + +" Returns the original path (shellescaped) at the buffer's diff base. +function! s:base_path(bufnr) + let diffbase = gitgutter#utility#get_diff_base(a:bufnr) + + " If we already know the original path at this diff base, return it. + let basepath = gitgutter#utility#getbufvar(a:bufnr, 'basepath', '') + if !empty(basepath) + let [base, bpath] = split(basepath, ':', 1) + if base == diffbase + return gitgutter#utility#shellescape(bpath) + endif + endif + + " Obtain buffers' paths. + let current_paths = {} + for bufnr in range(1, bufnr('$') + 1) + if gitgutter#utility#has_repo_path(bufnr) + let current_paths[gitgutter#utility#repo_path(bufnr, 0)] = bufnr + endif + endfor + + " Get a list of file renames at the buffer's diff base. + " Store the original paths on any corresponding buffers. + " If the buffer's file was one of them, return its original path. + let op = '' + let renames = s:obtain_file_renames(a:bufnr, diffbase) + for [current, original] in items(renames) + if has_key(current_paths, current) + let bufnr = current_paths[current] + let basepath = diffbase.':'.original + call gitgutter#utility#setbufvar(bufnr, 'basepath', basepath) + + if bufnr == a:bufnr + let op = original + endif + endif + endfor + if !empty(op) + return gitgutter#utility#shellescape(op) + endif + + " Buffer's file was not renamed, so store current path and return it. + let current_path = gitgutter#utility#repo_path(a:bufnr, 0) + let basepath = diffbase.':'.current_path + call gitgutter#utility#setbufvar(a:bufnr, 'basepath', basepath) + return gitgutter#utility#shellescape(current_path) +endfunction + + +" Returns a dict of current path to original path at the given base. +function! s:obtain_file_renames(bufnr, base) + let renames = {} + let cmd = gitgutter#git().' diff --diff-filter=R --name-status '.a:base + let [out, error_code] = gitgutter#utility#system(gitgutter#utility#cd_cmd(a:bufnr, cmd)) + for line in split(out, '\n') + let [original, current] = split(line)[1:] + let renames[current] = original + endfor + return renames +endfunction