From c989c1f59ea00a2fe719e37eb782a4eb95c430e9 Mon Sep 17 00:00:00 2001 From: Tim Pope Date: Mon, 20 Jan 2020 08:25:58 -0500 Subject: [PATCH] Replace :Grebase/:Gmerge/:Gpull with standard job runner --- autoload/fugitive.vim | 296 ++++++------------------------------------ doc/fugitive.txt | 27 ++-- 2 files changed, 49 insertions(+), 274 deletions(-) diff --git a/autoload/fugitive.vim b/autoload/fugitive.vim index 782695f..2c2d0aa 100644 --- a/autoload/fugitive.vim +++ b/autoload/fugitive.vim @@ -257,6 +257,25 @@ function! s:QuickfixStream(nr, event, title, cmd, first, callback, ...) abort endif endfunction +let s:common_efm = '' + \ . '%+Egit:%.%#,' + \ . '%+Eusage:%.%#,' + \ . '%+Eerror:%.%#,' + \ . '%+Efatal:%.%#,' + \ . '%-G%.%#%\e[K%.%#,' + \ . '%-G%.%#%\r%.%\+' + +function! fugitive#Cwindow() abort + if &buftype == 'quickfix' + cwindow + else + botright cwindow + if &buftype == 'quickfix' + wincmd p + endif + endif +endfunction + " Section: Git function! s:UserCommandList(...) abort @@ -1630,6 +1649,20 @@ function! s:AddSection(label, lines, ...) abort call append(line('$'), ['', a:label . (len(note) ? ': ' . note : ' (' . len(a:lines) . ')')] + s:Format(a:lines)) endfunction +let s:rebase_abbrevs = { + \ 'p': 'pick', + \ 'r': 'reword', + \ 'e': 'edit', + \ 's': 'squash', + \ 'f': 'fixup', + \ 'x': 'exec', + \ 'd': 'drop', + \ 'l': 'label', + \ 't': 'reset', + \ 'm': 'merge', + \ 'b': 'break', + \ } + function! fugitive#BufReadStatus() abort let amatch = s:Slash(expand('%:p')) let b:fugitive_type = 'index' @@ -3701,10 +3734,6 @@ function! s:FinishCommit() abort let args = getbufvar(buf, 'fugitive_commit_arguments') if !empty(args) call setbufvar(buf, 'fugitive_commit_arguments', []) - if getbufvar(buf, 'fugitive_commit_rebase') - call setbufvar(buf, 'fugitive_commit_rebase', 0) - let s:rebase_continue = [s:Dir(buf), 0] - endif return s:CommitSubcommand(-1, -1, 0, 0, '', args, s:Dir(buf)) endif return '' @@ -3724,227 +3753,6 @@ function! fugitive#PullComplete(A, L, P) abort return s:CompleteSub('pull', a:A, a:L, a:P, function('s:CompleteRemote')) endfunction -function! s:RebaseSequenceAborter() abort - return s:TempScript('echo exec false | cat - "$1" > "$1.fugitive"', 'mv "$1.fugitive" "$1"') -endfunction - -function! fugitive#Cwindow() abort - if &buftype == 'quickfix' - cwindow - else - botright cwindow - if &buftype == 'quickfix' - wincmd p - endif - endif -endfunction - -let s:common_efm = '' - \ . '%+Egit:%.%#,' - \ . '%+Eusage:%.%#,' - \ . '%+Eerror:%.%#,' - \ . '%+Efatal:%.%#,' - \ . '%-G%.%#%\e[K%.%#,' - \ . '%-G%.%#%\r%.%\+' - -let s:rebase_abbrevs = { - \ 'p': 'pick', - \ 'r': 'reword', - \ 'e': 'edit', - \ 's': 'squash', - \ 'f': 'fixup', - \ 'x': 'exec', - \ 'd': 'drop', - \ 'l': 'label', - \ 't': 'reset', - \ 'm': 'merge', - \ 'b': 'break', - \ } - -function! s:RebaseEdit(cmd, dir) abort - let rebase_todo = s:fnameescape(fugitive#Find('.git/rebase-merge/git-rebase-todo', a:dir)) - - if filereadable(rebase_todo) - let new = readfile(rebase_todo) - let sha_length = 0 - let shas = {} - - for i in range(len(new)) - if new[i] =~# '^\l\+\s\+[0-9a-f]\{5,\}\>' - let sha = matchstr(new[i], '\C\<[a-f0-9]\{5,\}\>') - if !sha_length - let sha_length = len(s:TreeChomp(a:dir, 'rev-parse', '--short', sha)) - endif - let shortened_sha = strpart(sha, 0, sha_length) - let shas[shortened_sha] = sha - let new[i] = substitute(new[i], sha, shortened_sha, '') - endif - endfor - call writefile(new, rebase_todo) - endif - return a:cmd . ' +setlocal\ bufhidden=wipe\|' . escape('let b:fugitive_rebase_shas = ' . string(shas), ' ') . ' ' . rebase_todo -endfunction - -function! s:MergeRebase(cmd, bang, mods, args, ...) abort - let dir = a:0 ? a:1 : s:Dir() - let args = a:args - let mods = s:Mods(a:mods) - if a:cmd =~# '^rebase' && s:HasOpt(args, '-i', '--interactive') - let cmd = fugitive#Prepare(dir, '-c', 'sequence.editor=sh ' . s:RebaseSequenceAborter(), 'rebase') . ' ' . s:shellesc(args) - let out = system(cmd)[0:-2] - for file in ['end', 'msgnum'] - let file = fugitive#Find('.git/rebase-merge/' . file, dir) - if !filereadable(file) - return 'echoerr ' . string("fugitive: " . out) - endif - call writefile([readfile(file)[0] - 1], file) - endfor - call writefile([], fugitive#Find('.git/rebase-merge/done', dir)) - if a:bang - return 'exe' - endif - return s:RebaseEdit(mods . 'split', dir) - elseif a:cmd =~# '^rebase' && s:HasOpt(args, '--edit-todo') && filereadable(fugitive#Find('.git/rebase-merge/git-rebase-todo', dir)) - return s:RebaseEdit(mods . 'split', dir) - elseif a:cmd =~# '^rebase' && s:HasOpt(args, '--continue') && !a:0 - let rdir = fugitive#Find('.git/rebase-merge', dir) - let exec_error = s:ChompError([dir, 'diff-index', '--cached', '--quiet', 'HEAD', '--'])[1] - if exec_error && isdirectory(rdir) - if getfsize(rdir . '/amend') <= 0 - return 'exe ' . string(mods . 'Gcommit -n -F ' . s:fnameescape(rdir .'/message') . ' -e') . '|let b:fugitive_commit_rebase = 1' - elseif readfile(rdir . '/amend')[0] ==# fugitive#Head(-1, dir) - return 'exe ' . string(mods . 'Gcommit --amend -n -F ' . s:fnameescape(rdir . '/message') . ' -e') . '|let b:fugitive_commit_rebase = 1' - endif - endif - endif - let had_merge_msg = filereadable(fugitive#Find('.git/MERGE_MSG', dir)) - let argv = [] - if a:cmd ==# 'pull' - let argv += s:AskPassArgs(dir) + ['pull', '--progress'] - else - call add(argv, a:cmd) - endif - if !s:HasOpt(args, '--no-edit', '--abort', '-m') && a:cmd !=# 'rebase' - call add(argv, '--edit') - endif - if a:cmd ==# 'rebase' && s:HasOpt(args, '--autosquash') && !s:HasOpt(args, '--interactive', '-i') - call add(argv, '--interactive') - endif - call extend(argv, args) - - let [mp, efm] = [&l:mp, &l:efm] - try - let cdback = s:Cd(s:Tree(dir)) - let &l:errorformat = '' - \ . '%-Gerror:%.%#false''.,' - \ . '%-G%.%# ''git commit'' %.%#,' - \ . '%+Emerge:%.%#,' - \ . s:common_efm . ',' - \ . '%+ECannot %.%#: You have unstaged changes.,' - \ . '%+ECannot %.%#: Your index contains uncommitted changes.,' - \ . '%+EThere is no tracking information for the current branch.,' - \ . '%+EYou are not currently on a branch. Please specify which,' - \ . '%+I %#git rebase --continue,' - \ . 'CONFLICT (%m): %f deleted in %.%#,' - \ . 'CONFLICT (%m): Merge conflict in %f,' - \ . 'CONFLICT (%m): Rename \"%f\"->%.%#,' - \ . 'CONFLICT (%m): Rename %.%#->%f %.%#,' - \ . 'CONFLICT (%m): There is a directory with name %f in %.%#,' - \ . '%+ECONFLICT %.%#,' - \ . '%+EKONFLIKT %.%#,' - \ . '%+ECONFLIT %.%#,' - \ . "%+EXUNG \u0110\u1ed8T %.%#," - \ . "%+E\u51b2\u7a81 %.%#," - \ . 'U%\t%f' - let cmd = s:UserCommand(dir, argv) - if !empty($GIT_SEQUENCE_EDITOR) || has('win32') - let old_sequence_editor = $GIT_SEQUENCE_EDITOR - let $GIT_SEQUENCE_EDITOR = 'true' - else - let cmd = 'env GIT_SEQUENCE_EDITOR=true ' . cmd - endif - if !empty($GIT_EDITOR) || has('win32') - let old_editor = $GIT_EDITOR - let $GIT_EDITOR = 'false' - else - let cmd = 'env GIT_EDITOR=false ' . substitute(cmd, '^env ', '', '') - endif - if !has('patch-8.1.0334') && has('terminal') && &autowrite - let autowrite_was_set = 1 - set noautowrite - silent! wall - endif - let &l:makeprg = cmd - silent noautocmd make! - catch /^Vim\%((\a\+)\)\=:E211/ - let err = v:exception - finally - if exists('autowrite_was_set') - set autowrite - endif - redraw! - let [&l:mp, &l:efm] = [mp, efm] - if exists('old_editor') - let $GIT_EDITOR = old_editor - endif - if exists('old_sequence_editor') - let $GIT_SEQUENCE_EDITOR = old_sequence_editor - endif - execute cdback - endtry - call fugitive#ReloadStatus(dir, 1) - if empty(filter(getqflist(),'v:val.valid && v:val.type !=# "I"')) - if a:cmd =~# '^rebase' && - \ filereadable(fugitive#Find('.git/rebase-merge/done', dir)) && - \ get(readfile(fugitive#Find('.git/rebase-merge/done', dir)), -1, '') =~# '^[^bep]' - cclose - let amend = filereadable(fugitive#Find('.git/rebase-merge/amend', dir)) ? '--amend ' : '' - return 'exe ' . string(mods . 'Gcommit ' . amend . '-n -F ' . s:fnameescape(fugitive#Find('.git/rebase-merge/message', dir)) . ' -e') . '|let b:fugitive_commit_rebase = 1' - elseif !had_merge_msg && filereadable(fugitive#Find('.git/MERGE_MSG', dir)) - cclose - return mods . 'Gcommit --no-status -n -t '.s:fnameescape(fugitive#Find('.git/MERGE_MSG', dir)) - endif - endif - let qflist = getqflist() - let found = 0 - for e in qflist - if !empty(e.bufnr) - let found = 1 - let e.pattern = '^<<<<<<<' - endif - endfor - call fugitive#Cwindow() - if found - call setqflist(qflist, 'r') - if !a:bang - call s:BlurStatus() - return 'cfirst' - endif - endif - return exists('err') ? 'echoerr '.string(err) : 'exe' -endfunction - -function! s:RebaseClean(file) abort - if !filereadable(a:file) - return '' - endif - let old = readfile(a:file) - let new = copy(old) - for i in range(len(new)) - let new[i] = substitute(new[i], '^\l\>', '\=get(s:rebase_abbrevs,submatch(0),submatch(0))', '') - - let sha = matchstr(new[i], '\C\<[a-f0-9]\{5,\}\>') - let rebase_shas = getbufvar(a:file, 'fugitive_rebase_shas') - if len(sha) && type(rebase_shas) == type({}) && has_key(rebase_shas, sha) - let new[i] = substitute(new[i], '\C\<' . sha . '\>', rebase_shas[sha], '') - endif - endfor - if new !=# old - call writefile(new, a:file) - endif - return '' -endfunction - function! s:MergeSubcommand(line1, line2, range, bang, mods, args) abort let dir = s:Dir() if empty(a:args) && ( @@ -3953,44 +3761,16 @@ function! s:MergeSubcommand(line1, line2, range, bang, mods, args) abort \ !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' endif - return s:MergeRebase('merge', a:bang, a:mods, a:args) + return {} endfunction function! s:RebaseSubcommand(line1, line2, range, bang, mods, args) abort - return s:MergeRebase('rebase', a:bang, a:mods, a:args) + if s:HasOpt(a:args, '--autosquash') && !s:HasOpt(a:args, '-i', '--interactive') + return {'env': {'GIT_SEQUENCE_EDITOR': 'true'}, 'args': ['rebase', '--interactive'] + a:args} + endif + return {} endfunction -function! s:PullSubcommand(line1, line2, range, bang, mods, args) abort - return s:MergeRebase('pull', a:bang, a:mods, a:args) -endfunction - -function! s:RebaseContinue(arg, ...) abort - let [dir, edit_todo] = a:arg - exe s:MergeRebase('rebase', 0, '', [edit_todo && getfsize(fugitive#Find('.git/rebase-merge/git-rebase-todo', dir)) <= 0 ? '--abort' : '--continue'], dir) -endfunction - -augroup fugitive_merge - autocmd! - autocmd VimLeavePre,BufDelete git-rebase-todo - \ if type(getbufvar(+expand(''), 'fugitive_rebase_shas')) == type({}) && getbufvar(+expand(''), '&bufhidden') ==# 'wipe' | - \ if exists('*job_start') | - \ throw 'this should never be called' | - \ endif | - \ call s:RebaseClean(expand('')) | - \ if getfsize(FugitiveFind('.git/rebase-merge/done', +expand(''))) == 0 | - \ let s:rebase_continue = [FugitiveGitDir(+expand('')), 1] | - \ endif | - \ endif - autocmd BufEnter * nested - \ if exists('s:rebase_continue') | - \ if has('timers') | - \ call timer_start(0, function('s:RebaseContinue', [remove(s:, 'rebase_continue')])) | - \ else | - \ call s:RebaseContinue(remove(s:, 'rebase_continue')) | - \ endif | - \ endif -augroup END - " Section: :Git difftool, :Git mergetool function! s:ToolItems(state, from, to, offsets, text, ...) abort diff --git a/doc/fugitive.txt b/doc/fugitive.txt index 267c993..31335bb 100644 --- a/doc/fugitive.txt +++ b/doc/fugitive.txt @@ -45,22 +45,6 @@ that are part of Git repositories). :Git revert [args] A wrapper around git-revert. Similar to |:Gcommit|. :Grevert [args] - *:Git-merge* *:Gmerge* -:Git merge [args] Calls git-merge and loads errors and conflicted files -:Gmerge [args] into the |quickfix| list. Opens a |:Gcommit| style - split window for the commit message if the merge - succeeds. If called during a merge conflict, the - conflicted files from the current index are loaded - into the |quickfix| list. - - *:Git-pull* *:Gpull* -:Git pull [args] Like |:Gmerge|, but for git-pull. -:Gpull [args] - - *:Git-rebase* *:Grebase* -:Git rebase [args] Like |:Gmerge|, but for git-rebase. Interactive -:Grebase [args] rebase is experimentally supported. - *:Git-push* *:Gpush* :Git push [args] Invoke git-push, load the results into the |quickfix| :Gpush [args] list, and invoke |:cwindow| to reveal any errors. @@ -119,6 +103,17 @@ that are part of Git repositories). *:Git-mergetool* :Git mergetool [args] Like |:Git-difftool|, but target merge conflicts. + *:Git-merge* *:Gmerge* +:Gmerge [args] Deprecated alias for |:Git| merge. Use |:Git-mergetool| + to get the old behavior of loading merge conflicts + into the quickfix list. + + *:Git-pull* *:Gpull* +:Gpull [args] Deprecated alias for |:Git| pull. + + *:Git-rebase* *:Grebase* +:Grebase [args] Deprecated alias for |:Git| rebase. + *:Gclog* *:Glog* :Gclog[!] [args] Use git-log [args] to load the commit history into the :Glog[!] [args] |quickfix| list. Jumps to the first commit unless [!]