I'm a little surprised that gf
doesn't already support this, but it doesn't. There's a plugin that does, though: gf-diff (GitHub mirror).
Someone also wrote a blog post with a more ad-hoc solution, reproduced below. Credit to the blog author, Kana Natsuno.
" git-diff-aware version of gf commands.
nnoremap <expr> gf <SID>do_git_diff_aware_gf('gf')
nnoremap <expr> gF <SID>do_git_diff_aware_gf('gF')
nnoremap <expr> <C-w>f <SID>do_git_diff_aware_gf('<C-w>f')
nnoremap <expr> <C-w><C-f> <SID>do_git_diff_aware_gf('<C-w><C-f>')
nnoremap <expr> <C-w>F <SID>do_git_diff_aware_gf('<C-w>F')
nnoremap <expr> <C-w>gf <SID>do_git_diff_aware_gf('<C-w>gf')
nnoremap <expr> <C-w>gF <SID>do_git_diff_aware_gf('<C-w>gF')
function! s:do_git_diff_aware_gf(command)
let target_path = expand('<cfile>')
if target_path =~# '^[ab]/' " with a peculiar prefix of git-diff(1)?
if filereadable(target_path) || isdirectory(target_path)
return a:command
else
" BUGS: Side effect - Cursor position is changed.
let [_, c] = searchpos('\f\+', 'cenW')
return c . '|' . 'v' . (len(target_path) - 2 - 1) . 'h' . a:command
endif
else
return a:command
endif
endfunction