Files
vim-lsp-mirror/autoload/lsp/ui/vim.vim
2019-12-31 17:12:55 -08:00

771 lines
27 KiB
VimL

let s:last_req_id = 0
function! s:not_supported(what) abort
return lsp#utils#error(a:what.' not supported for '.&filetype)
endfunction
function! lsp#ui#vim#implementation(in_preview) abort
let l:servers = filter(lsp#get_whitelisted_servers(), 'lsp#capabilities#has_implementation_provider(v:val)')
let s:last_req_id = s:last_req_id + 1
call setqflist([])
if len(l:servers) == 0
call s:not_supported('Retrieving implementation')
return
endif
let l:ctx = { 'counter': len(l:servers), 'list':[], 'last_req_id': s:last_req_id, 'jump_if_one': 1, 'in_preview': a:in_preview }
for l:server in l:servers
call lsp#send_request(l:server, {
\ 'method': 'textDocument/implementation',
\ 'params': {
\ 'textDocument': lsp#get_text_document_identifier(),
\ 'position': lsp#get_position(),
\ },
\ 'on_notification': function('s:handle_location', [l:ctx, l:server, 'implementation']),
\ })
endfor
echo 'Retrieving implementation ...'
endfunction
function! lsp#ui#vim#type_definition(in_preview) abort
let l:servers = filter(lsp#get_whitelisted_servers(), 'lsp#capabilities#has_type_definition_provider(v:val)')
let s:last_req_id = s:last_req_id + 1
call setqflist([])
if len(l:servers) == 0
call s:not_supported('Retrieving type definition')
return
endif
let l:ctx = { 'counter': len(l:servers), 'list':[], 'last_req_id': s:last_req_id, 'jump_if_one': 1, 'in_preview': a:in_preview }
for l:server in l:servers
call lsp#send_request(l:server, {
\ 'method': 'textDocument/typeDefinition',
\ 'params': {
\ 'textDocument': lsp#get_text_document_identifier(),
\ 'position': lsp#get_position(),
\ },
\ 'on_notification': function('s:handle_location', [l:ctx, l:server, 'type definition']),
\ })
endfor
echo 'Retrieving type definition ...'
endfunction
function! lsp#ui#vim#type_hierarchy() abort
let l:servers = filter(lsp#get_whitelisted_servers(), 'lsp#capabilities#has_type_hierarchy_provider(v:val)')
let s:last_req_id = s:last_req_id + 1
if len(l:servers) == 0
call s:not_supported('Retrieving type hierarchy')
return
endif
let l:ctx = { 'counter': len(l:servers), 'list':[], 'last_req_id': s:last_req_id }
" direction 0 children, 1 parent, 2 both
for l:server in l:servers
call lsp#send_request(l:server, {
\ 'method': 'textDocument/typeHierarchy',
\ 'params': {
\ 'textDocument': lsp#get_text_document_identifier(),
\ 'position': lsp#get_position(),
\ 'direction': 2,
\ 'resolve': 1,
\ },
\ 'on_notification': function('s:handle_type_hierarchy', [l:ctx, l:server, 'type hierarchy']),
\ })
endfor
echo 'Retrieving type hierarchy ...'
endfunction
function! lsp#ui#vim#declaration(in_preview) abort
let l:servers = filter(lsp#get_whitelisted_servers(), 'lsp#capabilities#has_declaration_provider(v:val)')
let s:last_req_id = s:last_req_id + 1
call setqflist([])
if len(l:servers) == 0
call s:not_supported('Retrieving declaration')
return
endif
let l:ctx = { 'counter': len(l:servers), 'list':[], 'last_req_id': s:last_req_id, 'jump_if_one': 1, 'in_preview': a:in_preview }
for l:server in l:servers
call lsp#send_request(l:server, {
\ 'method': 'textDocument/declaration',
\ 'params': {
\ 'textDocument': lsp#get_text_document_identifier(),
\ 'position': lsp#get_position(),
\ },
\ 'on_notification': function('s:handle_location', [l:ctx, l:server, 'declaration']),
\ })
endfor
echo 'Retrieving declaration ...'
endfunction
function! lsp#ui#vim#definition(in_preview) abort
let l:servers = filter(lsp#get_whitelisted_servers(), 'lsp#capabilities#has_definition_provider(v:val)')
let s:last_req_id = s:last_req_id + 1
call setqflist([])
if len(l:servers) == 0
call s:not_supported('Retrieving definition')
return
endif
let l:ctx = { 'counter': len(l:servers), 'list':[], 'last_req_id': s:last_req_id, 'jump_if_one': 1, 'in_preview': a:in_preview }
for l:server in l:servers
call lsp#send_request(l:server, {
\ 'method': 'textDocument/definition',
\ 'params': {
\ 'textDocument': lsp#get_text_document_identifier(),
\ 'position': lsp#get_position(),
\ },
\ 'on_notification': function('s:handle_location', [l:ctx, l:server, 'definition']),
\ })
endfor
echo 'Retrieving definition ...'
endfunction
function! lsp#ui#vim#references() abort
let l:servers = filter(lsp#get_whitelisted_servers(), 'lsp#capabilities#has_references_provider(v:val)')
let s:last_req_id = s:last_req_id + 1
call setqflist([])
let l:ctx = { 'counter': len(l:servers), 'list':[], 'last_req_id': s:last_req_id, 'jump_if_one': 0, 'in_preview': 0 }
if len(l:servers) == 0
call s:not_supported('Retrieving references')
return
endif
for l:server in l:servers
call lsp#send_request(l:server, {
\ 'method': 'textDocument/references',
\ 'params': {
\ 'textDocument': lsp#get_text_document_identifier(),
\ 'position': lsp#get_position(),
\ 'context': {'includeDeclaration': v:false},
\ },
\ 'on_notification': function('s:handle_location', [l:ctx, l:server, 'references']),
\ })
endfor
echo 'Retrieving references ...'
endfunction
function! s:rename(server, new_name, pos) abort
if empty(a:new_name)
echo '... Renaming aborted ...'
return
endif
" needs to flush existing open buffers
call lsp#send_request(a:server, {
\ 'method': 'textDocument/rename',
\ 'params': {
\ 'textDocument': lsp#get_text_document_identifier(),
\ 'position': a:pos,
\ 'newName': a:new_name,
\ },
\ 'on_notification': function('s:handle_workspace_edit', [a:server, s:last_req_id, 'rename']),
\ })
echo ' ... Renaming ...'
endfunction
function! lsp#ui#vim#rename() abort
let l:servers = filter(lsp#get_whitelisted_servers(), 'lsp#capabilities#has_rename_prepare_provider(v:val)')
let l:prepare_support = 1
if len(l:servers) == 0
let l:servers = filter(lsp#get_whitelisted_servers(), 'lsp#capabilities#has_rename_provider(v:val)')
let l:prepare_support = 0
endif
let s:last_req_id = s:last_req_id + 1
if len(l:servers) == 0
call s:not_supported('Renaming')
return
endif
" TODO: ask the user which server it should use to rename if there are multiple
let l:server = l:servers[0]
if l:prepare_support
call lsp#send_request(l:server, {
\ 'method': 'textDocument/prepareRename',
\ 'params': {
\ 'textDocument': lsp#get_text_document_identifier(),
\ 'position': lsp#get_position(),
\ },
\ 'on_notification': function('s:handle_rename_prepare', [l:server, s:last_req_id, 'rename_prepare']),
\ })
return
endif
call s:rename(l:server, input('new name: ', expand('<cword>')), lsp#get_position())
endfunction
function! s:document_format(sync) abort
let l:servers = filter(lsp#get_whitelisted_servers(), 'lsp#capabilities#has_document_formatting_provider(v:val)')
let s:last_req_id = s:last_req_id + 1
if len(l:servers) == 0
call s:not_supported('Document formatting')
return
endif
" TODO: ask user to select server for formatting
let l:server = l:servers[0]
redraw | echo 'Formatting document ...'
call lsp#send_request(l:server, {
\ 'method': 'textDocument/formatting',
\ 'params': {
\ 'textDocument': lsp#get_text_document_identifier(),
\ 'options': {
\ 'tabSize': getbufvar(bufnr('%'), '&tabstop'),
\ 'insertSpaces': getbufvar(bufnr('%'), '&expandtab') ? v:true : v:false,
\ },
\ },
\ 'sync': a:sync,
\ 'on_notification': function('s:handle_text_edit', [l:server, s:last_req_id, 'document format']),
\ })
endfunction
function! lsp#ui#vim#document_format_sync() abort
let l:mode = mode()
if l:mode =~# '[vV]' || l:mode ==# "\<C-V>"
return s:document_format_range(1)
endif
return s:document_format(1)
endfunction
function! lsp#ui#vim#document_format() abort
let l:mode = mode()
if l:mode =~# '[vV]' || l:mode ==# "\<C-V>"
return s:document_format_range(0)
endif
return s:document_format(0)
endfunction
function! lsp#ui#vim#stop_server(...) abort
let l:name = get(a:000, 0, '')
for l:server in lsp#get_whitelisted_servers()
if !empty(l:name) && l:server != l:name
continue
endif
echo 'Stopping' l:server 'server ...'
call lsp#stop_server(server)
endfor
endfunction
function! s:get_selection_pos(type) abort
if a:type ==? 'v'
let l:start_pos = getpos("'<")[1:2]
let l:end_pos = getpos("'>")[1:2]
" fix end_pos column (see :h getpos() and :h 'selection')
let l:end_line = getline(l:end_pos[0])
let l:offset = (&selection ==# 'inclusive' ? 1 : 2)
let l:end_pos[1] = len(l:end_line[:l:end_pos[1]-l:offset])
" edge case: single character selected with selection=exclusive
if l:start_pos[0] == l:end_pos[0] && l:start_pos[1] > l:end_pos[1]
let l:end_pos[1] = l:start_pos[1]
endif
elseif a:type ==? 'line'
let l:start_pos = [line("'["), 1]
let l:end_lnum = line("']")
let l:end_pos = [line("']"), len(getline(l:end_lnum))]
elseif a:type ==? 'char'
let l:start_pos = getpos("'[")[1:2]
let l:end_pos = getpos("']")[1:2]
else
let l:start_pos = [0, 0]
let l:end_pos = [0, 0]
endif
return l:start_pos + l:end_pos
endfunction
function! s:document_format_range(sync, type) abort
let l:servers = filter(lsp#get_whitelisted_servers(), 'lsp#capabilities#has_document_range_formatting_provider(v:val)')
let s:last_req_id = s:last_req_id + 1
if len(l:servers) == 0
call s:not_supported('Document range formatting')
return
endif
" TODO: ask user to select server for formatting
let l:server = l:servers[0]
let [l:start_lnum, l:start_col, l:end_lnum, l:end_col] = s:get_selection_pos(a:type)
let l:start_char = lsp#utils#to_char('%', l:start_lnum, l:start_col)
let l:end_char = lsp#utils#to_char('%', l:end_lnum, l:end_col)
redraw | echo 'Formatting document range ...'
call lsp#send_request(l:server, {
\ 'method': 'textDocument/rangeFormatting',
\ 'params': {
\ 'textDocument': lsp#get_text_document_identifier(),
\ 'range': {
\ 'start': { 'line': l:start_lnum - 1, 'character': l:start_char },
\ 'end': { 'line': l:end_lnum - 1, 'character': l:end_char },
\ },
\ 'options': {
\ 'tabSize': getbufvar(bufnr('%'), '&shiftwidth'),
\ 'insertSpaces': getbufvar(bufnr('%'), '&expandtab') ? v:true : v:false,
\ },
\ },
\ 'sync': a:sync,
\ 'on_notification': function('s:handle_text_edit', [l:server, s:last_req_id, 'range format']),
\ })
endfunction
function! lsp#ui#vim#document_range_format_sync() abort
return s:document_format_range(1, visualmode())
endfunction
function! lsp#ui#vim#document_range_format() abort
return s:document_format_range(0, visualmode())
endfunction
function! lsp#ui#vim#document_range_format_opfunc(type) abort
return s:document_format_range(1, a:type)
endfunction
function! lsp#ui#vim#workspace_symbol() abort
let l:servers = filter(lsp#get_whitelisted_servers(), 'lsp#capabilities#has_workspace_symbol_provider(v:val)')
let s:last_req_id = s:last_req_id + 1
call setqflist([])
if len(l:servers) == 0
call s:not_supported('Retrieving workspace symbols')
return
endif
let l:query = input('query>')
for l:server in l:servers
call lsp#send_request(l:server, {
\ 'method': 'workspace/symbol',
\ 'params': {
\ 'query': l:query,
\ },
\ 'on_notification': function('s:handle_symbol', [l:server, s:last_req_id, 'workspaceSymbol']),
\ })
endfor
echo 'Retrieving workspace symbols ...'
endfunction
function! lsp#ui#vim#document_symbol() abort
let l:servers = filter(lsp#get_whitelisted_servers(), 'lsp#capabilities#has_document_symbol_provider(v:val)')
let s:last_req_id = s:last_req_id + 1
call setqflist([])
if len(l:servers) == 0
call s:not_supported('Retrieving symbols')
return
endif
for l:server in l:servers
call lsp#send_request(l:server, {
\ 'method': 'textDocument/documentSymbol',
\ 'params': {
\ 'textDocument': lsp#get_text_document_identifier(),
\ },
\ 'on_notification': function('s:handle_symbol', [l:server, s:last_req_id, 'documentSymbol']),
\ })
endfor
echo 'Retrieving document symbols ...'
endfunction
" Returns currently selected range. If nothing is selected, returns empty
" dictionary.
"
" @returns
" Range - https://microsoft.github.io/language-server-protocol/specification#range
function! s:get_visual_selection_range() abort
" TODO: unify this method with s:get_visual_selection_pos()
let [l:line_start, l:column_start] = getpos("'<")[1:2]
let [l:line_end, l:column_end] = getpos("'>")[1:2]
call lsp#log([l:line_start, l:column_start, l:line_end, l:column_end])
if l:line_start == 0
return {}
endif
" For line selection, column_end is a very large number, so trim it to
" number of characters in this line.
if l:column_end - 1 > len(getline(l:line_end))
let l:column_end = len(getline(l:line_end)) + 1
endif
let l:char_start = lsp#utils#to_char('%', l:line_start, l:column_start)
let l:char_end = lsp#utils#to_char('%', l:line_end, l:column_end)
return {
\ 'start': { 'line': l:line_start - 1, 'character': l:char_start },
\ 'end': { 'line': l:line_end - 1, 'character': l:char_end },
\}
endfunction
" https://microsoft.github.io/language-server-protocol/specification#textDocument_codeAction
function! lsp#ui#vim#code_action() abort
let l:servers = filter(lsp#get_whitelisted_servers(), 'lsp#capabilities#has_code_action_provider(v:val)')
let s:last_req_id = s:last_req_id + 1
let l:diagnostic = lsp#ui#vim#diagnostics#get_diagnostics_under_cursor()
if len(l:servers) == 0
call s:not_supported('Code action')
return
endif
let l:range = s:get_visual_selection_range()
if empty(l:range)
if empty(l:diagnostic)
echo 'No diagnostics found under the cursors'
return
else
let l:range = l:diagnostic['range']
let l:diagnostics = [l:diagnostic]
end
else
let l:diagnostics = []
endif
for l:server in l:servers
call lsp#send_request(l:server, {
\ 'method': 'textDocument/codeAction',
\ 'params': {
\ 'textDocument': lsp#get_text_document_identifier(),
\ 'range': l:range,
\ 'context': {
\ 'diagnostics' : l:diagnostics,
\ 'only': ['', 'quickfix', 'refactor', 'refactor.extract', 'refactor.inline', 'refactor.rewrite', 'source', 'source.organizeImports'],
\ },
\ },
\ 'on_notification': function('s:handle_code_action', [l:server, s:last_req_id, 'codeAction']),
\ })
endfor
echo 'Retrieving code actions ...'
endfunction
function! s:handle_symbol(server, last_req_id, type, data) abort
if a:last_req_id != s:last_req_id
return
endif
if lsp#client#is_error(a:data['response'])
call lsp#utils#error('Failed to retrieve '. a:type . ' for ' . a:server . ': ' . lsp#client#error_message(a:data['response']))
return
endif
let l:list = lsp#ui#vim#utils#symbols_to_loc_list(a:server, a:data)
call setqflist(l:list)
if empty(l:list)
call lsp#utils#error('No ' . a:type .' found')
else
echo 'Retrieved ' . a:type
botright copen
endif
endfunction
function! s:update_tagstack() abort
let l:bufnr = bufnr('%')
let l:item = {'bufnr': l:bufnr, 'from': [l:bufnr, line('.'), col('.'), 0], 'tagname': expand('<cword>')}
let l:winid = win_getid()
let l:stack = gettagstack(l:winid)
if l:stack['length'] == l:stack['curidx']
" Replace the last items with item.
let l:action = 'r'
let l:stack['items'][l:stack['curidx']-1] = l:item
elseif l:stack['length'] > l:stack['curidx']
" Replace items after used items with item.
let l:action = 'r'
if l:stack['curidx'] > 1
let l:stack['items'] = add(l:stack['items'][:l:stack['curidx']-2], l:item)
else
let l:stack['items'] = [l:item]
endif
else
" Append item.
let l:action = 'a'
let l:stack['items'] = [l:item]
endif
let l:stack['curidx'] += 1
call settagstack(l:winid, l:stack, l:action)
endfunction
function! s:handle_location(ctx, server, type, data) abort "ctx = {counter, list, jump_if_one, last_req_id, in_preview}
if a:ctx['last_req_id'] != s:last_req_id
return
endif
let a:ctx['counter'] = a:ctx['counter'] - 1
if lsp#client#is_error(a:data['response'])
call lsp#utils#error('Failed to retrieve '. a:type . ' for ' . a:server . ': ' . lsp#client#error_message(a:data['response']))
else
let a:ctx['list'] = a:ctx['list'] + lsp#ui#vim#utils#locations_to_loc_list(a:data)
endif
if a:ctx['counter'] == 0
if empty(a:ctx['list'])
call lsp#utils#error('No ' . a:type .' found')
else
if exists('*gettagstack') && exists('*settagstack')
call s:update_tagstack()
endif
let l:loc = a:ctx['list'][0]
if len(a:ctx['list']) == 1 && a:ctx['jump_if_one'] && !a:ctx['in_preview']
normal! m'
let l:buffer = bufnr(l:loc['filename'])
if &modified && !&hidden
let l:cmd = l:buffer !=# -1 ? 'sb ' . l:buffer : 'split ' . fnameescape(l:loc['filename'])
else
let l:cmd = l:buffer !=# -1 ? 'b ' . l:buffer : 'edit ' . fnameescape(l:loc['filename'])
endif
execute l:cmd . ' | call cursor('.l:loc['lnum'].','.l:loc['col'].')'
echo 'Retrieved ' . a:type
redraw
elseif !a:ctx['in_preview']
call setqflist(a:ctx['list'])
echo 'Retrieved ' . a:type
botright copen
else
let l:lines = readfile(fnameescape(l:loc['filename']))
if has_key(l:loc,'viewstart') " showing a locationLink
let l:view = l:lines[l:loc['viewstart'] : l:loc['viewend']]
call lsp#ui#vim#output#preview(a:server, l:view, {
\ 'statusline': ' LSP Peek ' . a:type,
\ 'filetype': &filetype
\ })
else " showing a location
call lsp#ui#vim#output#preview(a:server, l:lines, {
\ 'statusline': ' LSP Peek ' . a:type,
\ 'cursor': { 'line': l:loc['lnum'], 'col': l:loc['col'], 'align': g:lsp_peek_alignment },
\ 'filetype': &filetype
\ })
endif
endif
endif
endif
endfunction
function! s:handle_rename_prepare(server, last_req_id, type, data) abort
if a:last_req_id != s:last_req_id
return
endif
if lsp#client#is_error(a:data['response'])
call lsp#utils#error('Failed to retrieve '. a:type . ' for ' . a:server . ': ' . lsp#client#error_message(a:data['response']))
return
endif
let l:range = a:data['response']['result']
let l:lines = getline(1, '$')
let l:start_line = l:range['start']['line'] + 1
let l:start_char = l:range['start']['character']
let l:start_col = lsp#utils#to_col('%', l:start_line, l:start_char)
let l:end_line = l:range['end']['line'] + 1
let l:end_char = l:range['end']['character']
let l:end_col = lsp#utils#to_col('%', l:end_line, l:end_char)
if l:start_line ==# l:end_line
let l:name = l:lines[l:start_line - 1][l:start_col - 1 : l:end_col - 2]
else
let l:name = l:lines[l:start_line - 1][l:start_col - 1 :]
for l:i in range(l:start_line, l:end_line - 2)
let l:name .= "\n" . l:lines[l:i]
endfor
if l:end_col - 2 < 0
let l:name .= "\n"
else
let l:name .= l:lines[l:end_line - 1][: l:end_col - 2]
endif
endif
call timer_start(1, {x->s:rename(a:server, input('new name: ', l:name), l:range['start'])})
endfunction
function! s:handle_workspace_edit(server, last_req_id, type, data) abort
if a:last_req_id != s:last_req_id
return
endif
if lsp#client#is_error(a:data['response'])
call lsp#utils#error('Failed to retrieve '. a:type . ' for ' . a:server . ': ' . lsp#client#error_message(a:data['response']))
return
endif
call lsp#utils#workspace_edit#apply_workspace_edit(a:data['response']['result'])
echo 'Renamed'
endfunction
function! s:handle_text_edit(server, last_req_id, type, data) abort
if a:last_req_id != s:last_req_id
return
endif
if lsp#client#is_error(a:data['response'])
call lsp#utils#error('Failed to '. a:type . ' for ' . a:server . ': ' . lsp#client#error_message(a:data['response']))
return
endif
call lsp#utils#text_edit#apply_text_edits(a:data['request']['params']['textDocument']['uri'], a:data['response']['result'])
redraw | echo 'Document formatted'
endfunction
function! s:handle_code_action(server, last_req_id, type, data) abort
if lsp#client#is_error(a:data['response'])
call lsp#utils#error('Failed to '. a:type . ' for ' . a:server . ': ' . lsp#client#error_message(a:data['response']))
return
endif
let l:codeActions = a:data['response']['result']
let l:index = 0
let l:choices = []
call lsp#log('s:handle_code_action', l:codeActions)
if len(l:codeActions) == 0
echo 'No code actions found'
return
endif
while l:index < len(l:codeActions)
call add(l:choices, string(l:index + 1) . ' - ' . l:codeActions[index]['title'])
let l:index += 1
endwhile
let l:choice = inputlist(l:choices)
if l:choice > 0 && l:choice <= l:index
call s:execute_command_or_code_action(a:server, l:codeActions[l:choice - 1])
endif
endfunction
function! s:handle_type_hierarchy(ctx, server, type, data) abort "ctx = {counter, list, last_req_id}
if a:ctx['last_req_id'] != s:last_req_id
return
endif
if lsp#client#is_error(a:data['response'])
call lsp#utils#error('Failed to '. a:type . ' for ' . a:server . ': ' . lsp#client#error_message(a:data['response']))
return
endif
if empty(a:data['response']['result'])
echo 'No type hierarchy found'
return
endif
" Create new buffer in a split
let l:position = 'topleft'
let l:orientation = 'new'
exec l:position . ' ' . 10 . l:orientation
let l:provider = {
\ 'root': a:data['response']['result'],
\ 'root_state': 'expanded',
\ 'bufnr': bufnr('%'),
\ 'getChildren': function('s:get_children_for_tree_hierarchy'),
\ 'getParent': function('s:get_parent_for_tree_hierarchy'),
\ 'getTreeItem': function('s:get_treeitem_for_tree_hierarchy'),
\ }
call lsp#utils#tree#new(l:provider)
echo 'Retrieved type hierarchy'
endfunction
function! s:hierarchyitem_to_treeitem(hierarchyitem) abort
return {
\ 'id': a:hierarchyitem,
\ 'label': a:hierarchyitem['name'],
\ 'command': function('s:hierarchy_treeitem_command', [a:hierarchyitem]),
\ 'collapsibleState': has_key(a:hierarchyitem, 'parents') && !empty(a:hierarchyitem['parents']) ? 'expanded' : 'none',
\ }
endfunction
function! s:hierarchy_treeitem_command(hierarchyitem) abort
bwipeout
let l:path = lsp#utils#uri_to_path(a:hierarchyitem['uri'])
let l:line = a:hierarchyitem['range']['start']['line'] + 1
let l:char = a:hierarchyitem['range']['start']['character']
let l:col = lsp#utils#to_col(l:path, l:line, l:char)
let l:buffer = bufnr(l:path)
if &modified && !&hidden
let l:cmd = l:buffer !=# -1 ? 'sb ' . l:buffer : 'split ' . fnameescape(l:path)
else
echom 'edit'
let l:cmd = l:buffer !=# -1 ? 'b ' . l:buffer : 'edit ' . fnameescape(l:path)
endif
execute l:cmd . ' | call cursor('.l:line.','.l:col.')'
endfunction
function! s:get_children_for_tree_hierarchy(Callback, ...) dict abort
if a:0 == 0
call a:Callback('success', [l:self['root']])
return
else
call a:Callback('success', a:1['parents'])
endif
endfunction
function! s:get_parent_for_tree_hierarchy(...) dict abort
" TODO
endfunction
function! s:get_treeitem_for_tree_hierarchy(Callback, object) dict abort
call a:Callback('success', s:hierarchyitem_to_treeitem(a:object))
endfunction
" @params
" server - string
" comand_or_code_action - Command | CodeAction
function! s:execute_command_or_code_action(server, command_or_code_action) abort
if has_key(a:command_or_code_action, 'command') && type(a:command_or_code_action['command']) == type('')
let l:command = a:command_or_code_action
call s:execute_command(a:server, l:command)
else
let l:code_action = a:command_or_code_action
if has_key(l:code_action, 'edit')
call lsp#utils#workspace_edit#apply_workspace_edit(a:command_or_code_action['edit'])
endif
if has_key(l:code_action, 'command')
call s:execute_command(a:server, l:code_action['command'])
endif
endif
endfunction
" Sends workspace/executeCommand with given command.
" @params
" server - string
" command - https://microsoft.github.io/language-server-protocol/specification#command
function! s:execute_command(server, command) abort
let l:params = {'command': a:command['command']}
if has_key(a:command, 'arguments')
let l:params['arguments'] = a:command['arguments']
endif
call lsp#send_request(a:server, {
\ 'method': 'workspace/executeCommand',
\ 'params': l:params,
\ })
endfunction