]> git.madduck.net Git - etc/vim.git/blobdiff - .vim/bundle/vim-lsp/autoload/lsp/internal/document_highlight.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 'a39f715c13be3352193ffd9c5b7536b8786eff64' as '.vim/bundle/vim-lsp'
[etc/vim.git] / .vim / bundle / vim-lsp / autoload / lsp / internal / document_highlight.vim
diff --git a/.vim/bundle/vim-lsp/autoload/lsp/internal/document_highlight.vim b/.vim/bundle/vim-lsp/autoload/lsp/internal/document_highlight.vim
new file mode 100644 (file)
index 0000000..a6022e0
--- /dev/null
@@ -0,0 +1,238 @@
+let s:use_vim_textprops = lsp#utils#_has_textprops() && !has('nvim')
+let s:prop_id = 11
+
+function! lsp#internal#document_highlight#_enable() abort
+    " don't event bother registering if the feature is disabled
+    if !g:lsp_document_highlight_enabled | return | endif
+
+    " Highlight group for references
+    if !hlexists('lspReference')
+        highlight link lspReference CursorColumn
+    endif
+
+    " Note:
+    " - update highlight references when CusorMoved or CursorHold
+    " - clear highlights when InsertEnter or BufLeave
+    " - debounce highlight requests
+    " - automatically switch to latest highlight request via switchMap()
+    " - cancel highlight request via takeUntil() when BufLeave
+    let s:Dispose = lsp#callbag#pipe(
+        \ lsp#callbag#merge(
+        \   lsp#callbag#fromEvent(['CursorMoved', 'CursorHold']),
+        \   lsp#callbag#pipe(
+        \       lsp#callbag#fromEvent(['InsertEnter', 'BufLeave']),
+        \       lsp#callbag#tap({_ -> s:clear_highlights() }),
+        \   )
+        \ ),
+        \ lsp#callbag#filter({_ -> g:lsp_document_highlight_enabled }),
+        \ lsp#callbag#debounceTime(g:lsp_document_highlight_delay),
+        \ lsp#callbag#map({_->{'bufnr': bufnr('%'), 'curpos': getcurpos()[0:2], 'changedtick': b:changedtick }}),
+        \ lsp#callbag#distinctUntilChanged({a,b -> a['bufnr'] == b['bufnr'] && a['curpos'] == b['curpos'] && a['changedtick'] == b['changedtick']}),
+        \ lsp#callbag#filter({_->mode() is# 'n' && getbufvar(bufnr('%'), '&buftype') !=# 'terminal' }),
+        \ lsp#callbag#switchMap({_->
+        \   lsp#callbag#pipe(
+        \       s:send_highlight_request(),
+        \       lsp#callbag#materialize(),
+        \       lsp#callbag#filter({x->lsp#callbag#isNextNotification(x)}),
+        \       lsp#callbag#map({x->x['value']}),
+        \       lsp#callbag#takeUntil(
+        \           lsp#callbag#fromEvent('BufLeave')
+        \       )
+        \   )
+        \ }),
+        \ lsp#callbag#filter({_->mode() is# 'n'}),
+        \ lsp#callbag#subscribe({x->s:set_highlights(x)}),
+        \)
+endfunction
+
+function! lsp#internal#document_highlight#_disable() abort
+    if exists('s:Dispose')
+        call s:Dispose()
+        unlet s:Dispose
+    endif
+endfunction
+
+function! s:send_highlight_request() abort
+    let l:capability = 'lsp#capabilities#has_document_highlight_provider(v:val)'
+    let l:servers = filter(lsp#get_allowed_servers(), l:capability)
+
+    if empty(l:servers)
+        return lsp#callbag#empty()
+    endif
+
+    return lsp#request(l:servers[0], {
+        \ 'method': 'textDocument/documentHighlight',
+        \ 'params': {
+        \   'textDocument': lsp#get_text_document_identifier(),
+        \   'position': lsp#get_position(),
+        \  },
+        \ })
+endfunction
+
+function! s:set_highlights(data) abort
+    let l:bufnr = bufnr('%')
+
+    call s:clear_highlights()
+
+    if mode() !=# 'n' | return | endif
+
+    if lsp#client#is_error(a:data['response']) | return | endif
+
+    " Get references from the response
+    let l:reference_list = a:data['response']['result']
+    if empty(l:reference_list)
+        return
+    endif
+
+    " Convert references to vim positions
+    let l:position_list = []
+    for l:reference in l:reference_list
+        call extend(l:position_list, lsp#utils#range#lsp_to_vim(l:bufnr, l:reference['range']))
+    endfor
+
+    call sort(l:position_list, function('s:compare_positions'))
+
+    " Ignore response if the cursor is not over a reference anymore
+    if s:in_reference(l:position_list) == -1 | return | endif
+
+    " Store references
+    if s:use_vim_textprops
+        let b:lsp_reference_positions = l:position_list
+        let b:lsp_reference_matches = []
+    else
+        let w:lsp_reference_positions = l:position_list
+        let w:lsp_reference_matches = []
+    endif
+
+    " Apply highlights to the buffer
+    call s:init_reference_highlight(l:bufnr)
+    if s:use_vim_textprops
+        for l:position in l:position_list
+            try
+                " TODO: need to check for valid range before calling prop_add
+                " See https://github.com/prabirshrestha/vim-lsp/pull/721
+                silent! call prop_add(l:position[0], l:position[1], {
+                    \ 'id': s:prop_id,
+                    \ 'bufnr': l:bufnr,
+                    \ 'length': l:position[2],
+                    \ 'type': 'vim-lsp-reference-highlight'})
+                call add(b:lsp_reference_matches, l:position[0])
+            catch
+                call lsp#log('document_highlight', 'set_highlights', v:exception, v:throwpoint)
+            endtry
+        endfor
+    else
+        for l:position in l:position_list
+            let l:match = matchaddpos('lspReference', [l:position], -5)
+            call add(w:lsp_reference_matches, l:match)
+        endfor
+    endif
+endfunction
+
+function! s:clear_highlights() abort
+    if s:use_vim_textprops
+        if exists('b:lsp_reference_matches')
+            let l:bufnr = bufnr('%')
+            for l:line in b:lsp_reference_matches
+                silent! call prop_remove(
+                \   {'id': s:prop_id,
+                \    'bufnr': l:bufnr,
+                \    'all': v:true}, l:line)
+            endfor
+            unlet b:lsp_reference_matches
+            unlet b:lsp_reference_positions
+        endif
+    else
+        if exists('w:lsp_reference_matches')
+            for l:match in w:lsp_reference_matches
+                silent! call matchdelete(l:match)
+            endfor
+            unlet w:lsp_reference_matches
+            unlet w:lsp_reference_positions
+        endif
+    endif
+endfunction
+
+" Compare two positions
+function! s:compare_positions(p1, p2) abort
+    let l:line_1 = a:p1[0]
+    let l:line_2 = a:p2[0]
+    if l:line_1 != l:line_2
+        return l:line_1 > l:line_2 ? 1 : -1
+    endif
+    let l:col_1 = a:p1[1]
+    let l:col_2 = a:p2[1]
+    return l:col_1 - l:col_2
+endfunction
+
+" If the cursor is over a reference, return its index in
+" the array. Otherwise, return -1.
+function! s:in_reference(reference_list) abort
+    let l:line = line('.')
+    let l:column = col('.')
+    let l:index = 0
+    for l:position in a:reference_list
+        if l:line == l:position[0] &&
+        \  l:column >= l:position[1] &&
+        \  l:column < l:position[1] + l:position[2]
+            return l:index
+        endif
+        let l:index += 1
+    endfor
+    return -1
+endfunction
+
+function! s:init_reference_highlight(buf) abort
+    if s:use_vim_textprops
+        let l:props = {
+            \   'bufnr': a:buf,
+            \   'highlight': 'lspReference',
+            \   'combine': v:true,
+            \   'priority': lsp#internal#textprop#priority('document_highlight')
+            \ }
+        if prop_type_get('vim-lsp-reference-highlight', { 'bufnr': a:buf }) == {}
+            call prop_type_add('vim-lsp-reference-highlight', l:props)
+        endif
+    endif
+endfunction
+
+" Cyclically move between references by `offset` occurrences.
+function! lsp#internal#document_highlight#jump(offset) abort
+    if s:use_vim_textprops && !exists('b:lsp_reference_positions') ||
+          \ !s:use_vim_textprops && !exists('w:lsp_reference_positions')
+        echohl WarningMsg
+        echom 'References not available'
+        echohl None
+        return
+    endif
+
+    " Get index of reference under cursor
+    let l:index = s:use_vim_textprops ? s:in_reference(b:lsp_reference_positions) : s:in_reference(w:lsp_reference_positions)
+    if l:index < 0
+        return
+    endif
+
+    let l:n = s:use_vim_textprops ? len(b:lsp_reference_positions) : len(w:lsp_reference_positions)
+    let l:index += a:offset
+
+    " Show a message when reaching TOP/BOTTOM of the file
+    if l:index < 0
+        echohl WarningMsg
+        echom 'search hit TOP, continuing at BOTTOM'
+        echohl None
+    elseif l:index >= (s:use_vim_textprops ? len(b:lsp_reference_positions) : len(w:lsp_reference_positions))
+        echohl WarningMsg
+        echom 'search hit BOTTOM, continuing at TOP'
+        echohl None
+    endif
+
+    " Wrap index
+    if l:index < 0 || l:index >= (s:use_vim_textprops ? len(b:lsp_reference_positions) : len(w:lsp_reference_positions))
+        let l:index = (l:index % l:n + l:n) % l:n
+    endif
+
+    " Jump
+    let l:target = (s:use_vim_textprops ? b:lsp_reference_positions : w:lsp_reference_positions)[l:index][0:1]
+    normal! m`
+    call cursor(l:target[0], l:target[1])
+endfunction