Get automatic completion with tsserver to work
This commit is contained in:
parent
5b731f761f
commit
b731bd77ab
@ -1,189 +1,280 @@
|
|||||||
" Author: w0rp <devw0rp@gmail.com>
|
" Author: w0rp <devw0rp@gmail.com>
|
||||||
" Description: Completion support for LSP linters
|
" Description: Completion support for LSP linters
|
||||||
|
|
||||||
let s:timer = -1
|
let s:timer_id = -1
|
||||||
let s:delay = 300
|
|
||||||
let s:max_suggestions = 20
|
|
||||||
let s:buffer_completion_map = {}
|
|
||||||
|
|
||||||
function! s:RememberCompletionInfo(buffer, conn_id, request_id, line, column) abort
|
function! s:GetRegex(map, filetype) abort
|
||||||
let s:buffer_completion_map[a:buffer] = {
|
for l:part in reverse(split(a:filetype, '\.'))
|
||||||
\ 'conn_id': a:conn_id,
|
let l:regex = get(a:map, l:part, [])
|
||||||
\ 'request_id': a:request_id,
|
|
||||||
\ 'line': a:line,
|
|
||||||
\ 'column': a:column,
|
|
||||||
\}
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Find completion information for a response, and delete the information
|
if !empty(l:regex)
|
||||||
" if the request failed.
|
return l:regex
|
||||||
function! s:FindCompletionInfo(response) abort
|
|
||||||
let l:matched_buffer = -1
|
|
||||||
let l:matched_data = {}
|
|
||||||
|
|
||||||
for l:key in keys(s:buffer_completion_map)
|
|
||||||
let l:obj = s:buffer_completion_map[l:key]
|
|
||||||
|
|
||||||
if l:obj.request_id ==# a:response.request_seq
|
|
||||||
if get(a:response, 'success')
|
|
||||||
let l:matched_buffer = str2nr(l:key)
|
|
||||||
let l:matched_data = l:obj
|
|
||||||
else
|
|
||||||
" Clean up the data we remembered if the request failed.
|
|
||||||
call remove(s:buffer_completion_map, l:matched_buffer)
|
|
||||||
endif
|
|
||||||
endif
|
endif
|
||||||
endfor
|
endfor
|
||||||
|
|
||||||
return [l:matched_buffer, l:matched_data]
|
return ''
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:HandleCompletions(response) abort
|
" Regular expressions for checking the characters in the line before where
|
||||||
let [l:buffer, l:info] = s:FindCompletionInfo(a:response)
|
" the insert cursor is. If one of these matches, we'll check for completions.
|
||||||
|
let s:should_complete_map = {
|
||||||
|
\ 'javascript': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$',
|
||||||
|
\ 'typescript': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$',
|
||||||
|
\}
|
||||||
|
|
||||||
if l:buffer >= 0
|
" Check if we should look for completions for a language.
|
||||||
let l:names = []
|
function! ale#completion#GetPrefix(filetype, line, column) abort
|
||||||
|
let l:regex = s:GetRegex(s:should_complete_map, a:filetype)
|
||||||
|
" The column we're using completions for is where we are inserting text,
|
||||||
|
" like so:
|
||||||
|
" abc
|
||||||
|
" ^
|
||||||
|
" So we need check the text in the column before that position.
|
||||||
|
return matchstr(getline(a:line)[: a:column - 2], l:regex)
|
||||||
|
endfunction
|
||||||
|
|
||||||
for l:suggestion in a:response.body[: s:max_suggestions]
|
" Regular expressions for finding the start column to replace with completion.
|
||||||
call add(l:names, l:suggestion.name)
|
let s:omni_start_map = {
|
||||||
|
\ 'javascript': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$',
|
||||||
|
\ 'typescript': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$',
|
||||||
|
\}
|
||||||
|
|
||||||
|
function! ale#completion#OmniFunc(findstart, base) abort
|
||||||
|
if a:findstart
|
||||||
|
let l:line = b:ale_completion_info.line
|
||||||
|
let l:column = b:ale_completion_info.column
|
||||||
|
let l:regex = s:GetRegex(s:omni_start_map, &filetype)
|
||||||
|
let l:up_to_column = getline(l:line)[: l:column - 1]
|
||||||
|
let l:match = matchstr(l:up_to_column, l:regex)
|
||||||
|
|
||||||
|
return l:column - len(l:match) - 1
|
||||||
|
else
|
||||||
|
" Reset the settings now
|
||||||
|
let &omnifunc = b:ale_old_omnifunc
|
||||||
|
let &completeopt = b:ale_old_completeopt
|
||||||
|
let l:response = b:ale_completion_response
|
||||||
|
let l:parser = b:ale_completion_parser
|
||||||
|
|
||||||
|
unlet b:ale_completion_response
|
||||||
|
unlet b:ale_completion_parser
|
||||||
|
unlet b:ale_old_omnifunc
|
||||||
|
unlet b:ale_old_completeopt
|
||||||
|
|
||||||
|
return function(l:parser)(l:response)
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! ale#completion#Show(response, completion_parser) abort
|
||||||
|
" Remember the old omnifunc value.
|
||||||
|
if !exists('b:ale_old_omnifunc')
|
||||||
|
let b:ale_old_omnifunc = &omnifunc
|
||||||
|
let b:ale_old_completeopt = &completeopt
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Set the list in the buffer, temporarily replace omnifunc with our
|
||||||
|
" function, and then start omni-completion.
|
||||||
|
let b:ale_completion_response = a:response
|
||||||
|
let b:ale_completion_parser = a:completion_parser
|
||||||
|
let &omnifunc = 'ale#completion#OmniFunc'
|
||||||
|
let &completeopt = 'menu,noinsert,noselect'
|
||||||
|
call feedkeys("\<C-x>\<C-o>", 'n')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:CompletionStillValid(request_id) abort
|
||||||
|
let [l:line, l:column] = getcurpos()[1:2]
|
||||||
|
|
||||||
|
return has_key(b:, 'ale_completion_info')
|
||||||
|
\&& b:ale_completion_info.request_id == a:request_id
|
||||||
|
\&& b:ale_completion_info.line == l:line
|
||||||
|
\&& b:ale_completion_info.column == l:column
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! ale#completion#ParseTSServerCompletions(response) abort
|
||||||
|
let l:names = []
|
||||||
|
|
||||||
|
for l:suggestion in a:response.body[: g:ale_completion_max_suggestions]
|
||||||
|
call add(l:names, l:suggestion.name)
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return l:names
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
|
||||||
|
let l:results = []
|
||||||
|
|
||||||
|
for l:suggestion in a:response.body
|
||||||
|
let l:displayParts = []
|
||||||
|
|
||||||
|
for l:part in l:suggestion.displayParts
|
||||||
|
call add(l:displayParts, l:part.text)
|
||||||
endfor
|
endfor
|
||||||
|
|
||||||
let l:request_id = ale#lsp#Send(
|
" Each one of these parts has 'kind' properties
|
||||||
\ l:info.conn_id,
|
let l:documentationParts = []
|
||||||
\ ale#lsp#tsserver_message#CompletionEntryDetails(
|
|
||||||
\ l:buffer,
|
|
||||||
\ l:info.line,
|
|
||||||
\ l:info.column,
|
|
||||||
\ l:names,
|
|
||||||
\ ),
|
|
||||||
\)
|
|
||||||
|
|
||||||
if l:request_id
|
for l:part in get(l:suggestion, 'documentation', [])
|
||||||
let l:info.request_id = l:request_id
|
call add(l:documentationParts, l:part.text)
|
||||||
|
endfor
|
||||||
|
|
||||||
|
if l:suggestion.kind ==# 'clasName'
|
||||||
|
let l:kind = 'f'
|
||||||
|
elseif l:suggestion.kind ==# 'parameterName'
|
||||||
|
let l:kind = 'f'
|
||||||
else
|
else
|
||||||
" Remove the info now if we failed to start the request.
|
let l:kind = 'v'
|
||||||
call remove(s:buffer_completion_map, l:buffer)
|
|
||||||
endif
|
endif
|
||||||
endif
|
|
||||||
|
" See :help complete-items
|
||||||
|
call add(l:results, {
|
||||||
|
\ 'word': l:suggestion.name,
|
||||||
|
\ 'kind': l:kind,
|
||||||
|
\ 'menu': join(l:displayParts, ''),
|
||||||
|
\ 'info': join(l:documentationParts, ''),
|
||||||
|
\})
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return l:results
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:HandleCompletionDetails(response) abort
|
function! s:HandleTSServerLSPResponse(response) abort
|
||||||
let [l:buffer, l:info] = s:FindCompletionInfo(a:response)
|
if !s:CompletionStillValid(get(a:response, 'request_seq'))
|
||||||
|
return
|
||||||
if l:buffer >= 0
|
endif
|
||||||
call remove(s:buffer_completion_map, l:buffer)
|
|
||||||
|
if !has_key(a:response, 'body')
|
||||||
let l:name_list = []
|
return
|
||||||
|
|
||||||
for l:suggestion in a:response.body[: s:max_suggestions]
|
|
||||||
" Each suggestion has 'kind' and 'kindModifier' properties
|
|
||||||
" which could be useful.
|
|
||||||
" Each one of these parts has 'kind' properties
|
|
||||||
let l:displayParts = []
|
|
||||||
|
|
||||||
for l:part in l:suggestion.displayParts
|
|
||||||
call add(l:displayParts, l:part.text)
|
|
||||||
endfor
|
|
||||||
|
|
||||||
" Each one of these parts has 'kind' properties
|
|
||||||
let l:documentationParts = []
|
|
||||||
|
|
||||||
for l:part in l:suggestion.documentation
|
|
||||||
call add(l:documentationParts, l:part.text)
|
|
||||||
endfor
|
|
||||||
|
|
||||||
let l:text = l:suggestion.name
|
|
||||||
\ . ' - '
|
|
||||||
\ . join(l:displayParts, '')
|
|
||||||
\ . (!empty(l:documentationParts) ? ' ' : '')
|
|
||||||
\ . join(l:documentationParts, '')
|
|
||||||
|
|
||||||
call add(l:name_list, l:text)
|
|
||||||
endfor
|
|
||||||
|
|
||||||
echom string(l:name_list)
|
|
||||||
endif
|
endif
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:HandleLSPResponse(response) abort
|
|
||||||
let l:command = get(a:response, 'command', '')
|
let l:command = get(a:response, 'command', '')
|
||||||
|
|
||||||
if l:command ==# 'completions'
|
if l:command ==# 'completions'
|
||||||
call s:HandleCompletions(a:response)
|
let l:names = ale#completion#ParseTSServerCompletions(a:response)
|
||||||
|
|
||||||
|
if !empty(l:names)
|
||||||
|
let b:ale_completion_info.request_id = ale#lsp#Send(
|
||||||
|
\ b:ale_completion_info.conn_id,
|
||||||
|
\ ale#lsp#tsserver_message#CompletionEntryDetails(
|
||||||
|
\ bufnr(''),
|
||||||
|
\ b:ale_completion_info.line,
|
||||||
|
\ b:ale_completion_info.column,
|
||||||
|
\ l:names,
|
||||||
|
\ ),
|
||||||
|
\)
|
||||||
|
endif
|
||||||
elseif l:command ==# 'completionEntryDetails'
|
elseif l:command ==# 'completionEntryDetails'
|
||||||
call s:HandleCompletionDetails(a:response)
|
call ale#completion#Show(
|
||||||
|
\ a:response,
|
||||||
|
\ 'ale#completion#ParseTSServerCompletionEntryDetails',
|
||||||
|
\)
|
||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:GetCompletionsForTSServer(buffer, linter, line, column) abort
|
function! s:GetCompletionsForTSServer(linter) abort
|
||||||
|
let l:buffer = bufnr('')
|
||||||
let l:executable = has_key(a:linter, 'executable_callback')
|
let l:executable = has_key(a:linter, 'executable_callback')
|
||||||
\ ? ale#util#GetFunction(a:linter.executable_callback)(a:buffer)
|
\ ? ale#util#GetFunction(a:linter.executable_callback)(l:buffer)
|
||||||
\ : a:linter.executable
|
\ : a:linter.executable
|
||||||
let l:command = ale#job#PrepareCommand(l:executable)
|
let l:command = ale#job#PrepareCommand(l:executable)
|
||||||
|
|
||||||
let l:id = ale#lsp#StartProgram(
|
let l:id = ale#lsp#StartProgram(
|
||||||
\ l:executable,
|
\ l:executable,
|
||||||
\ l:command,
|
\ l:command,
|
||||||
\ function('s:HandleLSPResponse')
|
\ function('s:HandleTSServerLSPResponse'),
|
||||||
\)
|
\)
|
||||||
|
|
||||||
if !l:id
|
if !l:id
|
||||||
if g:ale_history_enabled
|
if g:ale_history_enabled
|
||||||
call ale#history#Add(a:buffer, 'failed', l:id, l:command)
|
call ale#history#Add(l:buffer, 'failed', l:id, l:command)
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if ale#lsp#OpenTSServerDocumentIfNeeded(l:id, a:buffer)
|
if ale#lsp#OpenTSServerDocumentIfNeeded(l:id, l:buffer)
|
||||||
if g:ale_history_enabled
|
if g:ale_history_enabled
|
||||||
call ale#history#Add(a:buffer, 'started', l:id, l:command)
|
call ale#history#Add(l:buffer, 'started', l:id, l:command)
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
call ale#lsp#Send(l:id, ale#lsp#tsserver_message#Change(a:buffer))
|
call ale#lsp#Send(l:id, ale#lsp#tsserver_message#Change(l:buffer))
|
||||||
|
|
||||||
let l:request_id = ale#lsp#Send(
|
let l:request_id = ale#lsp#Send(
|
||||||
\ l:id,
|
\ l:id,
|
||||||
\ ale#lsp#tsserver_message#Completions(a:buffer, a:line, a:column),
|
\ ale#lsp#tsserver_message#Completions(
|
||||||
|
\ l:buffer,
|
||||||
|
\ b:ale_completion_info.line,
|
||||||
|
\ b:ale_completion_info.column,
|
||||||
|
\ b:ale_completion_info.prefix,
|
||||||
|
\ ),
|
||||||
\)
|
\)
|
||||||
|
|
||||||
if l:request_id
|
if l:request_id
|
||||||
call s:RememberCompletionInfo(
|
let b:ale_completion_info.conn_id = l:id
|
||||||
\ a:buffer,
|
let b:ale_completion_info.request_id = l:request_id
|
||||||
\ l:id,
|
|
||||||
\ l:request_id,
|
|
||||||
\ a:line,
|
|
||||||
\ a:column,
|
|
||||||
\)
|
|
||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! ale#completion#GetCompletions() abort
|
function! ale#completion#GetCompletions() abort
|
||||||
let l:buffer = bufnr('')
|
|
||||||
let [l:line, l:column] = getcurpos()[1:2]
|
let [l:line, l:column] = getcurpos()[1:2]
|
||||||
|
|
||||||
for l:linter in ale#linter#Get(getbufvar(l:buffer, '&filetype'))
|
if s:timer_pos != [l:line, l:column]
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:prefix = ale#completion#GetPrefix(&filetype, l:line, l:column)
|
||||||
|
|
||||||
|
if empty(l:prefix)
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
let b:ale_completion_info = {
|
||||||
|
\ 'line': l:line,
|
||||||
|
\ 'column': l:column,
|
||||||
|
\ 'prefix': l:prefix,
|
||||||
|
\ 'conn_id': 0,
|
||||||
|
\ 'request_id': 0,
|
||||||
|
\}
|
||||||
|
|
||||||
|
for l:linter in ale#linter#Get(&filetype)
|
||||||
if l:linter.lsp ==# 'tsserver'
|
if l:linter.lsp ==# 'tsserver'
|
||||||
call s:GetCompletionsForTSServer(l:buffer, l:linter, l:line, l:column)
|
call s:GetCompletionsForTSServer(l:linter)
|
||||||
endif
|
endif
|
||||||
endfor
|
endfor
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:TimerHandler(...) abort
|
function! s:TimerHandler(...) abort
|
||||||
|
let s:timer_id = -1
|
||||||
|
|
||||||
call ale#completion#GetCompletions()
|
call ale#completion#GetCompletions()
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! ale#completion#Queue() abort
|
function! ale#completion#Queue() abort
|
||||||
if s:timer != -1
|
let s:timer_pos = getcurpos()[1:2]
|
||||||
call timer_stop(s:timer)
|
|
||||||
let s:timer = -1
|
if s:timer_id != -1
|
||||||
|
call timer_stop(s:timer_id)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let s:timer = timer_start(s:delay, function('s:TimerHandler'))
|
let s:timer_id = timer_start(g:ale_completion_delay, function('s:TimerHandler'))
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! ale#completion#Start() abort
|
function! s:Setup(enabled) abort
|
||||||
augroup ALECompletionGroup
|
augroup ALECompletionGroup
|
||||||
autocmd!
|
autocmd!
|
||||||
autocmd TextChangedI * call ale#completion#Queue()
|
|
||||||
|
if a:enabled
|
||||||
|
autocmd TextChangedI * call ale#completion#Queue()
|
||||||
|
autocmd CompleteDone * silent! pclose
|
||||||
|
endif
|
||||||
augroup END
|
augroup END
|
||||||
|
|
||||||
|
if !a:enabled
|
||||||
|
augroup! ALECompletionGroup
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! ale#completion#Enable() abort
|
||||||
|
call s:Setup(1)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! ale#completion#Disable() abort
|
||||||
|
call s:Setup(0)
|
||||||
endfunction
|
endfunction
|
||||||
|
@ -36,12 +36,12 @@ function! ale#lsp#tsserver_message#Geterr(buffer) abort
|
|||||||
return [1, 'ts@geterr', {'files': [expand('#' . a:buffer . ':p')]}]
|
return [1, 'ts@geterr', {'files': [expand('#' . a:buffer . ':p')]}]
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! ale#lsp#tsserver_message#Completions(buffer, line, column) abort
|
function! ale#lsp#tsserver_message#Completions(buffer, line, column, prefix) abort
|
||||||
" An optional 'prefix' key can be added here for a completion prefix.
|
|
||||||
return [0, 'ts@completions', {
|
return [0, 'ts@completions', {
|
||||||
\ 'line': a:line,
|
\ 'line': a:line,
|
||||||
\ 'offset': a:column,
|
\ 'offset': a:column,
|
||||||
\ 'file': expand('#' . a:buffer . ':p'),
|
\ 'file': expand('#' . a:buffer . ':p'),
|
||||||
|
\ 'prefix': a:prefix,
|
||||||
\}]
|
\}]
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
@ -181,6 +181,11 @@ call ale#Set('maximum_file_size', 0)
|
|||||||
" Remapping of linter problems.
|
" Remapping of linter problems.
|
||||||
call ale#Set('type_map', {})
|
call ale#Set('type_map', {})
|
||||||
|
|
||||||
|
" Enable automatic completion with LSP servers and tsserver
|
||||||
|
call ale#Set('completion_enabled', 0)
|
||||||
|
call ale#Set('completion_delay', 300)
|
||||||
|
call ale#Set('completion_max_suggestions', 20)
|
||||||
|
|
||||||
function! ALEInitAuGroups() abort
|
function! ALEInitAuGroups() abort
|
||||||
" This value used to be a Boolean as a Number, and is now a String.
|
" This value used to be a Boolean as a Number, and is now a String.
|
||||||
let l:text_changed = '' . g:ale_lint_on_text_changed
|
let l:text_changed = '' . g:ale_lint_on_text_changed
|
||||||
@ -313,6 +318,10 @@ if g:ale_set_balloons
|
|||||||
call ale#balloon#Enable()
|
call ale#balloon#Enable()
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if g:ale_completion_enabled
|
||||||
|
call ale#completion#Enable()
|
||||||
|
endif
|
||||||
|
|
||||||
" Define commands for moving through warnings and errors.
|
" Define commands for moving through warnings and errors.
|
||||||
command! -bar ALEPrevious :call ale#loclist_jumping#Jump('before', 0)
|
command! -bar ALEPrevious :call ale#loclist_jumping#Jump('before', 0)
|
||||||
command! -bar ALEPreviousWrap :call ale#loclist_jumping#Jump('before', 1)
|
command! -bar ALEPreviousWrap :call ale#loclist_jumping#Jump('before', 1)
|
||||||
|
@ -158,9 +158,10 @@ Execute(ale#lsp#tsserver_message#Completions() should return correct messages):
|
|||||||
\ 'file': b:dir . '/foo.ts',
|
\ 'file': b:dir . '/foo.ts',
|
||||||
\ 'line': 347,
|
\ 'line': 347,
|
||||||
\ 'offset': 12,
|
\ 'offset': 12,
|
||||||
|
\ 'prefix': 'abc',
|
||||||
\ }
|
\ }
|
||||||
\ ],
|
\ ],
|
||||||
\ ale#lsp#tsserver_message#Completions(bufnr(''), 347, 12)
|
\ ale#lsp#tsserver_message#Completions(bufnr(''), 347, 12, 'abc')
|
||||||
|
|
||||||
Execute(ale#lsp#tsserver_message#CompletionEntryDetails() should return correct messages):
|
Execute(ale#lsp#tsserver_message#CompletionEntryDetails() should return correct messages):
|
||||||
silent! noautocmd file foo.ts
|
silent! noautocmd file foo.ts
|
||||||
|
90
test/test_completion.vader
Normal file
90
test/test_completion.vader
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
Execute(TypeScript completions responses should be parsed correctly):
|
||||||
|
AssertEqual [],
|
||||||
|
\ ale#completion#ParseTSServerCompletions({
|
||||||
|
\ 'body': [],
|
||||||
|
\})
|
||||||
|
AssertEqual ['foo', 'bar', 'baz'],
|
||||||
|
\ ale#completion#ParseTSServerCompletions({
|
||||||
|
\ 'body': [
|
||||||
|
\ {'name': 'foo'},
|
||||||
|
\ {'name': 'bar'},
|
||||||
|
\ {'name': 'baz'},
|
||||||
|
\ ],
|
||||||
|
\})
|
||||||
|
|
||||||
|
Execute(TypeScript completion details responses should be parsed correctly):
|
||||||
|
AssertEqual
|
||||||
|
\ [
|
||||||
|
\ {
|
||||||
|
\ 'word': 'abc',
|
||||||
|
\ 'menu': '(property) Foo.abc: number',
|
||||||
|
\ 'info': '',
|
||||||
|
\ 'kind': 'f'
|
||||||
|
\ },
|
||||||
|
\ {
|
||||||
|
\ 'word': 'def',
|
||||||
|
\ 'menu': '(property) Foo.def: number',
|
||||||
|
\ 'info': 'foo bar baz',
|
||||||
|
\ 'kind': 'f'
|
||||||
|
\ },
|
||||||
|
\ ],
|
||||||
|
\ ale#completion#ParseTSServerCompletionEntryDetails({
|
||||||
|
\ 'body': [
|
||||||
|
\ {
|
||||||
|
\ 'name': 'abc',
|
||||||
|
\ 'kind': 'parameterName',
|
||||||
|
\ 'displayParts': [
|
||||||
|
\ {'text': '('},
|
||||||
|
\ {'text': 'property'},
|
||||||
|
\ {'text': ')'},
|
||||||
|
\ {'text': ' '},
|
||||||
|
\ {'text': 'Foo'},
|
||||||
|
\ {'text': '.'},
|
||||||
|
\ {'text': 'abc'},
|
||||||
|
\ {'text': ':'},
|
||||||
|
\ {'text': ' '},
|
||||||
|
\ {'text': 'number'},
|
||||||
|
\ ],
|
||||||
|
\ },
|
||||||
|
\ {
|
||||||
|
\ 'name': 'def',
|
||||||
|
\ 'kind': 'parameterName',
|
||||||
|
\ 'displayParts': [
|
||||||
|
\ {'text': '('},
|
||||||
|
\ {'text': 'property'},
|
||||||
|
\ {'text': ')'},
|
||||||
|
\ {'text': ' '},
|
||||||
|
\ {'text': 'Foo'},
|
||||||
|
\ {'text': '.'},
|
||||||
|
\ {'text': 'def'},
|
||||||
|
\ {'text': ':'},
|
||||||
|
\ {'text': ' '},
|
||||||
|
\ {'text': 'number'},
|
||||||
|
\ ],
|
||||||
|
\ 'documentation': [
|
||||||
|
\ {'text': 'foo'},
|
||||||
|
\ {'text': ' '},
|
||||||
|
\ {'text': 'bar'},
|
||||||
|
\ {'text': ' '},
|
||||||
|
\ {'text': 'baz'},
|
||||||
|
\ ],
|
||||||
|
\ },
|
||||||
|
\ ],
|
||||||
|
\})
|
||||||
|
|
||||||
|
Given typescript():
|
||||||
|
let abc = y.
|
||||||
|
let foo = ab
|
||||||
|
let foo = (ab)
|
||||||
|
|
||||||
|
Execute(Completion should be done after dots in TypeScript):
|
||||||
|
AssertEqual '.', ale#completion#GetPrefix(&filetype, 1, 13)
|
||||||
|
|
||||||
|
Execute(Completion should be done after words in TypeScript):
|
||||||
|
AssertEqual 'ab', ale#completion#GetPrefix(&filetype, 2, 13)
|
||||||
|
|
||||||
|
Execute(Completion should be done after words in parens in TypeScript):
|
||||||
|
AssertEqual 'ab', ale#completion#GetPrefix(&filetype, 3, 14)
|
||||||
|
|
||||||
|
Execute(Completion should not be done after parens in TypeScript):
|
||||||
|
AssertEqual '', ale#completion#GetPrefix(&filetype, 3, 15)
|
Loading…
Reference in New Issue
Block a user