Introduce helper to normalize to backslashes on win32

FugitiveVimPath() is intended to potentially convert between UNIX and
Windows paths in mixed environments.  Let's separate uses that require
that from those that simply normalize slashes.
This commit is contained in:
Tim Pope
2022-05-30 11:00:04 -04:00
parent 92870eb6d2
commit 950f9c49fc
2 changed files with 74 additions and 41 deletions

View File

@@ -139,15 +139,29 @@ function! s:Mods(mods, ...) abort
endfunction endfunction
if exists('+shellslash') if exists('+shellslash')
let s:dir_commit_file = '\c^fugitive://\%(/\a\@=\)\=\(.\{-\}\)//\%(\(\x\{40,\}\|[0-3]\)\(/.*\)\=\)\=$' let s:dir_commit_file = '\c^fugitive://\%(/\a\@=\)\=\(.\{-\}\)//\%(\(\x\{40,\}\|[0-3]\)\(/.*\)\=\)\=$'
function! s:Slash(path) abort function! s:Slash(path) abort
return tr(a:path, '\', '/') return tr(a:path, '\', '/')
endfunction endfunction
function! s:VimSlash(path) abort
return tr(a:path, '\/', &shellslash ? '//' : '\\')
endfunction
else else
let s:dir_commit_file = '\c^fugitive://\(.\{-\}\)//\%(\(\x\{40,\}\|[0-3]\)\(/.*\)\=\)\=$' let s:dir_commit_file = '\c^fugitive://\(.\{-\}\)//\%(\(\x\{40,\}\|[0-3]\)\(/.*\)\=\)\=$'
function! s:Slash(path) abort function! s:Slash(path) abort
return a:path return a:path
endfunction endfunction
function! s:VimSlash(path) abort
return a:path
endfunction
endif endif
function! s:AbsoluteVimPath(...) abort function! s:AbsoluteVimPath(...) abort
@@ -169,7 +183,7 @@ endfunction
function! s:Resolve(path) abort function! s:Resolve(path) abort
let path = resolve(a:path) let path = resolve(a:path)
if has('win32') if has('win32')
let path = FugitiveVimPath(fnamemodify(fnamemodify(path, ':h'), ':p') . fnamemodify(path, ':t')) let path = s:VimSlash(fnamemodify(fnamemodify(path, ':h'), ':p') . fnamemodify(path, ':t'))
endif endif
return path return path
endfunction endfunction
@@ -181,9 +195,9 @@ endfunction
function! s:cpath(path, ...) abort function! s:cpath(path, ...) abort
if s:FileIgnoreCase(0) if s:FileIgnoreCase(0)
let path = FugitiveVimPath(tolower(a:path)) let path = s:VimSlash(tolower(a:path))
else else
let path = FugitiveVimPath(a:path) let path = s:VimSlash(a:path)
endif endif
return a:0 ? path ==# s:cpath(a:1) : path return a:0 ? path ==# s:cpath(a:1) : path
endfunction endfunction
@@ -433,7 +447,7 @@ endfunction
function! s:UserCommandCwd(dir) abort function! s:UserCommandCwd(dir) abort
let tree = s:Tree(a:dir) let tree = s:Tree(a:dir)
return len(tree) ? FugitiveVimPath(tree) : getcwd() return len(tree) ? s:VimSlash(tree) : getcwd()
endfunction endfunction
function! s:UserCommandList(...) abort function! s:UserCommandList(...) abort
@@ -728,7 +742,7 @@ function! fugitive#PrepareJob(...) abort
let dict.cwd = getcwd() let dict.cwd = getcwd()
call extend(cmd, ['--git-dir=' . FugitiveGitPath(dir)], 'keep') call extend(cmd, ['--git-dir=' . FugitiveGitPath(dir)], 'keep')
else else
let dict.cwd = FugitiveVimPath(tree) let dict.cwd = s:VimSlash(tree)
call extend(cmd, ['-C', FugitiveGitPath(tree)], 'keep') call extend(cmd, ['-C', FugitiveGitPath(tree)], 'keep')
if !s:cpath(tree . '/.git', dir) || len($GIT_DIR) if !s:cpath(tree . '/.git', dir) || len($GIT_DIR)
call extend(cmd, ['--git-dir=' . FugitiveGitPath(dir)], 'keep') call extend(cmd, ['--git-dir=' . FugitiveGitPath(dir)], 'keep')
@@ -1674,7 +1688,7 @@ function! fugitive#Real(url) abort
let [dir, commit, file] = s:DirCommitFile(a:url) let [dir, commit, file] = s:DirCommitFile(a:url)
if len(dir) if len(dir)
let tree = s:Tree(dir) let tree = s:Tree(dir)
return FugitiveVimPath((len(tree) ? tree : s:GitDir(dir)) . file) return s:VimSlash((len(tree) ? tree : s:GitDir(dir)) . file)
endif endif
let pre = substitute(matchstr(a:url, '^\a\a\+\ze:'), '^.', '\u&', '') let pre = substitute(matchstr(a:url, '^\a\a\+\ze:'), '^.', '\u&', '')
if len(pre) && pre !=? 'fugitive' && exists('*' . pre . 'Real') if len(pre) && pre !=? 'fugitive' && exists('*' . pre . 'Real')
@@ -1682,7 +1696,7 @@ function! fugitive#Real(url) abort
else else
let url = fnamemodify(a:url, ':p' . (a:url =~# '[\/]$' ? '' : ':s?[\/]$??')) let url = fnamemodify(a:url, ':p' . (a:url =~# '[\/]$' ? '' : ':s?[\/]$??'))
endif endif
return FugitiveVimPath(empty(url) ? a:url : url) return s:VimSlash(empty(url) ? a:url : url)
endfunction endfunction
function! fugitive#Path(url, ...) abort function! fugitive#Path(url, ...) abort
@@ -1742,17 +1756,17 @@ endfunction
function! fugitive#Find(object, ...) abort function! fugitive#Find(object, ...) abort
if type(a:object) == type(0) if type(a:object) == type(0)
let name = bufname(a:object) let name = bufname(a:object)
return FugitiveVimPath(name =~# '^$\|^/\|^\a\+:' ? name : getcwd() . '/' . name) return s:VimSlash(name =~# '^$\|^/\|^\a\+:' ? name : getcwd() . '/' . name)
elseif a:object =~# '^[~$]' elseif a:object =~# '^[~$]'
let prefix = matchstr(a:object, '^[~$]\i*') let prefix = matchstr(a:object, '^[~$]\i*')
let owner = expand(prefix) let owner = expand(prefix)
return FugitiveVimPath((len(owner) ? owner : prefix) . strpart(a:object, len(prefix))) return s:VimSlash(FugitiveVimPath((len(owner) ? owner : prefix) . strpart(a:object, len(prefix))))
endif endif
let rev = s:Slash(a:object) let rev = s:Slash(a:object)
if rev =~# '^$\|^/\|^\%(\a\a\+:\).*\%(//\|::\)' . (has('win32') ? '\|^\a:/' : '') if rev =~# '^$\|^/\|^\%(\a\a\+:\).*\%(//\|::\)' . (has('win32') ? '\|^\a:/' : '')
return FugitiveVimPath(a:object) return s:VimSlash(a:object)
elseif rev =~# '^\.\.\=\%(/\|$\)' elseif rev =~# '^\.\.\=\%(/\|$\)'
return FugitiveVimPath(simplify(getcwd() . '/' . a:object)) return s:VimSlash(simplify(getcwd() . '/' . a:object))
endif endif
let dir = call('s:GitDir', a:000) let dir = call('s:GitDir', a:000)
if empty(dir) if empty(dir)
@@ -1778,7 +1792,7 @@ function! fugitive#Find(object, ...) abort
elseif cdir !=# fdir && ( elseif cdir !=# fdir && (
\ f =~# '^\%(config\|hooks\|info\|logs/refs\|objects\|refs\|worktrees\)\%(/\|$\)' || \ f =~# '^\%(config\|hooks\|info\|logs/refs\|objects\|refs\|worktrees\)\%(/\|$\)' ||
\ f !~# '^\%(index$\|index\.lock$\|\w*MSG$\|\w*HEAD$\|logs/\w*HEAD$\|logs$\|rebase-\w\+\)\%(/\|$\)' && \ f !~# '^\%(index$\|index\.lock$\|\w*MSG$\|\w*HEAD$\|logs/\w*HEAD$\|logs$\|rebase-\w\+\)\%(/\|$\)' &&
\ getftime(FugitiveVimPath(fdir . f)) < 0 && getftime(FugitiveVimPath(cdir . f)) >= 0) \ getftime(fdir . f) < 0 && getftime(cdir . f) >= 0)
let f = simplify(cdir . f) let f = simplify(cdir . f)
else else
let f = simplify(fdir . f) let f = simplify(fdir . f)
@@ -1859,7 +1873,7 @@ function! fugitive#Find(object, ...) abort
endif endif
endif endif
endif endif
return FugitiveVimPath(f) return s:VimSlash(f)
endfunction endfunction
function! s:Generate(object, ...) abort function! s:Generate(object, ...) abort
@@ -1868,10 +1882,10 @@ function! s:Generate(object, ...) abort
if !empty(f) if !empty(f)
return f return f
elseif a:object ==# ':/' elseif a:object ==# ':/'
return len(dir) ? FugitiveVimPath(s:DirUrlPrefix(dir) . '0') : '.' return len(dir) ? s:VimSlash(s:DirUrlPrefix(dir) . '0') : '.'
endif endif
let file = matchstr(a:object, '^\%(:\d:\|[^:]*:\)\zs.*') let file = matchstr(a:object, '^\%(:\d:\|[^:]*:\)\zs.*')
return fnamemodify(FugitiveVimPath(len(file) ? file : a:object), ':p') return fnamemodify(s:VimSlash(len(file) ? file : a:object), ':p')
endfunction endfunction
function! s:DotRelative(path, ...) abort function! s:DotRelative(path, ...) abort
@@ -2126,11 +2140,11 @@ function! fugitive#simplify(url) abort
if len(tree) if len(tree)
let path = simplify(tree . file) let path = simplify(tree . file)
if strpart(path . '/', 0, len(tree) + 1) !=# tree . '/' if strpart(path . '/', 0, len(tree) + 1) !=# tree . '/'
return FugitiveVimPath(path) return s:VimSlash(path)
endif endif
endif endif
endif endif
return FugitiveVimPath('fugitive://' . simplify(dir) . '//' . commit . simplify(file)) return s:VimSlash('fugitive://' . simplify(dir) . '//' . commit . simplify(file))
endfunction endfunction
function! fugitive#resolve(url) abort function! fugitive#resolve(url) abort
@@ -2308,7 +2322,7 @@ function! fugitive#glob(url, ...) abort
call filter(files, 'v:val =~# pattern') call filter(files, 'v:val =~# pattern')
let prepend = s:DirUrlPrefix(dir) . substitute(commit, '^:', '', '') . '/' let prepend = s:DirUrlPrefix(dir) . substitute(commit, '^:', '', '') . '/'
call sort(files) call sort(files)
call map(files, 'FugitiveVimPath(prepend . v:val . append)') call map(files, 's:VimSlash(prepend . v:val . append)')
call extend(results, files) call extend(results, files)
endfor endfor
if a:0 > 1 && a:2 if a:0 > 1 && a:2
@@ -3274,8 +3288,8 @@ augroup END
function! s:AskPassArgs(dir) abort function! s:AskPassArgs(dir) abort
if (len($DISPLAY) || len($TERM_PROGRAM) || has('gui_running')) && if (len($DISPLAY) || len($TERM_PROGRAM) || has('gui_running')) &&
\ empty($GIT_ASKPASS) && empty($SSH_ASKPASS) && empty(fugitive#ConfigGetAll('core.askpass', a:dir)) \ empty($GIT_ASKPASS) && empty($SSH_ASKPASS) && empty(fugitive#ConfigGetAll('core.askpass', a:dir))
if s:executable(FugitiveVimPath(s:ExecPath() . '/git-gui--askpass')) if s:executable(s:VimExecPath() . '/git-gui--askpass')
return ['-c', 'core.askPass=' . s:ExecPath() . '/git-gui--askpass'] return ['-c', 'core.askPass=' . s:ExecPath()[0] . '/git-gui--askpass']
elseif s:executable('ssh-askpass') elseif s:executable('ssh-askpass')
return ['-c', 'core.askPass=ssh-askpass'] return ['-c', 'core.askPass=ssh-askpass']
endif endif
@@ -3709,8 +3723,8 @@ function! fugitive#Command(line1, line2, range, bang, mods, arg, ...) abort
return (empty(cmd) ? 'exe' : cmd) . after return (empty(cmd) ? 'exe' : cmd) . after
endif endif
let alias = FugitiveConfigGet('alias.' . get(args, 0, ''), config) let alias = FugitiveConfigGet('alias.' . get(args, 0, ''), config)
if get(args, 1, '') !=# '--help' && alias !~# '^$\|^!\|[\"'']' && !filereadable(FugitiveVimPath(s:ExecPath() . '/git-' . args[0])) if get(args, 1, '') !=# '--help' && alias !~# '^$\|^!\|[\"'']' && !filereadable(s:VimExecPath() . '/git-' . args[0])
\ && !(has('win32') && filereadable(FugitiveVimPath(s:ExecPath() . '/git-' . args[0] . '.exe'))) \ && !(has('win32') && filereadable(s:VimExecPath() . '/git-' . args[0] . '.exe'))
call remove(args, 0) call remove(args, 0)
call extend(args, split(alias, '\s\+'), 'keep') call extend(args, split(alias, '\s\+'), 'keep')
endif endif
@@ -3923,11 +3937,16 @@ let s:exec_paths = {}
function! s:ExecPath() abort function! s:ExecPath() abort
let git = s:GitShellCmd() let git = s:GitShellCmd()
if !has_key(s:exec_paths, git) if !has_key(s:exec_paths, git)
let s:exec_paths[git] = get(s:JobExecute(s:GitCmd() + ['--exec-path'], {}, [], [], {}).stdout, 0, '') let path = get(s:JobExecute(s:GitCmd() + ['--exec-path'], {}, [], [], {}).stdout, 0, '')
let s:exec_paths[git] = [path, FugitiveVimPath(path)]
endif endif
return s:exec_paths[git] return s:exec_paths[git]
endfunction endfunction
function! s:VimExecPath() abort
return s:ExecPath()[1]
endfunction
let s:subcommands_before_2_5 = [ let s:subcommands_before_2_5 = [
\ 'add', 'am', 'apply', 'archive', 'bisect', 'blame', 'branch', 'bundle', \ 'add', 'am', 'apply', 'archive', 'bisect', 'blame', 'branch', 'bundle',
\ 'checkout', 'cherry', 'cherry-pick', 'citool', 'clean', 'clone', 'commit', 'config', \ 'checkout', 'cherry', 'cherry-pick', 'citool', 'clean', 'clone', 'commit', 'config',
@@ -3940,7 +3959,7 @@ let s:subcommands_before_2_5 = [
\ ] \ ]
let s:path_subcommands = {} let s:path_subcommands = {}
function! s:CompletableSubcommands(dir) abort function! s:CompletableSubcommands(dir) abort
let c_exec_path = s:cpath(s:ExecPath()) let c_exec_path = s:cpath(s:VimExecPath())
if !has_key(s:path_subcommands, c_exec_path) if !has_key(s:path_subcommands, c_exec_path)
if fugitive#GitVersion(2, 18) if fugitive#GitVersion(2, 18)
let [lines, exec_error] = s:LinesError([a:dir, '--list-cmds=list-mainporcelain,nohelpers,list-complete']) let [lines, exec_error] = s:LinesError([a:dir, '--list-cmds=list-mainporcelain,nohelpers,list-complete'])
@@ -4035,7 +4054,7 @@ function! fugitive#Cd(path, ...) abort
exe s:DirCheck(dir) exe s:DirCheck(dir)
let path = (empty(s:Tree(dir)) ? dir : s:Tree(dir)) . '/' . path let path = (empty(s:Tree(dir)) ? dir : s:Tree(dir)) . '/' . path
endif endif
return (a:0 && a:1 ? 'lcd ' : 'cd ') . s:fnameescape(FugitiveVimPath(path)) return (a:0 && a:1 ? 'lcd ' : 'cd ') . fnameescape(s:VimSlash(path))
endfunction endfunction
" Section: :Gstatus " Section: :Gstatus
@@ -4955,13 +4974,13 @@ function! s:StageDelete(lnum1, lnum2, count) abort
call s:TreeChomp('clean', '-f', '--', info.paths[0]) call s:TreeChomp('clean', '-f', '--', info.paths[0])
elseif a:count == 2 elseif a:count == 2
if get(b:fugitive_files['Staged'], info.filename, {'status': ''}).status ==# 'D' if get(b:fugitive_files['Staged'], info.filename, {'status': ''}).status ==# 'D'
call delete(FugitiveVimPath(info.paths[0])) call delete(info.paths[0])
else else
call s:TreeChomp('checkout', '--ours', '--', info.paths[0]) call s:TreeChomp('checkout', '--ours', '--', info.paths[0])
endif endif
elseif a:count == 3 elseif a:count == 3
if get(b:fugitive_files['Unstaged'], info.filename, {'status': ''}).status ==# 'D' if get(b:fugitive_files['Unstaged'], info.filename, {'status': ''}).status ==# 'D'
call delete(FugitiveVimPath(info.paths[0])) call delete(info.paths[0])
else else
call s:TreeChomp('checkout', '--theirs', '--', info.paths[0]) call s:TreeChomp('checkout', '--theirs', '--', info.paths[0])
endif endif
@@ -4977,7 +4996,7 @@ function! s:StageDelete(lnum1, lnum2, count) abort
continue continue
endif endif
elseif info.status ==# 'U' elseif info.status ==# 'U'
call delete(FugitiveVimPath(info.paths[0])) call delete(info.paths[0])
elseif info.status ==# 'A' elseif info.status ==# 'A'
call s:TreeChomp('rm', '-f', '--', info.paths[0]) call s:TreeChomp('rm', '-f', '--', info.paths[0])
elseif info.section ==# 'Unstaged' elseif info.section ==# 'Unstaged'
@@ -5336,7 +5355,7 @@ function! s:ToolItems(state, from, to, offsets, text, ...) abort
endif endif
let item = { let item = {
\ 'valid': a:0 ? a:1 : 1, \ 'valid': a:0 ? a:1 : 1,
\ 'filename': diff.filename . FugitiveVimPath(path), \ 'filename': diff.filename . s:VimSlash(path),
\ 'lnum': matchstr(get(a:offsets, i), '\d\+'), \ 'lnum': matchstr(get(a:offsets, i), '\d\+'),
\ 'text': a:text} \ 'text': a:text}
if len(get(diff, 'module', '')) if len(get(diff, 'module', ''))
@@ -5626,7 +5645,7 @@ function! s:GrepOptions(args, dir) abort
let options = {'name_only': 0, 'name_count': 0, 'line_number': 0} let options = {'name_only': 0, 'name_count': 0, 'line_number': 0}
let tree = s:Tree(a:dir) let tree = s:Tree(a:dir)
let prefix = empty(tree) ? fugitive#Find(':0:', a:dir) : let prefix = empty(tree) ? fugitive#Find(':0:', a:dir) :
\ s:cpath(getcwd(), tree) ? '' : FugitiveVimPath(tree . '/') \ s:cpath(getcwd(), tree) ? '' : s:VimSlash(tree . '/')
let options.prefix = prefix let options.prefix = prefix
for arg in a:args for arg in a:args
if arg ==# '--' if arg ==# '--'
@@ -5850,7 +5869,7 @@ function! s:LogParse(state, dir, prefix, line) abort
call add(a:state.queue, { call add(a:state.queue, {
\ 'valid': 1, \ 'valid': 1,
\ 'context': context, \ 'context': context,
\ 'filename': FugitiveVimPath(a:state.base . '/' . a:state.to), \ 'filename': s:VimSlash(a:state.base . '/' . a:state.to),
\ 'module': a:state.base_module . ':' . a:state.to, \ 'module': a:state.base_module . ':' . a:state.to,
\ 'lnum': offsets[-1], \ 'lnum': offsets[-1],
\ 'text': a:state.message . matchstr(a:line, ' @@\+ .\+')}) \ 'text': a:state.message . matchstr(a:line, ' @@\+ .\+')})
@@ -6551,7 +6570,7 @@ function! fugitive#Diffsplit(autodir, keepfocus, mods, arg, ...) abort
endif endif
let spec = s:Generate(file) let spec = s:Generate(file)
if spec =~# '^fugitive:' && empty(s:DirCommitFile(spec)[2]) if spec =~# '^fugitive:' && empty(s:DirCommitFile(spec)[2])
let spec = FugitiveVimPath(spec . s:Relative('/')) let spec = s:VimSlash(spec . s:Relative('/'))
endif endif
exe pre exe pre
let restore = s:diff_restore() let restore = s:diff_restore()

View File

@@ -58,7 +58,7 @@ function! FugitiveReal(...) abort
if type(file) ==# type({}) if type(file) ==# type({})
let dir = FugitiveGitDir(file) let dir = FugitiveGitDir(file)
let tree = s:Tree(dir) let tree = s:Tree(dir)
return FugitiveVimPath(empty(tree) ? dir : tree) return s:VimSlash(empty(tree) ? dir : tree)
elseif file =~# '^\a\a\+:' || a:0 > 1 elseif file =~# '^\a\a\+:' || a:0 > 1
return call('fugitive#Real', [file] + a:000[1:-1]) return call('fugitive#Real', [file] + a:000[1:-1])
elseif file =~# '^/\|^\a:\|^$' elseif file =~# '^/\|^\a:\|^$'
@@ -490,28 +490,42 @@ function! FugitiveDetect(...) abort
return '' return ''
endfunction endfunction
function! FugitiveVimPath(path) abort
if exists('+shellslash') && !&shellslash
return tr(a:path, '/', '\')
else
return a:path
endif
endfunction
function! FugitiveGitPath(path) abort function! FugitiveGitPath(path) abort
return s:Slash(a:path) return s:Slash(a:path)
endfunction endfunction
if exists('+shellslash') if exists('+shellslash')
let s:dir_commit_file = '\c^fugitive://\%(/\a\@=\)\=\(.\{-\}\)//\%(\(\x\{40,\}\|[0-3]\)\(/.*\)\=\)\=$' let s:dir_commit_file = '\c^fugitive://\%(/\a\@=\)\=\(.\{-\}\)//\%(\(\x\{40,\}\|[0-3]\)\(/.*\)\=\)\=$'
function! s:Slash(path) abort function! s:Slash(path) abort
return tr(a:path, '\', '/') return tr(a:path, '\', '/')
endfunction endfunction
function! s:VimSlash(path) abort
return tr(a:path, '\/', &shellslash ? '//' : '\\')
endfunction
function FugitiveVimPath(path) abort
return tr(a:path, '\/', &shellslash ? '//' : '\\')
endfunction
else else
let s:dir_commit_file = '\c^fugitive://\(.\{-\}\)//\%(\(\x\{40,\}\|[0-3]\)\(/.*\)\=\)\=$' let s:dir_commit_file = '\c^fugitive://\(.\{-\}\)//\%(\(\x\{40,\}\|[0-3]\)\(/.*\)\=\)\=$'
function! s:Slash(path) abort function! s:Slash(path) abort
return a:path return a:path
endfunction endfunction
function! s:VimSlash(path) abort
return a:path
endfunction
function! FugitiveVimPath(path) abort
return a:path
endfunction
endif endif
function! s:ProjectionistDetect() abort function! s:ProjectionistDetect() abort