vim-signify/autoload/sy/sign.vim
Marco Hinz 82d6df9f71
Don't switch window in exit handler
Since we don't switch the window anymore, we can't simply refer to b:sy as we
used to do while Sy worked only synchronously.

Now we provide the buffer number to each job and the exit handler gets a pointer
to the b:sy of that buffer and passes it to all the subsequent functions.

References #209, #210.
2017-01-30 14:50:32 +01:00

254 lines
7.2 KiB
VimL
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

" vim: et sw=2 sts=2
scriptencoding utf-8
" Init: values {{{1
if get(g:, 'signify_sign_show_text', 1)
let s:sign_delete = get(g:, 'signify_sign_delete', '_')
let s:sign_show_count = get(g:, 'signify_sign_show_count', 1)
else
let s:sign_delete = ' '
let s:sign_show_count = 0
endif
let s:delete_highlight = ['', 'SignifyLineDelete']
" Function: #id_next {{{1
function! sy#sign#id_next(sy) abort
let id = a:sy.signid
let a:sy.signid += 1
return id
endfunction
" Function: #get_current_signs {{{1
function! sy#sign#get_current_signs(sy) abort
let a:sy.internal = {}
let a:sy.external = {}
redir => signlist
silent! execute 'sign place buffer='. a:sy.buffer
redir END
for signline in split(signlist, '\n')[2:]
let tokens = matchlist(signline, '\v^\s+\S+\=(\d+)\s+\S+\=(\d+)\s+\S+\=(.*)$')
let line = str2nr(tokens[1])
let id = str2nr(tokens[2])
let type = tokens[3]
if type =~# '^Signify'
" Handle ambiguous signs. Assume you have signs on line 3 and 4.
" Removing line 3 would lead to the second sign to be shifted up
" to line 3. Now there are still 2 signs, both one line 3.
if has_key(a:sy.internal, line)
execute 'sign unplace' a:sy.internal[line].id 'buffer='.a:sy.buffer
endif
let a:sy.internal[line] = { 'type': type, 'id': id }
else
let a:sy.external[line] = id
endif
endfor
endfunction
" Function: #process_diff {{{1
function! sy#sign#process_diff(sy, diff) abort
let a:sy.signtable = {}
let a:sy.hunks = []
let [added, modified, deleted] = [0, 0, 0]
call sy#sign#get_current_signs(a:sy)
" Determine where we have to put our signs.
for line in filter(a:diff, 'v:val =~ "^@@ "')
let a:sy.lines = []
let ids = []
let tokens = matchlist(line, '^@@ -\v(\d+),?(\d*) \+(\d+),?(\d*)')
let old_line = str2nr(tokens[1])
let new_line = str2nr(tokens[3])
let old_count = empty(tokens[2]) ? 1 : str2nr(tokens[2])
let new_count = empty(tokens[4]) ? 1 : str2nr(tokens[4])
" 2 lines added:
" @@ -5,0 +6,2 @@ this is line 5
" +this is line 5
" +this is line 5
if (old_count == 0) && (new_count >= 1)
let added += new_count
let offset = 0
while offset < new_count
let line = new_line + offset
let offset += 1
if s:external_sign_present(a:sy, line) | continue | endif
call add(ids, s:add_sign(a:sy, line, 'SignifyAdd'))
endwhile
" 2 lines removed:
" @@ -6,2 +5,0 @@ this is line 5
" -this is line 6
" -this is line 7
elseif (old_count >= 1) && (new_count == 0)
if s:external_sign_present(a:sy, new_line) | continue | endif
let deleted += old_count
if new_line == 0
call add(ids, s:add_sign(a:sy, 1, 'SignifyRemoveFirstLine'))
elseif s:sign_show_count
if old_count <= 99
let text = substitute(s:sign_delete . old_count, '.*\ze..$', '', '')
else
let text = s:sign_delete .'>'
endif
call add(ids, s:add_sign(a:sy, new_line, 'SignifyDelete'. old_count, text))
else
call add(ids, s:add_sign(a:sy, new_line, 'SignifyDeleteMore', s:sign_delete))
endif
" 2 lines changed:
" @@ -5,2 +5,2 @@ this is line 4
" -this is line 5
" -this is line 6
" +this os line 5
" +this os line 6
elseif old_count == new_count
let modified += old_count
let offset = 0
while offset < new_count
let line = new_line + offset
let offset += 1
if s:external_sign_present(a:sy, line) | continue | endif
call add(ids, s:add_sign(a:sy, line, 'SignifyChange'))
endwhile
else
" 2 lines changed; 2 lines removed:
" @@ -5,4 +5,2 @@ this is line 4
" -this is line 5
" -this is line 6
" -this is line 7
" -this is line 8
" +this os line 5
" +this os line 6
if old_count > new_count
let modified += new_count
let removed = old_count - new_count
let deleted += removed
let offset = 0
while offset < new_count - 1
let line = new_line + offset
let offset += 1
if s:external_sign_present(a:sy, line) | continue | endif
call add(ids, s:add_sign(a:sy, line, 'SignifyChange'))
endwhile
let line = new_line + offset
if s:external_sign_present(a:sy, line) | continue | endif
call add(ids, s:add_sign(a:sy, line, (removed > 9)
\ ? 'SignifyChangeDeleteMore'
\ : 'SignifyChangeDelete'. removed))
" lines changed and added:
" @@ -5 +5,3 @@ this is line 4
" -this is line 5
" +this os line 5
" +this is line 42
" +this is line 666
else
let modified += old_count
let offset = 0
while offset < old_count
let line = new_line + offset
let offset += 1
if s:external_sign_present(a:sy, line) | continue | endif
call add(ids, s:add_sign(a:sy, line, 'SignifyChange'))
let added += 1
endwhile
while offset < new_count
let line = new_line + offset
let offset += 1
if s:external_sign_present(a:sy, line) | continue | endif
call add(ids, s:add_sign(a:sy, line, 'SignifyAdd'))
endwhile
endif
endif
if !empty(ids)
call add(a:sy.hunks, {
\ 'ids' : ids,
\ 'start': a:sy.lines[0],
\ 'end' : a:sy.lines[-1] })
endif
endfor
" Remove obsoleted signs.
for line in filter(keys(a:sy.internal), '!has_key(a:sy.signtable, v:val)')
execute 'sign unplace' a:sy.internal[line].id 'buffer='.a:sy.buffer
endfor
let a:sy.stats = [added, modified, deleted]
endfunction
" Function: #remove_all_signs {{{1
function! sy#sign#remove_all_signs(bufnr) abort
let sy = getbufvar(a:bufnr, 'sy')
for hunk in sy.hunks
for id in hunk.ids
execute 'sign unplace' id 'buffer='.a:bufnr
endfor
endfor
let sy.hunks = []
endfunction
" Function: s:add_sign {{{1
function! s:add_sign(sy, line, type, ...) abort
call add(a:sy.lines, a:line)
let a:sy.signtable[a:line] = 1
if has_key(a:sy.internal, a:line)
" There is a sign on this line already.
if a:type == a:sy.internal[a:line].type
" Keep current sign since the new one is of the same type.
return a:sy.internal[a:line].id
else
" Update sign by overwriting the ID of the current sign.
let id = a:sy.internal[a:line].id
endif
endif
if !exists('id')
let id = sy#sign#id_next(a:sy)
endif
if a:type =~# 'SignifyDelete'
execute printf('sign define %s text=%s texthl=SignifySignDelete linehl=%s',
\ a:type,
\ a:1,
\ s:delete_highlight[g:signify_line_highlight])
endif
execute printf('sign place %d line=%d name=%s buffer=%s',
\ id,
\ a:line,
\ a:type,
\ a:sy.buffer)
return id
endfunction
" Function: s:external_sign_present {{{1
function! s:external_sign_present(sy, line) abort
if has_key(a:sy.external, a:line)
if has_key(a:sy.internal, a:line)
" Remove Sy signs from lines with other signs.
execute 'sign unplace' a:sy.internal[a:line].id 'buffer='.a:sy.buffer
endif
return 1
endif
endfunction