-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 7b28ba7
Showing
2 changed files
with
219 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
set tw=110 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,218 @@ | ||
command! -buffer -bang Extradite :execute s:Extradite(<bang>0) | ||
|
||
autocmd Syntax extradite call s:ExtraditeSyntax() | ||
let g:extradite_bufnr = -1 | ||
|
||
function! s:Extradite(bang) abort | ||
|
||
if !exists('b:git_dir') | ||
echo 'Not a git repository.' | ||
return | ||
endif | ||
|
||
" if we are open, close. | ||
if g:extradite_bufnr >= 0 | ||
call <SID>ExtraditeClose() | ||
return | ||
endif | ||
|
||
let path = fugitive#buffer().path() | ||
try | ||
let git_dir = fugitive#buffer().repo().dir() | ||
" insert literal tabs in the format string because git does not seem to provide an escape code for it | ||
let template_cmd = ['--no-pager', 'log', '-n100'] | ||
let bufnr = bufnr('') | ||
let base_file_name = tempname() | ||
call s:ExtraditeLoadCommitData(a:bang, base_file_name, template_cmd, path) | ||
let b:base_file_name = base_file_name | ||
let b:git_dir = git_dir | ||
let b:fugitive_type = 'log' | ||
let b:fugitive_logged_bufnr = bufnr | ||
vertical resize 60 | ||
command! -buffer -bang Extradite :execute s:Extradite(<bang>0) | ||
" invoke ExtraditeClose instead of bdelete so we can do the necessary cleanup | ||
nnoremap <buffer> <silent> q :<C-U>call <SID>ExtraditeClose()<CR> | ||
nnoremap <buffer> <silent> <CR> :<C-U>exe <SID>ExtraditeJump("edit")<CR> | ||
nnoremap <buffer> <silent> o :<C-U>exe <SID>ExtraditeJump((&splitbelow ? "botright" : "topleft")." split")<CR> | ||
nnoremap <buffer> <silent> O :<C-U>exe <SID>ExtraditeJump("tabedit")<CR> | ||
nnoremap <buffer> <silent> d :<C-U>exe <SID>ExtraditeDiff(0)<CR> | ||
nnoremap <buffer> <silent> D :<C-U>exe <SID>ExtraditeDiff(1)<CR> | ||
nnoremap <buffer> <silent> a :<C-U>exe <SID>ExtraditeLoadCommitData(0, b:base_file_name, ['--no-pager','log','-n100'])<CR> | ||
" hack to make the cursor stay in the same position. putting line= in ExtraditeDiffToggle / removing <C-U> | ||
" doesn't seem to work | ||
nnoremap <buffer> <silent> t :let line=line('.')<cr> :<C-U>exe <SID>ExtraditeDiffToggle()<CR> :exe line<cr> | ||
autocmd CursorMoved <buffer> exe 'setlocal statusline='.escape(b:extradata_list[line(".")-1]['date'], ' ') | ||
call s:ExtraditeDiffToggle() | ||
let g:extradite_bufnr = bufnr('') | ||
return '' | ||
catch /^fugitive:/ | ||
return 'echoerr v:errmsg' | ||
endtry | ||
endfunction | ||
|
||
function! s:ExtraditeLoadCommitData(bang, base_file_name, template_cmd, ...) abort | ||
if a:0 >= 1 | ||
let path = a:1 | ||
else | ||
let path = '' | ||
endif | ||
|
||
let cmd = a:template_cmd + ['--pretty=format:\%an \%d \%s', '--', path] | ||
let extradata_cmd = a:template_cmd + ['--pretty=format:\%h \%ad', '--', path] | ||
let basecmd = call(fugitive#buffer().repo().git_command,cmd,fugitive#buffer().repo()) | ||
let extradata_basecmd = call(fugitive#buffer().repo().git_command,extradata_cmd,fugitive#buffer().repo()) | ||
|
||
let log_file = a:base_file_name.'.extradite' | ||
" put the commit IDs in a separate file -- the user doesn't have to know | ||
" exactly what they are | ||
let extradata_file = a:base_file_name.'.extraditecommits' | ||
if &shell =~# 'csh' | ||
silent! execute '%write !('.extradata_basecmd.' > '.extradata_file.') >& '.a:base_file_name | ||
silent! execute '%write !('.basecmd.' > '.log_file.') >& '.a:base_file_name | ||
else | ||
silent! execute '%write !'.extradata_basecmd.' > '.extradata_file.' 2> '.a:base_file_name | ||
silent! execute '%write !'.basecmd.' > '.log_file.' 2> '.a:base_file_name | ||
endif | ||
if v:shell_error | ||
call s:throw(join(readfile(error),"\n")) | ||
endif | ||
|
||
if g:extradite_bufnr >= 0 | ||
edit | ||
else | ||
if a:bang | ||
exe 'leftabove vsplit '.log_file | ||
else | ||
exe 'edit' log_file | ||
endif | ||
endif | ||
|
||
" Some components of the log may have no value. Or may insert whitespace of their own. Remove the repeated | ||
" whitespace that result from this. Side effect: removes intended whitespace in the commit data. | ||
setlocal modifiable | ||
silent! %s/\(\s\)\s\+/\1/g | ||
normal! gg | ||
let b:extradata_list = [] | ||
let extradata = readfile(extradata_file) | ||
for line in extradata | ||
let tokens = matchlist(line, '\([^\t]\+\)\t\([^\t]\+\)') | ||
call add(b:extradata_list, {'commit': tokens[1], 'date': tokens[2]}) | ||
endfor | ||
setlocal nomodified nomodifiable bufhidden=delete nonumber nowrap foldcolumn=0 nofoldenable filetype=extradite ts=1 cursorline nobuflisted | ||
endfunction | ||
|
||
" Returns the `commit:path` associated with the current line in the Extradite buffer | ||
function! s:ExtraditePath(...) abort | ||
if exists('a:1') | ||
let modifier = a:1 | ||
else | ||
let modifier = '' | ||
endif | ||
return b:extradata_list[line(".")-1]['commit'].modifier.':'.fugitive#buffer(b:fugitive_logged_bufnr).path() | ||
endfunction | ||
|
||
" Closes the file log and returns the selected `commit:path` | ||
function! s:ExtraditeClose() abort | ||
|
||
if (g:extradite_bufnr >= 0) | ||
let filelog_winnr = bufwinnr(g:extradite_bufnr) | ||
exe filelog_winnr.'wincmd w' | ||
else | ||
return | ||
endif | ||
|
||
let rev = s:ExtraditePath() | ||
let fugitive_logged_bufnr = b:fugitive_logged_bufnr | ||
if exists('b:fugitive_simplediff_bufnr') && bufwinnr(b:fugitive_simplediff_bufnr) >= 0 | ||
exe 'bd!' . b:fugitive_simplediff_bufnr | ||
endif | ||
bd | ||
let logged_winnr = bufwinnr(fugitive_logged_bufnr) | ||
if logged_winnr >= 0 | ||
exe logged_winnr.'wincmd w' | ||
endif | ||
let g:extradite_bufnr = -1 | ||
return rev | ||
endfunction | ||
|
||
function! s:ExtraditeJump(cmd) abort | ||
let rev = s:ExtraditeClose() | ||
exe s:Edit(a:cmd,rev) | ||
endfunction | ||
|
||
function! s:ExtraditeDiff(bang) abort | ||
let rev = s:ExtraditeClose() | ||
call s:Diff(a:bang,rev) | ||
endfunction | ||
|
||
function! s:ExtraditeSyntax() abort | ||
let b:current_syntax = 'extradite' | ||
syn match FugitivelogName "\(\w\| \)\+\t" | ||
syn match FugitivelogTag "(.*)\t" | ||
hi def link FugitivelogName String | ||
hi def link FugitivelogTag Identifier | ||
hi! def link CursorLine Visual | ||
" make the cursor less obvious. has no effect on xterm | ||
hi! def link Cursor Visual | ||
endfunction | ||
|
||
function! s:ExtraditeDiffToggle() abort | ||
if !exists('b:fugitive_simplediff_bufnr') || b:fugitive_simplediff_bufnr == -1 | ||
augroup extradite | ||
autocmd CursorMoved <buffer> call s:SimpleFileDiff(s:ExtraditePath('~1'), s:ExtraditePath()) | ||
" vim seems to get confused if we jump around buffers during a CursorMoved event. Moving the cursor | ||
" around periodically helps vim figure out where it should really be. | ||
autocmd CursorHold <buffer> normal! lh | ||
augroup END | ||
call s:SimpleFileDiff(s:ExtraditePath('~1'), s:ExtraditePath()) | ||
else | ||
exe "bd" b:fugitive_simplediff_bufnr | ||
unlet b:fugitive_simplediff_bufnr | ||
au! extradite | ||
endif | ||
endfunction | ||
|
||
" Does a git diff on a single file and discards the top few lines of extraneous | ||
" information | ||
function! s:SimpleFileDiff(a,b) abort | ||
call s:SimpleDiff(a:a,a:b) | ||
let win = bufwinnr(b:fugitive_simplediff_bufnr) | ||
exe win.'wincmd w' | ||
set modifiable | ||
silent normal! gg5dd | ||
set nomodifiable | ||
wincmd p | ||
endfunction | ||
|
||
" Does a git diff of commits a and b. Will create one simplediff-buffer that is | ||
" unique wrt the buffer that it is invoked from. | ||
function! s:SimpleDiff(a,b) abort | ||
|
||
if !exists('b:fugitive_simplediff_bufnr') || b:fugitive_simplediff_bufnr == -1 | ||
belowright split | ||
enew! | ||
let bufnr = bufnr('') | ||
wincmd p | ||
let b:fugitive_simplediff_bufnr = bufnr | ||
endif | ||
|
||
let win = bufwinnr(b:fugitive_simplediff_bufnr) | ||
exe win.'wincmd w' | ||
|
||
" check if we have generated this diff already, to reduce unnecessary shell requests | ||
if exists('b:files') && b:files['a'] == a:a && b:files['b'] == a:b | ||
wincmd p | ||
return | ||
endif | ||
|
||
set modifiable | ||
silent! %delete _ | ||
let diff = system('git diff '.a:a.' '.a:b) | ||
silent put = diff | ||
setlocal ft=diff buftype=nofile nomodifiable | ||
" somehow this is necessary to prevent future buffers from having `nomodifiable` | ||
autocmd BufDelete <buffer> set modifiable | ||
let b:files = { 'a': a:a, 'b': a:b } | ||
wincmd p | ||
|
||
endfunction |