Normalize path specs when generating commands

This commit is contained in:
Tim Pope 2018-08-13 00:08:59 -04:00
parent 8dc13a6a72
commit 45c21fc384

View File

@ -203,9 +203,25 @@ function! s:Tree(...) abort
return FugitiveTreeForGitDir(a:0 ? a:1 : get(b:, 'git_dir', '')) return FugitiveTreeForGitDir(a:0 ? a:1 : get(b:, 'git_dir', ''))
endfunction endfunction
function! s:PreparePathArgs(cmd, dir) abort
if fugitive#GitVersion() !~# '^[01]\.'
call insert(a:cmd, '--literal-pathspecs')
endif
let split = index(a:cmd, '--')
let tree = s:Tree(a:dir)
if empty(tree) || split < 0
return a:cmd
endif
for i in range(split + 1, len(a:cmd) - 1)
let a:cmd[i] = fugitive#Path(a:cmd[i], './', a:dir)
endfor
return a:cmd
endfunction
function! s:TreeChomp(...) abort function! s:TreeChomp(...) abort
let args = copy(type(a:1) == type([]) ? a:1 : a:000) let args = copy(type(a:1) == type([]) ? a:1 : a:000)
let dir = a:0 > 1 && type(a:1) == type([]) ? a:2 : b:git_dir let dir = a:0 > 1 && type(a:1) == type([]) ? a:2 : b:git_dir
call s:PreparePathArgs(args, dir)
let tree = s:Tree(dir) let tree = s:Tree(dir)
let pre = '' let pre = ''
if empty(tree) if empty(tree)
@ -224,9 +240,9 @@ endfunction
function! fugitive#Prepare(cmd, ...) abort function! fugitive#Prepare(cmd, ...) abort
let dir = a:0 ? a:1 : get(b:, 'git_dir', '') let dir = a:0 ? a:1 : get(b:, 'git_dir', '')
let tree = s:Tree(dir) let tree = s:Tree(dir)
let args = type(a:cmd) == type([]) ? join(map(copy(a:cmd), 's:shellesc(v:val)')) : a:cmd let args = type(a:cmd) == type([]) ? join(map(s:PreparePathArgs(copy(a:cmd), dir), 's:shellesc(v:val)')) : a:cmd
let pre = '' let pre = ''
if empty(tree) if empty(tree) || (type(a:cmd) == type([]) && index(a:cmd, '--') == len(a:cmd) - 1)
let args = s:shellesc('--git-dir=' . dir) . ' ' . args let args = s:shellesc('--git-dir=' . dir) . ' ' . args
elseif fugitive#GitVersion() =~# '^[01]\.' elseif fugitive#GitVersion() =~# '^[01]\.'
let pre = 'cd ' . s:shellesc(tree) . (s:winshell() ? ' & ' : '; ') let pre = 'cd ' . s:shellesc(tree) . (s:winshell() ? ' & ' : '; ')
@ -1688,16 +1704,16 @@ function! s:StageUndo() abort
if empty(filename) if empty(filename)
return '' return ''
endif endif
let hash = s:TreeChomp('hash-object', '-w', filename) let hash = s:TreeChomp('hash-object', '-w', './' . filename)
if !empty(hash) if !empty(hash)
if section ==# 'untracked' if section ==# 'untracked'
call s:TreeChomp('clean', '-f', '--', filename) call s:TreeChomp('clean', '-f', './' . filename)
elseif section ==# 'unmerged' elseif section ==# 'unmerged'
call s:TreeChomp('rm', '--', filename) call s:TreeChomp('rm', './' . filename)
elseif section ==# 'unstaged' elseif section ==# 'unstaged'
call s:TreeChomp('checkout', '--', filename) call s:TreeChomp('checkout', './' . filename)
else else
call s:TreeChomp('checkout', 'HEAD', '--', filename) call s:TreeChomp('checkout', 'HEAD^{}', './' . filename)
endif endif
call s:StageReloadSeek(filename, line('.'), line('.')) call s:StageReloadSeek(filename, line('.'), line('.'))
let @" = hash let @" = hash
@ -1731,7 +1747,7 @@ function! s:StageDiffEdit() abort
if section ==# 'staged' if section ==# 'staged'
return 'Git! diff --no-ext-diff --cached '.s:shellesc(arg) return 'Git! diff --no-ext-diff --cached '.s:shellesc(arg)
elseif section ==# 'untracked' elseif section ==# 'untracked'
call s:TreeChomp('add','--intent-to-add',arg) call s:TreeChomp('add', '--intent-to-add', './' . arg)
if arg ==# '.' if arg ==# '.'
silent! edit! silent! edit!
1 1
@ -1773,7 +1789,7 @@ function! s:StageToggle(lnum1,lnum2) abort
endif endif
return '' return ''
else else
call s:TreeChomp('add','.') call s:TreeChomp('add', '.')
silent! edit! silent! edit!
1 1
call search(':$','W') call search(':$','W')
@ -1791,13 +1807,13 @@ function! s:StageToggle(lnum1,lnum2) abort
let files_to_unstage = [filename] let files_to_unstage = [filename]
endif endif
let filename = files_to_unstage[-1] let filename = files_to_unstage[-1]
let cmd = ['reset','-q','--'] + files_to_unstage let cmd = ['reset', '-q'] + map(copy(files_to_unstage), '"./" . v:val')
elseif getline(lnum) =~# '^.\=\tdeleted:' elseif getline(lnum) =~# '^.\=\tdeleted:'
let cmd = ['rm','--',filename] let cmd = ['rm', './' . filename]
elseif getline(lnum) =~# '^.\=\tmodified:' elseif getline(lnum) =~# '^.\=\tmodified:'
let cmd = ['add','--',filename] let cmd = ['add', './' . filename]
else else
let cmd = ['add','-A','--',filename] let cmd = ['add','-A', './' . filename]
endif endif
if !exists('first_filename') if !exists('first_filename')
let first_filename = filename let first_filename = filename
@ -2361,15 +2377,15 @@ function! s:Write(force,...) abort
return 'wq' return 'wq'
elseif get(b:, 'fugitive_type', '') ==# 'index' elseif get(b:, 'fugitive_type', '') ==# 'index'
return 'Gcommit' return 'Gcommit'
elseif s:Relative('') ==# '' && getline(4) =~# '^+++ ' elseif &buftype ==# 'nowrite' && getline(4) =~# '^+++ '
let filename = getline(4)[6:-1] let filename = getline(4)[6:-1]
setlocal buftype= setlocal buftype=
silent write silent write
setlocal buftype=nowrite setlocal buftype=nowrite
if matchstr(getline(2),'index [[:xdigit:]]\+\.\.\zs[[:xdigit:]]\{7\}') ==# fugitive#RevParse(':0:'.filename)[0:6] if matchstr(getline(2),'index [[:xdigit:]]\+\.\.\zs[[:xdigit:]]\{7\}') ==# fugitive#RevParse(':0:'.filename)[0:6]
let err = s:TreeChomp('apply', '--cached', '--reverse', expand('%:p')) let err = s:TreeChomp('apply', '--cached', '--reverse', '--', expand('%:p'))
else else
let err = s:TreeChomp('apply', '--cached', expand('%:p')) let err = s:TreeChomp('apply', '--cached', '--', expand('%:p'))
endif endif
if err !=# '' if err !=# ''
let v:errmsg = split(err,"\n")[0] let v:errmsg = split(err,"\n")[0]
@ -2382,19 +2398,18 @@ function! s:Write(force,...) abort
endif endif
let mytab = tabpagenr() let mytab = tabpagenr()
let mybufnr = bufnr('') let mybufnr = bufnr('')
let path = a:0 ? s:Expand(join(a:000, ' ')) : s:Relative() let file = a:0 ? s:Generate(s:Expand(join(a:000, ' '))) : fugitive#Real(@%)
if empty(path) if empty(file)
return 'echoerr '.string('fugitive: cannot determine file path') return 'echoerr '.string('fugitive: cannot determine file path')
endif endif
if path =~# '^:\d\>' if file =~# '^fugitive:'
return 'write'.(a:force ? '! ' : ' ').s:fnameescape(s:Generate(path)) return 'write' . (a:force ? '! ' : ' ') . s:fnameescape(file)
endif endif
let always_permitted = ((s:Relative() ==# path || s:Relative('') ==# path) && s:DirCommitFile(@%)[1] =~# '^0\=$') let always_permitted = s:cpath(fugitive#Real(@%), file) && s:DirCommitFile(@%)[1] =~# '^0\=$'
if !always_permitted && !a:force && (len(s:TreeChomp('diff','--name-status','HEAD','--',path)) || len(s:TreeChomp('ls-files','--others','--',path))) if !always_permitted && !a:force && (len(s:TreeChomp('diff', '--name-status', 'HEAD', '--', file)) || len(s:TreeChomp('ls-files', '--others', '--', file)))
let v:errmsg = 'fugitive: file has uncommitted changes (use ! to override)' let v:errmsg = 'fugitive: file has uncommitted changes (use ! to override)'
return 'echoerr v:errmsg' return 'echoerr v:errmsg'
endif endif
let file = s:Generate(path)
let treebufnr = 0 let treebufnr = 0
for nr in range(1,bufnr('$')) for nr in range(1,bufnr('$'))
if fnamemodify(bufname(nr),':p') ==# file if fnamemodify(bufname(nr),':p') ==# file
@ -2434,25 +2449,25 @@ function! s:Write(force,...) abort
call writefile(readfile(temp,'b'),file,'b') call writefile(readfile(temp,'b'),file,'b')
endif endif
else else
execute 'write! '.s:fnameescape(s:Generate(path)) execute 'write! '.s:fnameescape(file)
endif endif
if a:force if a:force
let error = s:TreeChomp('add', '--force', '--', path) let error = s:TreeChomp('add', '--force', '--', file)
else else
let error = s:TreeChomp('add', '--', path) let error = s:TreeChomp('add', '--', file)
endif endif
if v:shell_error if v:shell_error
let v:errmsg = 'fugitive: '.error let v:errmsg = 'fugitive: '.error
return 'echoerr v:errmsg' return 'echoerr v:errmsg'
endif endif
if s:Relative('') ==# path && s:DirCommitFile(@%)[1] =~# '^\d$' if s:cpath(fugitive#Real(@%), file) && s:DirCommitFile(@%)[1] =~# '^\d$'
set nomodified set nomodified
endif endif
let one = s:Generate(':1:'.path) let one = s:Generate(':1:'.file)
let two = s:Generate(':2:'.path) let two = s:Generate(':2:'.file)
let three = s:Generate(':3:'.path) let three = s:Generate(':3:'.file)
for nr in range(1,bufnr('$')) for nr in range(1,bufnr('$'))
let name = fnamemodify(bufname(nr), ':p') let name = fnamemodify(bufname(nr), ':p')
if bufloaded(nr) && !getbufvar(nr,'&modified') && (name ==# one || name ==# two || name ==# three) if bufloaded(nr) && !getbufvar(nr,'&modified') && (name ==# one || name ==# two || name ==# three)
@ -2461,7 +2476,7 @@ function! s:Write(force,...) abort
endfor endfor
unlet! restorewinnr unlet! restorewinnr
let zero = s:Generate(':0:'.path) let zero = s:Generate(':0:'.file)
silent execute 'doautocmd BufWritePost' s:fnameescape(zero) silent execute 'doautocmd BufWritePost' s:fnameescape(zero)
for tab in range(1,tabpagenr('$')) for tab in range(1,tabpagenr('$'))
for winnr in range(1,tabpagewinnr(tab,'$')) for winnr in range(1,tabpagewinnr(tab,'$'))
@ -2655,8 +2670,8 @@ function! s:CompareAge(mine, theirs) abort
elseif base ==# theirs elseif base ==# theirs
return 1 return 1
endif endif
let my_time = +s:TreeChomp('log','--max-count=1','--pretty=format:%at',a:mine) let my_time = +s:TreeChomp('log', '--max-count=1', '--pretty=format:%at', a:mine, '--')
let their_time = +s:TreeChomp('log','--max-count=1','--pretty=format:%at',a:theirs) let their_time = +s:TreeChomp('log', '--max-count=1', '--pretty=format:%at', a:theirs, '--')
return my_time < their_time ? -1 : my_time != their_time return my_time < their_time ? -1 : my_time != their_time
endfunction endfunction
@ -2671,9 +2686,9 @@ function! s:Diff(vert,keepfocus,...) abort
let back = exists('*win_getid') ? 'call win_gotoid(' . win_getid() . ')' : 'wincmd p' let back = exists('*win_getid') ? 'call win_gotoid(' . win_getid() . ')' : 'wincmd p'
if exists(':DiffGitCached') if exists(':DiffGitCached')
return 'DiffGitCached' return 'DiffGitCached'
elseif (empty(args) || args[0] ==# ':') && commit =~# '^[0-1]\=$' && !empty(s:TreeChomp('ls-files', '--unmerged', '--', s:Relative(''))) elseif (empty(args) || args[0] ==# ':') && commit =~# '^[0-1]\=$' && !empty(s:TreeChomp('ls-files', '--unmerged', '--', expand('%:p')))
if v:shell_error if v:shell_error
return 'echoerr ' . string("fugitive: error determining merge status of " . s:Relative('')) return 'echoerr ' . string("fugitive: error determining merge status of the current buffer")
endif endif
let vert = empty(a:vert) ? s:diff_modifier(3) : a:vert let vert = empty(a:vert) ? s:diff_modifier(3) : a:vert
let nr = bufnr('') let nr = bufnr('')
@ -2696,7 +2711,7 @@ function! s:Diff(vert,keepfocus,...) abort
if arg ==# '' if arg ==# ''
return post return post
elseif arg ==# '/' elseif arg ==# '/'
let file = s:Relative('/') let file = s:Relative()
elseif arg ==# ':' elseif arg ==# ':'
let file = s:Relative(':0:') let file = s:Relative(':0:')
elseif arg =~# '^:/.' elseif arg =~# '^:/.'
@ -2712,7 +2727,7 @@ function! s:Diff(vert,keepfocus,...) abort
let file = file.s:Relative(':') let file = file.s:Relative(':')
endif endif
else else
let file = s:Relative(empty(commit) ? ':0:' : '/') let file = empty(commit) ? s:Relative(':0:') : s:Relative()
endif endif
try try
let spec = s:Generate(file) let spec = s:Generate(file)
@ -2756,15 +2771,15 @@ function! s:Move(force, rename, destination) abort
else else
let destination = a:destination let destination = a:destination
endif endif
let destination = s:Tree() . '/' . destination
if isdirectory(@%) if isdirectory(@%)
setlocal noswapfile setlocal noswapfile
endif endif
let message = call('s:TreeChomp', ['mv'] + (a:force ? ['-f'] : []) + ['--', s:Relative(''), destination]) let message = call('s:TreeChomp', ['mv'] + (a:force ? ['-f'] : []) + ['--', expand('%:p'), destination])
if v:shell_error if v:shell_error
let v:errmsg = 'fugitive: '.message let v:errmsg = 'fugitive: '.message
return 'echoerr v:errmsg' return 'echoerr v:errmsg'
endif endif
let destination = s:Tree() . '/' . destination
if isdirectory(destination) if isdirectory(destination)
let destination = fnamemodify(s:sub(destination,'/$','').'/'.expand('%:t'),':.') let destination = fnamemodify(s:sub(destination,'/$','').'/'.expand('%:t'),':.')
endif endif
@ -2784,7 +2799,7 @@ function! s:RenameComplete(A,L,P) abort
if a:A =~# '^[.:]\=/' if a:A =~# '^[.:]\=/'
return fugitive#PathComplete(a:A) return fugitive#PathComplete(a:A)
else else
let pre = '/' . fnamemodify(s:Relative(''), ':h') . '/' let pre = s:Slash(fnamemodify(expand('%:p:s?[\/]$??'), ':h')) . '/'
return map(fugitive#PathComplete(pre.a:A), 'strpart(v:val, len(pre))') return map(fugitive#PathComplete(pre.a:A), 'strpart(v:val, len(pre))')
endif endif
endfunction endfunction
@ -2801,7 +2816,7 @@ function! s:Remove(after, force) abort
if a:force if a:force
let cmd += ['--force'] let cmd += ['--force']
endif endif
let message = call('s:TreeChomp', cmd+['--',s:Relative('')]) let message = call('s:TreeChomp', cmd + ['--', expand('%:p')])
if v:shell_error if v:shell_error
let v:errmsg = 'fugitive: '.s:sub(message,'error:.*\zs\n\(.*-f.*',' (add ! to force)') let v:errmsg = 'fugitive: '.s:sub(message,'error:.*\zs\n\(.*-f.*',' (add ! to force)')
return 'echoerr '.string(v:errmsg) return 'echoerr '.string(v:errmsg)
@ -2859,7 +2874,7 @@ function! s:Blame(bang, line1, line2, count, mods, args) abort
return 'bdelete' return 'bdelete'
endif endif
try try
if empty(s:Relative('')) if empty(s:Relative('/'))
call s:throw('file or blob required') call s:throw('file or blob required')
endif endif
if filter(copy(a:args),'v:val !~# "^\\%(--root\|--show-name\\|-\\=\\%([ltfnsew]\\|[MC]\\d*\\)\\+\\)$"') != [] if filter(copy(a:args),'v:val !~# "^\\%(--root\|--show-name\\|-\\=\\%([ltfnsew]\\|[MC]\\d*\\)\\+\\)$"') != []
@ -3143,14 +3158,14 @@ function! s:Browse(bang,line1,count,...) abort
let rev = s:DirRev(@%)[1] let rev = s:DirRev(@%)[1]
endif endif
if rev =~# '^:\=$' if rev =~# '^:\=$'
let expanded = s:Relative('/') let expanded = s:Relative()
else else
let expanded = s:Expand(rev) let expanded = s:Expand(rev)
endif endif
let cdir = fugitive#CommonDir(b:git_dir) let cdir = fugitive#CommonDir(b:git_dir)
for dir in ['tags/', 'heads/', 'remotes/'] for dir in ['tags/', 'heads/', 'remotes/']
if expanded !~# '^[./]' && filereadable(cdir . '/refs/' . dir . expanded) if expanded !~# '^[./]' && filereadable(cdir . '/refs/' . dir . expanded)
let expanded = '/.git/refs/' . dir . expanded let expanded = '.git/refs/' . dir . expanded
endif endif
endfor endfor
let full = s:Generate(expanded) let full = s:Generate(expanded)
@ -3244,7 +3259,7 @@ function! s:Browse(bang,line1,count,...) abort
call writefile([commit, ''], blame_list, 'b') call writefile([commit, ''], blame_list, 'b')
let blame_in = s:tempname() let blame_in = s:tempname()
silent exe '%write' blame_in silent exe '%write' blame_in
let blame = split(s:TreeChomp('blame', '--contents', blame_in, '-L', a:line1.','.a:count, '-S', blame_list, '-s', '--show-number', '--', path), "\n") let blame = split(s:TreeChomp('blame', '--contents', blame_in, '-L', a:line1.','.a:count, '-S', blame_list, '-s', '--show-number', './' . path), "\n")
if !v:shell_error if !v:shell_error
let blame_regex = '^\^\x\+\s\+\zs\d\+\ze\s' let blame_regex = '^\^\x\+\s\+\zs\d\+\ze\s'
if get(blame, 0) =~# blame_regex && get(blame, -1) =~# blame_regex if get(blame, 0) =~# blame_regex && get(blame, -1) =~# blame_regex