From 4415f562acb7617b7e2e7db5569bb3b9433c13d7 Mon Sep 17 00:00:00 2001 From: DarkWiiPlayer Date: Mon, 17 Aug 2020 13:43:24 +0200 Subject: [PATCH] Add git blame to vim statusline --- vim/plugin/git.vim | 46 +++++++++++++++++++++++++++++++++++++++++--- vim/plugin/shame.vim | 2 +- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/vim/plugin/git.vim b/vim/plugin/git.vim index f7a6e1d..8868463 100644 --- a/vim/plugin/git.vim +++ b/vim/plugin/git.vim @@ -7,6 +7,8 @@ " ┌┘ Git Stuff └┐ " " └───────────────────┘ " +augroup git + " Find the root of a git repository function! s:gitroot() let l:ret = substitute(system('git rev-parse --show-toplevel'), '\n\_.*', '', '') @@ -139,10 +141,28 @@ function! s:file_at_revision(rev) call setpos('.', l:pos) endfun +function s:split_blame_entry(idx, entry) + let l:map = {} + for l:pair in split(a:entry, "\n")[1:] + let l:split = match(l:pair, " ") + let l:map[l:pair[:l:split-1]] = l:pair[l:split+1:] + endfor + let l:map["commit"]=a:entry[:match(a:entry, " ")-1] + let l:map["time"]=strftime("%Y-%d-%m %H:%M:%S", l:map["committer-time"]) + let l:map["date"]=strftime("%Y-%d-%m", l:map["committer-time"]) + let l:map["short"]=l:map["commit"][1:8]." ".l:map["time"]." ".l:map["author"] + return l:map +endfun +let s:split_blame_entry_ref = funcref("s:split_blame_entry") + function! s:git_blame(first, last) let l:input = system('git blame '.expand('%').' --line-porcelain -L '.a:first.','.a:last) - let l:data = map(split(l:input, '\ze\x\{40} \d\+ \d\+'), {idx, elem -> split(elem, '\n')}) - return map(l:data, {idx, ary -> ary[1][match(ary[1], '\s\+\zs'):]}) + if v:shell_error + throw v:shell_error + else + let l:array = map(split(l:input, '\ze\x\{40} \d\+ \d\+'), s:split_blame_entry_ref) + return l:array + end endfun function! s:git_root_to_path() @@ -154,7 +174,25 @@ endfun call s:git_root_to_path() -command! -range Blame echom join(uniq(sort(git_blame(, ))), ', ') +function! s:blame_command(what, line1, line2) + let l:what=tolower(a:what) + if l:what=="date" + echom join(uniq(sort(map(git_blame(a:line1, a:line2), { i,a -> a["date"] }))), ', ') + elseif l:what=="adate" + echom join(uniq(sort(map(git_blame(a:line1, a:line2), { i,a -> a["author"]." @ ".a["date"] }))), ', ') + elseif l:what=="mail" + echom join(uniq(sort(map(git_blame(a:line1, a:line2), { i,a -> a["committer-mail"] }))), ', ') + elseif l:what=="author" || l:what=="" + echom join(uniq(sort(map(git_blame(a:line1, a:line2), { i,a -> a["author"] }))), ', ') + else + throw "Don't know what '".a:what."' is!" + end +endfun + +au BufReadPost * try | let b:blame=git_blame("","") | catch | unlet! b:blame | endtry +au BufWritePost * try | let b:blame=git_blame("","") | catch | unlet! b:blame | endtry + +command! -range -nargs=? Blame call blame_command(, , ) command! -range DBlame !git blame % -L , command! GitNext try \| call gitroot() @@ -180,3 +218,5 @@ command! ShowGitRoot try \| echo gitroot() \| catch | echo 'Not a git repository' \| endtry + +augroup END diff --git a/vim/plugin/shame.vim b/vim/plugin/shame.vim index 1d2b5d7..6c01e23 100644 --- a/vim/plugin/shame.vim +++ b/vim/plugin/shame.vim @@ -91,7 +91,7 @@ end set listchars=eol:¶,tab:\│\ ,trail:·,nbsp:…,space:· set modeline " Allows setting vim options in other files -set statusline=\ (%n)\ %f\ %a\ [%M%R]\ [%Y]\ %{strlen(@\")}\ %{&autowriteall?'💾\ ':''}\%=0x%B\ [%l/%L,\ %c%V]\ %4.P +set statusline=\ (%n)\ %f\ %a\ [%M%R]\ [%Y]\ %{strlen(@\")}\ %{&autowriteall?'💾\ ':''}%#TabLine#%{exists(\"b:blame\")?b:blame[min([getcurpos()[1],len(b:blame)])-1][\"short\"]:\"\"}%#StatusLine#\%=0x%B\ [%l/%L,\ %c%V]\ %4.P set laststatus=2 set cmdheight=1 set timeoutlen=1200