Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

highlight using text properties instead of matchaddpos() when possible #2652

Merged
merged 4 commits into from
Jan 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions autoload/go/guru.vim
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ function! s:same_ids_highlight(exit_val, output, mode) abort
let l:matches = add(l:matches, [str2nr(pos[-2]), str2nr(pos[-1]), str2nr(poslen)])
endfor

call go#util#MatchAddPos('goSameId', l:matches)
call go#util#HighlightPositions('goSameId', l:matches)

if go#config#AutoSameids()
" re-apply SameIds at the current cursor position at the time the buffer
Expand All @@ -492,7 +492,7 @@ endfunction
" ClearSameIds returns 0 when it removes goSameId groups and non-zero if no
" goSameId groups are found.
function! go#guru#ClearSameIds() abort
let l:cleared = go#util#ClearGroupFromMatches('goSameId')
let l:cleared = go#util#ClearHighlights('goSameId')

if !l:cleared
return 1
Expand Down
64 changes: 32 additions & 32 deletions autoload/go/lsp.vim
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,9 @@ function! s:newlsp() abort
endif

for l:diag in l:data.diagnostics
" TODO(bc): cache the raw diagnostics when they're not for the
" current buffer so that they can be processed when it is the
" current buffer and highlight the areas of concern.
let [l:error, l:matchpos] = s:errorFromDiagnostic(l:diag, l:bufname, l:fname)
let l:diagnostics = add(l:diagnostics, l:error)

Expand Down Expand Up @@ -1189,45 +1192,42 @@ function! s:errorFromDiagnostic(diagnostic, bufname, fname) abort
endfunction

function! s:highlightMatches(errorMatches, warningMatches) abort
" TODO(bc): use text properties instead of matchaddpos
if exists("*matchaddpos")
" set buffer variables for errors and warnings to zero values
let b:go_diagnostic_matches = {'errors': [], 'warnings': []}

if hlexists('goDiagnosticError')
" clear the old matches just before adding the new ones to keep flicker
" to a minimum.
call go#util#ClearGroupFromMatches('goDiagnosticError')
if go#config#HighlightDiagnosticErrors()
let b:go_diagnostic_matches.errors = copy(a:errorMatches)
call go#util#MatchAddPos('goDiagnosticError', a:errorMatches)
endif
" set buffer variables for errors and warnings to zero values
let b:go_diagnostic_matches = {'errors': [], 'warnings': []}

if hlexists('goDiagnosticError')
" clear the old matches just before adding the new ones to keep flicker
" to a minimum.
call go#util#ClearHighlights('goDiagnosticError')
if go#config#HighlightDiagnosticErrors()
let b:go_diagnostic_matches.errors = copy(a:errorMatches)
call go#util#HighlightPositions('goDiagnosticError', a:errorMatches)
endif
endif

if hlexists('goDiagnosticWarning')
" clear the old matches just before adding the new ones to keep flicker
" to a minimum.
call go#util#ClearGroupFromMatches('goDiagnosticWarning')
if go#config#HighlightDiagnosticWarnings()
let b:go_diagnostic_matches.warnings = copy(a:warningMatches)
call go#util#MatchAddPos('goDiagnosticWarning', a:warningMatches)
endif
if hlexists('goDiagnosticWarning')
" clear the old matches just before adding the new ones to keep flicker
" to a minimum.
call go#util#ClearHighlights('goDiagnosticWarning')
if go#config#HighlightDiagnosticWarnings()
let b:go_diagnostic_matches.warnings = copy(a:warningMatches)
call go#util#HighlightPositions('goDiagnosticWarning', a:warningMatches)
endif

" re-apply matches at the time the buffer is displayed in a new window or
" redisplayed in an existing window: e.g. :edit,
augroup vim-go-diagnostics
autocmd! * <buffer>
autocmd BufWinEnter <buffer> nested call s:highlightMatches(b:go_diagnostic_matches.errors, b:go_diagnostic_matches.warnings)
augroup end
endif

" re-apply matches at the time the buffer is displayed in a new window or
" redisplayed in an existing window: e.g. :edit,
augroup vim-go-diagnostics
autocmd! * <buffer>
autocmd BufWinEnter <buffer> nested call s:highlightMatches(b:go_diagnostic_matches.errors, b:go_diagnostic_matches.warnings)
augroup end
endfunction

" ClearDiagnosticsMatches removes all goDiagnosticError and
" ClearDiagnosticsHighlights removes all goDiagnosticError and
" goDiagnosticWarning matches.
function! go#lsp#ClearDiagnosticMatches() abort
call go#util#ClearGroupFromMatches('goDiagnosticError')
call go#util#ClearGroupFromMatches('goDiagnosticWarning')
function! go#lsp#ClearDiagnosticHighlights() abort
call go#util#ClearHighlights('goDiagnosticError')
call go#util#ClearHighlights('goDiagnosticWarning')
endfunction

