2018-03-31 14:55:20 +00:00
|
|
|
scriptencoding utf8
|
|
|
|
" Author: w0rp <devw0rp@gmail.com>
|
|
|
|
" Description: This module implements error/warning highlighting.
|
|
|
|
|
|
|
|
if !hlexists('ALEError')
|
|
|
|
highlight link ALEError SpellBad
|
|
|
|
endif
|
|
|
|
|
|
|
|
if !hlexists('ALEStyleError')
|
|
|
|
highlight link ALEStyleError ALEError
|
|
|
|
endif
|
|
|
|
|
|
|
|
if !hlexists('ALEWarning')
|
|
|
|
highlight link ALEWarning SpellCap
|
|
|
|
endif
|
|
|
|
|
|
|
|
if !hlexists('ALEStyleWarning')
|
|
|
|
highlight link ALEStyleWarning ALEWarning
|
|
|
|
endif
|
|
|
|
|
|
|
|
if !hlexists('ALEInfo')
|
|
|
|
highlight link ALEInfo ALEWarning
|
|
|
|
endif
|
|
|
|
|
|
|
|
" The maximum number of items for the second argument of matchaddpos()
|
|
|
|
let s:MAX_POS_VALUES = 8
|
|
|
|
let s:MAX_COL_SIZE = 1073741824 " pow(2, 30)
|
|
|
|
|
2019-11-16 15:28:42 +00:00
|
|
|
let s:has_nvim_highlight = exists('*nvim_buf_add_highlight') && exists('*nvim_buf_clear_namespace')
|
|
|
|
|
|
|
|
if s:has_nvim_highlight
|
|
|
|
let s:ns_id = nvim_create_namespace('ale_highlight')
|
|
|
|
endif
|
|
|
|
|
|
|
|
" Wrappers are necessary to test this functionality by faking the calls in tests.
|
|
|
|
function! ale#highlight#nvim_buf_add_highlight(buffer, ns_id, hl_group, line, col_start, col_end) abort
|
|
|
|
" Ignore all errors for adding highlights.
|
|
|
|
try
|
|
|
|
call nvim_buf_add_highlight(a:buffer, a:ns_id, a:hl_group, a:line, a:col_start, a:col_end)
|
|
|
|
catch
|
|
|
|
endtry
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
function! ale#highlight#nvim_buf_clear_namespace(buffer, ns_id, line_start, line_end) abort
|
|
|
|
call nvim_buf_clear_namespace(a:buffer, a:ns_id, a:line_start, a:line_end)
|
|
|
|
endfunction
|
|
|
|
|
2018-03-31 14:55:20 +00:00
|
|
|
function! ale#highlight#CreatePositions(line, col, end_line, end_col) abort
|
|
|
|
if a:line >= a:end_line
|
|
|
|
" For single lines, just return the one position.
|
|
|
|
return [[[a:line, a:col, a:end_col - a:col + 1]]]
|
|
|
|
endif
|
|
|
|
|
|
|
|
" Get positions from the first line at the first column, up to a large
|
|
|
|
" integer for highlighting up to the end of the line, followed by
|
|
|
|
" the lines in-between, for highlighting entire lines, and
|
|
|
|
" a highlight for the last line, up to the end column.
|
|
|
|
let l:all_positions =
|
|
|
|
\ [[a:line, a:col, s:MAX_COL_SIZE]]
|
|
|
|
\ + range(a:line + 1, a:end_line - 1)
|
|
|
|
\ + [[a:end_line, 1, a:end_col]]
|
|
|
|
|
|
|
|
return map(
|
|
|
|
\ range(0, len(l:all_positions) - 1, s:MAX_POS_VALUES),
|
|
|
|
\ 'l:all_positions[v:val : v:val + s:MAX_POS_VALUES - 1]',
|
|
|
|
\)
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
" Given a loclist for current items to highlight, remove all highlights
|
|
|
|
" except these which have matching loclist item entries.
|
2019-05-17 14:09:13 +00:00
|
|
|
|
2018-03-31 14:55:20 +00:00
|
|
|
function! ale#highlight#RemoveHighlights() abort
|
2019-11-16 15:28:42 +00:00
|
|
|
if s:has_nvim_highlight
|
|
|
|
call ale#highlight#nvim_buf_clear_namespace(bufnr(''), s:ns_id, 0, -1)
|
|
|
|
else
|
|
|
|
for l:match in getmatches()
|
|
|
|
if l:match.group =~? '\v^ALE(Style)?(Error|Warning|Info)(Line)?$'
|
|
|
|
call matchdelete(l:match.id)
|
|
|
|
endif
|
|
|
|
endfor
|
|
|
|
endif
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
" Same semantics of matchaddpos but will use nvim_buf_add_highlight if
|
|
|
|
" available. This involves iterating over the position list, switching from
|
|
|
|
" 1-based indexing to 0-based indexing, and translating the multiple ways
|
|
|
|
" that position can be specified for matchaddpos into line + col_start +
|
|
|
|
" col_end.
|
|
|
|
function! s:matchaddpos(group, pos_list) abort
|
|
|
|
if s:has_nvim_highlight
|
|
|
|
for l:pos in a:pos_list
|
|
|
|
let l:line = type(l:pos) == v:t_number
|
|
|
|
\ ? l:pos - 1
|
|
|
|
\ : l:pos[0] - 1
|
|
|
|
|
|
|
|
if type(l:pos) == v:t_number || len(l:pos) == 1
|
|
|
|
let l:col_start = 0
|
|
|
|
let l:col_end = s:MAX_COL_SIZE
|
|
|
|
else
|
|
|
|
let l:col_start = l:pos[1] - 1
|
|
|
|
let l:col_end = l:col_start + get(l:pos, 2, 1)
|
|
|
|
endif
|
|
|
|
|
|
|
|
call ale#highlight#nvim_buf_add_highlight(
|
|
|
|
\ bufnr(''),
|
|
|
|
\ s:ns_id,
|
|
|
|
\ a:group,
|
|
|
|
\ l:line,
|
|
|
|
\ l:col_start,
|
|
|
|
\ l:col_end,
|
|
|
|
\)
|
|
|
|
endfor
|
|
|
|
else
|
|
|
|
call matchaddpos(a:group, a:pos_list)
|
|
|
|
endif
|
2019-05-17 14:09:13 +00:00
|
|
|
endfunction
|
|
|
|
|
|
|
|
function! s:highlight_line(bufnr, lnum, group) abort
|
2019-11-16 15:28:42 +00:00
|
|
|
call s:matchaddpos(a:group, [a:lnum])
|
2019-05-17 14:09:13 +00:00
|
|
|
endfunction
|
|
|
|
|
|
|
|
function! s:highlight_range(bufnr, range, group) abort
|
2019-08-22 15:36:17 +00:00
|
|
|
" Set all of the positions, which are chunked into Lists which
|
|
|
|
" are as large as will be accepted by matchaddpos.
|
|
|
|
call map(
|
|
|
|
\ ale#highlight#CreatePositions(
|
|
|
|
\ a:range.lnum,
|
|
|
|
\ a:range.col,
|
|
|
|
\ a:range.end_lnum,
|
|
|
|
\ a:range.end_col
|
|
|
|
\ ),
|
2019-11-16 15:28:42 +00:00
|
|
|
\ 's:matchaddpos(a:group, v:val)'
|
2019-08-22 15:36:17 +00:00
|
|
|
\)
|
2018-03-31 14:55:20 +00:00
|
|
|
endfunction
|
|
|
|
|
|
|
|
function! ale#highlight#UpdateHighlights() abort
|
|
|
|
let l:item_list = get(b:, 'ale_enabled', 1) && g:ale_enabled
|
|
|
|
\ ? get(b:, 'ale_highlight_items', [])
|
|
|
|
\ : []
|
|
|
|
|
|
|
|
call ale#highlight#RemoveHighlights()
|
|
|
|
|
|
|
|
for l:item in l:item_list
|
|
|
|
if l:item.type is# 'W'
|
|
|
|
if get(l:item, 'sub_type', '') is# 'style'
|
|
|
|
let l:group = 'ALEStyleWarning'
|
|
|
|
else
|
|
|
|
let l:group = 'ALEWarning'
|
|
|
|
endif
|
|
|
|
elseif l:item.type is# 'I'
|
|
|
|
let l:group = 'ALEInfo'
|
|
|
|
elseif get(l:item, 'sub_type', '') is# 'style'
|
|
|
|
let l:group = 'ALEStyleError'
|
|
|
|
else
|
|
|
|
let l:group = 'ALEError'
|
|
|
|
endif
|
|
|
|
|
2019-05-17 14:09:13 +00:00
|
|
|
let l:range = {
|
|
|
|
\ 'lnum': l:item.lnum,
|
|
|
|
\ 'col': l:item.col,
|
|
|
|
\ 'end_lnum': get(l:item, 'end_lnum', l:item.lnum),
|
|
|
|
\ 'end_col': get(l:item, 'end_col', l:item.col)
|
|
|
|
\}
|
2018-03-31 14:55:20 +00:00
|
|
|
|
2019-05-17 14:09:13 +00:00
|
|
|
call s:highlight_range(l:item.bufnr, l:range, l:group)
|
2018-03-31 14:55:20 +00:00
|
|
|
endfor
|
|
|
|
|
|
|
|
" If highlights are enabled and signs are not enabled, we should still
|
|
|
|
" offer line highlights by adding a separate set of highlights.
|
|
|
|
if !g:ale_set_signs
|
|
|
|
let l:available_groups = {
|
|
|
|
\ 'ALEWarningLine': hlexists('ALEWarningLine'),
|
|
|
|
\ 'ALEInfoLine': hlexists('ALEInfoLine'),
|
|
|
|
\ 'ALEErrorLine': hlexists('ALEErrorLine'),
|
|
|
|
\}
|
|
|
|
|
|
|
|
for l:item in l:item_list
|
|
|
|
if l:item.type is# 'W'
|
|
|
|
let l:group = 'ALEWarningLine'
|
|
|
|
elseif l:item.type is# 'I'
|
|
|
|
let l:group = 'ALEInfoLine'
|
|
|
|
else
|
|
|
|
let l:group = 'ALEErrorLine'
|
|
|
|
endif
|
|
|
|
|
|
|
|
if l:available_groups[l:group]
|
2019-05-17 14:09:13 +00:00
|
|
|
call s:highlight_line(l:item.bufnr, l:item.lnum, l:group)
|
2018-03-31 14:55:20 +00:00
|
|
|
endif
|
|
|
|
endfor
|
|
|
|
endif
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
function! ale#highlight#BufferHidden(buffer) abort
|
|
|
|
" Remove highlights right away when buffers are hidden.
|
|
|
|
" They will be restored later when buffers are entered.
|
|
|
|
call ale#highlight#RemoveHighlights()
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
augroup ALEHighlightBufferGroup
|
|
|
|
autocmd!
|
|
|
|
autocmd BufEnter * call ale#highlight#UpdateHighlights()
|
|
|
|
autocmd BufHidden * call ale#highlight#BufferHidden(expand('<abuf>'))
|
|
|
|
augroup END
|
|
|
|
|
|
|
|
function! ale#highlight#SetHighlights(buffer, loclist) abort
|
|
|
|
let l:new_list = getbufvar(a:buffer, 'ale_enabled', 1) && g:ale_enabled
|
|
|
|
\ ? filter(copy(a:loclist), 'v:val.bufnr == a:buffer && v:val.col > 0')
|
|
|
|
\ : []
|
|
|
|
|
|
|
|
" Set the list in the buffer variable.
|
|
|
|
call setbufvar(str2nr(a:buffer), 'ale_highlight_items', l:new_list)
|
|
|
|
|
2020-04-26 01:56:16 +00:00
|
|
|
let l:exclude_list = ale#Var(a:buffer, 'exclude_highlights')
|
|
|
|
|
|
|
|
if !empty(l:exclude_list)
|
|
|
|
call filter(l:new_list, 'empty(ale#util#GetMatches(v:val.text, l:exclude_list))')
|
|
|
|
endif
|
|
|
|
|
2018-03-31 14:55:20 +00:00
|
|
|
" Update highlights for the current buffer, which may or may not
|
|
|
|
" be the buffer we just set highlights for.
|
|
|
|
call ale#highlight#UpdateHighlights()
|
|
|
|
endfunction
|