279 lines
8.0 KiB
VimL
279 lines
8.0 KiB
VimL
|
" Primary functions {{{
|
||
|
|
||
|
function! gitgutter#all(force) abort
|
||
|
let visible = tabpagebuflist()
|
||
|
|
||
|
for bufnr in range(1, bufnr('$') + 1)
|
||
|
if buflisted(bufnr)
|
||
|
let file = expand('#'.bufnr.':p')
|
||
|
if !empty(file)
|
||
|
if index(visible, bufnr) != -1
|
||
|
call gitgutter#process_buffer(bufnr, a:force)
|
||
|
elseif a:force
|
||
|
call s:reset_tick(bufnr)
|
||
|
endif
|
||
|
endif
|
||
|
endif
|
||
|
endfor
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
function! gitgutter#process_buffer(bufnr, force) abort
|
||
|
" NOTE a:bufnr is not necessarily the current buffer.
|
||
|
|
||
|
if gitgutter#utility#getbufvar(a:bufnr, 'enabled', -1) == -1
|
||
|
call gitgutter#utility#setbufvar(a:bufnr, 'enabled', g:gitgutter_enabled)
|
||
|
endif
|
||
|
|
||
|
if gitgutter#utility#is_active(a:bufnr)
|
||
|
|
||
|
if has('patch-7.4.1559')
|
||
|
let l:Callback = function('gitgutter#process_buffer', [a:bufnr, a:force])
|
||
|
else
|
||
|
let l:Callback = {'function': 'gitgutter#process_buffer', 'arguments': [a:bufnr, a:force]}
|
||
|
endif
|
||
|
let how = s:setup_path(a:bufnr, l:Callback)
|
||
|
if [how] == ['async'] " avoid string-to-number conversion if how is a number
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
if a:force || s:has_fresh_changes(a:bufnr)
|
||
|
|
||
|
let diff = 'NOT SET'
|
||
|
try
|
||
|
let diff = gitgutter#diff#run_diff(a:bufnr, g:gitgutter_diff_relative_to, 0)
|
||
|
catch /gitgutter not tracked/
|
||
|
call gitgutter#debug#log('Not tracked: '.gitgutter#utility#file(a:bufnr))
|
||
|
catch /gitgutter assume unchanged/
|
||
|
call gitgutter#debug#log('Assume unchanged: '.gitgutter#utility#file(a:bufnr))
|
||
|
catch /gitgutter diff failed/
|
||
|
call gitgutter#debug#log('Diff failed: '.gitgutter#utility#file(a:bufnr))
|
||
|
call gitgutter#hunk#reset(a:bufnr)
|
||
|
endtry
|
||
|
|
||
|
if diff != 'async' && diff != 'NOT SET'
|
||
|
call gitgutter#diff#handler(a:bufnr, diff)
|
||
|
endif
|
||
|
|
||
|
endif
|
||
|
endif
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
function! gitgutter#disable() abort
|
||
|
call s:toggle_each_buffer(0)
|
||
|
let g:gitgutter_enabled = 0
|
||
|
endfunction
|
||
|
|
||
|
function! gitgutter#enable() abort
|
||
|
call s:toggle_each_buffer(1)
|
||
|
let g:gitgutter_enabled = 1
|
||
|
endfunction
|
||
|
|
||
|
function s:toggle_each_buffer(enable)
|
||
|
for bufnr in range(1, bufnr('$') + 1)
|
||
|
if buflisted(bufnr)
|
||
|
let file = expand('#'.bufnr.':p')
|
||
|
if !empty(file)
|
||
|
if a:enable
|
||
|
call gitgutter#buffer_enable(bufnr)
|
||
|
else
|
||
|
call gitgutter#buffer_disable(bufnr)
|
||
|
end
|
||
|
endif
|
||
|
endif
|
||
|
endfor
|
||
|
endfunction
|
||
|
|
||
|
function! gitgutter#toggle() abort
|
||
|
if g:gitgutter_enabled
|
||
|
call gitgutter#disable()
|
||
|
else
|
||
|
call gitgutter#enable()
|
||
|
endif
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
function! gitgutter#buffer_disable(...) abort
|
||
|
let bufnr = a:0 ? a:1 : bufnr('')
|
||
|
call gitgutter#utility#setbufvar(bufnr, 'enabled', 0)
|
||
|
call s:clear(bufnr)
|
||
|
endfunction
|
||
|
|
||
|
function! gitgutter#buffer_enable(...) abort
|
||
|
let bufnr = a:0 ? a:1 : bufnr('')
|
||
|
call gitgutter#utility#setbufvar(bufnr, 'enabled', 1)
|
||
|
call gitgutter#process_buffer(bufnr, 1)
|
||
|
endfunction
|
||
|
|
||
|
function! gitgutter#buffer_toggle(...) abort
|
||
|
let bufnr = a:0 ? a:1 : bufnr('')
|
||
|
if gitgutter#utility#getbufvar(bufnr, 'enabled', 1)
|
||
|
call gitgutter#buffer_disable(bufnr)
|
||
|
else
|
||
|
call gitgutter#buffer_enable(bufnr)
|
||
|
endif
|
||
|
endfunction
|
||
|
|
||
|
" }}}
|
||
|
|
||
|
|
||
|
" Optional argument is buffer number
|
||
|
function! gitgutter#git(...)
|
||
|
let git = g:gitgutter_git_executable
|
||
|
if a:0
|
||
|
let git .= ' -C '.gitgutter#utility#dir(a:1)
|
||
|
endif
|
||
|
if empty(g:gitgutter_git_args)
|
||
|
return git
|
||
|
else
|
||
|
return git.' '.g:gitgutter_git_args
|
||
|
endif
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
function! gitgutter#setup_maps()
|
||
|
if !g:gitgutter_map_keys
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
" Note hasmapto() and maparg() operate on the current buffer.
|
||
|
|
||
|
let bufnr = bufnr('')
|
||
|
|
||
|
if gitgutter#utility#getbufvar(bufnr, 'mapped', 0)
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
if !hasmapto('<Plug>(GitGutterPrevHunk)') && maparg('[c', 'n') ==# ''
|
||
|
nmap <buffer> [c <Plug>(GitGutterPrevHunk)
|
||
|
endif
|
||
|
if !hasmapto('<Plug>(GitGutterNextHunk)') && maparg(']c', 'n') ==# ''
|
||
|
nmap <buffer> ]c <Plug>(GitGutterNextHunk)
|
||
|
endif
|
||
|
|
||
|
if !hasmapto('<Plug>(GitGutterStageHunk)', 'v') && maparg('<Leader>hs', 'x') ==# ''
|
||
|
xmap <buffer> <Leader>hs <Plug>(GitGutterStageHunk)
|
||
|
endif
|
||
|
if !hasmapto('<Plug>(GitGutterStageHunk)', 'n') && maparg('<Leader>hs', 'n') ==# ''
|
||
|
nmap <buffer> <Leader>hs <Plug>(GitGutterStageHunk)
|
||
|
endif
|
||
|
if !hasmapto('<Plug>(GitGutterUndoHunk)') && maparg('<Leader>hu', 'n') ==# ''
|
||
|
nmap <buffer> <Leader>hu <Plug>(GitGutterUndoHunk)
|
||
|
endif
|
||
|
if !hasmapto('<Plug>(GitGutterPreviewHunk)') && maparg('<Leader>hp', 'n') ==# ''
|
||
|
nmap <buffer> <Leader>hp <Plug>(GitGutterPreviewHunk)
|
||
|
endif
|
||
|
|
||
|
if !hasmapto('<Plug>(GitGutterTextObjectInnerPending)') && maparg('ic', 'o') ==# ''
|
||
|
omap <buffer> ic <Plug>(GitGutterTextObjectInnerPending)
|
||
|
endif
|
||
|
if !hasmapto('<Plug>(GitGutterTextObjectOuterPending)') && maparg('ac', 'o') ==# ''
|
||
|
omap <buffer> ac <Plug>(GitGutterTextObjectOuterPending)
|
||
|
endif
|
||
|
if !hasmapto('<Plug>(GitGutterTextObjectInnerVisual)') && maparg('ic', 'x') ==# ''
|
||
|
xmap <buffer> ic <Plug>(GitGutterTextObjectInnerVisual)
|
||
|
endif
|
||
|
if !hasmapto('<Plug>(GitGutterTextObjectOuterVisual)') && maparg('ac', 'x') ==# ''
|
||
|
xmap <buffer> ac <Plug>(GitGutterTextObjectOuterVisual)
|
||
|
endif
|
||
|
|
||
|
call gitgutter#utility#setbufvar(bufnr, 'mapped', 1)
|
||
|
endfunction
|
||
|
|
||
|
function! s:setup_path(bufnr, continuation)
|
||
|
if gitgutter#utility#has_repo_path(a:bufnr) | return | endif
|
||
|
|
||
|
return gitgutter#utility#set_repo_path(a:bufnr, a:continuation)
|
||
|
endfunction
|
||
|
|
||
|
function! s:has_fresh_changes(bufnr) abort
|
||
|
return getbufvar(a:bufnr, 'changedtick') != gitgutter#utility#getbufvar(a:bufnr, 'tick')
|
||
|
endfunction
|
||
|
|
||
|
function! s:reset_tick(bufnr) abort
|
||
|
call gitgutter#utility#setbufvar(a:bufnr, 'tick', 0)
|
||
|
endfunction
|
||
|
|
||
|
function! s:clear(bufnr)
|
||
|
call gitgutter#sign#clear_signs(a:bufnr)
|
||
|
call gitgutter#hunk#reset(a:bufnr)
|
||
|
call s:reset_tick(a:bufnr)
|
||
|
call gitgutter#utility#setbufvar(a:bufnr, 'path', '')
|
||
|
call gitgutter#utility#setbufvar(a:bufnr, 'basepath', '')
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
" Note:
|
||
|
" - this runs synchronously
|
||
|
" - it ignores unsaved changes in buffers
|
||
|
" - it does not change to the repo root
|
||
|
function! gitgutter#quickfix(current_file)
|
||
|
let cmd = gitgutter#git().' rev-parse --show-cdup'
|
||
|
let path_to_repo = get(systemlist(cmd), 0, '')
|
||
|
if !empty(path_to_repo) && path_to_repo[-1:] != '/'
|
||
|
let path_to_repo .= '/'
|
||
|
endif
|
||
|
|
||
|
let locations = []
|
||
|
let cmd = gitgutter#git().' --no-pager'.
|
||
|
\ ' diff --no-ext-diff --no-color -U0'.
|
||
|
\ ' --src-prefix=a/'.path_to_repo.' --dst-prefix=b/'.path_to_repo.' '.
|
||
|
\ g:gitgutter_diff_args. ' '. g:gitgutter_diff_base
|
||
|
if a:current_file
|
||
|
let cmd = cmd.' -- '.expand('%:p')
|
||
|
endif
|
||
|
let diff = systemlist(cmd)
|
||
|
let lnum = 0
|
||
|
for line in diff
|
||
|
if line =~ '^diff --git [^"]'
|
||
|
" No quotation mark therefore no spaces in filenames
|
||
|
let [fnamel, fnamer] = split(line)[2:3]
|
||
|
let fname = fnamel ==# fnamer ? fnamer : fnamer[2:]
|
||
|
elseif line =~ '^diff --git "'
|
||
|
" Quotation mark therefore do not split on space
|
||
|
let [_, fnamel, _, fnamer] = split(line, '"')
|
||
|
let fname = fnamel ==# fnamer ? fnamer : fnamer[2:]
|
||
|
elseif line =~ '^diff --cc [^"]'
|
||
|
let fname = line[10:]
|
||
|
elseif line =~ '^diff --cc "'
|
||
|
let [_, fname] = split(line, '"')
|
||
|
elseif line =~ '^@@'
|
||
|
let lnum = matchlist(line, '+\(\d\+\)')[1]
|
||
|
elseif lnum > 0
|
||
|
call add(locations, {'filename': fname, 'lnum': lnum, 'text': line})
|
||
|
let lnum = 0
|
||
|
endif
|
||
|
endfor
|
||
|
if !g:gitgutter_use_location_list
|
||
|
call setqflist(locations)
|
||
|
else
|
||
|
call setloclist(0, locations)
|
||
|
endif
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
function! gitgutter#difforig()
|
||
|
let bufnr = bufnr('')
|
||
|
let filetype = &filetype
|
||
|
|
||
|
vertical new
|
||
|
set buftype=nofile
|
||
|
let &filetype = filetype
|
||
|
|
||
|
if g:gitgutter_diff_relative_to ==# 'index'
|
||
|
let index_name = gitgutter#utility#get_diff_base(bufnr).':'.gitgutter#utility#base_path(bufnr)
|
||
|
let cmd = gitgutter#git(bufnr).' --no-pager show '.index_name
|
||
|
" NOTE: this uses &shell to execute cmd. Perhaps we should use instead
|
||
|
" gitgutter#utility's use_known_shell() / restore_shell() functions.
|
||
|
silent! execute "read ++edit !" cmd
|
||
|
else
|
||
|
silent! execute "read ++edit" gitgutter#utility#repo_path(bufnr, 1)
|
||
|
endif
|
||
|
|
||
|
0d_
|
||
|
diffthis
|
||
|
wincmd p
|
||
|
diffthis
|
||
|
endfunction
|