Refine handling of pagination via temp buffer

Use temp buffer for output of any command for which the Git
configuration option of pager.<command> is true.  Avoid using a temp
buffer if the value is false, even for commands like "show" where we
normally would.  If the configuration value is present and can't be
interpreted as a Boolean, punt to a :terminal where Git will invoke it
directly.

Generate and use custom config dictionary that includes -c values passed
to :Git.  This enables `:Git -c pager.status status` to correctly use a
pager.

Paginate "config", "branch", and "tag" for certain argument lists,
matching the logic found in the Git source code as closely as possible.
These 3 commands were identified as having special pagination logic by
the presence of the DELAY_PAGER_CONFIG flag on their definitions in
git.c.

Paginate "am --show-current-patch".

References https://github.com/tpope/vim-fugitive/issues/1415
This commit is contained in:
Tim Pope
2020-02-18 19:44:49 -05:00
parent a81ba999e8
commit 2e67f82b79
2 changed files with 58 additions and 13 deletions

View File

@@ -2356,6 +2356,37 @@ augroup fugitive_job
\ endfor \ endfor
augroup END augroup END
function! fugitive#PagerFor(argv, ...) abort
let args = a:argv
if empty(args)
return 0
elseif (args[0] ==# 'help' || get(args, 1, '') ==# '--help') && !s:HasOpt(args, '--web')
return 1
endif
if args[0] ==# 'config' && (s:HasOpt(args, '-e', '--edit') ||
\ !s:HasOpt(args, '--list', '--get-all', '--get-regexp', '--get-urlmatch')) ||
\ args[0] =~# '^\%(tag\|branch\)$' && (s:HasOpt(args, '--edit-description', '--unset-upstream') ||
\ len(filter(args[1:-1], 'v:val =~# "^[^-]\|^--set-upstream-to="')) &&
\ !s:HasOpt(args, '--contains', '--no-contains', '--merged', '--no-merged', '--points-at'))
return 0
endif
let config = a:0 ? a:1 : fugitive#Config()
let value = get(FugitiveConfigGetAll('pager.' . args[0], config), 0, -1)
if value =~# '^\%(true\|yes\|on\|1\)$'
return 1
elseif value =~# '^\%(false\|no|off\|0\|\)$'
return 0
elseif type(value) == type('')
return value
elseif args[0] =~# 'diff\%(tool\)\@!\|log\|^show$\|^config$\|^branch$\|^tag$' ||
\ (args[0] ==# 'stash' && get(args, 1, '') ==# 'show') ||
\ (args[0] ==# 'am' && s:HasOpt(args, '--show-current-patch'))
return 1
else
return 0
endif
endfunction
let s:disable_colors = [] let s:disable_colors = []
for s:colortype in ['advice', 'branch', 'diff', 'grep', 'interactive', 'pager', 'push', 'remote', 'showBranch', 'status', 'transport', 'ui'] for s:colortype in ['advice', 'branch', 'diff', 'grep', 'interactive', 'pager', 'push', 'remote', 'showBranch', 'status', 'transport', 'ui']
call extend(s:disable_colors, ['-c', 'color.' . s:colortype . '=false']) call extend(s:disable_colors, ['-c', 'color.' . s:colortype . '=false'])
@@ -2363,6 +2394,7 @@ endfor
unlet s:colortype unlet s:colortype
function! fugitive#Command(line1, line2, range, bang, mods, arg) abort function! fugitive#Command(line1, line2, range, bang, mods, arg) abort
let dir = s:Dir() let dir = s:Dir()
let config = copy(fugitive#Config(dir))
let [args, after] = s:SplitExpandChain(a:arg, s:Tree(dir)) let [args, after] = s:SplitExpandChain(a:arg, s:Tree(dir))
let flags = [] let flags = []
while len(args) > 1 while len(args) > 1
@@ -2403,23 +2435,33 @@ function! fugitive#Command(line1, line2, range, bang, mods, arg) abort
while i < len(flags) - 1 while i < len(flags) - 1
if flags[i] ==# '-c' if flags[i] ==# '-c'
let i += 1 let i += 1
let config_name = matchstr(flags[i], '^[^=]\+\ze=') let config_name = tolower(matchstr(flags[i], '^[^=]\+'))
if has_key(s:prepare_env, config_name) if has_key(s:prepare_env, config_name) && flags[i] =~# '=.'
let env[s:prepare_env[config_name]] = matchstr(flags[i], '=\zs.*') let env[s:prepare_env[config_name]] = matchstr(flags[i], '=\zs.*')
endif endif
if !has_key(config, config_name)
let config[config_name] = []
endif
if flags[i] =~# '='
let config[config_name] = [matchstr(flags[i], '=\zs.*')] + config[config_name]
else
let config[config_name] = [1] + config[config_name]
endif
endif endif
let i += 1 let i += 1
endwhile endwhile
if a:bang || args[0] =~# '^-p$\|^--paginate$\|diff\%(tool\)\@!\|log\|^show$' || if args[0] =~# '^-p$\|^--paginate$'
\ (args[0] ==# 'stash' && get(args, 1, '') ==# 'show') || call remove(args, 0)
\ (args[0] ==# 'help' || get(args, 1, '') ==# '--help') && !s:HasOpt(args, '--web') let pager = 1
if args[0] =~# '^-p$\|^--paginate$' else
call remove(args, 0) let pager = fugitive#PagerFor(args, config)
endif endif
if a:bang || pager is# 1
return s:OpenExec((a:line2 > 0 ? a:line2 : '') . (a:line2 ? 'split' : 'edit'), a:mods, env, flags + args, dir) . after return s:OpenExec((a:line2 > 0 ? a:line2 : '') . (a:line2 ? 'split' : 'edit'), a:mods, env, flags + args, dir) . after
endif endif
if s:HasOpt(args, ['add', 'checkout', 'commit', 'stage', 'stash', 'reset'], '-p', '--patch') || if s:HasOpt(args, ['add', 'checkout', 'commit', 'stage', 'stash', 'reset'], '-p', '--patch') ||
\ s:HasOpt(args, ['add', 'clean', 'stage'], '-i', '--interactive') \ s:HasOpt(args, ['add', 'clean', 'stage'], '-i', '--interactive') ||
\ type(pager) == type('')
let mods = substitute(s:Mods(a:mods), '\<tab\>', '-tab', 'g') let mods = substitute(s:Mods(a:mods), '\<tab\>', '-tab', 'g')
let assign = len(dir) ? '|let b:git_dir = ' . string(dir) : '' let assign = len(dir) ? '|let b:git_dir = ' . string(dir) : ''
if has('nvim') if has('nvim')

View File

@@ -25,10 +25,12 @@ that are part of Git repositories).
resume running the command. A few Git subcommands resume running the command. A few Git subcommands
have different behavior; these are documented below. have different behavior; these are documented below.
:Git! {args} Run an arbitrary git command, capture output to a temp :Git --paginate {args} Run an arbitrary git command, capture output to a temp
:Git --paginate {args} file, and |:split| that temp file. Use :0Git to :Git -p {args} file, and |:split| that temp file. Use :0Git to
:Git -p {args} |:edit| the temp file instead. A temp file is always :G --paginate {args} |:edit| the temp file instead. A temp file is always
:G ... used for diff and log commands. :G -p {args} used for commands like diff and log that typically
user a pager, and for any command that has the
pager.<cmd> Git configuration option set.
*fugitive-summary* *fugitive-summary*
:Git With no arguments, bring up a summary window vaguely :Git With no arguments, bring up a summary window vaguely
@@ -630,6 +632,7 @@ just one space character longer than the legacy version.
*:Gfetch* Superseded by |:Git-fetch|. *:Gfetch* Superseded by |:Git-fetch|.
*:Glog* Superseded by |:Gclog|. *:Glog* Superseded by |:Gclog|.
*:Gstatus* Superseded by |:Git| (with no arguments). *:Gstatus* Superseded by |:Git| (with no arguments).
*:Git!* Superseded by |:Git| --paginate.
*:Gsplit!* Superseded by |:Git| --paginate. *:Gsplit!* Superseded by |:Git| --paginate.
*:Gvsplit!* Superseded by |:vert| |:Git| --paginate. *:Gvsplit!* Superseded by |:vert| |:Git| --paginate.
*:Gtabsplit!* Superseded by |:tab| |:Git| --paginate. *:Gtabsplit!* Superseded by |:tab| |:Git| --paginate.