Add :Git! et al. for loading output into a buffer

This commit is contained in:
Tim Pope 2011-08-19 02:43:31 -04:00
parent dd52642d13
commit 7005789427
3 changed files with 87 additions and 27 deletions

View File

@ -43,7 +43,8 @@ GitHub, `git instaweb` will be spun up instead.
Add `%{fugitive#statusline()}` to `'statusline'` to get an indicator Add `%{fugitive#statusline()}` to `'statusline'` to get an indicator
with the current branch in (surprise!) your statusline. with the current branch in (surprise!) your statusline.
Oh, and of course there's `:Git` for running any arbitrary command. Last but not least, there's `:Git` for running any arbitrary command,
and `Git!` to open the output of a command in a temp file.
Screencasts Screencasts
----------- -----------

View File

@ -19,6 +19,10 @@ that are part of Git repositories).
:Git [args] Run an arbitrary git command. Similar to :!git [args] :Git [args] Run an arbitrary git command. Similar to :!git [args]
but chdir to the repository tree first. but chdir to the repository tree first.
*fugitive-:Git!*
:Git! [args] Like |:Git|, but capture the output into a temp file,
and edit that temp file.
*fugitive-:Gcd* *fugitive-:Gcd*
:Gcd [directory] |:cd| relative to the repository. :Gcd [directory] |:cd| relative to the repository.
@ -78,10 +82,15 @@ that are part of Git repositories).
:Gvsplit [revision] |:vsplit| a |fugitive-revision|. :Gvsplit [revision] |:vsplit| a |fugitive-revision|.
*fugitive-:Gtabedit* *fugitive-:Gtabedit*
:Gtabedit [revision] |:tabedit| a |fugitive-revision| :Gtabedit [revision] |:tabedit| a |fugitive-revision|.
*fugitive-:Gpedit* *fugitive-:Gpedit*
:Gpedit [revision] |:pedit| a |fugitive-revision| :Gpedit [revision] |:pedit| a |fugitive-revision|.
:Gsplit! [args] *fugitive-:Gsplit!* *fugitive-:Gvsplit!*
:Gvsplit! [args] *fugitive-:Gtabedit!* *fugitive-:Gpedit!*
:Gtabedit! [args] Like |:Git!|, but open the resulting temp file in a
:Gpedit! [args] split, tab, or preview window.
*fugitive-:Gread* *fugitive-:Gread*
:Gread [revision] Empty the buffer and |:read| a |fugitive-revision|. :Gread [revision] Empty the buffer and |:read| a |fugitive-revision|.
@ -92,6 +101,12 @@ that are part of Git repositories).
:{range}Gread [revision] :{range}Gread [revision]
|:read| in a |fugitive-revision| after {range}. |:read| in a |fugitive-revision| after {range}.
*fugitive-:Gread!*
:Gread! [args] Empty the buffer and |:read| the output of a Git
command. For example, :Gread! show HEAD:%.
:{range}Gread! [args] |:read| the output of a Git command after {range}.
*fugitive-:Gwrite* *fugitive-:Gwrite*
:Gwrite Write to the current file's path and stage the results. :Gwrite Write to the current file's path and stage the results.
When run in a work tree file, it is effectively git When run in a work tree file, it is effectively git

View File

