From 3221cdfbde27da59dfb593c07487e8be1a3ad36b Mon Sep 17 00:00:00 2001 From: Tim Pope Date: Sun, 2 Feb 2020 15:09:49 -0500 Subject: [PATCH] Support :Git -c config.name=value --- autoload/fugitive.vim | 135 ++++++++++++++++++++++++------------------ 1 file changed, 77 insertions(+), 58 deletions(-) diff --git a/autoload/fugitive.vim b/autoload/fugitive.vim index 622b9ee..ea6b6dc 100644 --- a/autoload/fugitive.vim +++ b/autoload/fugitive.vim @@ -2341,6 +2341,14 @@ unlet s:colortype function! fugitive#Command(line1, line2, range, bang, mods, arg) abort let dir = s:Dir() let [args, after] = s:SplitExpandChain(a:arg, s:Tree(dir)) + let flags = [] + while len(args) > 1 + if args[0] ==# '-c' + call extend(flags, remove(args, 0, 1)) + else + break + endif + endwhile if empty(args) let cmd = s:StatusCommand(a:line1, a:line2, a:range, a:line2, a:bang, a:mods, '', '', []) return (empty(cmd) ? 'exe' : cmd) . after @@ -2355,24 +2363,36 @@ function! fugitive#Command(line1, line2, range, bang, mods, arg) abort if exists('*s:' . name . 'Subcommand') && get(args, 1, '') !=# '--help' try exe s:DirCheck(dir) - let opts = s:{name}Subcommand(a:line1, a:line2, a:range, a:bang, a:mods, args[1:-1]) - if type(opts) == type('') - return 'exe ' . string(opts) . after + let options = s:{name}Subcommand(a:line1, a:line2, a:range, a:bang, a:mods, {'dir': dir, 'flags': flags, 'command': args[0], 'args': args[1:-1]}) + if type(options) == type('') + return 'exe ' . string(options) . after endif catch /^fugitive:/ return 'echoerr ' . string(v:exception) endtry else - let opts = {} + let options = {} endif - let args = get(opts, 'args', args) + let args = [get(options, 'command', args[0])] + get(options, 'insert_args', []) + args[1:-1] + let env = get(options, 'env', {}) + let i = 0 + while i < len(flags) - 1 + if flags[i] ==# '-c' + let i += 1 + let config_name = matchstr(flags[i], '^[^=]\+\ze=') + if has_key(s:prepare_env, config_name) + let env[s:prepare_env[config_name]] = matchstr(flags[i], '=\zs.*') + endif + endif + let i += 1 + endwhile if a:bang || args[0] =~# '^-p$\|^--paginate$\|diff\%(tool\)\@!\|log\|^show$' || \ (args[0] ==# 'stash' && get(args, 1, '') ==# 'show') || \ (args[0] ==# 'help' || get(args, 1, '') ==# '--help') && !s:HasOpt(args, '--web') if args[0] =~# '^-p$\|^--paginate$' call remove(args, 0) endif - return s:OpenExec((a:line2 > 0 ? a:line2 : '') . (a:line2 ? 'split' : 'edit'), a:mods, args, dir) . after + return s:OpenExec((a:line2 > 0 ? a:line2 : '') . (a:line2 ? 'split' : 'edit'), a:mods, env, flags + args, dir) . after endif if s:HasOpt(args, ['add', 'checkout', 'commit', 'stage', 'stash', 'reset'], '-p', '--patch') || \ s:HasOpt(args, ['add', 'clean', 'stage'], '-i', '--interactive') @@ -2380,13 +2400,12 @@ function! fugitive#Command(line1, line2, range, bang, mods, arg) abort let assign = len(dir) ? '|let b:git_dir = ' . string(dir) : '' if has('nvim') if &autowrite || &autowriteall | silent! wall | endif - return mods . (a:line2 ? 'split' : 'edit') . ' term://' . s:fnameescape(s:UserCommand(dir, args)) . assign . '|startinsert' . after + return mods . (a:line2 ? 'split' : 'edit') . ' term://' . s:fnameescape(s:UserCommand(dir, flags + args)) . assign . '|startinsert' . after elseif has('terminal') if &autowrite || &autowriteall | silent! wall | endif - return 'exe ' . string(mods . 'terminal ' . (a:line2 ? '' : '++curwin ') . join(map(s:UserCommandList(dir) + args, 's:fnameescape(v:val)'))) . assign . after + return 'exe ' . string(mods . 'terminal ' . (a:line2 ? '' : '++curwin ') . join(map(s:UserCommandList(dir) + flags + args, 's:fnameescape(v:val)'))) . assign . after endif endif - let env = get(opts, 'env', {}) if s:RunJobs() let state = {'dir': dir, 'mods': s:Mods(a:mods), 'temp': tempname(), 'log': []} let state.pty = get(g:, 'fugitive_pty', has('unix') && (has('patch-8.0.0744') || has('nvim'))) @@ -2407,7 +2426,7 @@ function! fugitive#Command(line1, line2, range, bang, mods, arg) abort \ 'GIT_MERGE_AUTOEDIT': '1', \ 'GIT_PAGER': 'cat', \ 'PAGER': 'cat'}, 'keep') - let args = ['-c', 'advice.waitingForEditor=false'] + s:disable_colors + args + let args = s:disable_colors + flags + ['-c', 'advice.waitingForEditor=false'] + args let argv = s:UserCommandList(dir) + args if !has('patch-8.0.0902') || has('nvim') let envlist = map(items(env), 'join(v:val, "=")') @@ -2457,7 +2476,7 @@ function! fugitive#Command(line1, line2, range, bang, mods, arg) abort let env.GIT_TERMINAL_PROMPT = '0' endif let pre = s:BuildEnvPrefix(env) - return 'exe ' . string('noautocmd !' . escape(pre . s:UserCommand(dir, args), '!#%')) . + return 'exe ' . string('noautocmd !' . escape(pre . s:UserCommand(dir, flags + args), '!#%')) . \ '|call fugitive#ReloadStatus(' . string(dir) . ', 1)' . \ after endif @@ -3614,8 +3633,8 @@ endfunction " Section: :Gcommit, :Grevert -function! s:CommitInteractive(line1, line2, range, bang, mods, args, patch) abort - let status = s:StatusCommand(a:line1, a:line2, a:range, a:line2, a:bang, a:mods, '', '', []) +function! s:CommitInteractive(line1, line2, range, bang, mods, options, patch) abort + let status = s:StatusCommand(a:line1, a:line2, a:range, a:line2, a:bang, a:mods, '', '', [], a:options.dir) let status = len(status) ? status . '|' : '' if a:patch return status . 'if search("^Unstaged")|exe "normal >"|exe "+"|endif' @@ -3624,8 +3643,8 @@ function! s:CommitInteractive(line1, line2, range, bang, mods, args, patch) abor endif endfunction -function! s:CommitSubcommand(line1, line2, range, bang, mods, args) abort - let argv = copy(a:args) +function! s:CommitSubcommand(line1, line2, range, bang, mods, options) abort + let argv = copy(a:options.args) let i = 0 while get(argv, i, '--') !=# '--' if argv[i] =~# '^-[apzsneiovq].' @@ -3636,16 +3655,16 @@ function! s:CommitSubcommand(line1, line2, range, bang, mods, args) abort endif endwhile if s:HasOpt(argv, '-i', '--interactive') - return s:CommitInteractive(a:line1, a:line2, a:range, a:bang, a:mods, argv, 0) + return s:CommitInteractive(a:line1, a:line2, a:range, a:bang, a:mods, a:options, 0) elseif s:HasOpt(argv, '-p', '--patch') - return s:CommitInteractive(a:line1, a:line2, a:range, a:bang, a:mods, argv, 1) + return s:CommitInteractive(a:line1, a:line2, a:range, a:bang, a:mods, a:options, 1) else return {} endif endfunction -function! s:RevertSubcommand(line1, line2, range, bang, mods, args) abort - return {'args': ['revert', '--edit'] + a:args} +function! s:RevertSubcommand(line1, line2, range, bang, mods, options) abort + return {'insert_args': ['--edit']} endfunction function! fugitive#CommitComplete(A, L, P) abort @@ -3683,20 +3702,21 @@ function! fugitive#PullComplete(A, L, P) abort return s:CompleteSub('pull', a:A, a:L, a:P, function('s:CompleteRemote')) endfunction -function! s:MergeSubcommand(line1, line2, range, bang, mods, args) abort - let dir = s:Dir() - if empty(a:args) && ( +function! s:MergeSubcommand(line1, line2, range, bang, mods, options) abort + let dir = a:options.dir + if empty(a:options.args) && ( \ filereadable(fugitive#Find('.git/MERGE_MSG', dir)) || \ isdirectory(fugitive#Find('.git/rebase-apply', dir)) || \ !empty(s:TreeChomp(dir, 'diff-files', '--diff-filter=U'))) - return 'echohl WarningMsg|echo ":Git merge for loading conflicts is deprecated in favor of :Git mergetool"|echohl NONE|silent Git' . (a:bang ? '!' : '') . ' mergetool' + return 'echohl WarningMsg|echo ":Git merge for loading conflicts is deprecated in favor of :Git mergetool"|echohl NONE|silent Git' . (a:bang ? '!' : '') . s:fnameescape(a:options.flags + ['mergetool']) endif return {} endfunction -function! s:RebaseSubcommand(line1, line2, range, bang, mods, args) abort - if s:HasOpt(a:args, '--autosquash') && !s:HasOpt(a:args, '-i', '--interactive') - return {'env': {'GIT_SEQUENCE_EDITOR': 'true'}, 'args': ['rebase', '--interactive'] + a:args} +function! s:RebaseSubcommand(line1, line2, range, bang, mods, options) abort + let args = a:options.args + if s:HasOpt(args, '--autosquash') && !s:HasOpt(args, '-i', '--interactive') + return {'env': {'GIT_SEQUENCE_EDITOR': 'true'}, 'insert_args': ['--interactive']} endif return {} endfunction @@ -3784,7 +3804,7 @@ function! s:ToolParse(state, line) abort return [] endfunction -function! s:ToolStream(dir, line1, line2, range, bang, mods, args, state, title) abort +function! s:ToolStream(dir, line1, line2, range, bang, mods, options, args, state) abort let i = 0 let argv = copy(a:args) let prompt = 1 @@ -3818,9 +3838,10 @@ function! s:ToolStream(dir, line1, line2, range, bang, mods, args, state, title) let a:state.mode = 'init' let a:state.from = '' let a:state.to = '' - let exec = s:UserCommandList(a:dir) + ['--no-pager', '-c', 'diff.context=0', 'diff', '--no-ext-diff', '--no-color', '--no-prefix'] + argv + let exec = s:UserCommandList(a:dir) + ['-c', 'diff.context=0'] + a:options.flags + ['--no-pager', 'diff', '--no-ext-diff', '--no-color', '--no-prefix'] + argv if prompt - return s:QuickfixStream(a:line2, 'difftool', a:title, exec, !a:bang, s:function('s:ToolParse'), a:state) + let title = ':Git ' . s:fnameescape(a:options.flags + [a:options.command] + a:options.args) + return s:QuickfixStream(a:line2, 'difftool', title, exec, !a:bang, s:function('s:ToolParse'), a:state) else let filename = '' let cmd = [] @@ -3841,23 +3862,21 @@ function! s:ToolStream(dir, line1, line2, range, bang, mods, args, state, title) endif endfunction -function! s:MergetoolSubcommand(line1, line2, range, bang, mods, args) abort - let dir = s:Dir() +function! s:MergetoolSubcommand(line1, line2, range, bang, mods, options) abort + let dir = a:options.dir let i = 0 - let argv = copy(a:args) let prompt = 1 - let title = ':Git mergetool' . (len(a:args) ? ' ' . s:fnameescape(a:args) : '') let cmd = ['diff', '--diff-filter=U'] let state = {'name_only': 0} let state.diff = [{'prefix': ':2:', 'module': ':2:'}, {'prefix': ':3:', 'module': ':3:'}, {'prefix': ':(top)'}] call map(state.diff, 'extend(v:val, {"filename": fugitive#Find(v:val.prefix, dir)})') - return s:ToolStream(dir, a:line1, a:line2, a:range, a:bang, a:mods, ['--diff-filter=U'] + a:args, state, title) + return s:ToolStream(dir, a:line1, a:line2, a:range, a:bang, a:mods, a:options, ['--diff-filter=U'] + a:options.args, state) endfunction -function! s:DifftoolSubcommand(line1, line2, range, bang, mods, args) abort - let dir = s:Dir() +function! s:DifftoolSubcommand(line1, line2, range, bang, mods, options) abort + let dir = a:options.dir let i = 0 - let argv = copy(a:args) + let argv = copy(a:options.args) let commits = [] let cached = 0 let reverse = 1 @@ -3910,7 +3929,6 @@ function! s:DifftoolSubcommand(line1, line2, range, bang, mods, args) abort endif let i += 1 endwhile - let title = ':Git difftool' . (len(a:args) ? ' ' . s:fnameescape(a:args) : '') if len(merge_base_against) call add(commits, merge_base_against) endif @@ -3935,7 +3953,7 @@ function! s:DifftoolSubcommand(line1, line2, range, bang, mods, args) abort endif call map(commits, 'extend(v:val, {"filename": fugitive#Find(v:val.prefix, dir)})') let state.diff = commits - return s:ToolStream(dir, a:line1, a:line2, a:range, a:bang, a:mods, argv, state, title) + return s:ToolStream(dir, a:line1, a:line2, a:range, a:bang, a:mods, a:options, argv, state) endfunction " Section: :Ggrep, :Glog @@ -3983,8 +4001,8 @@ function! s:GrepParseLine(prefix, name_only, dir, line) abort return entry endfunction -function! s:GrepSubcommand(line1, line2, range, bang, mods, args) abort - let dir = s:Dir() +function! s:GrepSubcommand(line1, line2, range, bang, mods, options) abort + let dir = a:options.dir exe s:DirCheck(dir) let listnr = a:line1 == 0 ? a:line1 : a:line2 let cmd = ['--no-pager', 'grep', '-n', '--no-color', '--full-name'] @@ -3992,7 +4010,7 @@ function! s:GrepSubcommand(line1, line2, range, bang, mods, args) abort call add(cmd, '--column') endif let tree = s:Tree(dir) - let args = a:args + let args = a:options.args let name_only = s:HasOpt(args, '-l', '--files-with-matches', '--name-only', '-L', '--files-without-match') let title = [listnr < 0 ? ':Ggrep' : ':Glgrep'] + args if listnr > 0 @@ -4008,7 +4026,7 @@ function! s:GrepSubcommand(line1, line2, range, bang, mods, args) abort let prefix = FugitiveVimPath(s:HasOpt(args, '--cached') || empty(tree) ? \ 'fugitive://' . dir . '//0/' : \ s:cpath(getcwd(), tree) ? '' : tree . '/') - exe '!' . escape(s:UserCommand(dir, cmd + args), '%#!') + exe '!' . escape(s:UserCommand(dir, a:options.flags + cmd + args), '%#!') \ printf(&shellpipe . (&shellpipe =~# '%s' ? '' : ' %s'), s:shellesc(tempfile)) let list = map(readfile(tempfile), 's:GrepParseLine(prefix, name_only, dir, v:val)') call s:QuickfixSet(listnr, list, 'a') @@ -4310,11 +4328,11 @@ function! s:BlurStatus() abort endif endfunction -function! s:OpenExec(cmd, mods, args, ...) abort +function! s:OpenExec(cmd, mods, env, args, ...) abort let dir = a:0 ? s:Dir(a:1) : s:Dir() let temp = tempname() let columns = get(g:, 'fugitive_columns', 80) - let env = s:BuildEnvPrefix({'COLUMNS': columns}) + let env = s:BuildEnvPrefix(extend({'COLUMNS': columns}, a:env)) silent! execute '!' . escape(env . s:UserCommand(dir, ['--no-pager'] + a:args), '!#%') . \ (&shell =~# 'csh' ? ' >& ' . temp : ' > ' . temp . ' 2>&1') redraw! @@ -4336,7 +4354,7 @@ endfunction function! fugitive#Open(cmd, bang, mods, arg, args) abort if a:bang - return s:OpenExec(a:cmd, a:mods, s:SplitExpand(a:arg, s:Tree())) + return s:OpenExec(a:cmd, a:mods, {}, s:SplitExpand(a:arg, s:Tree())) endif let mods = s:Mods(a:mods) @@ -4571,14 +4589,14 @@ function! s:AskPassArgs(dir) abort return [] endfunction -function! s:Dispatch(bang, cmd, args) abort - let dir = s:Dir() +function! s:Dispatch(bang, options) abort + let dir = a:options.dir let [mp, efm, cc] = [&l:mp, &l:efm, get(b:, 'current_compiler', '')] try let b:current_compiler = 'git' let &l:errorformat = s:common_efm . \ ',%\&git_dir=' . escape(substitute(dir, '%', '%%', 'g'), '\,') - let &l:makeprg = s:UserCommand(dir, s:AskPassArgs(dir) + [a:cmd] + a:args) + let &l:makeprg = s:UserCommand(dir, s:AskPassArgs(dir) + a:options.flags + [a:options.command] + a:options.args) if exists(':Make') == 2 Make return '' @@ -4601,12 +4619,12 @@ function! s:Dispatch(bang, cmd, args) abort endtry endfunction -function! s:PushSubcommand(line1, line2, range, bang, mods, args) abort - return s:Dispatch(a:bang ? '!' : '', 'push', a:args) +function! s:PushSubcommand(line1, line2, range, bang, mods, options) abort + return s:Dispatch(a:bang ? '!' : '', a:options) endfunction -function! s:FetchSubcommand(line1, line2, range, bang, mods, args) abort - return s:Dispatch(a:bang ? '!' : '', 'fetch', a:args) +function! s:FetchSubcommand(line1, line2, range, bang, mods, options) abort + return s:Dispatch(a:bang ? '!' : '', a:options) endfunction " Section: :Gdiff @@ -5015,9 +5033,9 @@ function! fugitive#BlameComplete(A, L, P) abort return s:CompleteSub('blame', a:A, a:L, a:P) endfunction -function! s:BlameSubcommand(line1, count, range, bang, mods, args) abort +function! s:BlameSubcommand(line1, count, range, bang, mods, options) abort exe s:DirCheck() - let flags = copy(a:args) + let flags = copy(a:options.args) let i = 0 let raw = 0 let commits = [] @@ -5090,7 +5108,7 @@ function! s:BlameSubcommand(line1, count, range, bang, mods, args) abort endif exe s:BlameLeave() try - let cmd = ['--no-pager', '-c', 'blame.coloring=none', '-c', 'blame.blankBoundary=false', 'blame', '--show-number'] + let cmd = a:options.flags + ['--no-pager', '-c', 'blame.coloring=none', '-c', 'blame.blankBoundary=false', 'blame', '--show-number'] call extend(cmd, filter(copy(flags), 'v:val !~# "\\v^%(-b|--%(no-)=color-.*|--progress)$"')) if a:count > 0 && empty(ranges) let cmd += ['-L', (a:line1 ? a:line1 : line('.')) . ',' . (a:line1 ? a:line1 : line('.'))] @@ -5305,12 +5323,13 @@ function! s:BlameJump(suffix, ...) abort endif if exists(':Gblame') let my_bufnr = bufnr('') + let options = {'dir': s:Dir(), 'flags': [], 'command': 'blame', 'args': blame_args} if blame_bufnr < 0 let blame_args = flags + [commit . suffix, '--', path] - let result = s:BlameSubcommand(0, 0, 0, 0, '', blame_args) + let result = s:BlameSubcommand(0, 0, 0, 0, '', options) else let blame_args = flags - let result = s:BlameSubcommand(-1, -1, 0, 0, '', blame_args) + let result = s:BlameSubcommand(-1, -1, 0, 0, '', options) endif if bufnr('') == my_bufnr return result