From 02c993bd2ddf6ec26f313375b0ba37b52a2e4c5f Mon Sep 17 00:00:00 2001 From: Stefan Liebl Date: Tue, 10 Feb 2015 15:43:27 +0100 Subject: [PATCH] + git-time-lapse --- vimfiles/GetLatest/GetLatestVimScripts.dat | 1 + vimfiles/plugin/time-lapse.vim | 156 +++++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 vimfiles/plugin/time-lapse.vim diff --git a/vimfiles/GetLatest/GetLatestVimScripts.dat b/vimfiles/GetLatest/GetLatestVimScripts.dat index b7c09a5..4fed8e4 100644 --- a/vimfiles/GetLatest/GetLatestVimScripts.dat +++ b/vimfiles/GetLatest/GetLatestVimScripts.dat @@ -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 diff --git a/vimfiles/plugin/time-lapse.vim b/vimfiles/plugin/time-lapse.vim new file mode 100644 index 0000000..3c855cc --- /dev/null +++ b/vimfiles/plugin/time-lapse.vim @@ -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 :call Move(1) + windo map :call Move(-1) + + " Rewind all the way to the start or end + windo map :call Goto(t:total - 2) + windo map :call Goto(0) + + windo map :call Blame() + + " 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