2019-05-21 06:38:28 +00:00
|
|
|
" vim: set noexpandtab :miv "
|
|
|
|
" ┌─────────────────┐ "
|
|
|
|
" └─┬─┬───┬─┬───┬─┬─┘ "
|
|
|
|
" │ │ │ │ │ │ "
|
|
|
|
" │ │ │ │ │ │ "
|
|
|
|
" ┌─┴─┴───┴─┴───┴─┴─┐ "
|
|
|
|
" ┌┘ Git Stuff └┐ "
|
|
|
|
" └───────────────────┘ "
|
2018-11-19 15:34:37 +00:00
|
|
|
|
2018-11-19 18:45:13 +00:00
|
|
|
" Find the root of a git repository
|
2018-11-19 15:34:37 +00:00
|
|
|
function! s:gitroot()
|
2018-11-19 18:45:13 +00:00
|
|
|
let l:ret = substitute(system('git rev-parse --show-toplevel'), '\n\_.*', '', '')
|
2018-11-19 15:34:37 +00:00
|
|
|
if v:shell_error
|
2018-11-19 18:45:13 +00:00
|
|
|
throw l:ret
|
2018-11-19 15:34:37 +00:00
|
|
|
else
|
2018-11-19 18:45:13 +00:00
|
|
|
return l:ret
|
2018-11-19 15:34:37 +00:00
|
|
|
end
|
|
|
|
endf
|
|
|
|
|
2019-11-18 12:20:55 +00:00
|
|
|
function! s:cd_git_root(path)
|
2019-11-18 13:01:16 +00:00
|
|
|
let l:path = fnamemodify(expand(a:path), ':p')
|
2018-11-19 18:45:13 +00:00
|
|
|
let l:wd = getcwd()
|
|
|
|
if isdirectory(l:path)
|
|
|
|
exec 'cd '.a:path
|
|
|
|
elseif filereadable(l:path)
|
|
|
|
exec 'cd '.fnamemodify(l:path, ':h')
|
|
|
|
else
|
2019-11-18 13:01:16 +00:00
|
|
|
throw 'Invalid Path'
|
2018-11-19 18:45:13 +00:00
|
|
|
endif
|
|
|
|
let l:ret = substitute(system('git rev-parse --show-toplevel'), '\n\_.*', '', '')
|
|
|
|
if v:shell_error
|
|
|
|
exec 'cd '.l:wd
|
2019-11-18 13:01:16 +00:00
|
|
|
throw 'Not a git repo!'
|
2018-11-19 18:45:13 +00:00
|
|
|
else
|
2019-11-18 12:20:55 +00:00
|
|
|
exec 'cd '.l:ret
|
2018-11-19 18:45:13 +00:00
|
|
|
return l:ret
|
|
|
|
end
|
|
|
|
endf
|
|
|
|
|
|
|
|
" Returns an array containing chronologically sorted commits
|
2018-11-19 15:34:37 +00:00
|
|
|
function! s:git_history()
|
|
|
|
if exists("b:git_history")
|
|
|
|
if b:git_history[0]+10 > localtime()
|
|
|
|
return b:git_history[1]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if exists("b:git_original_file") " Is this already a file@revision buffer?
|
|
|
|
let l:fname = b:git_original_file
|
|
|
|
else
|
|
|
|
let l:fname = substitute(expand("%"), "\\\\", "/", "g")
|
|
|
|
end
|
|
|
|
let l:commits = system('git log --format="%h" '.l:fname)
|
|
|
|
let l:hist = split(l:commits, "\n")
|
|
|
|
let b:git_history = [localtime(), l:hist]
|
|
|
|
|
|
|
|
return l:hist
|
|
|
|
endfun
|
|
|
|
|
|
|
|
function! s:git_first()
|
|
|
|
if &modified
|
2018-11-19 18:45:13 +00:00
|
|
|
throw "File has unsaved modifications!"
|
2018-11-19 15:34:37 +00:00
|
|
|
end
|
2018-11-19 18:45:13 +00:00
|
|
|
call s:file_at_revision(get(s:git_history(), -1))
|
2018-11-19 15:34:37 +00:00
|
|
|
endfun
|
|
|
|
|
|
|
|
function! s:git_last()
|
|
|
|
if &modified
|
2018-11-19 18:45:13 +00:00
|
|
|
throw "File has unsaved modifications!"
|
2018-11-19 15:34:37 +00:00
|
|
|
end
|
2018-11-19 18:45:13 +00:00
|
|
|
call s:file_at_revision(get(s:git_history(), 1, "HEAD"))
|
2018-11-19 15:34:37 +00:00
|
|
|
endfun
|
|
|
|
|
|
|
|
function! s:git_info()
|
|
|
|
if !exists("b:git_revision_hash") || !exists("b:git_original_file")
|
2019-11-18 12:36:08 +00:00
|
|
|
echom "Working copy or not in any repo"
|
|
|
|
return 0
|
2018-11-19 15:34:37 +00:00
|
|
|
end
|
|
|
|
echo system("git show --no-patch ".b:git_revision_hash)
|
|
|
|
endfun
|
|
|
|
|
|
|
|
function! s:git_next()
|
|
|
|
if !exists("b:git_revision_hash") || !exists("b:git_original_file")
|
2019-11-18 12:36:08 +00:00
|
|
|
echom "Error 01: Not a file@revision buffer!"
|
|
|
|
return 0
|
2018-11-19 15:34:37 +00:00
|
|
|
end
|
|
|
|
let l:history = s:git_history()
|
|
|
|
let l:idx = index(l:history, b:git_revision_hash)
|
|
|
|
if l:idx == -1
|
|
|
|
echo "Error 02"
|
|
|
|
return
|
|
|
|
end
|
|
|
|
let l:new_revision = get(l:history, l:idx-1, "LAST")
|
|
|
|
if l:new_revision=="LAST"
|
2018-11-19 18:45:13 +00:00
|
|
|
throw "Already at last revision!"
|
2018-11-19 15:34:37 +00:00
|
|
|
else
|
|
|
|
call s:file_at_revision(l:new_revision)
|
|
|
|
end
|
|
|
|
endfun
|
|
|
|
|
|
|
|
function! s:git_prev()
|
|
|
|
if !exists("b:git_revision_hash") || !exists("b:git_original_file")
|
|
|
|
let l:new_revision = s:git_history()[0]
|
|
|
|
else
|
|
|
|
let l:history = s:git_history()
|
|
|
|
let l:idx = index(l:history, b:git_revision_hash)
|
|
|
|
if l:idx == -1
|
|
|
|
echo "Error 03: cannot find revision ".b:git_revision_hash
|
|
|
|
return
|
|
|
|
end
|
|
|
|
let l:new_revision = get(l:history, l:idx+1, "FIRST")
|
|
|
|
end
|
|
|
|
if l:new_revision=="FIRST"
|
2018-11-19 18:45:13 +00:00
|
|
|
throw "Already at earliest revision!"
|
2018-11-19 15:34:37 +00:00
|
|
|
else
|
|
|
|
call s:file_at_revision(l:new_revision)
|
|
|
|
end
|
|
|
|
endfun
|
|
|
|
|
|
|
|
function! s:file_at_revision(rev)
|
|
|
|
let l:pos = getpos(".")
|
|
|
|
if exists("b:git_original_file") " Is this already a file@revision buffer?
|
|
|
|
let l:fname = b:git_original_file
|
|
|
|
let l:ftail = fnamemodify(b:git_original_file, ":t")
|
|
|
|
else
|
|
|
|
let l:fname = expand("%")
|
|
|
|
let l:ftail = expand("%:t")
|
|
|
|
end
|
|
|
|
let l:fname = substitute(l:fname, "\\\\", "/", "g")
|
|
|
|
let l:ftype = &filetype
|
|
|
|
|
|
|
|
ene!
|
|
|
|
set modifiable
|
|
|
|
silent exec "file ".l:ftail."@".a:rev
|
|
|
|
exec "r!git show ".a:rev.":".l:fname
|
|
|
|
1,1del
|
|
|
|
setl nomodifiable
|
|
|
|
setl buftype=nofile
|
|
|
|
setl bufhidden=delete
|
|
|
|
let &filetype = l:ftype
|
|
|
|
|
|
|
|
let b:git_original_file = l:fname
|
|
|
|
let b:git_revision_hash = a:rev
|
2019-11-18 12:36:08 +00:00
|
|
|
|
|
|
|
call setpos('.', l:pos)
|
2018-11-19 15:34:37 +00:00
|
|
|
endfun
|
|
|
|
|
|
|
|
function! s:git_diff(...)
|
|
|
|
if a:0
|
2019-11-18 12:20:55 +00:00
|
|
|
let l:wd = getcwd()
|
2019-11-18 13:01:16 +00:00
|
|
|
call s:cd_git_root('%')
|
2019-11-18 12:20:55 +00:00
|
|
|
split
|
2018-11-19 15:34:37 +00:00
|
|
|
call s:file_at_revision(a:1)
|
|
|
|
diffthis
|
|
|
|
au BufUnload <buffer> diffoff!
|
|
|
|
exec "normal \<C-w>\<C-p>"
|
|
|
|
diffthis
|
2019-11-18 12:20:55 +00:00
|
|
|
exec "normal \<C-w>\<C-p>"
|
2019-11-18 12:36:08 +00:00
|
|
|
exec "cd ".l:wd
|
2018-11-19 15:34:37 +00:00
|
|
|
else
|
|
|
|
if exists("b:git_revision_hash")
|
|
|
|
call s:git_diff(get(s:git_history(), index(s:git_history(), b:git_revision_hash)+1, "NIL"))
|
|
|
|
else
|
|
|
|
call s:git_diff(get(s:git_history(), 0, "HEAD"))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
endfun
|
|
|
|
|
2019-05-21 06:38:28 +00:00
|
|
|
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'):]})
|
2018-11-19 15:34:37 +00:00
|
|
|
endfun
|
|
|
|
|
2019-05-21 06:38:28 +00:00
|
|
|
command! -range Blame echom join(uniq(sort(<sid>git_blame(<line1>, <line2>))), ', ')
|
2019-05-21 06:43:46 +00:00
|
|
|
command! -range DBlame !git blame % -L <line1>,<line2>
|
2018-11-19 15:34:37 +00:00
|
|
|
command! GitNext try
|
2019-11-18 12:36:08 +00:00
|
|
|
\| call <sid>gitroot()
|
|
|
|
\| call <sid>git_next()
|
|
|
|
\| catch
|
|
|
|
\| echo 'Not a git repo!'
|
2019-05-21 06:38:28 +00:00
|
|
|
\| endtry
|
2019-11-18 12:36:08 +00:00
|
|
|
\| GitInfo
|
2019-11-18 12:20:55 +00:00
|
|
|
command! GitPrev call <sid>git_prev()
|
|
|
|
\| GitInfo
|
2018-11-19 15:34:37 +00:00
|
|
|
command! GitFirst call <sid>git_first() | call s:git_info()
|
|
|
|
command! GitLast call <sid>git_last() | call s:git_info()
|
|
|
|
command! GitInfo call <sid>git_info()
|
|
|
|
command! -nargs=1 GitCheckout call <sid>file_at_revision(<f-args>)
|
|
|
|
command! -nargs=? GitCompare try
|
2019-05-21 06:38:28 +00:00
|
|
|
\| call s:gitroot() | call <sid>git_diff(<f-args>)
|
2019-11-18 12:36:08 +00:00
|
|
|
\| catch
|
|
|
|
\| echo 'Not a git repo!'
|
2019-05-21 06:38:28 +00:00
|
|
|
\| endtry
|
2018-11-19 15:34:37 +00:00
|
|
|
command! Uncommited try
|
2019-11-18 12:20:55 +00:00
|
|
|
\| call <sid>git_diff()
|
2019-11-18 12:36:08 +00:00
|
|
|
\| catch
|
|
|
|
\| echo 'Not a git repo!'
|
2019-05-21 06:38:28 +00:00
|
|
|
\| endtry
|
2019-11-18 13:01:16 +00:00
|
|
|
command! GitRoot call <SID>cd_git_root('%')
|
2019-11-18 12:48:13 +00:00
|
|
|
command! GitOrig exec 'e '.b:git_original_file
|
2019-11-18 12:20:55 +00:00
|
|
|
command! ShowGitRoot try
|
2019-05-21 06:38:28 +00:00
|
|
|
\| echo <sid>gitroot()
|
|
|
|
\| catch | echo 'Not a git repository'
|
|
|
|
\| endtry
|