" restore Vi compatibility settings
Expand Down
66 changes: 60 additions & 6 deletions autoload/go/util.vim
Original file line number Diff line number Diff line change
Expand Up @@ -551,11 +551,17 @@ function! go#util#SetEnv(name, value) abort
return function('go#util#SetEnv', [a:name, l:oldvalue], l:state)
endfunction

function! go#util#ClearGroupFromMatches(group) abort
if !exists("*matchaddpos")
return 0
function! go#util#ClearHighlights(group) abort
if exists('*prop_remove')
return prop_remove({'type': a:group, 'all': 1})
endif

if exists("*matchaddpos")
return s:clear_group_from_matches(a:group)
endif
endfunction

function! s:clear_group_from_matches(group) abort
let l:cleared = 0

let m = getmatches()
Expand Down Expand Up @@ -589,9 +595,57 @@ endfunction
function! s:noop(...) abort dict
endfunction

" go#util#MatchAddPos works around matchaddpos()'s limit of only 8 positions
" per call by calling matchaddpos() with no more than 8 positions per call.
function! go#util#MatchAddPos(group, pos)
" go#util#HighlightPositions highlights using text properties if possible and
" falls back to matchaddpos() if necessary. It works around matchaddpos()'s
" limit of only 8 positions per call by calling matchaddpos() with no more
" than 8 positions per call.
"
" pos should be a list of 3 element lists. The lists should be [line, col,
" length] as used by matchaddpos().
function! go#util#HighlightPositions(group, pos) abort
if exists('*prop_add')
for l:pos in a:pos
" use a single line prop by default
let l:prop = {'type': a:group, 'length': l:pos[2]}

" specify end line and column if needed.
let l:line = getline(l:pos[0])

" l:max is the 1-based index within the buffer of the first character after l:pos.
let l:max = line2byte(l:pos[0]) + l:pos[1] + l:pos[2] - 1

if has('patch-8.2.115')
" Use byte2line as long as 8.2.115 (which resolved
" https://github.com/vim/vim/issues/5334) is available.
let l:end_lnum = byte2line(l:max)

if l:pos[0] != l:end_lnum
let l:end_col = l:max - line2byte(l:end_lnum)
let l:prop = {'type': a:group, 'end_lnum': l:end_lnum, 'end_col': l:end_col}
endif
elseif l:pos[1] + l:pos[2] - 1 > len(l:line)
let l:end_lnum = l:pos[0]
let l:end_col = l:pos[1] + l:pos[2] - 1
while line2byte(l:end_lnum+1) < l:max
let l:end_lnum += 1
let l:end_col -= line2byte(l:end_lnum)
endwhile
let l:prop = {'type': a:group, 'end_lnum': l:end_lnum, 'end_col': l:end_col}
endif
call prop_add(l:pos[0], l:pos[1], l:prop)
endfor
return
endif

if exists('*matchaddpos')
return s:matchaddpos(a:group, a:pos)
endif
endfunction


" s:matchaddpos works around matchaddpos()'s limit of only 8 positions per
" call by calling matchaddpos() with no more than 8 positions per call.
function! s:matchaddpos(group, pos) abort
let l:partitions = []
let l:partitionsIdx = 0
let l:posIdx = 0
Expand Down
16 changes: 14 additions & 2 deletions ftplugin/go.vim
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,18 @@ if get(g:, "go_textobj_enabled", 1)
xnoremap <buffer> <silent> [[ :<c-u>call go#textobj#FunctionJump('v', 'prev')<cr>
endif

if exists('*prop_type_add')
if empty(prop_type_get('goSameId'))
call prop_type_add('goSameId', {'highlight': 'goSameId'})
endif
if empty(prop_type_get('goDiagnosticError'))
call prop_type_add('goDiagnosticError', {'highlight': 'goDiagnosticError'})
endif
if empty(prop_type_get('goDiagnosticWarning'))
call prop_type_add('goDiagnosticWarning', {'highlight': 'goDiagnosticWarning'})
endif
endif

" Autocommands
" ============================================================================
"
Expand Down Expand Up @@ -117,10 +129,10 @@ augroup vim-go-buffer
" clear diagnostics when the buffer is unloaded from its last window so that
" loading another buffer (especially of a different filetype) in the same
" window doesn't highlight th previously loaded buffer's diagnostics.
autocmd BufWinLeave <buffer> call go#lsp#ClearDiagnosticMatches()
autocmd BufWinLeave <buffer> call go#lsp#ClearDiagnosticHighlights()
" clear diagnostics when a new buffer is loaded in the window so that the
" previous buffer's diagnostcs aren't used.
autocmd BufWinEnter <buffer> call go#lsp#ClearDiagnosticMatches()
autocmd BufWinEnter <buffer> call go#lsp#ClearDiagnosticHighlights()

autocmd BufEnter <buffer>
\ if go#config#AutodetectGopath() && !exists('b:old_gopath')
Expand Down