From fd83fcaf90023f2bd4b0193eee237b117b37c2be Mon Sep 17 00:00:00 2001 From: Tim Pope Date: Tue, 28 Aug 2018 00:35:06 -0400 Subject: [PATCH] Support expansion flags --- autoload/fugitive.vim | 75 +++++++++++++++++++++++++++++++++---------- doc/fugitive.txt | 21 ++++++------ 2 files changed, 69 insertions(+), 27 deletions(-) diff --git a/autoload/fugitive.vim b/autoload/fugitive.vim index a9390e4..27df8f6 100644 --- a/autoload/fugitive.vim +++ b/autoload/fugitive.vim @@ -53,11 +53,12 @@ function! s:shellesc(arg) abort endif endfunction +let s:fnameescape = " \t\n*?[{`$\\%#'\"|!<" function! s:fnameescape(file) abort if exists('*fnameescape') return fnameescape(a:file) else - return escape(a:file," \t\n*?[{`$\\%#'\"|!<") + return escape(a:file, s:fnameescape) endif endfunction @@ -641,18 +642,13 @@ function! s:Generate(rev, ...) abort return fugitive#Route(object, dir) endfunction -function! s:RemoveDot(path, ...) abort - if a:path !~# '^\./' - return a:path +function! s:DotRelative(path) abort + let cwd = getcwd() + let path = substitute(a:path, '^[~$]\i*', '\=expand(submatch(0))', '') + if s:cpath(cwd . '/', (path . '/')[0 : len(cwd)]) + return '.' . strpart(path, len(cwd)) endif - let dir = a:0 ? a:1 : get(b:, 'git_dir', '') - let cdir = fugitive#CommonDir(dir) - if len(filter(['', '/tags', '/heads', '/remotes'], 'getftime(cdir . "/refs" . v:val . a:path[1:-1]) >= 0')) || - \ a:path =~# 'HEAD$' && filereadable(dir . a:path[1:-1]) || - \ a:path =~# '^\./refs/' && filereadable(cdir . a:path[1:-1]) - return a:path - endif - return a:path[2:-1] + return a:path endfunction function! fugitive#Object(...) abort @@ -681,6 +677,44 @@ function! fugitive#Object(...) abort endif endfunction +let s:var = '\%(%\|#<\=\d\+\|##\=\)' +let s:flag = '\%(:[p8~.htre]\|:g\=s\(.\).\{-\}\1.\{-\}\1\)' +let s:expand = '\%(\(' . s:var . '\)\(' . s:flag . '*\)\(:S\)\=\)' + +function! s:BufName(var) abort + if a:var ==# '%' + return bufname(get(b:, 'fugitive_blamed_bufnr', '')) + elseif a:var =~# '^#\d*$' + let nr = getbufvar(+a:var[1:-1], 'fugitive_blamed_bufnr', '') + return bufname(nr ? nr : +a:var[1:-1]) + else + return expand(a:var) + endif +endfunction + +function! s:ExpandVar(other, var, flags, esc) abort + if a:other =~# '^\' + return a:other[1:-1] + elseif a:other =~# '^!' + let buffer = s:BufName(len(a:other) > 1 ? '#'. a:other[1:-1] : '%') + let owner = s:Owner(buffer) + return len(owner) ? owner : '@' + endif + let flags = a:flags + let file = s:DotRelative(fugitive#Real(s:BufName(a:var))) + while len(flags) + let flag = matchstr(flags, s:flag) + let flags = strpart(flags, len(flag)) + if flag ==# ':.' + let file = s:DotRelative(file) + else + let file = fnamemodify(file, flag) + endif + endwhile + let file = s:Slash(file) + return (len(a:esc) ? shellescape(file) : file) +endfunction + function! s:Expand(rev) abort if a:rev =~# '^:[0-3]$' let file = a:rev . s:Relative(':') @@ -688,19 +722,26 @@ function! s:Expand(rev) abort let file = 'HEAD^{}' . a:rev[1:-1] . s:Relative(':') elseif a:rev =~# '^@{' let file = 'HEAD' . a:rev. s:Relative(':') - elseif a:rev =~# '^[~^]/\@!' + elseif a:rev =~# '^\^[0-9~^{]\|^\~[0-9~^]' let commit = substitute(s:DirCommitFile(@%)[1], '^\d\=$', 'HEAD', '') let file = commit . a:rev . s:Relative(':') else let file = a:rev endif - return s:sub(substitute(file, - \ '\([%#]\)$\|\\\([[:punct:]]\)','\=len(submatch(2)) ? submatch(2) : fugitive#Path(expand(submatch(1)))','g'), - \ '\.\@<=/$','') + return substitute(file, + \ '\(\\[' . s:fnameescape . ']\|^\\[>+-]\|!\d*\)\|' . s:expand, + \ '\=s:ExpandVar(submatch(1),submatch(2),submatch(3),"")', 'g') +endfunction + +function! fugitive#Expand(object) abort + return substitute(a:object, + \ '\(\\[' . s:fnameescape . ']\|^\\[>+-]\|!\d*\)\|' . s:expand, + \ '\=s:ExpandVar(submatch(1),submatch(2),submatch(3),submatch(5))', 'g') endfunction function! s:ShellExpand(cmd) abort - return substitute(a:cmd, '\\\@