diff --git a/doc/fugitive.txt b/doc/fugitive.txt index e6b5e2f..3c90e8a 100644 --- a/doc/fugitive.txt +++ b/doc/fugitive.txt @@ -50,7 +50,19 @@ that are part of Git repositories). *fugitive-:Gstatus* :Gstatus Bring up the output of git status in the preview window. Press - to stage or unstage the file on the - cursor line. + cursor line. Press C to invoke |:Gcommit|. + + *fugitive-:Gcommit* +:Gcommit [args] A wrapper around git-commit. If there is nothing + to commit, |:Gstatus| is called instead. Unless the + arguments given would skip the invocation of an editor + (e.g., -m), a split window will be used to obtain a + commit message. Write and close that window (:wq or + |:Gwrite|) to finish the commit. Unlike when running + the actual git-commit command, it is possible (but + unadvisable) to muck with the index with commands like + git-add and git-reset while a commit message is + pending. *fugitive-:Ggrep* :Ggrep [args] |:grep| with git-grep as 'grepprg'. diff --git a/plugin/fugitive.vim b/plugin/fugitive.vim index 458425d..7f3f987 100644 --- a/plugin/fugitive.vim +++ b/plugin/fugitive.vim @@ -512,6 +512,9 @@ function! s:StageToggle(lnum1,lnum2) abort let output = '' for lnum in range(a:lnum1,a:lnum2) let line = getline(lnum) + if getline('.') == '# Changes to be committed:' + return 'Gcommit' + endif let filename = matchstr(line,'^#\t[[:alpha:] ]\+: *\zs.*') if filename ==# '' let filename = matchstr(line,'^#\t\zs.*') @@ -549,6 +552,91 @@ function! s:StageToggle(lnum1,lnum2) abort return 'checktime' endfunction +" }}}1 +" Gcommit {{{1 + +call s:command("-nargs=? -complete=customlist,s:CommitComplete Gcommit :execute s:Commit()") + +function! s:Commit(args) abort + let old_type = s:buffer().type() + let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' + let cd .= s:fnameescape(getcwd()) + let msgfile = s:repo().dir('COMMIT_EDITMSG') + let outfile = tempname() + let errorfile = tempname() + try + cd `=s:repo().tree()` + let command = 'GIT_EDITOR=false '.s:repo().git_command('commit').' '.a:args + if a:args =~# '\%(^\| \)--interactive\>' + execute '!'.command.' 2> '.errorfile + else + silent execute '!'.command.' > '.outfile.' 2> '.errorfile + end + if !v:shell_error + if filereadable(outfile) + for line in readfile(outfile) + echo line + endfor + endif + return '' + else + let error = get(readfile(errorfile,'',1),0,'!') + if error =~# "'false'\\.$" + let args = a:args + let args = s:gsub(args,'%(%(^| )-- )@' + let args = '--cleanup=strip '.args + endif + split `=msgfile` + if old_type ==# 'index' + bdelete # + endif + let b:fugitive_commit_arguments = args + setlocal bufhidden=delete filetype=gitcommit + return '1' + elseif error ==# '!' + return s:Status() + else + call s:throw(error) + endif + endif + catch /^fugitive:/ + return 'echoerr v:errmsg' + finally + call delete(outfile) + call delete(errorfile) + exe cd + call fugitive#reload_status() + endtry +endfunction + +function! s:CommitComplete(A,L,P) abort + if a:A =~ '^-' || type(a:A) == type(0) " a:A is 0 on :Gcommit - + let args = ['-C', '-F', '-a', '-c', '-e', '-i', '-m', '-n', '-o', '-q', '-s', '-t', '-u', '-v', '--all', '--allow-empty', '--amend', '--author=', '--cleanup=', '--dry-run', '--edit', '--file=', '--include', '--interactive', '--message=', '--no-verify', '--only', '--quiet', '--reedit-message=', '--reuse-message=', '--signoff', '--template=', '--untracked-files', '--verbose'] + return filter(args,'v:val[0 : strlen(a:A)-1] ==# a:A') + else + return s:repo().superglob(a:A) + endif +endfunction + +function! s:FinishCommit() + let args = getbufvar(+expand(''),'fugitive_commit_arguments') + let g:args = args + if !empty(args) + call setbufvar(+expand(''),'fugitive_commit_arguments','') + return s:Commit(args) + endif + return '' +endfunction + +augroup fugitive_commit + autocmd! + autocmd BufDelete *.git/COMMIT_EDITMSG execute s:sub(s:FinishCommit(), '^echoerr (.*)', 'echohl ErrorMsg|echo \1|echohl NONE') +augroup END + " }}}1 " Ggrep, Glog {{{1 @@ -675,6 +763,11 @@ call s:command("-bar -bang -nargs=? -count -complete=customlist,s:EditComplete G call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Gwrite :execute s:Write(0,)") function! s:Write(force,...) abort + if exists('b:fugitive_commit_arguments') + return 'write|bdelete' + elseif expand('%:t') == 'COMMIT_EDITMSG' && $GIT_INDEX_FILE != '' + return 'wq' + endif let mytab = tabpagenr() let mybufnr = bufnr('') let path = a:0 ? a:1 : s:buffer().path() @@ -1092,6 +1185,7 @@ function! s:BufReadIndex() nnoremap - :execute StageToggle(line('.'),line('.')+v:count1-1) xnoremap - :execute StageToggle(line("'<"),line("'>")) call s:JumpInit() + nnoremap C :Gcommit catch /^fugitive:/ return 'echoerr v:errmsg' endtry