@ -497,6 +497,9 @@ function! s:ExecuteInTree(cmd) abort
endfunction endfunction
function! s:Git(bang,cmd) abort function! s:Git(bang,cmd) abort
if a:bang
return s:Edit('edit',1,a:cmd)
endif
let git = s:repo().git_command() let git = s:repo().git_command()
if has('gui_running') && !has('win32') if has('gui_running') && !has('win32')
let git .= ' --no-pager' let git .= ' --no-pager'
@ -897,7 +900,7 @@ endfunction
" }}}1 " }}}1
" Gedit, Gpedit, Gsplit, Gvsplit, Gtabedit, Gread {{{1 " Gedit, Gpedit, Gsplit, Gvsplit, Gtabedit, Gread {{{1
function! s:Edit(cmd,...) abort function! s:Edit(cmd,bang,...) abort
if a:cmd !~# 'read' if a:cmd !~# 'read'
if &previewwindow && getbufvar('','fugitive_type') ==# 'index' if &previewwindow && getbufvar('','fugitive_type') ==# 'index'
wincmd p wincmd p
@ -914,6 +917,36 @@ function! s:Edit(cmd,...) abort
endif endif
endif endif
if a:bang
let args = s:gsub(a:0 ? a:1 : '', '\\@<!%(\\\\)*\zs[%#]', '\=s:buffer().expand(submatch(0))')
if a:cmd =~# 'read'
let git = s:repo().git_command()
let last = line('$')
silent call s:ExecuteInTree((a:cmd ==# 'read' ? '$read' : a:cmd).'!'.git.' --no-pager '.args)
if a:cmd ==# 'read'
silent execute '1,'.last.'delete_'
endif
call fugitive#reload_status()
diffupdate
return 'redraw|echo '.string(':!'.git.' '.args)
else
let temp = tempname()
let s:temp_files[temp] = s:repo().dir()
silent execute a:cmd.' '.temp
if a:cmd =~# 'pedit'
wincmd P
endif
let echo = s:Edit('read',1,args)
silent write!
setlocal readonly nomodified nomodifiable filetype=git foldmarker=<<<<<<<,>>>>>>>
if a:cmd =~# 'pedit'
wincmd p
endif
return echo
endif
return ''
endif
if a:0 && a:1 == '' if a:0 && a:1 == ''
return '' return ''
elseif a:0 elseif a:0
@ -936,16 +969,20 @@ function! s:Edit(cmd,...) abort
endfunction endfunction
function! s:EditComplete(A,L,P) abort function! s:EditComplete(A,L,P) abort
return s:repo().superglob(a:A) if a:L =~# '^\w\+!'
return s:GitComplete(a:A,a:L,a:P)
else
return s:repo().superglob(a:A)
endif
endfunction endfunction
call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Ge :execute s:Edit('edit<bang>',<f-args>)") call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Ge :execute s:Edit('edit<bang>',0,<f-args>)")
call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Gedit :execute s:Edit('edit<bang>',<f-args>)") call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Gedit :execute s:Edit('edit<bang>',0,<f-args>)")
call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Gpedit :execute s:Edit('pedit<bang>',<f-args>)") call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Gpedit :execute s:Edit('pedit',<bang>0,<f-args>)")
call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Gsplit :execute s:Edit('split<bang>',<f-args>)") call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Gsplit :execute s:Edit('split',<bang>0,<f-args>)")
call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Gvsplit :execute s:Edit('vsplit<bang>',<f-args>)") call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Gvsplit :execute s:Edit('vsplit',<bang>0,<f-args>)")
call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Gtabedit :execute s:Edit('tabedit<bang>',<f-args>)") call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Gtabedit :execute s:Edit('tabedit',<bang>0,<f-args>)")
call s:command("-bar -bang -nargs=? -count -complete=customlist,s:EditComplete Gread :execute s:Edit((!<count> && <line1> ? '' : <count>).'read<bang>',<f-args>)") call s:command("-bar -bang -nargs=? -count -complete=customlist,s:EditComplete Gread :execute s:Edit((!<count> && <line1> ? '' : <count>).'read',<bang>0,<f-args>)")
" }}}1 " }}}1
" Gwrite, Gwq {{{1 " Gwrite, Gwq {{{1
@ -1917,15 +1954,18 @@ function! s:GF(mode) abort
try try
let buffer = s:buffer() let buffer = s:buffer()
let myhash = buffer.sha1() let myhash = buffer.sha1()
if myhash ==# '' && getline(1) =~# '^\%(commit\|tag\) \w'
let myhash = matchstr(getline(1),'^\w\+ \zs\S\+')
endif
if buffer.type('tree') if buffer.type('tree')
let showtree = (getline(1) =~# '^tree ' && getline(2) == "") let showtree = (getline(1) =~# '^tree ' && getline(2) == "")
if showtree && line('.') == 1 if showtree && line('.') == 1
return "" return ""
elseif showtree && line('.') > 2 elseif showtree && line('.') > 2
return s:Edit(a:mode,buffer.commit().':'.s:buffer().path().(buffer.path() =~# '^$\|/$' ? '' : '/').s:sub(getline('.'),'/$','')) return s:Edit(a:mode,0,buffer.commit().':'.s:buffer().path().(buffer.path() =~# '^$\|/$' ? '' : '/').s:sub(getline('.'),'/$',''))
elseif getline('.') =~# '^\d\{6\} \l\{3,8\} \x\{40\}\t' elseif getline('.') =~# '^\d\{6\} \l\{3,8\} \x\{40\}\t'
return s:Edit(a:mode,buffer.commit().':'.s:buffer().path().(buffer.path() =~# '^$\|/$' ? '' : '/').s:sub(matchstr(getline('.'),'\t\zs.*'),'/$','')) return s:Edit(a:mode,0,buffer.commit().':'.s:buffer().path().(buffer.path() =~# '^$\|/$' ? '' : '/').s:sub(matchstr(getline('.'),'\t\zs.*'),'/$',''))
endif endif
elseif buffer.type('blob') elseif buffer.type('blob')
@ -1935,7 +1975,7 @@ function! s:GF(mode) abort
catch /^fugitive:/ catch /^fugitive:/
endtry endtry
if exists('sha1') if exists('sha1')
return s:Edit(a:mode,ref) return s:Edit(a:mode,0,ref)
endif endif
else else
@ -1944,29 +1984,29 @@ function! s:GF(mode) abort
if getline('.') =~# '^\d\{6\} \x\{40\} \d\t' if getline('.') =~# '^\d\{6\} \x\{40\} \d\t'
let ref = matchstr(getline('.'),'\x\{40\}') let ref = matchstr(getline('.'),'\x\{40\}')
let file = ':'.s:sub(matchstr(getline('.'),'\d\t.*'),'\t',':') let file = ':'.s:sub(matchstr(getline('.'),'\d\t.*'),'\t',':')
return s:Edit(a:mode,file) return s:Edit(a:mode,0,file)
elseif getline('.') =~# '^#\trenamed:.* -> ' elseif getline('.') =~# '^#\trenamed:.* -> '
let file = '/'.matchstr(getline('.'),' -> \zs.*') let file = '/'.matchstr(getline('.'),' -> \zs.*')
return s:Edit(a:mode,file) return s:Edit(a:mode,0,file)
elseif getline('.') =~# '^#\t[[:alpha:] ]\+: *.' elseif getline('.') =~# '^#\t[[:alpha:] ]\+: *.'
let file = '/'.matchstr(getline('.'),': *\zs.\{-\}\ze\%( (new commits)\)\=$') let file = '/'.matchstr(getline('.'),': *\zs.\{-\}\ze\%( (new commits)\)\=$')
return s:Edit(a:mode,file) return s:Edit(a:mode,0,file)
elseif getline('.') =~# '^#\t.' elseif getline('.') =~# '^#\t.'
let file = '/'.matchstr(getline('.'),'#\t\zs.*') let file = '/'.matchstr(getline('.'),'#\t\zs.*')
return s:Edit(a:mode,file) return s:Edit(a:mode,0,file)
elseif getline('.') =~# ': needs merge$' elseif getline('.') =~# ': needs merge$'
let file = '/'.matchstr(getline('.'),'.*\ze: needs merge$') let file = '/'.matchstr(getline('.'),'.*\ze: needs merge$')
return s:Edit(a:mode,file).'|Gdiff' return s:Edit(a:mode,0,file).'|Gdiff'
elseif getline('.') ==# '# Not currently on any branch.' elseif getline('.') ==# '# Not currently on any branch.'
return s:Edit(a:mode,'HEAD') return s:Edit(a:mode,0,'HEAD')
elseif getline('.') =~# '^# On branch ' elseif getline('.') =~# '^# On branch '
let file = 'refs/heads/'.getline('.')[12:] let file = 'refs/heads/'.getline('.')[12:]
return s:Edit(a:mode,file) return s:Edit(a:mode,0,file)
elseif getline('.') =~# "^# Your branch .*'" elseif getline('.') =~# "^# Your branch .*'"
let file = matchstr(getline('.'),"'\\zs\\S\\+\\ze'") let file = matchstr(getline('.'),"'\\zs\\S\\+\\ze'")
return s:Edit(a:mode,file) return s:Edit(a:mode,0,file)
endif endif
let showtree = (getline(1) =~# '^tree ' && getline(2) == "") let showtree = (getline(1) =~# '^tree ' && getline(2) == "")
@ -1974,6 +2014,10 @@ function! s:GF(mode) abort
if getline('.') =~# '^ref: ' if getline('.') =~# '^ref: '
let ref = strpart(getline('.'),5) let ref = strpart(getline('.'),5)
elseif getline('.') =~# '^commit \x\{40\}\>'
let ref = matchstr(getline('.'),'\x\{40\}')
return s:Edit(a:mode,0,ref)
elseif getline('.') =~# '^parent \x\{40\}\>' elseif getline('.') =~# '^parent \x\{40\}\>'
let ref = matchstr(getline('.'),'\x\{40\}') let ref = matchstr(getline('.'),'\x\{40\}')
let line = line('.') let line = line('.')
@ -1982,14 +2026,14 @@ function! s:GF(mode) abort
let parent += 1 let parent += 1
let line -= 1 let line -= 1
endwhile endwhile
return s:Edit(a:mode,ref) return s:Edit(a:mode,0,ref)
elseif getline('.') =~ '^tree \x\{40\}$' elseif getline('.') =~ '^tree \x\{40\}$'
let ref = matchstr(getline('.'),'\x\{40\}') let ref = matchstr(getline('.'),'\x\{40\}')
if s:repo().rev_parse(myhash.':') == ref if s:repo().rev_parse(myhash.':') == ref
let ref = myhash.':' let ref = myhash.':'
endif endif
return s:Edit(a:mode,ref) return s:Edit(a:mode,0,ref)
elseif getline('.') =~# '^object \x\{40\}$' && getline(line('.')+1) =~ '^type \%(commit\|tree\|blob\)$' elseif getline('.') =~# '^object \x\{40\}$' && getline(line('.')+1) =~ '^type \%(commit\|tree\|blob\)$'
let ref = matchstr(getline('.'),'\x\{40\}') let ref = matchstr(getline('.'),'\x\{40\}')
@ -2047,9 +2091,9 @@ function! s:GF(mode) abort
endif endif
if exists('dref') if exists('dref')
return s:Edit(a:mode,ref) . '|'.dcmd.' '.s:fnameescape(dref) return s:Edit(a:mode,0,ref) . '|'.dcmd.' '.s:fnameescape(dref)
elseif ref != "" elseif ref != ""
return s:Edit(a:mode,ref) return s:Edit(a:mode,0,ref)
endif endif
endif endif