+ git-time-lapse

This commit is contained in:
Stefan Liebl 2015-02-10 15:43:27 +01:00
parent e10d5d74a2
commit 02c993bd2d
2 changed files with 157 additions and 0 deletions

View File

@ -37,3 +37,4 @@ ScriptID SourceID Filename
974 4316 python.vim (indent)
2975 22815 fugitive.vim
2830 22798 csv.vim
3849 22637 git-time-lapse

View File

@ -0,0 +1,156 @@
" vim: sw=4 ts=4 noexpandtab
function! Display(commit)
" clears all input in every buffer of the tab
windo %d
diffoff!
wincmd t
exe ':silent :0 read !git show '.a:commit.'^:'.t:path
exe 'doautocmd filetypedetect BufRead '.t:path
wincmd l
exe ':silent :0 read !git show '.a:commit.':'.t:path
exe 'doautocmd filetypedetect BufRead '.t:path
wincmd j
exe ':silent :0 read !git log --stat '.a:commit.'^..'.a:commit
setfiletype git
wincmd t
diffthis
wincmd l
diffthis
" Move back to where we were if it's still there, otherwise go to the top
if s:here <= line('$')
exe ':'.s:here
else
:0
endif
normal z.
" Some people have reported that you need to do this to make sure the left
" buffer is in the right place.
wincmd t
normal z.
wincmd j
:0
endfunction
function! Goto(pos)
let t:current = a:pos
if t:current < 0
let t:current = 0
return 0
elseif t:current >= t:total - 1
let t:current = t:total - 2
return 0
endif
call Display(t:commits[t:current])
return 1
endfunction
function! Move(amount)
let t:current = t:current + a:amount
call Goto(t:current)
endfunction
function! Blame()
let current = t:commits[t:current]
let line = line('.')
let output = system('git blame -p -n -L'.line.','.line.' '.
\current.' -- '.t:path)
let results = split(output)
if results[0] == "fatal:"
return
endif
for i in range(len(t:commits))
if t:commits[i] =~ results[0]
call Goto(i)
break
endif
endfor
wincmd t
wincmd l
exe ':'.results[1]
normal z.
wincmd j
endfunction
function! GetLog()
let tmpfile = tempname()
exe ':silent :!git log --no-merges --pretty=format:"\%H" '.t:path.' > '.tmpfile
let t:commits = readfile(tmpfile)
call delete(tmpfile)
let t:total = len(t:commits)
return t:total
endfunction
function! ChDir()
" Change directory to the one with .git in it and return path to the
" current file from there. If you live in this directory and execute git
" commands on that path then everything will work.
cd %:p:h
let dir = finddir('.git', '.;')
exe 'cd '.dir.'/..'
let path = fnamemodify(@%, ':.')
return path
endfunction
function! TimeLapse()
" Open a new tab with a time-lapse view of the file in the current
" buffer.
let path = ChDir()
let s:here = line('.')
tabnew
let t:path = path
if GetLog() <= 1
tabclose
return
endif
set buftype=nofile
new
set buftype=nofile
wincmd j
resize 10
set winfixheight
wincmd k
vnew
set buftype=nofile
" The first line in the file is the most recent commit
let t:current = 0
call Display(t:commits[t:current])
" Go backwards and forwards one commit
windo map <buffer> <Left> :call Move(1) <cr>
windo map <buffer> <Right> :call Move(-1) <cr>
" Rewind all the way to the start or end
windo map <buffer> <S-Left> :call Goto(t:total - 2) <cr>
windo map <buffer> <S-Right> :call Goto(0) <cr>
windo map <buffer> :call Blame() <cr>
" Go to the top right window (which contains the latest version of the
" file) and go back to the line we were on when we opened the time-lapse,
" so we can immediately Blame from there which is a common use-case.
2 wincmd w
exe ':'.s:here
normal z.
endfunction