]> git.madduck.net Git - etc/vim.git/blobdiff - .vim/bundle/ale/autoload/ale/sign.vim

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Merge commit '76265755a1add77121c8f9dabb3e9bb70fe9a972' as '.vim/bundle/ale'
[etc/vim.git] / .vim / bundle / ale / autoload / ale / sign.vim
diff --git a/.vim/bundle/ale/autoload/ale/sign.vim b/.vim/bundle/ale/autoload/ale/sign.vim
new file mode 100644 (file)
index 0000000..369896a
--- /dev/null
@@ -0,0 +1,496 @@
+scriptencoding utf8
+" Author: w0rp <devw0rp@gmail.com>
+" Description: Draws error and warning signs into signcolumn
+
+" This flag can be set to some integer to control the maximum number of signs
+" that ALE will set.
+let g:ale_max_signs = get(g:, 'ale_max_signs', -1)
+" This flag can be set to 1 to enable changing the sign column colors when
+" there are errors.
+let g:ale_change_sign_column_color = get(g:, 'ale_change_sign_column_color', v:false)
+" These variables dictate what signs are used to indicate errors and warnings.
+let g:ale_sign_error = get(g:, 'ale_sign_error', 'E')
+let g:ale_sign_style_error = get(g:, 'ale_sign_style_error', g:ale_sign_error)
+let g:ale_sign_warning = get(g:, 'ale_sign_warning', 'W')
+let g:ale_sign_style_warning = get(g:, 'ale_sign_style_warning', g:ale_sign_warning)
+let g:ale_sign_info = get(g:, 'ale_sign_info', 'I')
+let g:ale_sign_priority = get(g:, 'ale_sign_priority', 30)
+" This variable sets an offset which can be set for sign IDs.
+" This ID can be changed depending on what IDs are set for other plugins.
+" The dummy sign will use the ID exactly equal to the offset.
+let g:ale_sign_offset = get(g:, 'ale_sign_offset', 1000000)
+" This flag can be set to 1 to keep sign gutter always open
+let g:ale_sign_column_always = get(g:, 'ale_sign_column_always', v:false)
+let g:ale_sign_highlight_linenrs = get(g:, 'ale_sign_highlight_linenrs', v:false)
+
+let s:supports_sign_groups = has('nvim-0.4.2') || has('patch-8.1.614')
+
+if !hlexists('ALEErrorSign')
+    highlight link ALEErrorSign error
+endif
+
+if !hlexists('ALEStyleErrorSign')
+    highlight link ALEStyleErrorSign ALEErrorSign
+endif
+
+if !hlexists('ALEWarningSign')
+    highlight link ALEWarningSign todo
+endif
+
+if !hlexists('ALEStyleWarningSign')
+    highlight link ALEStyleWarningSign ALEWarningSign
+endif
+
+if !hlexists('ALEInfoSign')
+    highlight link ALEInfoSign ALEWarningSign
+endif
+
+if !hlexists('ALESignColumnWithErrors')
+    highlight link ALESignColumnWithErrors error
+endif
+
+function! ale#sign#SetUpDefaultColumnWithoutErrorsHighlight() abort
+    let l:verbose = &verbose
+    set verbose=0
+    let l:output = execute('highlight SignColumn', 'silent')
+    let &verbose = l:verbose
+
+    let l:highlight_syntax = join(split(l:output)[2:])
+    let l:match = matchlist(l:highlight_syntax, '\vlinks to (.+)$')
+
+    if !empty(l:match)
+        execute 'highlight link ALESignColumnWithoutErrors ' . l:match[1]
+    elseif l:highlight_syntax isnot# 'cleared'
+        execute 'highlight ALESignColumnWithoutErrors ' . l:highlight_syntax
+    endif
+endfunction
+
+if !hlexists('ALESignColumnWithoutErrors')
+    call ale#sign#SetUpDefaultColumnWithoutErrorsHighlight()
+endif
+
+" Spaces and backslashes need to be escaped for signs.
+function! s:EscapeSignText(sign_text) abort
+    return substitute(substitute(a:sign_text, ' *$', '', ''), '\\\| ', '\\\0', 'g')
+endfunction
+
+" Signs show up on the left for error markers.
+execute 'sign define ALEErrorSign text=' . s:EscapeSignText(g:ale_sign_error)
+\   . ' texthl=ALEErrorSign linehl=ALEErrorLine'
+execute 'sign define ALEStyleErrorSign text=' .  s:EscapeSignText(g:ale_sign_style_error)
+\   . ' texthl=ALEStyleErrorSign linehl=ALEErrorLine'
+execute 'sign define ALEWarningSign text=' . s:EscapeSignText(g:ale_sign_warning)
+\   . ' texthl=ALEWarningSign linehl=ALEWarningLine'
+execute 'sign define ALEStyleWarningSign text=' . s:EscapeSignText(g:ale_sign_style_warning)
+\   . ' texthl=ALEStyleWarningSign linehl=ALEWarningLine'
+execute 'sign define ALEInfoSign text=' . s:EscapeSignText(g:ale_sign_info)
+\   . ' texthl=ALEInfoSign linehl=ALEInfoLine'
+sign define ALEDummySign text=\  texthl=SignColumn
+
+if g:ale_sign_highlight_linenrs && (has('nvim-0.3.2') || has('patch-8.2.3874'))
+    if !hlexists('ALEErrorSignLineNr')
+        highlight link ALEErrorSignLineNr CursorLineNr
+    endif
+
+    if !hlexists('ALEStyleErrorSignLineNr')
+        highlight link ALEStyleErrorSignLineNr CursorLineNr
+    endif
+
+    if !hlexists('ALEWarningSignLineNr')
+        highlight link ALEWarningSignLineNr CursorLineNr
+    endif
+
+    if !hlexists('ALEStyleWarningSignLineNr')
+        highlight link ALEStyleWarningSignLineNr CursorLineNr
+    endif
+
+    if !hlexists('ALEInfoSignLineNr')
+        highlight link ALEInfoSignLineNr CursorLineNr
+    endif
+
+    sign define ALEErrorSign numhl=ALEErrorSignLineNr
+    sign define ALEStyleErrorSign numhl=ALEStyleErrorSignLineNr
+    sign define ALEWarningSign numhl=ALEWarningSignLineNr
+    sign define ALEStyleWarningSign numhl=ALEStyleWarningSignLineNr
+    sign define ALEInfoSign numhl=ALEInfoSignLineNr
+endif
+
+function! ale#sign#GetSignName(sublist) abort
+    let l:priority = g:ale#util#style_warning_priority
+
+    " Determine the highest priority item for the line.
+    for l:item in a:sublist
+        let l:item_priority = ale#util#GetItemPriority(l:item)
+
+        if l:item_priority > l:priority
+            let l:priority = l:item_priority
+        endif
+    endfor
+
+    if l:priority is# g:ale#util#error_priority
+        return 'ALEErrorSign'
+    endif
+
+    if l:priority is# g:ale#util#warning_priority
+        return 'ALEWarningSign'
+    endif
+
+    if l:priority is# g:ale#util#style_error_priority
+        return 'ALEStyleErrorSign'
+    endif
+
+    if l:priority is# g:ale#util#style_warning_priority
+        return 'ALEStyleWarningSign'
+    endif
+
+    if l:priority is# g:ale#util#info_priority
+        return 'ALEInfoSign'
+    endif
+
+    " Use the error sign for invalid severities.
+    return 'ALEErrorSign'
+endfunction
+
+function! s:PriorityCmd() abort
+    if s:supports_sign_groups
+        return ' priority=' . g:ale_sign_priority . ' '
+    else
+        return ''
+    endif
+endfunction
+
+function! s:GroupCmd() abort
+    if s:supports_sign_groups
+        return ' group=ale_signs '
+    else
+        return ' '
+    endif
+endfunction
+
+" Read sign data for a buffer to a list of lines.
+function! ale#sign#ReadSigns(buffer) abort
+    let l:output = execute(
+    \   'sign place ' . s:GroupCmd() . s:PriorityCmd()
+    \   . ' buffer=' . a:buffer
+    \ )
+
+    return split(l:output, "\n")
+endfunction
+
+function! ale#sign#ParsePattern() abort
+    if s:supports_sign_groups
+        " Matches output like :
+        " line=4  id=1  group=ale_signs  name=ALEErrorSign
+        " строка=1  id=1000001  группа=ale_signs  имя=ALEErrorSign
+        " 行=1  識別子=1000001  グループ=ale_signs  名前=ALEWarningSign
+        " línea=12 id=1000001 grupo=ale_signs  nombre=ALEWarningSign
+        " riga=1 id=1000001  gruppo=ale_signs   nome=ALEWarningSign
+        " Zeile=235  id=1000001 Gruppe=ale_signs  Name=ALEErrorSign
+        let l:pattern = '\v^.*\=(\d+).*\=(\d+).*\=ale_signs>.*\=(ALE[a-zA-Z]+Sign)'
+    else
+        " Matches output like :
+        " line=4  id=1  name=ALEErrorSign
+        " строка=1  id=1000001  имя=ALEErrorSign
+        " 行=1  識別子=1000001  名前=ALEWarningSign
+        " línea=12 id=1000001 nombre=ALEWarningSign
+        " riga=1 id=1000001  nome=ALEWarningSign
+        " Zeile=235  id=1000001  Name=ALEErrorSign
+        let l:pattern = '\v^.*\=(\d+).*\=(\d+).*\=(ALE[a-zA-Z]+Sign)'
+    endif
+
+    return l:pattern
+endfunction
+
+" Given a buffer number, return a List of placed signs [line, id, group]
+function! ale#sign#ParseSignsWithGetPlaced(buffer) abort
+    let l:signs = sign_getplaced(a:buffer, { 'group': s:supports_sign_groups ? 'ale_signs' : '' })[0].signs
+    let l:result = []
+    let l:is_dummy_sign_set = 0
+
+    for l:sign in l:signs
+        if l:sign['name'] is# 'ALEDummySign'
+            let l:is_dummy_sign_set = 1
+        else
+            call add(l:result, [
+            \   str2nr(l:sign['lnum']),
+            \   str2nr(l:sign['id']),
+            \   l:sign['name'],
+            \])
+        endif
+    endfor
+
+    return [l:is_dummy_sign_set, l:result]
+endfunction
+
+" Given a list of lines for sign output, return a List of [line, id, group]
+function! ale#sign#ParseSigns(line_list) abort
+    let l:pattern =ale#sign#ParsePattern()
+    let l:result = []
+    let l:is_dummy_sign_set = 0
+
+    for l:line in a:line_list
+        let l:match = matchlist(l:line, l:pattern)
+
+        if len(l:match) > 0
+            if l:match[3] is# 'ALEDummySign'
+                let l:is_dummy_sign_set = 1
+            else
+                call add(l:result, [
+                \   str2nr(l:match[1]),
+                \   str2nr(l:match[2]),
+                \   l:match[3],
+                \])
+            endif
+        endif
+    endfor
+
+    return [l:is_dummy_sign_set, l:result]
+endfunction
+
+function! ale#sign#FindCurrentSigns(buffer) abort
+    if exists('*sign_getplaced')
+        return ale#sign#ParseSignsWithGetPlaced(a:buffer)
+    else
+        let l:line_list = ale#sign#ReadSigns(a:buffer)
+
+        return ale#sign#ParseSigns(l:line_list)
+    endif
+endfunction
+
+" Given a loclist, group the List into with one List per line.
+function! s:GroupLoclistItems(buffer, loclist) abort
+    let l:grouped_items = []
+    let l:last_lnum = -1
+
+    for l:obj in a:loclist
+        if l:obj.bufnr != a:buffer
+            continue
+        endif
+
+        " Create a new sub-List when we hit a new line.
+        if l:obj.lnum != l:last_lnum
+            call add(l:grouped_items, [])
+        endif
+
+        call add(l:grouped_items[-1], l:obj)
+        let l:last_lnum = l:obj.lnum
+    endfor
+
+    return l:grouped_items
+endfunction
+
+function! s:UpdateLineNumbers(buffer, current_sign_list, loclist) abort
+    let l:line_map = {}
+    let l:line_numbers_changed = 0
+
+    for [l:line, l:sign_id, l:name] in a:current_sign_list
+        let l:line_map[l:sign_id] = l:line
+    endfor
+
+    for l:item in a:loclist
+        if l:item.bufnr == a:buffer
+            let l:lnum = get(l:line_map, get(l:item, 'sign_id', 0), 0)
+
+            if l:lnum && l:item.lnum != l:lnum
+                let l:item.lnum = l:lnum
+                let l:line_numbers_changed = 1
+            endif
+        endif
+    endfor
+
+    " When the line numbers change, sort the list again
+    if l:line_numbers_changed
+        call sort(a:loclist, 'ale#util#LocItemCompare')
+    endif
+endfunction
+
+function! s:BuildSignMap(buffer, current_sign_list, grouped_items) abort
+    let l:max_signs = ale#Var(a:buffer, 'max_signs')
+
+    if l:max_signs is 0
+        let l:selected_grouped_items = []
+    elseif type(l:max_signs) is v:t_number && l:max_signs > 0
+        let l:selected_grouped_items = a:grouped_items[:l:max_signs - 1]
+    else
+        let l:selected_grouped_items = a:grouped_items
+    endif
+
+    let l:sign_map = {}
+    let l:sign_offset = g:ale_sign_offset
+
+    for [l:line, l:sign_id, l:name] in a:current_sign_list
+        let l:sign_info = get(l:sign_map, l:line, {
+        \   'current_id_list': [],
+        \   'current_name_list': [],
+        \   'new_id': 0,
+        \   'new_name': '',
+        \   'items': [],
+        \})
+
+        " Increment the sign offset for new signs, by the maximum sign ID.
+        if l:sign_id > l:sign_offset
+            let l:sign_offset = l:sign_id
+        endif
+
+        " Remember the sign names and IDs in separate Lists, so they are easy
+        " to work with.
+        call add(l:sign_info.current_id_list, l:sign_id)
+        call add(l:sign_info.current_name_list, l:name)
+
+        let l:sign_map[l:line] = l:sign_info
+    endfor
+
+    for l:group in l:selected_grouped_items
+        let l:line = l:group[0].lnum
+        let l:sign_info = get(l:sign_map, l:line, {
+        \   'current_id_list': [],
+        \   'current_name_list': [],
+        \   'new_id': 0,
+        \   'new_name': '',
+        \   'items': [],
+        \})
+
+        let l:sign_info.new_name = ale#sign#GetSignName(l:group)
+        let l:sign_info.items = l:group
+
+        let l:index = index(
+        \   l:sign_info.current_name_list,
+        \   l:sign_info.new_name
+        \)
+
+        if l:index >= 0
+            " We have a sign with this name already, so use the same ID.
+            let l:sign_info.new_id = l:sign_info.current_id_list[l:index]
+        else
+            " This sign name replaces the previous name, so use a new ID.
+            let l:sign_info.new_id = l:sign_offset + 1
+            let l:sign_offset += 1
+        endif
+
+        let l:sign_map[l:line] = l:sign_info
+    endfor
+
+    return l:sign_map
+endfunction
+
+function! ale#sign#GetSignCommands(buffer, was_sign_set, sign_map) abort
+    let l:command_list = []
+    let l:is_dummy_sign_set = a:was_sign_set
+
+    " Set the dummy sign if we need to.
+    " The dummy sign is needed to keep the sign column open while we add
+    " and remove signs.
+    if !l:is_dummy_sign_set && (!empty(a:sign_map) || g:ale_sign_column_always)
+        call add(l:command_list, 'sign place '
+        \   .  g:ale_sign_offset
+        \   . s:GroupCmd()
+        \   . s:PriorityCmd()
+        \   . ' line=1 name=ALEDummySign '
+        \   . ' buffer=' . a:buffer
+        \)
+        let l:is_dummy_sign_set = 1
+    endif
+
+    " Place new items first.
+    for [l:line_str, l:info] in items(a:sign_map)
+        if l:info.new_id
+            " Save the sign IDs we are setting back on our loclist objects.
+            " These IDs will be used to preserve items which are set many times.
+            for l:item in l:info.items
+                let l:item.sign_id = l:info.new_id
+            endfor
+
+            if index(l:info.current_id_list, l:info.new_id) < 0
+                call add(l:command_list, 'sign place '
+                \   . (l:info.new_id)
+                \   . s:GroupCmd()
+                \   . s:PriorityCmd()
+                \   . ' line=' . l:line_str
+                \   . ' name=' . (l:info.new_name)
+                \   . ' buffer=' . a:buffer
+                \)
+            endif
+        endif
+    endfor
+
+    " Remove signs without new IDs.
+    for l:info in values(a:sign_map)
+        for l:current_id in l:info.current_id_list
+            if l:current_id isnot l:info.new_id
+                call add(l:command_list, 'sign unplace '
+                \   . l:current_id
+                \   . s:GroupCmd()
+                \   . ' buffer=' . a:buffer
+                \)
+            endif
+        endfor
+    endfor
+
+    " Remove the dummy sign to close the sign column if we need to.
+    if l:is_dummy_sign_set && !g:ale_sign_column_always
+        call add(l:command_list, 'sign unplace '
+        \   . g:ale_sign_offset
+        \   . s:GroupCmd()
+        \   . ' buffer=' . a:buffer
+        \)
+    endif
+
+    return l:command_list
+endfunction
+
+" This function will set the signs which show up on the left.
+function! ale#sign#SetSigns(buffer, loclist) abort
+    if !bufexists(str2nr(a:buffer))
+        " Stop immediately when attempting to set signs for a buffer which
+        " does not exist.
+        return
+    endif
+
+    " Find the current markers
+    let [l:is_dummy_sign_set, l:current_sign_list] =
+    \   ale#sign#FindCurrentSigns(a:buffer)
+
+    " Update the line numbers for items from before which may have moved.
+    call s:UpdateLineNumbers(a:buffer, l:current_sign_list, a:loclist)
+
+    " Group items after updating the line numbers.
+    let l:grouped_items = s:GroupLoclistItems(a:buffer, a:loclist)
+
+    " Build a map of current and new signs, with the lines as the keys.
+    let l:sign_map = s:BuildSignMap(
+    \   a:buffer,
+    \   l:current_sign_list,
+    \   l:grouped_items,
+    \)
+
+    let l:command_list = ale#sign#GetSignCommands(
+    \   a:buffer,
+    \   l:is_dummy_sign_set,
+    \   l:sign_map,
+    \)
+
+    " Change the sign column color if the option is on.
+    if g:ale_change_sign_column_color && !empty(a:loclist)
+        highlight clear SignColumn
+        highlight link SignColumn ALESignColumnWithErrors
+    endif
+
+    for l:command in l:command_list
+        silent! execute l:command
+    endfor
+
+    " Reset the sign column color when there are no more errors.
+    if g:ale_change_sign_column_color && empty(a:loclist)
+        highlight clear SignColumn
+        highlight link SignColumn ALESignColumnWithoutErrors
+    endif
+endfunction
+
+" Remove all signs.
+function! ale#sign#Clear() abort
+    if s:supports_sign_groups
+        sign unplace group=ale_signs *
+    else
+        sign unplace *
+    endif
+endfunction