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.
1 let s:tag_kind_priority = ['definition', 'declaration', 'implementation', 'type definition']
3 function! s:not_supported(what) abort
4 call lsp#log(a:what . ' not supported for ' . &filetype)
7 function! s:location_to_tag(loc) abort
8 if has_key(a:loc, 'targetUri')
9 let l:uri = a:loc['targetUri']
10 let l:range = a:loc['targetRange']
12 let l:uri = a:loc['uri']
13 let l:range = a:loc['range']
16 if !lsp#utils#is_file_uri(l:uri)
20 let l:path = lsp#utils#uri_to_path(l:uri)
21 let [l:line, l:col] = lsp#utils#position#lsp_to_vim(l:path, l:range['start'])
24 \ 'cmd': printf('/\%%%dl\%%%dc/', l:line, l:col)
28 function! s:handle_locations(ctx, server, type, data) abort
30 if lsp#client#is_error(a:data['response']) || !has_key(a:data['response'], 'result')
31 call lsp#utils#error('Failed to retrieve ' . a:type . ' for ' . a:server . ': ' . lsp#client#error_message(a:data['response']))
35 let l:list = a:ctx['list']
36 let l:result = a:data['response']['result']
37 if type(l:result) != type([])
38 let l:result = [l:result]
41 let l:tag = s:location_to_tag(l:loc)
43 call add(l:list, extend(l:tag, { 'name': a:ctx['pattern'], 'kind': a:type }))
47 let a:ctx['counter'] -= 1
51 function! s:handle_symbols(ctx, server, data) abort
53 if lsp#client#is_error(a:data['response']) || !has_key(a:data['response'], 'result')
54 call lsp#utils#error('Failed to retrieve workspace symbols for ' . a:server . ': ' . lsp#client#error_message(a:data['response']))
58 let l:list = a:ctx['list']
59 for l:symbol in a:data['response']['result']
60 let l:tag = s:location_to_tag(l:symbol['location'])
65 let l:tag['name'] = l:symbol['name']
66 if has_key(l:symbol, 'kind')
67 let l:tag['kind'] = lsp#ui#vim#utils#_get_symbol_text_from_kind(a:server, l:symbol['kind'])
69 call add(l:list, l:tag)
72 let a:ctx['counter'] -= 1
76 function! s:tag_view_sub(ctx, method, params) abort
77 let l:operation = substitute(a:method, '\u', ' \l\0', 'g')
79 let l:capabilities_func = printf('lsp#capabilities#has_%s_provider(v:val)', substitute(l:operation, ' ', '_', 'g'))
80 let l:servers = filter(lsp#get_allowed_servers(), l:capabilities_func)
82 call s:not_supported('retrieving ' . l:operation)
86 let a:ctx['counter'] += len(l:servers)
87 for l:server in l:servers
88 call lsp#send_request(l:server, {
89 \ 'method': 'textDocument/'.a:method,
91 \ 'on_notification': function('s:handle_locations', [a:ctx, l:server, l:operation])
97 function! s:tag_view(ctx) abort
99 \ 'textDocument': lsp#get_text_document_identifier(),
100 \ 'position': lsp#get_position(),
102 return !empty(filter(copy(g:lsp_tagfunc_source_methods),
103 \ {_, m -> s:tag_view_sub(a:ctx, m, l:params)}))
106 function! s:tag_search(ctx) abort
107 let l:servers = filter(lsp#get_allowed_servers(), 'lsp#capabilities#has_workspace_symbol_provider(v:val)')
109 call s:not_supported('retrieving workspace symbols')
113 let a:ctx['counter'] = len(l:servers)
114 for l:server in l:servers
115 call lsp#send_request(l:server, {
116 \ 'method': 'workspace/symbol',
117 \ 'params': { 'query': a:ctx['pattern'] },
118 \ 'on_notification': function('s:handle_symbols', [a:ctx, l:server])
124 function! s:compare_tags(path, a, b) abort
125 " TODO: custom tag sorting, maybe?
126 if a:a['filename'] !=# a:b['filename']
127 if a:a['filename'] ==# a:path
129 elseif a:b['filename'] ==# a:path
133 let l:rank_a = index(s:tag_kind_priority, get(a:a, 'kind', ''))
134 let l:rank_b = index(s:tag_kind_priority, get(a:b, 'kind', ''))
135 if l:rank_a != l:rank_b
136 return l:rank_a < l:rank_b ? -1 : 1
138 if a:a['filename'] !=# a:b['filename']
139 return a:a['filename'] <# a:b['filename'] ? -1 : 1
141 return str2nr(a:a['cmd']) - str2nr(a:b['cmd'])
144 function! lsp#tag#tagfunc(pattern, flags, info) abort
145 if stridx(a:flags, 'i') >= 0
149 let l:ctx = { 'pattern': a:pattern, 'counter': 0, 'list': [] }
150 if !(stridx(a:flags, 'c') >= 0 ? s:tag_view(l:ctx) : s:tag_search(l:ctx))
151 " No supported methods so use builtin tag source
154 call lsp#utils#_wait(-1, {-> l:ctx['counter'] == 0}, 50)
155 call sort(l:ctx['list'], function('s:compare_tags', [a:info['buf_ffname']]))