mirror of
https://github.com/amix/vimrc
synced 2025-06-23 06:35:01 +08:00
Updated plugins
This commit is contained in:
@ -10,7 +10,6 @@ function! gitgutter#all(force) abort
|
||||
let file = expand('#'.bufnr.':p')
|
||||
if !empty(file)
|
||||
if index(visible, bufnr) != -1
|
||||
call gitgutter#init_buffer(bufnr)
|
||||
call gitgutter#process_buffer(bufnr, a:force)
|
||||
elseif a:force
|
||||
call s:reset_tick(bufnr)
|
||||
@ -21,22 +20,21 @@ function! gitgutter#all(force) abort
|
||||
endfunction
|
||||
|
||||
|
||||
" Finds the file's path relative to the repo root.
|
||||
function! gitgutter#init_buffer(bufnr)
|
||||
if gitgutter#utility#is_active(a:bufnr)
|
||||
let p = gitgutter#utility#repo_path(a:bufnr, 0)
|
||||
if type(p) != s:t_string || empty(p)
|
||||
call gitgutter#utility#set_repo_path(a:bufnr)
|
||||
call s:setup_maps()
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
|
||||
function! gitgutter#process_buffer(bufnr, force) abort
|
||||
" NOTE a:bufnr is not necessarily the current buffer.
|
||||
|
||||
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 = ''
|
||||
@ -108,11 +106,19 @@ endfunction
|
||||
|
||||
" }}}
|
||||
|
||||
function! s:setup_maps()
|
||||
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
|
||||
@ -120,7 +126,10 @@ function! s:setup_maps()
|
||||
nmap <buffer> ]c <Plug>GitGutterNextHunk
|
||||
endif
|
||||
|
||||
if !hasmapto('<Plug>GitGutterStageHunk') && maparg('<Leader>hs', 'n') ==# ''
|
||||
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') ==# ''
|
||||
@ -142,6 +151,18 @@ function! s:setup_maps()
|
||||
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)
|
||||
let p = gitgutter#utility#repo_path(a:bufnr, 0)
|
||||
|
||||
if type(p) == s:t_string && !empty(p) " if path is known
|
||||
return
|
||||
endif
|
||||
|
||||
return gitgutter#utility#set_repo_path(a:bufnr, a:continuation)
|
||||
endfunction
|
||||
|
||||
function! s:has_fresh_changes(bufnr) abort
|
||||
@ -154,7 +175,7 @@ endfunction
|
||||
|
||||
function! s:clear(bufnr)
|
||||
call gitgutter#sign#clear_signs(a:bufnr)
|
||||
call gitgutter#sign#remove_dummy_sign(a:bufnr, 1)
|
||||
call gitgutter#hunk#reset(a:bufnr)
|
||||
call s:reset_tick(a:bufnr)
|
||||
call gitgutter#utility#setbufvar(a:bufnr, 'path', '')
|
||||
endfunction
|
||||
|
@ -4,7 +4,7 @@ let s:hunk_re = '^@@ -\(\d\+\),\?\(\d*\) +\(\d\+\),\?\(\d*\) @@'
|
||||
|
||||
" True for git v1.7.2+.
|
||||
function! s:git_supports_command_line_config_override() abort
|
||||
call system(g:gitgutter_git_executable.' -c foo.bar=baz --version')
|
||||
call system(g:gitgutter_git_executable.' '.g:gitgutter_git_args.' -c foo.bar=baz --version')
|
||||
return !v:shell_error
|
||||
endfunction
|
||||
|
||||
@ -68,9 +68,9 @@ let s:counter = 0
|
||||
" the hunk headers (@@ -x,y +m,n @@); only possible if
|
||||
" grep is available.
|
||||
function! gitgutter#diff#run_diff(bufnr, from, preserve_full_diff) abort
|
||||
while gitgutter#utility#repo_path(a:bufnr, 0) == -1
|
||||
sleep 5m
|
||||
endwhile
|
||||
if gitgutter#utility#repo_path(a:bufnr, 0) == -1
|
||||
throw 'gitgutter author fail'
|
||||
endif
|
||||
|
||||
if gitgutter#utility#repo_path(a:bufnr, 0) == -2
|
||||
throw 'gitgutter not tracked'
|
||||
@ -119,14 +119,14 @@ function! gitgutter#diff#run_diff(bufnr, from, preserve_full_diff) abort
|
||||
|
||||
" Write file from index to temporary file.
|
||||
let index_name = g:gitgutter_diff_base.':'.gitgutter#utility#repo_path(a:bufnr, 1)
|
||||
let cmd .= g:gitgutter_git_executable.' --no-pager show '.index_name.' > '.from_file.' && '
|
||||
let cmd .= g:gitgutter_git_executable.' '.g:gitgutter_git_args.' --no-pager show '.index_name.' > '.from_file.' && '
|
||||
|
||||
elseif a:from ==# 'working_tree'
|
||||
let from_file = gitgutter#utility#repo_path(a:bufnr, 1)
|
||||
endif
|
||||
|
||||
" Call git-diff.
|
||||
let cmd .= g:gitgutter_git_executable.' --no-pager '.g:gitgutter_git_args
|
||||
let cmd .= g:gitgutter_git_executable.' '.g:gitgutter_git_args.' --no-pager '.g:gitgutter_git_args
|
||||
if s:c_flag
|
||||
let cmd .= ' -c "diff.autorefreshindex=0"'
|
||||
let cmd .= ' -c "diff.noprefix=false"'
|
||||
|
@ -4,7 +4,6 @@ function! gitgutter#highlight#line_disable() abort
|
||||
|
||||
if !g:gitgutter_signs
|
||||
call gitgutter#sign#clear_signs(bufnr(''))
|
||||
call gitgutter#sign#remove_dummy_sign(bufnr(''), 0)
|
||||
endif
|
||||
|
||||
redraw!
|
||||
@ -31,6 +30,38 @@ function! gitgutter#highlight#line_toggle() abort
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! gitgutter#highlight#linenr_disable() abort
|
||||
let g:gitgutter_highlight_linenrs = 0
|
||||
call s:define_sign_linenr_highlights()
|
||||
|
||||
if !g:gitgutter_signs
|
||||
call gitgutter#sign#clear_signs(bufnr(''))
|
||||
endif
|
||||
|
||||
redraw!
|
||||
endfunction
|
||||
|
||||
function! gitgutter#highlight#linenr_enable() abort
|
||||
let old_highlight_lines = g:gitgutter_highlight_linenrs
|
||||
|
||||
let g:gitgutter_highlight_linenrs = 1
|
||||
call s:define_sign_linenr_highlights()
|
||||
|
||||
if !old_highlight_lines && !g:gitgutter_signs
|
||||
call gitgutter#all(1)
|
||||
endif
|
||||
|
||||
redraw!
|
||||
endfunction
|
||||
|
||||
function! gitgutter#highlight#linenr_toggle() abort
|
||||
if g:gitgutter_highlight_linenrs
|
||||
call gitgutter#highlight#linenr_disable()
|
||||
else
|
||||
call gitgutter#highlight#linenr_enable()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
|
||||
function! gitgutter#highlight#define_sign_column_highlight() abort
|
||||
if g:gitgutter_override_sign_column_highlight
|
||||
@ -66,6 +97,11 @@ function! gitgutter#highlight#define_highlights() abort
|
||||
highlight default link GitGutterChangeLine DiffChange
|
||||
highlight default link GitGutterDeleteLine DiffDelete
|
||||
highlight default link GitGutterChangeDeleteLine GitGutterChangeLine
|
||||
|
||||
highlight default link GitGutterAddLineNr CursorLineNr
|
||||
highlight default link GitGutterChangeLineNr CursorLineNr
|
||||
highlight default link GitGutterDeleteLineNr CursorLineNr
|
||||
highlight default link GitGutterChangeDeleteLineNr CursorLineNr
|
||||
endfunction
|
||||
|
||||
function! gitgutter#highlight#define_signs() abort
|
||||
@ -75,11 +111,11 @@ function! gitgutter#highlight#define_signs() abort
|
||||
sign define GitGutterLineRemovedFirstLine
|
||||
sign define GitGutterLineRemovedAboveAndBelow
|
||||
sign define GitGutterLineModifiedRemoved
|
||||
sign define GitGutterDummy
|
||||
|
||||
call s:define_sign_text()
|
||||
call gitgutter#highlight#define_sign_text_highlights()
|
||||
call s:define_sign_line_highlights()
|
||||
call s:define_sign_linenr_highlights()
|
||||
endfunction
|
||||
|
||||
function! s:define_sign_text() abort
|
||||
@ -131,40 +167,45 @@ function! s:define_sign_line_highlights() abort
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:get_foreground_colors(group) abort
|
||||
redir => highlight
|
||||
silent execute 'silent highlight ' . a:group
|
||||
redir END
|
||||
|
||||
let link_matches = matchlist(highlight, 'links to \(\S\+\)')
|
||||
if len(link_matches) > 0 " follow the link
|
||||
return s:get_foreground_colors(link_matches[1])
|
||||
function! s:define_sign_linenr_highlights() abort
|
||||
if has('nvim-0.3.2')
|
||||
try
|
||||
if g:gitgutter_highlight_linenrs
|
||||
sign define GitGutterLineAdded numhl=GitGutterAddLineNr
|
||||
sign define GitGutterLineModified numhl=GitGutterChangeLineNr
|
||||
sign define GitGutterLineRemoved numhl=GitGutterDeleteLineNr
|
||||
sign define GitGutterLineRemovedFirstLine numhl=GitGutterDeleteLineNr
|
||||
sign define GitGutterLineRemovedAboveAndBelow numhl=GitGutterDeleteLineNr
|
||||
sign define GitGutterLineModifiedRemoved numhl=GitGutterChangeDeleteLineNr
|
||||
else
|
||||
sign define GitGutterLineAdded numhl=
|
||||
sign define GitGutterLineModified numhl=
|
||||
sign define GitGutterLineRemoved numhl=
|
||||
sign define GitGutterLineRemovedFirstLine numhl=
|
||||
sign define GitGutterLineRemovedAboveAndBelow numhl=
|
||||
sign define GitGutterLineModifiedRemoved numhl=
|
||||
endif
|
||||
catch /E475/
|
||||
endtry
|
||||
endif
|
||||
endfunction
|
||||
|
||||
let ctermfg = s:match_highlight(highlight, 'ctermfg=\([0-9A-Za-z]\+\)')
|
||||
let guifg = s:match_highlight(highlight, 'guifg=\([#0-9A-Za-z]\+\)')
|
||||
function! s:get_hl(group, what, mode) abort
|
||||
let r = synIDattr(synIDtrans(hlID(a:group)), a:what, a:mode)
|
||||
if empty(r) || r == -1
|
||||
return 'NONE'
|
||||
endif
|
||||
return r
|
||||
endfunction
|
||||
|
||||
function! s:get_foreground_colors(group) abort
|
||||
let ctermfg = s:get_hl(a:group, 'fg', 'cterm')
|
||||
let guifg = s:get_hl(a:group, 'fg', 'gui')
|
||||
return [guifg, ctermfg]
|
||||
endfunction
|
||||
|
||||
function! s:get_background_colors(group) abort
|
||||
redir => highlight
|
||||
silent execute 'silent highlight ' . a:group
|
||||
redir END
|
||||
|
||||
let link_matches = matchlist(highlight, 'links to \(\S\+\)')
|
||||
if len(link_matches) > 0 " follow the link
|
||||
return s:get_background_colors(link_matches[1])
|
||||
endif
|
||||
|
||||
let ctermbg = s:match_highlight(highlight, 'ctermbg=\([0-9A-Za-z]\+\)')
|
||||
let guibg = s:match_highlight(highlight, 'guibg=\([#0-9A-Za-z]\+\)')
|
||||
let ctermbg = s:get_hl(a:group, 'bg', 'cterm')
|
||||
let guibg = s:get_hl(a:group, 'bg', 'gui')
|
||||
return [guibg, ctermbg]
|
||||
endfunction
|
||||
|
||||
function! s:match_highlight(highlight, pattern) abort
|
||||
let matches = matchlist(a:highlight, a:pattern)
|
||||
if len(matches) == 0
|
||||
return 'NONE'
|
||||
endif
|
||||
return matches[1]
|
||||
endfunction
|
||||
|
@ -169,8 +169,12 @@ function! gitgutter#hunk#text_object(inner) abort
|
||||
endfunction
|
||||
|
||||
|
||||
function! gitgutter#hunk#stage() abort
|
||||
call s:hunk_op(function('s:stage'))
|
||||
function! gitgutter#hunk#stage(...) abort
|
||||
if a:0 && (a:1 != 1 || a:2 != line('$'))
|
||||
call s:hunk_op(function('s:stage'), a:1, a:2)
|
||||
else
|
||||
call s:hunk_op(function('s:stage'))
|
||||
endif
|
||||
silent! call repeat#set("\<Plug>GitGutterStageHunk", -1)
|
||||
endfunction
|
||||
|
||||
@ -185,9 +189,39 @@ function! gitgutter#hunk#preview() abort
|
||||
endfunction
|
||||
|
||||
|
||||
function! s:hunk_op(op)
|
||||
function! s:hunk_op(op, ...)
|
||||
let bufnr = bufnr('')
|
||||
|
||||
if &previewwindow
|
||||
if string(a:op) =~ '_stage'
|
||||
" combine hunk-body in preview window with updated hunk-header
|
||||
let hunk_body = getline(1, '$')
|
||||
|
||||
let [removed, added] = [0, 0]
|
||||
for line in hunk_body
|
||||
if line[0] == '-'
|
||||
let removed += 1
|
||||
elseif line[0] == '+'
|
||||
let added += 1
|
||||
endif
|
||||
endfor
|
||||
|
||||
let hunk_header = b:hunk_header
|
||||
" from count
|
||||
let hunk_header[4] = substitute(hunk_header[4], '\(-\d\+\)\(,\d\+\)\?', '\=submatch(1).",".removed', '')
|
||||
" to count
|
||||
let hunk_header[4] = substitute(hunk_header[4], '\(+\d\+\)\(,\d\+\)\?', '\=submatch(1).",".added', '')
|
||||
|
||||
let hunk_diff = join(hunk_header + hunk_body, "\n")."\n"
|
||||
|
||||
wincmd p
|
||||
pclose
|
||||
call s:stage(hunk_diff)
|
||||
endif
|
||||
|
||||
return
|
||||
endif
|
||||
|
||||
if gitgutter#utility#is_active(bufnr)
|
||||
" Get a (synchronous) diff.
|
||||
let [async, g:gitgutter_async] = [g:gitgutter_async, 0]
|
||||
@ -210,7 +244,14 @@ function! s:hunk_op(op)
|
||||
call gitgutter#utility#warn('did not recognise your choice')
|
||||
endif
|
||||
else
|
||||
call a:op(gitgutter#diff#hunk_diff(bufnr, diff))
|
||||
let hunk_diff = gitgutter#diff#hunk_diff(bufnr, diff)
|
||||
|
||||
if a:0
|
||||
let hunk_first_line = s:current_hunk()[2]
|
||||
let hunk_diff = s:part_of_diff(hunk_diff, a:1-hunk_first_line, a:2-hunk_first_line)
|
||||
endif
|
||||
|
||||
call a:op(hunk_diff)
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
@ -221,8 +262,11 @@ function! s:stage(hunk_diff)
|
||||
let diff = s:adjust_header(bufnr, a:hunk_diff)
|
||||
" Apply patch to index.
|
||||
call gitgutter#utility#system(
|
||||
\ gitgutter#utility#cd_cmd(bufnr, g:gitgutter_git_executable.' apply --cached --unidiff-zero - '),
|
||||
\ gitgutter#utility#cd_cmd(bufnr, g:gitgutter_git_executable.' '.g:gitgutter_git_args.' apply --cached --unidiff-zero - '),
|
||||
\ diff)
|
||||
if v:shell_error
|
||||
call gitgutter#utility#warn('patch does not apply')
|
||||
endif
|
||||
|
||||
" Refresh gitgutter's view of buffer.
|
||||
call gitgutter#process_buffer(bufnr, 1)
|
||||
@ -240,37 +284,58 @@ function! s:undo(hunk_diff)
|
||||
if removed_only
|
||||
call append(lnum, lines)
|
||||
elseif added_only
|
||||
execute lnum .','. (lnum+len(lines)-1) .'d'
|
||||
execute lnum .','. (lnum+len(lines)-1) .'d _'
|
||||
else
|
||||
call append(lnum-1, lines[0:hunk[1]])
|
||||
execute (lnum+hunk[1]) .','. (lnum+hunk[1]+hunk[3]) .'d'
|
||||
execute (lnum+hunk[1]) .','. (lnum+hunk[1]+hunk[3]) .'d _'
|
||||
endif
|
||||
endfunction
|
||||
|
||||
|
||||
function! s:preview(hunk_diff)
|
||||
let hunk_lines = split(s:discard_header(a:hunk_diff), "\n")
|
||||
let hunk_lines_length = len(hunk_lines)
|
||||
let previewheight = min([hunk_lines_length, &previewheight])
|
||||
let lines = split(a:hunk_diff, '\n')
|
||||
let header = lines[0:4]
|
||||
let body = lines[5:]
|
||||
|
||||
let body_length = len(body)
|
||||
let previewheight = min([body_length, &previewheight])
|
||||
|
||||
silent! wincmd P
|
||||
if !&previewwindow
|
||||
noautocmd execute 'bo' previewheight 'new'
|
||||
noautocmd execute g:gitgutter_preview_win_location previewheight 'new'
|
||||
set previewwindow
|
||||
else
|
||||
execute 'resize' previewheight
|
||||
endif
|
||||
|
||||
let b:hunk_header = header
|
||||
|
||||
setlocal noreadonly modifiable filetype=diff buftype=nofile bufhidden=delete noswapfile
|
||||
execute "%delete_"
|
||||
call append(0, hunk_lines)
|
||||
call setline(1, body)
|
||||
normal! gg
|
||||
setlocal readonly nomodifiable
|
||||
|
||||
cnoreabbrev <buffer> <expr> w getcmdtype() == ':' && getcmdline() == 'w' ? 'GitGutterStageHunk' : 'w'
|
||||
" Staging hunk from the preview window closes the window anyway.
|
||||
cnoreabbrev <buffer> <expr> wq getcmdtype() == ':' && getcmdline() == 'wq' ? 'GitGutterStageHunk' : 'wq'
|
||||
|
||||
noautocmd wincmd p
|
||||
endfunction
|
||||
|
||||
|
||||
" Returns a new hunk diff using the specified lines from the given one.
|
||||
" Assumes all lines are additions.
|
||||
" a:first, a:last - 0-based indexes into the body of the hunk.
|
||||
function! s:part_of_diff(hunk_diff, first, last)
|
||||
let diff_lines = split(a:hunk_diff, '\n', 1)
|
||||
|
||||
" adjust 'to' line count in header
|
||||
let diff_lines[4] = substitute(diff_lines[4], '\(+\d\+\)\(,\d\+\)\?', '\=submatch(1).",".(a:last-a:first+1)', '')
|
||||
|
||||
return join(diff_lines[0:4] + diff_lines[5+a:first:5+a:last], "\n")."\n"
|
||||
endfunction
|
||||
|
||||
|
||||
function! s:adjust_header(bufnr, hunk_diff)
|
||||
let filepath = gitgutter#utility#repo_path(a:bufnr, 0)
|
||||
return s:adjust_hunk_summary(s:fix_file_references(filepath, a:hunk_diff))
|
||||
@ -305,16 +370,11 @@ endif
|
||||
function! s:adjust_hunk_summary(hunk_diff) abort
|
||||
let line_adjustment = s:line_adjustment_for_current_hunk()
|
||||
let diff = split(a:hunk_diff, '\n', 1)
|
||||
let diff[4] = substitute(diff[4], '+\@<=\(\d\+\)', '\=submatch(1)+line_adjustment', '')
|
||||
let diff[4] = substitute(diff[4], '+\zs\(\d\+\)', '\=submatch(1)+line_adjustment', '')
|
||||
return join(diff, "\n")
|
||||
endfunction
|
||||
|
||||
|
||||
function! s:discard_header(hunk_diff)
|
||||
return join(split(a:hunk_diff, '\n', 1)[5:], "\n")
|
||||
endfunction
|
||||
|
||||
|
||||
" Returns the number of lines the current hunk is offset from where it would
|
||||
" be if any changes above it in the file didn't exist.
|
||||
function! s:line_adjustment_for_current_hunk() abort
|
||||
|
@ -1,11 +1,6 @@
|
||||
" Vim doesn't namespace sign ids so every plugin shares the same
|
||||
" namespace. Sign ids are simply integers so to avoid clashes with other
|
||||
" signs we guess at a clear run.
|
||||
"
|
||||
" Note also we currently never reset s:next_sign_id.
|
||||
" For older Vims without sign_place() the plugin has to manaage the sign ids.
|
||||
let s:first_sign_id = 3000
|
||||
let s:next_sign_id = s:first_sign_id
|
||||
let s:dummy_sign_id = s:first_sign_id - 1
|
||||
" Remove-all-signs optimisation requires Vim 7.3.596+.
|
||||
let s:supports_star = v:version > 703 || (v:version == 703 && has("patch596"))
|
||||
|
||||
@ -27,7 +22,6 @@ function! gitgutter#sign#disable() abort
|
||||
|
||||
if !g:gitgutter_highlight_lines
|
||||
call gitgutter#sign#clear_signs(bufnr(''))
|
||||
call gitgutter#sign#remove_dummy_sign(bufnr(''), 0)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
@ -40,8 +34,14 @@ function! gitgutter#sign#toggle() abort
|
||||
endfunction
|
||||
|
||||
|
||||
" Removes gitgutter's signs (excluding dummy sign) from the buffer being processed.
|
||||
" Removes gitgutter's signs from the buffer being processed.
|
||||
function! gitgutter#sign#clear_signs(bufnr) abort
|
||||
if exists('*sign_unplace')
|
||||
call sign_unplace('gitgutter', {'buffer': a:bufnr})
|
||||
return
|
||||
endif
|
||||
|
||||
|
||||
call s:find_current_signs(a:bufnr)
|
||||
|
||||
let sign_ids = map(values(gitgutter#utility#getbufvar(a:bufnr, 'gitgutter_signs')), 'v:val.id')
|
||||
@ -55,37 +55,42 @@ endfunction
|
||||
" modified_lines: list of [<line_number (number)>, <name (string)>]
|
||||
" where name = 'added|removed|modified|modified_removed'
|
||||
function! gitgutter#sign#update_signs(bufnr, modified_lines) abort
|
||||
if exists('*sign_unplace')
|
||||
" Vim is (hopefully) now quick enough to remove all signs then place new ones.
|
||||
call sign_unplace('gitgutter', {'buffer': a:bufnr})
|
||||
|
||||
let modified_lines = s:handle_double_hunk(a:modified_lines)
|
||||
let signs = map(copy(modified_lines), '{'.
|
||||
\ '"buffer": a:bufnr,'.
|
||||
\ '"group": "gitgutter",'.
|
||||
\ '"name": s:highlight_name_for_change(v:val[1]),'.
|
||||
\ '"lnum": v:val[0],'.
|
||||
\ '"priority": g:gitgutter_sign_priority'.
|
||||
\ '}')
|
||||
|
||||
if exists('*sign_placelist')
|
||||
call sign_placelist(signs)
|
||||
return
|
||||
endif
|
||||
|
||||
for sign in signs
|
||||
call sign_place(0, sign.group, sign.name, sign.buffer, {'lnum': sign.lnum, 'priority': sign.priority})
|
||||
endfor
|
||||
return
|
||||
endif
|
||||
|
||||
|
||||
" Derive a delta between the current signs and the ones we want.
|
||||
" Remove signs from lines that no longer need a sign.
|
||||
" Upsert the remaining signs.
|
||||
|
||||
call s:find_current_signs(a:bufnr)
|
||||
|
||||
let new_gitgutter_signs_line_numbers = map(copy(a:modified_lines), 'v:val[0]')
|
||||
let obsolete_signs = s:obsolete_gitgutter_signs_to_remove(a:bufnr, new_gitgutter_signs_line_numbers)
|
||||
|
||||
let flicker_possible = s:remove_all_old_signs && !empty(a:modified_lines)
|
||||
if flicker_possible
|
||||
call s:add_dummy_sign(a:bufnr)
|
||||
endif
|
||||
|
||||
call s:remove_signs(a:bufnr, obsolete_signs, s:remove_all_old_signs)
|
||||
call s:upsert_new_gitgutter_signs(a:bufnr, a:modified_lines)
|
||||
|
||||
if flicker_possible
|
||||
call gitgutter#sign#remove_dummy_sign(a:bufnr, 0)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
|
||||
function! s:add_dummy_sign(bufnr) abort
|
||||
if !gitgutter#utility#getbufvar(a:bufnr, 'dummy_sign')
|
||||
execute "sign place" s:dummy_sign_id "line=" . 9999 "name=GitGutterDummy buffer=" . a:bufnr
|
||||
call gitgutter#utility#setbufvar(a:bufnr, 'dummy_sign', 1)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! gitgutter#sign#remove_dummy_sign(bufnr, force) abort
|
||||
if gitgutter#utility#getbufvar(a:bufnr, 'dummy_sign') && (a:force || !g:gitgutter_sign_column_always)
|
||||
execute "sign unplace" s:dummy_sign_id "buffer=" . a:bufnr
|
||||
call gitgutter#utility#setbufvar(a:bufnr, 'dummy_sign', 0)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
|
||||
@ -96,40 +101,52 @@ endfunction
|
||||
|
||||
function! s:find_current_signs(bufnr) abort
|
||||
let gitgutter_signs = {} " <line_number (string)>: {'id': <id (number)>, 'name': <name (string)>}
|
||||
let other_signs = [] " [<line_number (number),...]
|
||||
let dummy_sign_placed = 0
|
||||
if !g:gitgutter_sign_allow_clobber
|
||||
let other_signs = [] " [<line_number (number),...]
|
||||
endif
|
||||
|
||||
redir => signs
|
||||
silent execute "sign place buffer=" . a:bufnr
|
||||
redir END
|
||||
if exists('*getbufinfo')
|
||||
let bufinfo = getbufinfo(a:bufnr)[0]
|
||||
let signs = has_key(bufinfo, 'signs') ? bufinfo.signs : []
|
||||
else
|
||||
let signs = []
|
||||
|
||||
for sign_line in filter(split(signs, '\n')[2:], 'v:val =~# "="')
|
||||
" Typical sign line: line=88 id=1234 name=GitGutterLineAdded
|
||||
" We assume splitting is faster than a regexp.
|
||||
let components = split(sign_line)
|
||||
let name = split(components[2], '=')[1]
|
||||
if name =~# 'GitGutterDummy'
|
||||
let dummy_sign_placed = 1
|
||||
else
|
||||
let line_number = str2nr(split(components[0], '=')[1])
|
||||
if name =~# 'GitGutter'
|
||||
let id = str2nr(split(components[1], '=')[1])
|
||||
" Remove orphaned signs (signs placed on lines which have been deleted).
|
||||
" (When a line is deleted its sign lingers. Subsequent lines' signs'
|
||||
" line numbers are decremented appropriately.)
|
||||
if has_key(gitgutter_signs, line_number)
|
||||
execute "sign unplace" gitgutter_signs[line_number].id
|
||||
endif
|
||||
let gitgutter_signs[line_number] = {'id': id, 'name': name}
|
||||
else
|
||||
call add(other_signs, line_number)
|
||||
redir => signlines
|
||||
silent execute "sign place buffer=" . a:bufnr
|
||||
redir END
|
||||
|
||||
for signline in filter(split(signlines, '\n')[2:], 'v:val =~# "="')
|
||||
" Typical sign line before v8.1.0614: line=88 id=1234 name=GitGutterLineAdded
|
||||
" We assume splitting is faster than a regexp.
|
||||
let components = split(signline)
|
||||
call add(signs, {
|
||||
\ 'lnum': str2nr(split(components[0], '=')[1]),
|
||||
\ 'id': str2nr(split(components[1], '=')[1]),
|
||||
\ 'name': split(components[2], '=')[1]
|
||||
\ })
|
||||
endfor
|
||||
endif
|
||||
|
||||
for sign in signs
|
||||
if sign.name =~# 'GitGutter'
|
||||
" Remove orphaned signs (signs placed on lines which have been deleted).
|
||||
" (When a line is deleted its sign lingers. Subsequent lines' signs'
|
||||
" line numbers are decremented appropriately.)
|
||||
if has_key(gitgutter_signs, sign.lnum)
|
||||
execute "sign unplace" gitgutter_signs[sign.lnum].id
|
||||
endif
|
||||
end
|
||||
let gitgutter_signs[sign.lnum] = {'id': sign.id, 'name': sign.name}
|
||||
else
|
||||
if !g:gitgutter_sign_allow_clobber
|
||||
call add(other_signs, sign.lnum)
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
|
||||
call gitgutter#utility#setbufvar(a:bufnr, 'dummy_sign', dummy_sign_placed)
|
||||
call gitgutter#utility#setbufvar(a:bufnr, 'gitgutter_signs', gitgutter_signs)
|
||||
call gitgutter#utility#setbufvar(a:bufnr, 'other_signs', other_signs)
|
||||
if !g:gitgutter_sign_allow_clobber
|
||||
call gitgutter#utility#setbufvar(a:bufnr, 'other_signs', other_signs)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
|
||||
@ -152,12 +169,8 @@ endfunction
|
||||
|
||||
|
||||
function! s:remove_signs(bufnr, sign_ids, all_signs) abort
|
||||
if a:all_signs && s:supports_star && empty(gitgutter#utility#getbufvar(a:bufnr, 'other_signs'))
|
||||
let dummy_sign_present = gitgutter#utility#getbufvar(a:bufnr, 'dummy_sign')
|
||||
if a:all_signs && s:supports_star && (g:gitgutter_sign_allow_clobber || empty(gitgutter#utility#getbufvar(a:bufnr, 'other_signs')))
|
||||
execute "sign unplace * buffer=" . a:bufnr
|
||||
if dummy_sign_present
|
||||
execute "sign place" s:dummy_sign_id "line=" . 9999 "name=GitGutterDummy buffer=" . a:bufnr
|
||||
endif
|
||||
else
|
||||
for id in a:sign_ids
|
||||
execute "sign unplace" id
|
||||
@ -167,21 +180,16 @@ endfunction
|
||||
|
||||
|
||||
function! s:upsert_new_gitgutter_signs(bufnr, modified_lines) abort
|
||||
let other_signs = gitgutter#utility#getbufvar(a:bufnr, 'other_signs')
|
||||
if !g:gitgutter_sign_allow_clobber
|
||||
let other_signs = gitgutter#utility#getbufvar(a:bufnr, 'other_signs')
|
||||
endif
|
||||
let old_gitgutter_signs = gitgutter#utility#getbufvar(a:bufnr, 'gitgutter_signs')
|
||||
|
||||
" Handle special case where the first line is the site of two hunks:
|
||||
" lines deleted above at the start of the file, and lines deleted
|
||||
" immediately below.
|
||||
if a:modified_lines[0:1] == [[1, 'removed_first_line'], [1, 'removed']]
|
||||
let modified_lines = [[1, 'removed_above_and_below']] + a:modified_lines[2:]
|
||||
else
|
||||
let modified_lines = a:modified_lines
|
||||
endif
|
||||
let modified_lines = s:handle_double_hunk(a:modified_lines)
|
||||
|
||||
for line in modified_lines
|
||||
let line_number = line[0] " <number>
|
||||
if index(other_signs, line_number) == -1 " don't clobber others' signs
|
||||
if g:gitgutter_sign_allow_clobber || index(other_signs, line_number) == -1 " don't clobber others' signs
|
||||
let name = s:highlight_name_for_change(line[1])
|
||||
if !has_key(old_gitgutter_signs, line_number) " insert
|
||||
let id = s:next_sign_id()
|
||||
@ -198,6 +206,18 @@ function! s:upsert_new_gitgutter_signs(bufnr, modified_lines) abort
|
||||
endfunction
|
||||
|
||||
|
||||
" Handle special case where the first line is the site of two hunks:
|
||||
" lines deleted above at the start of the file, and lines deleted
|
||||
" immediately below.
|
||||
function! s:handle_double_hunk(modified_lines)
|
||||
if a:modified_lines[0:1] == [[1, 'removed_first_line'], [1, 'removed']]
|
||||
return [[1, 'removed_above_and_below']] + a:modified_lines[2:]
|
||||
endif
|
||||
|
||||
return a:modified_lines
|
||||
endfunction
|
||||
|
||||
|
||||
function! s:next_sign_id() abort
|
||||
let next_id = s:next_sign_id
|
||||
let s:next_sign_id += 1
|
||||
|
@ -22,14 +22,16 @@ function! gitgutter#utility#setbufvar(buffer, varname, val)
|
||||
endfunction
|
||||
|
||||
function! gitgutter#utility#getbufvar(buffer, varname, ...)
|
||||
let dict = get(getbufvar(a:buffer, ''), 'gitgutter', {})
|
||||
if has_key(dict, a:varname)
|
||||
return dict[a:varname]
|
||||
else
|
||||
if a:0
|
||||
return a:1
|
||||
let bvars = getbufvar(a:buffer, '')
|
||||
if !empty(bvars)
|
||||
let dict = get(bvars, 'gitgutter', {})
|
||||
if has_key(dict, a:varname)
|
||||
return dict[a:varname]
|
||||
endif
|
||||
endif
|
||||
if a:0
|
||||
return a:1
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! gitgutter#utility#warn(message) abort
|
||||
@ -114,58 +116,52 @@ function! gitgutter#utility#repo_path(bufnr, shellesc) abort
|
||||
return a:shellesc ? gitgutter#utility#shellescape(p) : p
|
||||
endfunction
|
||||
|
||||
function! gitgutter#utility#set_repo_path(bufnr) abort
|
||||
|
||||
let s:set_path_handler = {}
|
||||
|
||||
function! s:set_path_handler.out(buffer, path) abort
|
||||
let path = s:strip_trailing_new_line(a:path)
|
||||
call gitgutter#utility#setbufvar(a:buffer, 'path', path)
|
||||
|
||||
if type(self.continuation) == type(function('tr'))
|
||||
call self.continuation()
|
||||
else
|
||||
call call(self.continuation.function, self.continuation.arguments)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:set_path_handler.err(buffer) abort
|
||||
call gitgutter#utility#setbufvar(a:buffer, 'path', -2)
|
||||
endfunction
|
||||
|
||||
|
||||
" continuation - a funcref or hash to call after setting the repo path asynchronously.
|
||||
"
|
||||
" Returns 'async' if the the path is set asynchronously, 0 otherwise.
|
||||
function! gitgutter#utility#set_repo_path(bufnr, continuation) abort
|
||||
" Values of path:
|
||||
" * non-empty string - path
|
||||
" * -1 - pending
|
||||
" * -2 - not tracked by git
|
||||
|
||||
call gitgutter#utility#setbufvar(a:bufnr, 'path', -1)
|
||||
let cmd = gitgutter#utility#cd_cmd(a:bufnr, g:gitgutter_git_executable.' ls-files --error-unmatch --full-name -z -- '.gitgutter#utility#shellescape(s:filename(a:bufnr)))
|
||||
let cmd = gitgutter#utility#cd_cmd(a:bufnr, g:gitgutter_git_executable.' '.g:gitgutter_git_args.' ls-files --error-unmatch --full-name -z -- '.gitgutter#utility#shellescape(s:filename(a:bufnr)))
|
||||
|
||||
if g:gitgutter_async && gitgutter#async#available()
|
||||
if has('lambda')
|
||||
call gitgutter#async#execute(cmd, a:bufnr, {
|
||||
\ 'out': {bufnr, path -> gitgutter#utility#setbufvar(bufnr, 'path', s:strip_trailing_new_line(path))},
|
||||
\ 'err': {bufnr -> gitgutter#utility#setbufvar(bufnr, 'path', -2)},
|
||||
\ })
|
||||
else
|
||||
if has('nvim') && !has('nvim-0.2.0')
|
||||
call gitgutter#async#execute(cmd, a:bufnr, {
|
||||
\ 'out': function('s:set_path'),
|
||||
\ 'err': function('s:not_tracked_by_git')
|
||||
\ })
|
||||
else
|
||||
call gitgutter#async#execute(cmd, a:bufnr, {
|
||||
\ 'out': function('s:set_path'),
|
||||
\ 'err': function('s:set_path', [-2])
|
||||
\ })
|
||||
endif
|
||||
endif
|
||||
if g:gitgutter_async && gitgutter#async#available() && !has('vim_starting')
|
||||
let handler = copy(s:set_path_handler)
|
||||
let handler.continuation = a:continuation
|
||||
call gitgutter#async#execute(cmd, a:bufnr, handler)
|
||||
return 'async'
|
||||
endif
|
||||
|
||||
let path = gitgutter#utility#system(cmd)
|
||||
if v:shell_error
|
||||
call gitgutter#utility#setbufvar(a:bufnr, 'path', -2)
|
||||
else
|
||||
let path = gitgutter#utility#system(cmd)
|
||||
if v:shell_error
|
||||
call gitgutter#utility#setbufvar(a:bufnr, 'path', -2)
|
||||
else
|
||||
call gitgutter#utility#setbufvar(a:bufnr, 'path', s:strip_trailing_new_line(path))
|
||||
endif
|
||||
call gitgutter#utility#setbufvar(a:bufnr, 'path', s:strip_trailing_new_line(path))
|
||||
endif
|
||||
endfunction
|
||||
|
||||
if has('nvim') && !has('nvim-0.2.0')
|
||||
function! s:not_tracked_by_git(bufnr)
|
||||
call s:set_path(a:bufnr, -2)
|
||||
endfunction
|
||||
endif
|
||||
|
||||
function! s:set_path(bufnr, path)
|
||||
if a:bufnr == -2
|
||||
let [bufnr, path] = [a:path, a:bufnr]
|
||||
call gitgutter#utility#setbufvar(bufnr, 'path', path)
|
||||
else
|
||||
call gitgutter#utility#setbufvar(a:bufnr, 'path', s:strip_trailing_new_line(a:path))
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! gitgutter#utility#cd_cmd(bufnr, cmd) abort
|
||||
let cd = s:unc_path(a:bufnr) ? 'pushd' : (gitgutter#utility#windows() ? 'cd /d' : 'cd')
|
||||
|
Reference in New Issue
Block a user