mirror of
https://github.com/amix/vimrc
synced 2025-06-16 09:35:01 +08:00
Update Ale.
This commit is contained in:
@ -0,0 +1,562 @@
|
||||
Before:
|
||||
Save g:ale_enabled
|
||||
Save b:ale_enabled
|
||||
Save g:ale_lint_on_text_changed
|
||||
Save g:ale_completion_enabled
|
||||
Save g:ale_completion_autoimport
|
||||
Save g:ale_completion_max_suggestions
|
||||
Save g:ale_linters
|
||||
Save b:ale_linters
|
||||
|
||||
let g:ale_enabled = 0
|
||||
let b:ale_enabled = 0
|
||||
let g:ale_lint_on_text_changed = 'always'
|
||||
let g:ale_completion_enabled = 0
|
||||
let g:ale_completion_autoimport = 0
|
||||
let g:ale_completion_max_suggestions = 50
|
||||
let g:ale_linters = {'typescript': ['tsserver'], 'python': ['pyre']}
|
||||
unlet! b:ale_linters
|
||||
|
||||
let g:server_started_value = 1
|
||||
let g:request_id = 0
|
||||
let g:LastCallback = v:null
|
||||
let g:LastHandleCallback = v:null
|
||||
let g:sent_message_list = []
|
||||
let g:code_action_list = []
|
||||
let g:execute_list = []
|
||||
let g:ale_queue_call_list = []
|
||||
|
||||
runtime autoload/ale.vim
|
||||
runtime autoload/ale/util.vim
|
||||
runtime autoload/ale/code_action.vim
|
||||
runtime autoload/ale/lsp.vim
|
||||
runtime autoload/ale/lsp_linter.vim
|
||||
|
||||
function! ale#util#Execute(expr) abort
|
||||
call add(g:execute_list, a:expr)
|
||||
endfunction
|
||||
|
||||
function! ale#Queue(...) abort
|
||||
call add(g:ale_queue_call_list, a:000)
|
||||
endfunction
|
||||
|
||||
function! ale#lsp#RegisterCallback(id, Callback) abort
|
||||
let g:LastHandleCallback = a:Callback
|
||||
endfunction
|
||||
|
||||
function! ale#lsp#NotifyForChanges(id, buffer) abort
|
||||
endfunction
|
||||
|
||||
function! ale#lsp#HasCapability(id, capability) abort
|
||||
return 1
|
||||
endfunction
|
||||
|
||||
function! ale#lsp#Send(id, message) abort
|
||||
let g:request_id += 1
|
||||
|
||||
call add(g:sent_message_list, a:message)
|
||||
|
||||
return g:request_id
|
||||
endfunction
|
||||
|
||||
function! ale#lsp_linter#StartLSP(buffer, linter, Callback) abort
|
||||
let g:LastCallback = a:Callback
|
||||
|
||||
return g:server_started_value
|
||||
endfunction
|
||||
|
||||
function! ale#code_action#HandleCodeAction(code_action, options) abort
|
||||
Assert !get(a:options, 'should_save')
|
||||
|
||||
call add(g:code_action_list, a:code_action)
|
||||
endfunction
|
||||
|
||||
function GetLastMessage()
|
||||
return get(g:execute_list, -1, '')
|
||||
endfunction
|
||||
|
||||
function CheckLintStates(conn_id, message)
|
||||
" Check that we request more linter results after adding completions.
|
||||
AssertEqual [[0, '']], g:ale_queue_call_list
|
||||
|
||||
let g:ale_enabled = 0
|
||||
|
||||
let g:ale_queue_call_list = []
|
||||
call g:LastHandleCallback(a:conn_id, a:message)
|
||||
AssertEqual [], g:ale_queue_call_list
|
||||
|
||||
let g:ale_enabled = 1
|
||||
let g:ale_lint_on_text_changed = 1
|
||||
|
||||
let g:ale_queue_call_list = []
|
||||
call g:LastHandleCallback(a:conn_id, a:message)
|
||||
AssertEqual [[0, '']], g:ale_queue_call_list
|
||||
|
||||
let g:ale_lint_on_text_changed = 'normal'
|
||||
|
||||
let g:ale_queue_call_list = []
|
||||
call g:LastHandleCallback(a:conn_id, a:message)
|
||||
AssertEqual [[0, '']], g:ale_queue_call_list
|
||||
|
||||
let g:ale_lint_on_text_changed = 'insert'
|
||||
|
||||
let g:ale_queue_call_list = []
|
||||
call g:LastHandleCallback(a:conn_id, a:message)
|
||||
AssertEqual [[0, '']], g:ale_queue_call_list
|
||||
|
||||
let g:ale_queue_call_list = []
|
||||
let g:ale_lint_on_text_changed = 'never'
|
||||
|
||||
call g:LastHandleCallback(a:conn_id, a:message)
|
||||
AssertEqual [], g:ale_queue_call_list
|
||||
|
||||
let g:ale_lint_on_text_changed = '0'
|
||||
|
||||
call g:LastHandleCallback(a:conn_id, a:message)
|
||||
AssertEqual [], g:ale_queue_call_list
|
||||
|
||||
let g:ale_lint_on_text_changed = 0
|
||||
|
||||
call g:LastHandleCallback(a:conn_id, a:message)
|
||||
AssertEqual [], g:ale_queue_call_list
|
||||
|
||||
let g:ale_lint_on_text_changed = 'xxx'
|
||||
|
||||
call g:LastHandleCallback(a:conn_id, a:message)
|
||||
AssertEqual [], g:ale_queue_call_list
|
||||
endfunction
|
||||
|
||||
After:
|
||||
call ale#linter#Reset()
|
||||
|
||||
Restore
|
||||
|
||||
delfunction GetLastMessage
|
||||
delfunction CheckLintStates
|
||||
|
||||
unlet! g:LastCallback
|
||||
unlet! g:LastHandleCallback
|
||||
unlet! g:request_id
|
||||
unlet! g:server_started_value
|
||||
unlet! g:sent_message_list
|
||||
unlet! g:code_action_list
|
||||
unlet! g:ale_queue_call_list
|
||||
unlet! g:execute_list
|
||||
unlet! g:received_message
|
||||
unlet! b:ale_old_omnifunc
|
||||
unlet! b:ale_old_completeopt
|
||||
unlet! b:ale_completion_info
|
||||
unlet! b:ale_completion_result
|
||||
unlet! b:ale_complete_done_time
|
||||
|
||||
runtime autoload/ale.vim
|
||||
runtime autoload/ale/util.vim
|
||||
runtime autoload/ale/code_action.vim
|
||||
runtime autoload/ale/lsp.vim
|
||||
runtime autoload/ale/lsp_linter.vim
|
||||
|
||||
Given typescript(Some example TypeScript code):
|
||||
let xyz = 123
|
||||
let foo = missingword
|
||||
|
||||
let abc = 456
|
||||
|
||||
Execute(ALEImport should complain when there's no word at the cursor):
|
||||
call setpos('.', [bufnr(''), 3, 1, 0])
|
||||
ALEImport
|
||||
|
||||
AssertEqual 'echom ''Nothing to complete at cursor!''', GetLastMessage()
|
||||
|
||||
Execute(ALEImport should tell the user if no LSP is available):
|
||||
let g:server_started_value = 0
|
||||
|
||||
call setpos('.', [bufnr(''), 2, 16, 0])
|
||||
ALEImport
|
||||
|
||||
AssertEqual
|
||||
\ 'echom ''No completion providers are available.''',
|
||||
\ GetLastMessage()
|
||||
|
||||
Execute(ALEImport should request imports correctly for tsserver):
|
||||
call setpos('.', [bufnr(''), 2, 16, 0])
|
||||
|
||||
ALEImport
|
||||
|
||||
AssertEqual
|
||||
\ {
|
||||
\ 'conn_id': 0,
|
||||
\ 'request_id': 0,
|
||||
\ 'source': 'ale-import',
|
||||
\ 'column': 21,
|
||||
\ 'line': 2,
|
||||
\ 'line_length': 21,
|
||||
\ 'prefix': 'missingword',
|
||||
\ 'additional_edits_only': 1,
|
||||
\ },
|
||||
\ b:ale_completion_info
|
||||
Assert g:LastCallback isnot v:null
|
||||
|
||||
call g:LastCallback(ale#linter#Get(&filetype)[0], {
|
||||
\ 'connection_id': 347,
|
||||
\ 'buffer': bufnr(''),
|
||||
\})
|
||||
|
||||
AssertEqual
|
||||
\ {
|
||||
\ 'conn_id': 347,
|
||||
\ 'request_id': 1,
|
||||
\ 'source': 'ale-import',
|
||||
\ 'column': 21,
|
||||
\ 'line': 2,
|
||||
\ 'line_length': 21,
|
||||
\ 'prefix': 'missingword',
|
||||
\ 'additional_edits_only': 1,
|
||||
\ },
|
||||
\ b:ale_completion_info
|
||||
Assert g:LastHandleCallback isnot v:null
|
||||
|
||||
call g:LastHandleCallback(347, {
|
||||
\ 'request_seq': 1,
|
||||
\ 'command': 'completions',
|
||||
\ 'body': [
|
||||
\ {'name': 'missingwordIgnoreMe'},
|
||||
\ {'name': 'missingword'},
|
||||
\ ],
|
||||
\})
|
||||
|
||||
AssertEqual
|
||||
\ [
|
||||
\ [0, 'ts@completions', {
|
||||
\ 'file': expand('%:p'),
|
||||
\ 'includeExternalModuleExports': 1,
|
||||
\ 'offset': 21,
|
||||
\ 'line': 2,
|
||||
\ 'prefix': 'missingword',
|
||||
\ }],
|
||||
\ [0, 'ts@completionEntryDetails', {
|
||||
\ 'file': expand('%:p'),
|
||||
\ 'entryNames': [{'name': 'missingword'}],
|
||||
\ 'offset': 21,
|
||||
\ 'line': 2,
|
||||
\ }]
|
||||
\ ],
|
||||
\ g:sent_message_list
|
||||
AssertEqual 2, b:ale_completion_info.request_id
|
||||
|
||||
let g:ale_enabled = 1
|
||||
let g:received_message = {
|
||||
\ 'request_seq': 2,
|
||||
\ 'command': 'completionEntryDetails',
|
||||
\ 'body': [
|
||||
\ {
|
||||
\ 'name': 'missingword',
|
||||
\ 'kind': 'className',
|
||||
\ 'displayParts': [],
|
||||
\ 'codeActions': [{
|
||||
\ 'description': 'import { missingword } from "./Something";',
|
||||
\ 'changes': [],
|
||||
\ }],
|
||||
\ },
|
||||
\ ],
|
||||
\}
|
||||
call g:LastHandleCallback(347, g:received_message)
|
||||
|
||||
AssertEqual
|
||||
\ [
|
||||
\ {
|
||||
\ 'description': 'import { missingword } from "./Something";',
|
||||
\ 'changes': [],
|
||||
\ },
|
||||
\ ],
|
||||
\ g:code_action_list
|
||||
|
||||
call CheckLintStates(347, g:received_message)
|
||||
|
||||
Execute(ALEImport should tell the user when no completions were found from tsserver):
|
||||
call setpos('.', [bufnr(''), 2, 16, 0])
|
||||
|
||||
ALEImport
|
||||
|
||||
AssertEqual
|
||||
\ {
|
||||
\ 'conn_id': 0,
|
||||
\ 'request_id': 0,
|
||||
\ 'source': 'ale-import',
|
||||
\ 'column': 21,
|
||||
\ 'line': 2,
|
||||
\ 'line_length': 21,
|
||||
\ 'prefix': 'missingword',
|
||||
\ 'additional_edits_only': 1,
|
||||
\ },
|
||||
\ b:ale_completion_info
|
||||
Assert g:LastCallback isnot v:null
|
||||
|
||||
call g:LastCallback(ale#linter#Get(&filetype)[0], {
|
||||
\ 'connection_id': 347,
|
||||
\ 'buffer': bufnr(''),
|
||||
\})
|
||||
|
||||
AssertEqual
|
||||
\ {
|
||||
\ 'conn_id': 347,
|
||||
\ 'request_id': 1,
|
||||
\ 'source': 'ale-import',
|
||||
\ 'column': 21,
|
||||
\ 'line': 2,
|
||||
\ 'line_length': 21,
|
||||
\ 'prefix': 'missingword',
|
||||
\ 'additional_edits_only': 1,
|
||||
\ },
|
||||
\ b:ale_completion_info
|
||||
Assert g:LastHandleCallback isnot v:null
|
||||
|
||||
call g:LastHandleCallback(347, {
|
||||
\ 'request_seq': 1,
|
||||
\ 'command': 'completions',
|
||||
\ 'body': [
|
||||
\ {'name': 'missingwordIgnoreMe'},
|
||||
\ ],
|
||||
\})
|
||||
|
||||
AssertEqual 'echom ''No possible imports found.''', GetLastMessage()
|
||||
|
||||
Given python(Some example Python code):
|
||||
xyz = 123
|
||||
foo = missingword
|
||||
|
||||
abc = 456
|
||||
|
||||
Execute(ALEImport should request imports correctly for language servers):
|
||||
call setpos('.', [bufnr(''), 2, 12, 0])
|
||||
|
||||
ALEImport
|
||||
|
||||
AssertEqual
|
||||
\ {
|
||||
\ 'conn_id': 0,
|
||||
\ 'request_id': 0,
|
||||
\ 'source': 'ale-import',
|
||||
\ 'column': 17,
|
||||
\ 'line': 2,
|
||||
\ 'line_length': 17,
|
||||
\ 'prefix': 'missingword',
|
||||
\ 'additional_edits_only': 1,
|
||||
\ },
|
||||
\ b:ale_completion_info
|
||||
Assert g:LastCallback isnot v:null
|
||||
|
||||
call g:LastCallback(ale#linter#Get(&filetype)[0], {
|
||||
\ 'connection_id': 347,
|
||||
\ 'buffer': bufnr(''),
|
||||
\})
|
||||
|
||||
AssertEqual
|
||||
\ {
|
||||
\ 'conn_id': 347,
|
||||
\ 'request_id': 1,
|
||||
\ 'source': 'ale-import',
|
||||
\ 'column': 17,
|
||||
\ 'line': 2,
|
||||
\ 'line_length': 17,
|
||||
\ 'prefix': 'missingword',
|
||||
\ 'additional_edits_only': 1,
|
||||
\ 'completion_filter': 'ale#completion#python#CompletionItemFilter',
|
||||
\ },
|
||||
\ b:ale_completion_info
|
||||
Assert g:LastHandleCallback isnot v:null
|
||||
|
||||
AssertEqual
|
||||
\ [
|
||||
\ [0, 'textDocument/completion', {
|
||||
\ 'textDocument': {'uri': ale#path#ToFileURI(expand('%:p'))},
|
||||
\ 'position': {'character': 16, 'line': 1}
|
||||
\ }],
|
||||
\ ],
|
||||
\ g:sent_message_list
|
||||
AssertEqual 1, b:ale_completion_info.request_id
|
||||
|
||||
let g:ale_enabled = 1
|
||||
let g:received_message = {
|
||||
\ 'id': 1,
|
||||
\ 'jsonrpc': '2.0',
|
||||
\ 'result': {
|
||||
\ 'isIncomplete': v:false,
|
||||
\ 'items': [
|
||||
\ {
|
||||
\ 'detail': 'Some other word we should ignore',
|
||||
\ 'filterText': 'missingwordIgnoreMe',
|
||||
\ 'insertText': 'missingwordIgnoreMe',
|
||||
\ 'insertTextFormat': 1,
|
||||
\ 'kind': 6,
|
||||
\ 'label': ' missingwordIgnoreMe',
|
||||
\ 'sortText': '3ee19999missingword',
|
||||
\ 'additionalTextEdits': [
|
||||
\ {
|
||||
\ 'range': {
|
||||
\ 'start': {'line': 1, 'character': 1},
|
||||
\ 'end': {'line': 2, 'character': 1},
|
||||
\ },
|
||||
\ 'newText': 'from something import missingwordIgnoreMe',
|
||||
\ },
|
||||
\ ],
|
||||
\ },
|
||||
\ {
|
||||
\ 'detail': 'Some word without text edits',
|
||||
\ 'filterText': 'missingword',
|
||||
\ 'insertText': 'missingword',
|
||||
\ 'insertTextFormat': 1,
|
||||
\ 'kind': 6,
|
||||
\ 'label': ' missingword',
|
||||
\ 'sortText': '3ee19999missingword',
|
||||
\ },
|
||||
\ {
|
||||
\ 'detail': 'The word we should use',
|
||||
\ 'filterText': 'missingword',
|
||||
\ 'insertText': 'missingword',
|
||||
\ 'insertTextFormat': 1,
|
||||
\ 'kind': 6,
|
||||
\ 'label': ' missingword',
|
||||
\ 'sortText': '3ee19999missingword',
|
||||
\ 'additionalTextEdits': [
|
||||
\ {
|
||||
\ 'range': {
|
||||
\ 'start': {'line': 1, 'character': 1},
|
||||
\ 'end': {'line': 2, 'character': 1},
|
||||
\ },
|
||||
\ 'newText': 'from something import missingword',
|
||||
\ },
|
||||
\ ],
|
||||
\ },
|
||||
\ {
|
||||
\ 'detail': 'The other word we should not use',
|
||||
\ 'filterText': 'missingword',
|
||||
\ 'insertText': 'missingword',
|
||||
\ 'insertTextFormat': 1,
|
||||
\ 'kind': 6,
|
||||
\ 'label': ' missingword',
|
||||
\ 'sortText': '3ee19999missingword',
|
||||
\ 'additionalTextEdits': [
|
||||
\ {
|
||||
\ 'range': {
|
||||
\ 'start': {'line': 1, 'character': 1},
|
||||
\ 'end': {'line': 2, 'character': 1},
|
||||
\ },
|
||||
\ 'newText': 'from something_else import missingword',
|
||||
\ },
|
||||
\ ],
|
||||
\ },
|
||||
\ ],
|
||||
\ },
|
||||
\}
|
||||
call g:LastHandleCallback(347, g:received_message)
|
||||
|
||||
AssertEqual
|
||||
\ [
|
||||
\ {
|
||||
\ 'description': 'completion',
|
||||
\ 'changes': [
|
||||
\ {
|
||||
\ 'fileName': expand('%:p'),
|
||||
\ 'textChanges': [
|
||||
\ {
|
||||
\ 'start': {'line': 2, 'offset': 2},
|
||||
\ 'end': {'line': 3, 'offset': 2},
|
||||
\ 'newText': 'from something import missingword',
|
||||
\ },
|
||||
\ ],
|
||||
\ },
|
||||
\ ],
|
||||
\ },
|
||||
\ ],
|
||||
\ g:code_action_list
|
||||
|
||||
call CheckLintStates(347, g:received_message)
|
||||
|
||||
Execute(ALEImport should tell the user when no completions were found from a language server):
|
||||
call setpos('.', [bufnr(''), 2, 12, 0])
|
||||
|
||||
ALEImport
|
||||
|
||||
AssertEqual
|
||||
\ {
|
||||
\ 'conn_id': 0,
|
||||
\ 'request_id': 0,
|
||||
\ 'source': 'ale-import',
|
||||
\ 'column': 17,
|
||||
\ 'line': 2,
|
||||
\ 'line_length': 17,
|
||||
\ 'prefix': 'missingword',
|
||||
\ 'additional_edits_only': 1,
|
||||
\ },
|
||||
\ b:ale_completion_info
|
||||
Assert g:LastCallback isnot v:null
|
||||
|
||||
call g:LastCallback(ale#linter#Get(&filetype)[0], {
|
||||
\ 'connection_id': 347,
|
||||
\ 'buffer': bufnr(''),
|
||||
\})
|
||||
|
||||
AssertEqual
|
||||
\ {
|
||||
\ 'conn_id': 347,
|
||||
\ 'request_id': 1,
|
||||
\ 'source': 'ale-import',
|
||||
\ 'column': 17,
|
||||
\ 'line': 2,
|
||||
\ 'line_length': 17,
|
||||
\ 'prefix': 'missingword',
|
||||
\ 'additional_edits_only': 1,
|
||||
\ 'completion_filter': 'ale#completion#python#CompletionItemFilter',
|
||||
\ },
|
||||
\ b:ale_completion_info
|
||||
Assert g:LastHandleCallback isnot v:null
|
||||
|
||||
AssertEqual
|
||||
\ [
|
||||
\ [0, 'textDocument/completion', {
|
||||
\ 'textDocument': {'uri': ale#path#ToFileURI(expand('%:p'))},
|
||||
\ 'position': {'character': 16, 'line': 1}
|
||||
\ }],
|
||||
\ ],
|
||||
\ g:sent_message_list
|
||||
AssertEqual 1, b:ale_completion_info.request_id
|
||||
|
||||
let g:received_message = {
|
||||
\ 'id': 1,
|
||||
\ 'jsonrpc': '2.0',
|
||||
\ 'result': {
|
||||
\ 'isIncomplete': v:false,
|
||||
\ 'items': [
|
||||
\ {
|
||||
\ 'detail': 'Some other word we should ignore',
|
||||
\ 'filterText': 'missingwordIgnoreMe',
|
||||
\ 'insertText': 'missingwordIgnoreMe',
|
||||
\ 'insertTextFormat': 1,
|
||||
\ 'kind': 6,
|
||||
\ 'label': ' missingwordIgnoreMe',
|
||||
\ 'sortText': '3ee19999missingword',
|
||||
\ 'additionalTextEdits': [
|
||||
\ {
|
||||
\ 'range': {
|
||||
\ 'start': {'line': 1, 'character': 1},
|
||||
\ 'end': {'line': 2, 'character': 1},
|
||||
\ },
|
||||
\ 'newText': 'from something import missingwordIgnoreMe',
|
||||
\ },
|
||||
\ ],
|
||||
\ },
|
||||
\ {
|
||||
\ 'detail': 'Some word without text edits',
|
||||
\ 'filterText': 'missingword',
|
||||
\ 'insertText': 'missingword',
|
||||
\ 'insertTextFormat': 1,
|
||||
\ 'kind': 6,
|
||||
\ 'label': ' missingword',
|
||||
\ 'sortText': '3ee19999missingword',
|
||||
\ },
|
||||
\ ],
|
||||
\ },
|
||||
\}
|
||||
call g:LastHandleCallback(347, g:received_message)
|
||||
|
||||
AssertEqual 'echom ''No possible imports found.''', GetLastMessage()
|
@ -0,0 +1,35 @@
|
||||
Before:
|
||||
let g:complete_post_triggered = 0
|
||||
|
||||
augroup VaderTest
|
||||
autocmd!
|
||||
autocmd User ALECompletePost let g:complete_post_triggered = 1
|
||||
augroup END
|
||||
|
||||
After:
|
||||
unlet! b:ale_completion_info
|
||||
unlet! g:complete_post_triggered
|
||||
|
||||
augroup VaderTest
|
||||
autocmd!
|
||||
augroup END
|
||||
|
||||
augroup! VaderTest
|
||||
|
||||
Execute(ALECompletePost should not be triggered when completion is cancelled):
|
||||
call ale#completion#HandleUserData({})
|
||||
|
||||
Assert !g:complete_post_triggered
|
||||
|
||||
Execute(ALECompletePost should not be triggered when tools other than ALE insert completions):
|
||||
call ale#completion#HandleUserData({'user_data': ''})
|
||||
call ale#completion#HandleUserData({'user_data': '{}'})
|
||||
|
||||
Assert !g:complete_post_triggered
|
||||
|
||||
Execute(ALECompletePost should be triggered when ALE inserts completions):
|
||||
call ale#completion#HandleUserData({
|
||||
\ 'user_data': json_encode({'_ale_completion_item': 1}),
|
||||
\})
|
||||
|
||||
Assert g:complete_post_triggered
|
@ -0,0 +1,486 @@
|
||||
Before:
|
||||
Save g:ale_completion_enabled
|
||||
Save g:ale_completion_delay
|
||||
Save g:ale_completion_max_suggestions
|
||||
Save &l:omnifunc
|
||||
Save &l:completeopt
|
||||
|
||||
unlet! b:ale_completion_enabled
|
||||
let g:ale_completion_enabled = 1
|
||||
let g:get_completions_called = 0
|
||||
let g:feedkeys_calls = []
|
||||
let g:fake_mode = 'i'
|
||||
|
||||
let b:ale_linters = {
|
||||
\ 'typescript': ['tsserver'],
|
||||
\}
|
||||
|
||||
let &l:completeopt = 'menu,menuone,preview,noselect,noinsert'
|
||||
|
||||
runtime autoload/ale/util.vim
|
||||
|
||||
function! ale#util#FeedKeys(string) abort
|
||||
call add(g:feedkeys_calls, [a:string])
|
||||
endfunction
|
||||
|
||||
" Pretend we're in insert mode for most tests.
|
||||
function! ale#util#Mode(...) abort
|
||||
return g:fake_mode
|
||||
endfunction
|
||||
|
||||
function! CheckCompletionCalled(expect_success) abort
|
||||
let g:get_completions_called = 0
|
||||
|
||||
" We just want to check if the function is called.
|
||||
function! ale#completion#GetCompletions(source)
|
||||
let g:get_completions_called = 1
|
||||
endfunction
|
||||
|
||||
let g:ale_completion_delay = 0
|
||||
|
||||
" Run this check a few times, as it can fail randomly.
|
||||
for l:i in range(has('nvim-0.3') || has('win32') ? 5 : 1)
|
||||
call ale#completion#Queue()
|
||||
sleep 1m
|
||||
|
||||
if g:get_completions_called is a:expect_success
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
|
||||
AssertEqual a:expect_success, g:get_completions_called
|
||||
endfunction
|
||||
|
||||
let g:handle_code_action_called = 0
|
||||
function! MockHandleCodeAction() abort
|
||||
" delfunction! ale#code_action#HandleCodeAction
|
||||
function! ale#code_action#HandleCodeAction(action, options) abort
|
||||
Assert !get(a:options, 'should_save')
|
||||
let g:handle_code_action_called += 1
|
||||
endfunction
|
||||
endfunction
|
||||
|
||||
After:
|
||||
Restore
|
||||
|
||||
unlet! b:ale_completion_enabled
|
||||
unlet! g:output
|
||||
unlet! g:fake_mode
|
||||
unlet! g:get_completions_called
|
||||
unlet! g:handle_code_action_called
|
||||
unlet! b:ale_old_omnifunc
|
||||
unlet! b:ale_old_completeopt
|
||||
unlet! b:ale_completion_info
|
||||
unlet! b:ale_completion_result
|
||||
unlet! b:ale_complete_done_time
|
||||
unlet! b:ale_linters
|
||||
|
||||
delfunction CheckCompletionCalled
|
||||
delfunction ale#code_action#HandleCodeAction
|
||||
delfunction MockHandleCodeAction
|
||||
|
||||
if exists('*CompleteCallback')
|
||||
delfunction CompleteCallback
|
||||
endif
|
||||
|
||||
" Stop any timers we left behind.
|
||||
" This stops the tests from failing randomly.
|
||||
call ale#completion#StopTimer()
|
||||
|
||||
" Reset the function. The runtime command below should fix this, but doesn't
|
||||
" seem to fix it.
|
||||
function! ale#util#Mode(...) abort
|
||||
return call('mode', a:000)
|
||||
endfunction
|
||||
|
||||
runtime autoload/ale/completion.vim
|
||||
runtime autoload/ale/code_action.vim
|
||||
runtime autoload/ale/util.vim
|
||||
|
||||
Execute(ale#completion#GetCompletions should be called when the cursor position stays the same):
|
||||
call CheckCompletionCalled(1)
|
||||
|
||||
Execute(ale#completion#GetCompletions should not be called if the global setting is disabled):
|
||||
let g:ale_completion_enabled = 0
|
||||
call CheckCompletionCalled(0)
|
||||
|
||||
Execute(ale#completion#GetCompletions should not be called if the buffer setting is disabled):
|
||||
let b:ale_completion_enabled = 0
|
||||
call CheckCompletionCalled(0)
|
||||
|
||||
Given typescript():
|
||||
let abc = y.
|
||||
let foo = ab
|
||||
let foo = (ab)
|
||||
|
||||
Execute(ale#completion#GetCompletions should not be called when the cursor position changes):
|
||||
call setpos('.', [bufnr(''), 1, 2, 0])
|
||||
|
||||
" We just want to check if the function is called.
|
||||
function! ale#completion#GetCompletions(source)
|
||||
let g:get_completions_called = 1
|
||||
endfunction
|
||||
|
||||
let g:ale_completion_delay = 0
|
||||
call ale#completion#Queue()
|
||||
|
||||
" Change the cursor position before the callback is triggered.
|
||||
call setpos('.', [bufnr(''), 2, 2, 0])
|
||||
|
||||
sleep 1m
|
||||
|
||||
Assert !g:get_completions_called
|
||||
|
||||
Execute(ale#completion#GetCompletions should not be called if you switch to normal mode):
|
||||
let &l:completeopt = 'menu,preview'
|
||||
let g:fake_mode = 'n'
|
||||
|
||||
" We just want to check if the function is called.
|
||||
function! ale#completion#GetCompletions(source)
|
||||
let g:get_completions_called = 1
|
||||
endfunction
|
||||
|
||||
let g:ale_completion_delay = 0
|
||||
call ale#completion#Queue()
|
||||
|
||||
sleep 1m
|
||||
|
||||
Assert !g:get_completions_called
|
||||
|
||||
Execute(Completion should not be done shortly after the CompleteDone function):
|
||||
call CheckCompletionCalled(1)
|
||||
call ale#completion#Done()
|
||||
call CheckCompletionCalled(0)
|
||||
|
||||
Execute(ale#completion#Show() should remember the omnifunc setting and replace it):
|
||||
let &l:omnifunc = 'FooBar'
|
||||
|
||||
let b:ale_completion_info = {'source': 'ale-automatic'}
|
||||
call ale#completion#Show([{'word': 'x', 'kind': 'v', 'icase': 1}])
|
||||
|
||||
AssertEqual 'FooBar', b:ale_old_omnifunc
|
||||
AssertEqual 'ale#completion#AutomaticOmniFunc', &l:omnifunc
|
||||
|
||||
AssertEqual [], g:feedkeys_calls
|
||||
sleep 1ms
|
||||
AssertEqual [["\<Plug>(ale_show_completion_menu)"]], g:feedkeys_calls
|
||||
|
||||
Execute(ale#completion#Show() should remember the completeopt setting and replace it):
|
||||
let &l:completeopt = 'menu'
|
||||
|
||||
let b:ale_completion_info = {'source': 'ale-automatic'}
|
||||
call ale#completion#Show([{'word': 'x', 'kind': 'v', 'icase': 1}])
|
||||
|
||||
AssertEqual 'menu', b:ale_old_completeopt
|
||||
AssertEqual 'menu,menuone,noinsert', &l:completeopt
|
||||
|
||||
AssertEqual [], g:feedkeys_calls
|
||||
sleep 1ms
|
||||
AssertEqual [["\<Plug>(ale_show_completion_menu)"]], g:feedkeys_calls
|
||||
|
||||
Execute(ale#completion#Show() should set the preview option if it's set):
|
||||
let &l:completeopt = 'menu,preview'
|
||||
|
||||
let b:ale_completion_info = {'source': 'ale-automatic'}
|
||||
call ale#completion#Show([{'word': 'x', 'kind': 'v', 'icase': 1}])
|
||||
|
||||
AssertEqual 'menu,preview', b:ale_old_completeopt
|
||||
AssertEqual 'menu,menuone,noinsert,preview', &l:completeopt
|
||||
|
||||
AssertEqual [], g:feedkeys_calls
|
||||
sleep 1ms
|
||||
AssertEqual [["\<Plug>(ale_show_completion_menu)"]], g:feedkeys_calls
|
||||
|
||||
Execute(ale#completion#Show() should not replace the completeopt setting for manual completion):
|
||||
let b:ale_completion_info = {'source': 'ale-manual'}
|
||||
|
||||
let &l:completeopt = 'menu,preview'
|
||||
|
||||
call ale#completion#Show([{'word': 'x', 'kind': 'v', 'icase': 1}])
|
||||
|
||||
Assert !exists('b:ale_old_completeopt')
|
||||
|
||||
AssertEqual [], g:feedkeys_calls
|
||||
sleep 1ms
|
||||
AssertEqual [["\<Plug>(ale_show_completion_menu)"]], g:feedkeys_calls
|
||||
|
||||
Execute(ale#completion#AutomaticOmniFunc() should also remember the completeopt setting and replace it):
|
||||
let &l:completeopt = 'menu,noselect'
|
||||
|
||||
let b:ale_completion_info = {'source': 'ale-automatic'}
|
||||
call ale#completion#AutomaticOmniFunc(0, '')
|
||||
|
||||
AssertEqual 'menu,noselect', b:ale_old_completeopt
|
||||
AssertEqual 'menu,menuone,noinsert,noselect', &l:completeopt
|
||||
|
||||
Execute(ale#completion#AutomaticOmniFunc() should set the preview option if it's set):
|
||||
let &l:completeopt = 'menu,preview'
|
||||
|
||||
let b:ale_completion_info = {'source': 'ale-automatic'}
|
||||
call ale#completion#AutomaticOmniFunc(0, '')
|
||||
|
||||
AssertEqual 'menu,preview', b:ale_old_completeopt
|
||||
AssertEqual 'menu,menuone,noinsert,preview', &l:completeopt
|
||||
|
||||
Execute(ale#completion#Show() should make the correct feedkeys() call for automatic completion):
|
||||
let b:ale_completion_info = {'source': 'ale-automatic'}
|
||||
call ale#completion#Show([{'word': 'x', 'kind': 'v', 'icase': 1}])
|
||||
|
||||
AssertEqual [], g:feedkeys_calls
|
||||
sleep 1ms
|
||||
AssertEqual [["\<Plug>(ale_show_completion_menu)"]], g:feedkeys_calls
|
||||
|
||||
Execute(ale#completion#Show() should make the correct feedkeys() call for manual completion):
|
||||
let b:ale_completion_info = {'source': 'ale-automatic'}
|
||||
call ale#completion#Show([{'word': 'x', 'kind': 'v', 'icase': 1}])
|
||||
|
||||
AssertEqual [], g:feedkeys_calls
|
||||
sleep 1ms
|
||||
AssertEqual [["\<Plug>(ale_show_completion_menu)"]], g:feedkeys_calls
|
||||
|
||||
Execute(ale#completion#Show() should not call feedkeys() for other sources):
|
||||
let b:ale_completion_info = {'source': 'other-source'}
|
||||
call ale#completion#Show([{'word': 'x', 'kind': 'v', 'icase': 1}])
|
||||
|
||||
sleep 1ms
|
||||
AssertEqual [], g:feedkeys_calls
|
||||
|
||||
Execute(ale#completion#Show() shouldn't do anything if you switch back to normal mode):
|
||||
let &l:completeopt = 'menu,preview'
|
||||
let g:fake_mode = 'n'
|
||||
|
||||
call ale#completion#Show([{'word': 'x', 'kind': 'v', 'icase': 1}])
|
||||
|
||||
AssertEqual 'menu,preview', &l:completeopt
|
||||
Assert !exists('b:ale_old_omnifunc')
|
||||
Assert !exists('b:ale_old_completeopt')
|
||||
Assert !exists('b:ale_completion_result')
|
||||
AssertEqual [], g:feedkeys_calls
|
||||
|
||||
Execute(ale#completion#Show() should save the result it is given):
|
||||
call ale#completion#Show([])
|
||||
|
||||
AssertEqual [], b:ale_completion_result
|
||||
|
||||
call ale#completion#Show([{'word': 'x', 'kind': 'v', 'icase': 1}])
|
||||
|
||||
AssertEqual [{'word': 'x', 'kind': 'v', 'icase': 1}], b:ale_completion_result
|
||||
|
||||
Execute(ale#completion#Done() should restore old omnifunc values):
|
||||
let b:ale_old_omnifunc = 'FooBar'
|
||||
|
||||
call ale#completion#Done()
|
||||
|
||||
" We reset the old omnifunc setting and remove the buffer variable.
|
||||
AssertEqual 'FooBar', &l:omnifunc
|
||||
Assert !has_key(b:, 'ale_old_omnifunc')
|
||||
|
||||
Execute(ale#completion#Done() should restore the old completeopt setting):
|
||||
let b:ale_old_completeopt = 'menu'
|
||||
|
||||
call ale#completion#Done()
|
||||
|
||||
AssertEqual 'menu', &l:completeopt
|
||||
Assert !has_key(b:, 'ale_old_completeopt')
|
||||
|
||||
Execute(ale#completion#Done() should leave settings alone when none were remembered):
|
||||
let &l:omnifunc = 'BazBoz'
|
||||
let &l:completeopt = 'menu'
|
||||
|
||||
call ale#completion#Done()
|
||||
|
||||
AssertEqual 'BazBoz', &l:omnifunc
|
||||
AssertEqual 'menu', &l:completeopt
|
||||
|
||||
Execute(The completion request_id should be reset when queuing again):
|
||||
let b:ale_completion_info = {'request_id': 123}
|
||||
|
||||
let g:ale_completion_delay = 0
|
||||
call ale#completion#Queue()
|
||||
sleep 1m
|
||||
|
||||
AssertEqual 0, b:ale_completion_info.request_id
|
||||
|
||||
Execute(b:ale_completion_info should be set up correctly when requesting completions automatically):
|
||||
let b:ale_completion_result = []
|
||||
call setpos('.', [bufnr(''), 3, 14, 0])
|
||||
call ale#completion#GetCompletions('ale-automatic')
|
||||
|
||||
AssertEqual
|
||||
\ {
|
||||
\ 'request_id': 0,
|
||||
\ 'conn_id': 0,
|
||||
\ 'column': 14,
|
||||
\ 'line_length': 14,
|
||||
\ 'line': 3,
|
||||
\ 'prefix': 'ab',
|
||||
\ 'source': 'ale-automatic',
|
||||
\ },
|
||||
\ b:ale_completion_info
|
||||
Assert !exists('b:ale_completion_result')
|
||||
|
||||
Execute(b:ale_completion_info should be set up correctly when requesting completions manually):
|
||||
let b:ale_completion_result = []
|
||||
call setpos('.', [bufnr(''), 3, 14, 0])
|
||||
ALEComplete
|
||||
|
||||
AssertEqual
|
||||
\ {
|
||||
\ 'request_id': 0,
|
||||
\ 'conn_id': 0,
|
||||
\ 'column': 14,
|
||||
\ 'line_length': 14,
|
||||
\ 'line': 3,
|
||||
\ 'prefix': 'ab',
|
||||
\ 'source': 'ale-manual',
|
||||
\ },
|
||||
\ b:ale_completion_info
|
||||
Assert !exists('b:ale_completion_result')
|
||||
|
||||
Execute(b:ale_completion_info should be set up correctly for other sources):
|
||||
let b:ale_completion_result = []
|
||||
call setpos('.', [bufnr(''), 3, 14, 0])
|
||||
call ale#completion#GetCompletions('ale-callback')
|
||||
|
||||
AssertEqual
|
||||
\ {
|
||||
\ 'request_id': 0,
|
||||
\ 'conn_id': 0,
|
||||
\ 'column': 14,
|
||||
\ 'line_length': 14,
|
||||
\ 'line': 3,
|
||||
\ 'prefix': 'ab',
|
||||
\ 'source': 'ale-callback',
|
||||
\ },
|
||||
\ b:ale_completion_info
|
||||
Assert !exists('b:ale_completion_result')
|
||||
|
||||
Execute(b:ale_completion_info should be set up correctly when requesting completions via callback):
|
||||
let b:ale_completion_result = []
|
||||
call setpos('.', [bufnr(''), 3, 14, 0])
|
||||
|
||||
function! CompleteCallback() abort
|
||||
echo 'Called'
|
||||
endfunction
|
||||
|
||||
|
||||
call ale#completion#GetCompletions('ale-callback', {'callback': funcref('CompleteCallback')})
|
||||
|
||||
AssertEqual
|
||||
\ {
|
||||
\ 'request_id': 0,
|
||||
\ 'conn_id': 0,
|
||||
\ 'column': 14,
|
||||
\ 'line_length': 14,
|
||||
\ 'line': 3,
|
||||
\ 'prefix': 'ab',
|
||||
\ 'source': 'ale-callback',
|
||||
\ },
|
||||
\ b:ale_completion_info
|
||||
Assert !exists('b:ale_completion_result')
|
||||
|
||||
Execute(The correct keybinds should be configured):
|
||||
redir => g:output
|
||||
silent map <Plug>(ale_show_completion_menu)
|
||||
redir END
|
||||
|
||||
AssertEqual
|
||||
\ [
|
||||
\ 'n <Plug>(ale_show_completion_menu) * :call ale#completion#RestoreCompletionOptions()<CR>',
|
||||
\ 'o <Plug>(ale_show_completion_menu) * <Nop>',
|
||||
\ 'v <Plug>(ale_show_completion_menu) * <Nop>',
|
||||
\ ],
|
||||
\ sort(split(g:output, "\n"))
|
||||
|
||||
Execute(Running the normal mode <Plug> keybind should reset the settings):
|
||||
let b:ale_old_omnifunc = 'FooBar'
|
||||
let b:ale_old_completeopt = 'menu'
|
||||
|
||||
" We can't run the keybind, but we can call the function.
|
||||
call ale#completion#RestoreCompletionOptions()
|
||||
|
||||
AssertEqual 'FooBar', &l:omnifunc
|
||||
AssertEqual 'menu', &l:completeopt
|
||||
Assert !has_key(b:, 'ale_old_omnifunc')
|
||||
Assert !has_key(b:, 'ale_old_completeopt')
|
||||
|
||||
Execute(HandleUserData should call ale#code_action#HandleCodeAction):
|
||||
let b:ale_completion_info = {'source': 'ale-manual'}
|
||||
call MockHandleCodeAction()
|
||||
|
||||
call ale#completion#HandleUserData({})
|
||||
AssertEqual g:handle_code_action_called, 0
|
||||
|
||||
call ale#completion#HandleUserData({
|
||||
\ 'user_data': ''
|
||||
\})
|
||||
AssertEqual g:handle_code_action_called, 0
|
||||
|
||||
call ale#completion#HandleUserData({
|
||||
\ 'user_data': json_encode({}),
|
||||
\})
|
||||
AssertEqual g:handle_code_action_called, 0
|
||||
|
||||
call ale#completion#HandleUserData({
|
||||
\ 'user_data': json_encode({
|
||||
\ '_ale_completion_item': 1,
|
||||
\ 'code_actions': [],
|
||||
\ }),
|
||||
\})
|
||||
AssertEqual g:handle_code_action_called, 0
|
||||
|
||||
call ale#completion#HandleUserData({
|
||||
\ 'user_data': json_encode({
|
||||
\ '_ale_completion_item': 1,
|
||||
\ 'code_actions': [
|
||||
\ {'description': '', 'changes': []},
|
||||
\ ],
|
||||
\ }),
|
||||
\})
|
||||
AssertEqual g:handle_code_action_called, 1
|
||||
|
||||
let b:ale_completion_info = {'source': 'ale-automatic'}
|
||||
call ale#completion#HandleUserData({
|
||||
\ 'user_data': json_encode({
|
||||
\ '_ale_completion_item': 1,
|
||||
\ 'code_actions': [
|
||||
\ {'description': '', 'changes': []},
|
||||
\ ],
|
||||
\ }),
|
||||
\})
|
||||
AssertEqual g:handle_code_action_called, 2
|
||||
|
||||
let b:ale_completion_info = {'source': 'ale-callback'}
|
||||
call ale#completion#HandleUserData({
|
||||
\ 'user_data': json_encode({
|
||||
\ '_ale_completion_item': 1,
|
||||
\ 'code_actions': [
|
||||
\ {'description': '', 'changes': []},
|
||||
\ ],
|
||||
\ }),
|
||||
\})
|
||||
AssertEqual g:handle_code_action_called, 3
|
||||
|
||||
let b:ale_completion_info = {'source': 'ale-omnifunc'}
|
||||
call ale#completion#HandleUserData({
|
||||
\ 'user_data': json_encode({
|
||||
\ '_ale_completion_item': 1,
|
||||
\ 'code_actions': [
|
||||
\ {'description': '', 'changes': []},
|
||||
\ ],
|
||||
\ }),
|
||||
\})
|
||||
AssertEqual g:handle_code_action_called, 4
|
||||
|
||||
Execute(ale#code_action#HandleCodeAction should not be called when when source is not ALE):
|
||||
call MockHandleCodeAction()
|
||||
let b:ale_completion_info = {'source': 'syntastic'}
|
||||
call ale#completion#HandleUserData({
|
||||
\ 'user_data': json_encode({
|
||||
\ '_ale_completion_item': 1,
|
||||
\ 'code_actions': [
|
||||
\ {'description': '', 'changes': []},
|
||||
\ ],
|
||||
\ }),
|
||||
\})
|
||||
AssertEqual g:handle_code_action_called, 0
|
@ -0,0 +1,142 @@
|
||||
Before:
|
||||
Save g:ale_completion_excluded_words
|
||||
|
||||
let g:ale_completion_excluded_words = []
|
||||
|
||||
After:
|
||||
Restore
|
||||
|
||||
unlet! b:ale_completion_excluded_words
|
||||
unlet! b:suggestions
|
||||
|
||||
Execute(Prefix filtering should work for Lists of strings):
|
||||
AssertEqual
|
||||
\ ['FooBar', 'foo'],
|
||||
\ ale#completion#Filter(bufnr(''), '', ['FooBar', 'FongBar', 'baz', 'foo'], 'foo', 0)
|
||||
AssertEqual
|
||||
\ ['FooBar', 'FongBar', 'baz', 'foo'],
|
||||
\ ale#completion#Filter(bufnr(''), '', ['FooBar', 'FongBar', 'baz', 'foo'], '.', 0)
|
||||
AssertEqual
|
||||
\ ['FooBar', 'FongBar', 'baz', 'foo'],
|
||||
\ ale#completion#Filter(bufnr(''), '', ['FooBar', 'FongBar', 'baz', 'foo'], '', 0)
|
||||
|
||||
Execute(Exact filtering should work):
|
||||
AssertEqual
|
||||
\ ['foo'],
|
||||
\ ale#completion#Filter(bufnr(''), '', ['FooBar', 'FongBar', 'baz', 'foo'], 'foo', 1)
|
||||
AssertEqual
|
||||
\ ['FooBar', 'FongBar', 'baz', 'foo'],
|
||||
\ ale#completion#Filter(bufnr(''), '', ['FooBar', 'FongBar', 'baz', 'foo'], '.', 1)
|
||||
AssertEqual
|
||||
\ ['Foo'],
|
||||
\ ale#completion#Filter(bufnr(''), '', ['FooBar', 'FongBar', 'Foo', 'foo'], 'Foo', 1)
|
||||
|
||||
Execute(Prefix filtering should work for completion items):
|
||||
AssertEqual
|
||||
\ [{'word': 'FooBar'}, {'word': 'foo'}],
|
||||
\ ale#completion#Filter(
|
||||
\ bufnr(''),
|
||||
\ '',
|
||||
\ [
|
||||
\ {'word': 'FooBar'},
|
||||
\ {'word': 'FongBar'},
|
||||
\ {'word': 'baz'},
|
||||
\ {'word': 'foo'},
|
||||
\ ],
|
||||
\ 'foo',
|
||||
\ 0,
|
||||
\ )
|
||||
|
||||
AssertEqual
|
||||
\ [
|
||||
\ {'word': 'FooBar'},
|
||||
\ {'word': 'FongBar'},
|
||||
\ {'word': 'baz'},
|
||||
\ {'word': 'foo'},
|
||||
\ ],
|
||||
\ ale#completion#Filter(
|
||||
\ bufnr(''),
|
||||
\ '',
|
||||
\ [
|
||||
\ {'word': 'FooBar'},
|
||||
\ {'word': 'FongBar'},
|
||||
\ {'word': 'baz'},
|
||||
\ {'word': 'foo'},
|
||||
\ ],
|
||||
\ '.',
|
||||
\ 0,
|
||||
\ )
|
||||
|
||||
Execute(Excluding words from completion results should work):
|
||||
let b:ale_completion_excluded_words = ['it', 'describe']
|
||||
|
||||
AssertEqual
|
||||
\ [{'word': 'Italian'}],
|
||||
\ ale#completion#Filter(
|
||||
\ bufnr(''),
|
||||
\ '',
|
||||
\ [
|
||||
\ {'word': 'Italian'},
|
||||
\ {'word': 'it'},
|
||||
\ ],
|
||||
\ 'it',
|
||||
\ 0,
|
||||
\ )
|
||||
|
||||
AssertEqual
|
||||
\ [{'word': 'Deutsch'}],
|
||||
\ ale#completion#Filter(
|
||||
\ bufnr(''),
|
||||
\ '',
|
||||
\ [
|
||||
\ {'word': 'describe'},
|
||||
\ {'word': 'Deutsch'},
|
||||
\ ],
|
||||
\ 'de',
|
||||
\ 0,
|
||||
\ )
|
||||
|
||||
AssertEqual
|
||||
\ [{'word': 'Deutsch'}],
|
||||
\ ale#completion#Filter(
|
||||
\ bufnr(''),
|
||||
\ '',
|
||||
\ [
|
||||
\ {'word': 'describe'},
|
||||
\ {'word': 'Deutsch'},
|
||||
\ ],
|
||||
\ '.',
|
||||
\ 0,
|
||||
\ )
|
||||
|
||||
Execute(Excluding words from completion results should work with lists of Strings):
|
||||
let b:ale_completion_excluded_words = ['it', 'describe']
|
||||
|
||||
AssertEqual
|
||||
\ ['Italian'],
|
||||
\ ale#completion#Filter(bufnr(''), '', ['Italian', 'it'], 'it', 0)
|
||||
AssertEqual
|
||||
\ ['Deutsch'],
|
||||
\ ale#completion#Filter(bufnr(''), '', ['describe', 'Deutsch'], 'de', 0)
|
||||
AssertEqual
|
||||
\ ['Deutsch'],
|
||||
\ ale#completion#Filter(bufnr(''), '', ['describe', 'Deutsch'], '.', 0)
|
||||
AssertEqual
|
||||
\ ['Deutsch'],
|
||||
\ ale#completion#Filter(bufnr(''), '', ['Deutsch'], '', 0)
|
||||
|
||||
Execute(Filtering shouldn't modify the original list):
|
||||
let b:ale_completion_excluded_words = ['it', 'describe']
|
||||
let b:suggestions = [{'word': 'describe'}]
|
||||
|
||||
AssertEqual [], ale#completion#Filter(bufnr(''), '', b:suggestions, '.', 0)
|
||||
AssertEqual b:suggestions, [{'word': 'describe'}]
|
||||
AssertEqual [], ale#completion#Filter(bufnr(''), '', b:suggestions, 'de', 0)
|
||||
AssertEqual b:suggestions, [{'word': 'describe'}]
|
||||
|
||||
Execute(Filtering should respect filetype triggers):
|
||||
let b:suggestions = [{'word': 'describe'}]
|
||||
|
||||
AssertEqual b:suggestions, ale#completion#Filter(bufnr(''), '', b:suggestions, '.', 0)
|
||||
AssertEqual b:suggestions, ale#completion#Filter(bufnr(''), 'rust', b:suggestions, '.', 0)
|
||||
AssertEqual b:suggestions, ale#completion#Filter(bufnr(''), 'rust', b:suggestions, '::', 0)
|
@ -0,0 +1,65 @@
|
||||
Given typescript():
|
||||
let abc = y.
|
||||
let foo = ab
|
||||
let foo = (ab)
|
||||
let string1 = '
|
||||
let string2 = "
|
||||
|
||||
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)
|
||||
|
||||
Execute(Completion should be done after strings in TypeScript):
|
||||
AssertEqual '''', ale#completion#GetPrefix(&filetype, 4, 16)
|
||||
AssertEqual '"', ale#completion#GetPrefix(&filetype, 5, 16)
|
||||
|
||||
Execute(Completion prefixes should work for other filetypes):
|
||||
AssertEqual 'ab', ale#completion#GetPrefix('xxxyyyzzz', 3, 14)
|
||||
|
||||
Execute(Completion prefixes should work for other filetypes):
|
||||
AssertEqual 'ab', ale#completion#GetPrefix('xxxyyyzzz', 3, 14)
|
||||
|
||||
Given rust():
|
||||
let abc = y.
|
||||
let abc = String::
|
||||
let foo = (ab)
|
||||
|
||||
Execute(Completion should be done after dots in Rust):
|
||||
AssertEqual '.', ale#completion#GetPrefix(&filetype, 1, 13)
|
||||
|
||||
Execute(Completion should be done after colons in Rust):
|
||||
AssertEqual '::', ale#completion#GetPrefix(&filetype, 2, 19)
|
||||
|
||||
Execute(Completion should be done after words in parens in Rust):
|
||||
AssertEqual 'ab', ale#completion#GetPrefix(&filetype, 3, 14)
|
||||
|
||||
Execute(Completion should not be done after parens in Rust):
|
||||
AssertEqual '', ale#completion#GetPrefix(&filetype, 3, 15)
|
||||
|
||||
Given lisp():
|
||||
(minus-name
|
||||
(full-name)
|
||||
|
||||
Execute(Completion should be done for function names with minuses in Lisp):
|
||||
AssertEqual 'minus-name', ale#completion#GetPrefix(&filetype, 1, 12)
|
||||
|
||||
Execute(Completion should not be done after parens in Lisp):
|
||||
AssertEqual '', ale#completion#GetPrefix(&filetype, 2, 12)
|
||||
|
||||
Given clojure():
|
||||
(minus-name
|
||||
(full-name)
|
||||
|
||||
Execute(Completion should be done for function names with minuses in Clojure):
|
||||
AssertEqual 'minus-name', ale#completion#GetPrefix(&filetype, 1, 12)
|
||||
|
||||
Execute(Completion should not be done after parens in Clojure):
|
||||
AssertEqual '', ale#completion#GetPrefix(&filetype, 2, 12)
|
@ -0,0 +1,307 @@
|
||||
Before:
|
||||
Save g:ale_completion_delay
|
||||
Save g:ale_completion_max_suggestions
|
||||
Save g:ale_completion_info
|
||||
Save &l:omnifunc
|
||||
Save &l:completeopt
|
||||
|
||||
let g:ale_completion_enabled = 1
|
||||
|
||||
call ale#test#SetDirectory('/testplugin/test/completion')
|
||||
call ale#test#SetFilename('dummy.txt')
|
||||
|
||||
runtime autoload/ale/lsp.vim
|
||||
|
||||
let g:message_list = []
|
||||
let g:capability_checked = ''
|
||||
let g:conn_id = v:null
|
||||
let g:Callback = ''
|
||||
let g:init_callback_list = []
|
||||
|
||||
function! ale#lsp_linter#StartLSP(buffer, linter, Callback) abort
|
||||
let g:conn_id = ale#lsp#Register('executable', '/foo/bar', {})
|
||||
call ale#lsp#MarkDocumentAsOpen(g:conn_id, a:buffer)
|
||||
|
||||
let l:details = {
|
||||
\ 'command': 'foobar',
|
||||
\ 'buffer': a:buffer,
|
||||
\ 'connection_id': g:conn_id,
|
||||
\ 'project_root': '/foo/bar',
|
||||
\}
|
||||
|
||||
call add(g:init_callback_list, {-> a:Callback(a:linter, l:details)})
|
||||
endfunction
|
||||
|
||||
" Pretend we're in insert mode for most tests.
|
||||
function! ale#util#Mode(...) abort
|
||||
return 'i'
|
||||
endfunction
|
||||
|
||||
function! ale#lsp#HasCapability(conn_id, capability) abort
|
||||
let g:capability_checked = a:capability
|
||||
|
||||
return 1
|
||||
endfunction
|
||||
|
||||
function! ale#lsp#RegisterCallback(conn_id, callback) abort
|
||||
let g:Callback = a:callback
|
||||
endfunction
|
||||
|
||||
" Replace the Send function for LSP, so we can monitor calls to it.
|
||||
function! ale#lsp#Send(conn_id, message) abort
|
||||
call add(g:message_list, a:message)
|
||||
|
||||
return 1
|
||||
endfunction
|
||||
|
||||
After:
|
||||
Restore
|
||||
|
||||
if g:conn_id isnot v:null
|
||||
call ale#lsp#RemoveConnectionWithID(g:conn_id)
|
||||
endif
|
||||
|
||||
unlet! g:message_list
|
||||
unlet! g:capability_checked
|
||||
unlet! g:init_callback_list
|
||||
unlet! g:conn_id
|
||||
unlet! g:Callback
|
||||
unlet! b:ale_old_omnifunc
|
||||
unlet! b:ale_old_completeopt
|
||||
unlet! b:ale_completion_info
|
||||
unlet! b:ale_complete_done_time
|
||||
unlet! b:ale_linters
|
||||
unlet! b:ale_tsserver_completion_names
|
||||
|
||||
" Reset the function.
|
||||
function! ale#util#Mode(...) abort
|
||||
return call('mode', a:000)
|
||||
endfunction
|
||||
|
||||
call ale#test#RestoreDirectory()
|
||||
call ale#linter#Reset()
|
||||
|
||||
" Stop any timers we left behind.
|
||||
" This stops the tests from failing randomly.
|
||||
call ale#completion#StopTimer()
|
||||
|
||||
runtime autoload/ale/completion.vim
|
||||
runtime autoload/ale/lsp.vim
|
||||
runtime autoload/ale/lsp_linter.vim
|
||||
|
||||
Given typescript(Some typescript file):
|
||||
foo
|
||||
somelongerline
|
||||
bazxyzxyzxyz
|
||||
|
||||
Execute(The right message should be sent for the initial tsserver request):
|
||||
runtime ale_linters/typescript/tsserver.vim
|
||||
let b:ale_linters = ['tsserver']
|
||||
" The cursor position needs to match what was saved before.
|
||||
call setpos('.', [bufnr(''), 1, 3, 0])
|
||||
|
||||
call ale#completion#GetCompletions('ale-automatic')
|
||||
|
||||
" We shouldn't register the callback yet.
|
||||
AssertEqual '''''', string(g:Callback)
|
||||
|
||||
AssertEqual 1, len(g:init_callback_list)
|
||||
call map(g:init_callback_list, 'v:val()')
|
||||
|
||||
AssertEqual 'completion', g:capability_checked
|
||||
|
||||
" We should send the right callback.
|
||||
AssertEqual
|
||||
\ 'function(''ale#completion#HandleTSServerResponse'')',
|
||||
\ string(g:Callback)
|
||||
" We should send the right message.
|
||||
AssertEqual
|
||||
\ [[0, 'ts@completions', {
|
||||
\ 'file': expand('%:p'),
|
||||
\ 'line': 1,
|
||||
\ 'offset': 3,
|
||||
\ 'prefix': 'fo',
|
||||
\ 'includeExternalModuleExports': g:ale_completion_autoimport,
|
||||
\ }]],
|
||||
\ g:message_list
|
||||
" We should set up the completion info correctly.
|
||||
AssertEqual
|
||||
\ {
|
||||
\ 'line_length': 3,
|
||||
\ 'conn_id': g:conn_id,
|
||||
\ 'column': 3,
|
||||
\ 'request_id': 1,
|
||||
\ 'line': 1,
|
||||
\ 'prefix': 'fo',
|
||||
\ 'source': 'ale-automatic',
|
||||
\ },
|
||||
\ get(b:, 'ale_completion_info', {})
|
||||
|
||||
Execute(The right message sent to the tsserver LSP when the first completion message is received):
|
||||
" The cursor position needs to match what was saved before.
|
||||
call setpos('.', [bufnr(''), 1, 1, 0])
|
||||
let b:ale_completion_info = {
|
||||
\ 'conn_id': 123,
|
||||
\ 'prefix': 'f',
|
||||
\ 'request_id': 4,
|
||||
\ 'line': 1,
|
||||
\ 'column': 1,
|
||||
\}
|
||||
" We should only show up to this many suggestions.
|
||||
let g:ale_completion_max_suggestions = 3
|
||||
|
||||
" Handle the response for completions.
|
||||
call ale#completion#HandleTSServerResponse(123, {
|
||||
\ 'request_seq': 4,
|
||||
\ 'command': 'completions',
|
||||
\ 'body': [
|
||||
\ {'name': 'Baz'},
|
||||
\ {'name': 'dingDong'},
|
||||
\ {'name': 'Foo', 'source': '/path/to/foo.ts'},
|
||||
\ {'name': 'FooBar'},
|
||||
\ {'name': 'frazzle'},
|
||||
\ {'name': 'FFS'},
|
||||
\ ],
|
||||
\})
|
||||
|
||||
" We should save the names we got in the buffer, as TSServer doesn't return
|
||||
" details for every name.
|
||||
AssertEqual [{
|
||||
\ 'word': 'Foo',
|
||||
\ 'source': '/path/to/foo.ts',
|
||||
\ }, {
|
||||
\ 'word': 'FooBar',
|
||||
\ 'source': '',
|
||||
\ }, {
|
||||
\ 'word': 'frazzle',
|
||||
\ 'source': '',
|
||||
\}],
|
||||
\ get(b:, 'ale_tsserver_completion_names', [])
|
||||
|
||||
" The entry details messages should have been sent.
|
||||
AssertEqual
|
||||
\ [[
|
||||
\ 0,
|
||||
\ 'ts@completionEntryDetails',
|
||||
\ {
|
||||
\ 'file': expand('%:p'),
|
||||
\ 'entryNames': [{
|
||||
\ 'name': 'Foo',
|
||||
\ 'source': '/path/to/foo.ts',
|
||||
\ }, {
|
||||
\ 'name': 'FooBar',
|
||||
\ }, {
|
||||
\ 'name': 'frazzle',
|
||||
\ }],
|
||||
\ 'offset': 1,
|
||||
\ 'line': 1,
|
||||
\ },
|
||||
\ ]],
|
||||
\ g:message_list
|
||||
|
||||
Given python(Some Python file):
|
||||
foo
|
||||
somelongerline
|
||||
bazxyzxyzxyz
|
||||
|
||||
Execute(The right message should be sent for the initial LSP request):
|
||||
runtime ale_linters/python/pylsp.vim
|
||||
let b:ale_linters = ['pylsp']
|
||||
" The cursor position needs to match what was saved before.
|
||||
call setpos('.', [bufnr(''), 1, 5, 0])
|
||||
|
||||
call ale#completion#GetCompletions('ale-automatic')
|
||||
|
||||
" We shouldn't register the callback yet.
|
||||
AssertEqual '''''', string(g:Callback)
|
||||
|
||||
AssertEqual 1, len(g:init_callback_list)
|
||||
call map(g:init_callback_list, 'v:val()')
|
||||
|
||||
AssertEqual 'completion', g:capability_checked
|
||||
|
||||
" We should send the right callback.
|
||||
AssertEqual
|
||||
\ 'function(''ale#completion#HandleLSPResponse'')',
|
||||
\ string(g:Callback)
|
||||
" We should send the right message.
|
||||
" The character index needs to be at most the index of the last character on
|
||||
" the line, or integration with pylsp will be broken.
|
||||
"
|
||||
" We need to send the message for changing the document first.
|
||||
AssertEqual
|
||||
\ [
|
||||
\ [1, 'textDocument/didChange', {
|
||||
\ 'textDocument': {
|
||||
\ 'uri': ale#path#ToFileURI(expand('%:p')),
|
||||
\ 'version': g:ale_lsp_next_version_id - 1,
|
||||
\ },
|
||||
\ 'contentChanges': [{'text': join(getline(1, '$'), "\n") . "\n"}]
|
||||
\ }],
|
||||
\ [0, 'textDocument/completion', {
|
||||
\ 'textDocument': {'uri': ale#path#ToFileURI(expand('%:p'))},
|
||||
\ 'position': {'line': 0, 'character': 2},
|
||||
\ }],
|
||||
\ ],
|
||||
\ g:message_list
|
||||
" We should set up the completion info correctly.
|
||||
AssertEqual
|
||||
\ {
|
||||
\ 'line_length': 3,
|
||||
\ 'conn_id': g:conn_id,
|
||||
\ 'column': 3,
|
||||
\ 'request_id': 1,
|
||||
\ 'line': 1,
|
||||
\ 'prefix': 'fo',
|
||||
\ 'source': 'ale-automatic',
|
||||
\ 'completion_filter': 'ale#completion#python#CompletionItemFilter',
|
||||
\ },
|
||||
\ get(b:, 'ale_completion_info', {})
|
||||
|
||||
Execute(Two completion requests shouldn't be sent in a row):
|
||||
call ale#linter#PreventLoading('python')
|
||||
call ale#linter#Define('python', {
|
||||
\ 'name': 'foo',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'executable': 'foo',
|
||||
\ 'command': 'foo',
|
||||
\ 'project_root': {-> '/foo/bar'},
|
||||
\})
|
||||
call ale#linter#Define('python', {
|
||||
\ 'name': 'bar',
|
||||
\ 'lsp': 'stdio',
|
||||
\ 'executable': 'foo',
|
||||
\ 'command': 'foo',
|
||||
\ 'project_root': {-> '/foo/bar'},
|
||||
\})
|
||||
let b:ale_linters = ['foo', 'bar']
|
||||
|
||||
" The cursor position needs to match what was saved before.
|
||||
call setpos('.', [bufnr(''), 1, 5, 0])
|
||||
|
||||
call ale#completion#GetCompletions('ale-automatic')
|
||||
|
||||
" We shouldn't register the callback yet.
|
||||
AssertEqual '''''', string(g:Callback)
|
||||
|
||||
AssertEqual 2, len(g:init_callback_list)
|
||||
call map(g:init_callback_list, 'v:val()')
|
||||
|
||||
AssertEqual 'completion', g:capability_checked
|
||||
|
||||
" We should only send one completion message for two LSP servers.
|
||||
AssertEqual
|
||||
\ [
|
||||
\ [1, 'textDocument/didChange', {
|
||||
\ 'textDocument': {
|
||||
\ 'uri': ale#path#ToFileURI(expand('%:p')),
|
||||
\ 'version': g:ale_lsp_next_version_id - 1,
|
||||
\ },
|
||||
\ 'contentChanges': [{'text': join(getline(1, '$'), "\n") . "\n"}]
|
||||
\ }],
|
||||
\ [0, 'textDocument/completion', {
|
||||
\ 'textDocument': {'uri': ale#path#ToFileURI(expand('%:p'))},
|
||||
\ 'position': {'line': 0, 'character': 2},
|
||||
\ }],
|
||||
\ ],
|
||||
\ g:message_list
|
@ -0,0 +1,736 @@
|
||||
Before:
|
||||
Save g:ale_completion_autoimport
|
||||
Save g:ale_completion_max_suggestions
|
||||
|
||||
let g:ale_completion_max_suggestions = 50
|
||||
|
||||
After:
|
||||
Restore
|
||||
|
||||
unlet! b:ale_completion_info
|
||||
|
||||
Execute(Should handle Rust completion results correctly):
|
||||
let g:ale_completion_autoimport = 0
|
||||
|
||||
AssertEqual
|
||||
\ [
|
||||
\ {'word': 'new', 'dup': 0, 'menu': 'pub fn new() -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ {'word': 'with_capacity', 'dup': 0, 'menu': 'pub fn with_capacity(capacity: usize) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ {'word': 'from_utf8', 'dup': 0, 'menu': 'pub fn from_utf8(vec: Vec<u8>) -> Result<String, FromUtf8Error>', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ {'word': 'from_utf8_lossy', 'dup': 0, 'menu': 'pub fn from_utf8_lossy<''a>(v: &''a [u8]) -> Cow<''a, str>', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ {'word': 'from_utf16', 'dup': 0, 'menu': 'pub fn from_utf16(v: &[u16]) -> Result<String, FromUtf16Error>', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ {'word': 'from_utf16_lossy', 'dup': 0, 'menu': 'pub fn from_utf16_lossy(v: &[u16]) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ {'word': 'from_raw_parts', 'dup': 0, 'menu': 'pub unsafe fn from_raw_parts(buf: *mut u8, length: usize, capacity: usize) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ {'word': 'from_utf8_unchecked', 'dup': 0, 'menu': 'pub unsafe fn from_utf8_unchecked(bytes: Vec<u8>) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ {'word': 'from_iter', 'dup': 0, 'menu': 'fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ {'word': 'from_iter', 'dup': 0, 'menu': 'fn from_iter<I: IntoIterator<Item = &''a char>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ {'word': 'from_iter', 'dup': 0, 'menu': 'fn from_iter<I: IntoIterator<Item = &''a str>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ {'word': 'from_iter', 'dup': 0, 'menu': 'fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ {'word': 'from_iter', 'dup': 0, 'menu': 'fn from_iter<I: IntoIterator<Item = Cow<''a, str>>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ {'word': 'Searcher', 'dup': 0, 'menu': 'type Searcher = <&''b str as Pattern<''a>>::Searcher;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ {'word': 'default', 'dup': 0, 'menu': 'fn default() -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ {'word': 'Output', 'dup': 0, 'menu': 'type Output = String;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ {'word': 'Output', 'dup': 0, 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ {'word': 'Output', 'dup': 0, 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ {'word': 'Output', 'dup': 0, 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ {'word': 'Output', 'dup': 0, 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ {'word': 'Output', 'dup': 0, 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ {'word': 'Output', 'dup': 0, 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ {'word': 'Target', 'dup': 0, 'menu': 'type Target = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ {'word': 'Err', 'dup': 0, 'menu': 'type Err = ParseError;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ {'word': 'from_str', 'dup': 0, 'menu': 'fn from_str(s: &str) -> Result<String, ParseError>', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ {'word': 'from', 'dup': 0, 'menu': 'fn from(s: &''a str) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ {'word': 'from', 'dup': 0, 'menu': 'fn from(s: Box<str>) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ {'word': 'from', 'dup': 0, 'menu': 'fn from(s: Cow<''a, str>) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ {'word': 'to_vec', 'dup': 0, 'menu': 'pub fn to_vec(&self) -> Vec<T> where T: Clone,', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\],
|
||||
\ ale#completion#ParseLSPCompletions({
|
||||
\ "jsonrpc":"2.0",
|
||||
\ "id":65,
|
||||
\ "result":[
|
||||
\ {
|
||||
\ "label":"new",
|
||||
\ "kind":3,
|
||||
\ "detail":"pub fn new() -> String"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"with_capacity",
|
||||
\ "kind":3,
|
||||
\ "detail":"pub fn with_capacity(capacity: usize) -> String"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"from_utf8",
|
||||
\ "kind":3,
|
||||
\ "detail":"pub fn from_utf8(vec: Vec<u8>) -> Result<String, FromUtf8Error>"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"from_utf8_lossy",
|
||||
\ "kind":3,
|
||||
\ "detail":"pub fn from_utf8_lossy<'a>(v: &'a [u8]) -> Cow<'a, str>"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"from_utf16",
|
||||
\ "kind":3,
|
||||
\ "detail":"pub fn from_utf16(v: &[u16]) -> Result<String, FromUtf16Error>"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"from_utf16_lossy",
|
||||
\ "kind":3,
|
||||
\ "detail":"pub fn from_utf16_lossy(v: &[u16]) -> String"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"from_raw_parts",
|
||||
\ "kind":3,
|
||||
\ "detail":"pub unsafe fn from_raw_parts(buf: *mut u8, length: usize, capacity: usize) -> String"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"from_utf8_unchecked",
|
||||
\ "kind":3,
|
||||
\ "detail":"pub unsafe fn from_utf8_unchecked(bytes: Vec<u8>) -> String"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"from_iter",
|
||||
\ "kind":3,
|
||||
\ "detail":"fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> String"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"from_iter",
|
||||
\ "kind":3,
|
||||
\ "detail":"fn from_iter<I: IntoIterator<Item = &'a char>>(iter: I) -> String"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"from_iter",
|
||||
\ "kind":3,
|
||||
\ "detail":"fn from_iter<I: IntoIterator<Item = &'a str>>(iter: I) -> String"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"from_iter",
|
||||
\ "kind":3,
|
||||
\ "detail":"fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> String"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"from_iter",
|
||||
\ "kind":3,
|
||||
\ "detail":"fn from_iter<I: IntoIterator<Item = Cow<'a, str>>>(iter: I) -> String"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"Searcher",
|
||||
\ "kind":8,
|
||||
\ "detail":"type Searcher = <&'b str as Pattern<'a>>::Searcher;"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"default",
|
||||
\ "kind":3,
|
||||
\ "detail":"fn default() -> String"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"Output",
|
||||
\ "kind":8,
|
||||
\ "detail":"type Output = String;"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"Output",
|
||||
\ "kind":8,
|
||||
\ "detail":"type Output = str;"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"Output",
|
||||
\ "kind":8,
|
||||
\ "detail":"type Output = str;"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"Output",
|
||||
\ "kind":8,
|
||||
\ "detail":"type Output = str;"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"Output",
|
||||
\ "kind":8,
|
||||
\ "detail":"type Output = str;"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"Output",
|
||||
\ "kind":8,
|
||||
\ "detail":"type Output = str;"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"Output",
|
||||
\ "kind":8,
|
||||
\ "detail":"type Output = str;"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"Target",
|
||||
\ "kind":8,
|
||||
\ "detail":"type Target = str;"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"Err",
|
||||
\ "kind":8,
|
||||
\ "detail":"type Err = ParseError;"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"from_str",
|
||||
\ "kind":3,
|
||||
\ "detail":"fn from_str(s: &str) -> Result<String, ParseError>"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"from",
|
||||
\ "kind":3,
|
||||
\ "detail":"fn from(s: &'a str) -> String"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"from",
|
||||
\ "kind":3,
|
||||
\ "detail":"fn from(s: Box<str>) -> String"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"from",
|
||||
\ "kind":3,
|
||||
\ "detail":"fn from(s: Cow<'a, str>) -> String"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"to_vec",
|
||||
\ "kind":3,
|
||||
\ "detail":"pub fn to_vec(&self) -> Vec<T>\nwhere\n T: Clone,"
|
||||
\ }
|
||||
\ ]
|
||||
\ })
|
||||
|
||||
Execute(Should handle Python completion results correctly):
|
||||
let g:ale_completion_autoimport = 0
|
||||
let b:ale_completion_info = {
|
||||
\ 'completion_filter': 'ale#completion#python#CompletionItemFilter',
|
||||
\}
|
||||
|
||||
AssertEqual
|
||||
\ [
|
||||
\ {'word': 'what', 'dup': 0, 'menu': 'example-python-project.bar.Bar', 'info': "what()\n\n", 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ ],
|
||||
\ ale#completion#ParseLSPCompletions({
|
||||
\ "jsonrpc":"2.0",
|
||||
\ "id":6,
|
||||
\ "result":{
|
||||
\ "isIncomplete":v:false,
|
||||
\ "items":[
|
||||
\ {
|
||||
\ "label":"what()",
|
||||
\ "kind":3,
|
||||
\ "detail":"example-python-project.bar.Bar",
|
||||
\ "documentation":"what()\n\n",
|
||||
\ "sortText":"awhat",
|
||||
\ "insertText":"what"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"__class__",
|
||||
\ "kind":7,
|
||||
\ "detail":"object",
|
||||
\ "documentation":"type(object_or_name, bases, dict)\ntype(object) -> the object's type\ntype(name, bases, dict) -> a new type",
|
||||
\ "sortText":"z__class__",
|
||||
\ "insertText":"__class__"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"__delattr__(name)",
|
||||
\ "kind":3,
|
||||
\ "detail":"object",
|
||||
\ "documentation":"Implement delattr(self, name).",
|
||||
\ "sortText":"z__delattr__",
|
||||
\ "insertText":"__delattr__"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"__dir__()",
|
||||
\ "kind":3,
|
||||
\ "detail":"object",
|
||||
\ "documentation":"__dir__() -> list\ndefault dir() implementation",
|
||||
\ "sortText":"z__dir__",
|
||||
\ "insertText":"__dir__"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"__doc__",
|
||||
\ "kind":18,
|
||||
\ "detail":"object",
|
||||
\ "documentation":"str(object='') -> str\nstr(bytes_or_buffer[, encoding[, errors]]) -> str\n\nCreate a new string object from the given object. If encoding or\nerrors is specified, then the object must expose a data buffer\nthat will be decoded using the given encoding and error handler.\nOtherwise, returns the result of object.__str__() (if defined)\nor repr(object).\nencoding defaults to sys.getdefaultencoding().\nerrors defaults to 'strict'.",
|
||||
\ "sortText":"z__doc__",
|
||||
\ "insertText":"__doc__"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"__eq__(value)",
|
||||
\ "kind":3,
|
||||
\ "detail":"object",
|
||||
\ "documentation":"Return self==value.",
|
||||
\ "sortText":"z__eq__",
|
||||
\ "insertText":"__eq__"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"__format__()",
|
||||
\ "kind":3,
|
||||
\ "detail":"object",
|
||||
\ "documentation":"default object formatter",
|
||||
\ "sortText":"z__format__",
|
||||
\ "insertText":"__format__"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"__ge__(value)",
|
||||
\ "kind":3,
|
||||
\ "detail":"object",
|
||||
\ "documentation":"Return self>=value.",
|
||||
\ "sortText":"z__ge__",
|
||||
\ "insertText":"__ge__"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"__getattribute__(name)",
|
||||
\ "kind":3,
|
||||
\ "detail":"object",
|
||||
\ "documentation":"Return getattr(self, name).",
|
||||
\ "sortText":"z__getattribute__",
|
||||
\ "insertText":"__getattribute__"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"__gt__(value)",
|
||||
\ "kind":3,
|
||||
\ "detail":"object",
|
||||
\ "documentation":"Return self>value.",
|
||||
\ "sortText":"z__gt__",
|
||||
\ "insertText":"__gt__"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"__hash__()",
|
||||
\ "kind":3,
|
||||
\ "detail":"object",
|
||||
\ "documentation":"Return hash(self).",
|
||||
\ "sortText":"z__hash__",
|
||||
\ "insertText":"__hash__"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"__init__(args, kwargs)",
|
||||
\ "kind":3,
|
||||
\ "detail":"object",
|
||||
\ "documentation":"Initialize self.\u00a0\u00a0See help(type(self)) for accurate signature.",
|
||||
\ "sortText":"z__init__",
|
||||
\ "insertText":"__init__"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"__init_subclass__()",
|
||||
\ "kind":3,
|
||||
\ "detail":"object",
|
||||
\ "documentation":"This method is called when a class is subclassed.\n\nThe default implementation does nothing. It may be\noverridden to extend subclasses.",
|
||||
\ "sortText":"z__init_subclass__",
|
||||
\ "insertText":"__init_subclass__"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"__le__(value)",
|
||||
\ "kind":3,
|
||||
\ "detail":"object",
|
||||
\ "documentation":"Return self<=value.",
|
||||
\ "sortText":"z__le__",
|
||||
\ "insertText":"__le__"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"__lt__(value)",
|
||||
\ "kind":3,
|
||||
\ "detail":"object",
|
||||
\ "documentation":"Return self<value.",
|
||||
\ "sortText":"z__lt__",
|
||||
\ "insertText":"__lt__"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"__ne__(value)",
|
||||
\ "kind":3,
|
||||
\ "detail":"object",
|
||||
\ "documentation":"Return self!=value.",
|
||||
\ "sortText":"z__ne__",
|
||||
\ "insertText":"__ne__"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"__new__(kwargs)",
|
||||
\ "kind":3,
|
||||
\ "detail":"object",
|
||||
\ "documentation":"Create and return a new object.\u00a0\u00a0See help(type) for accurate signature.",
|
||||
\ "sortText":"z__new__",
|
||||
\ "insertText":"__new__"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"__reduce__()",
|
||||
\ "kind":3,
|
||||
\ "detail":"object",
|
||||
\ "documentation":"helper for pickle",
|
||||
\ "sortText":"z__reduce__",
|
||||
\ "insertText":"__reduce__"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"__reduce_ex__()",
|
||||
\ "kind":3,
|
||||
\ "detail":"object",
|
||||
\ "documentation":"helper for pickle",
|
||||
\ "sortText":"z__reduce_ex__",
|
||||
\ "insertText":"__reduce_ex__"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"__repr__()",
|
||||
\ "kind":3,
|
||||
\ "detail":"object",
|
||||
\ "documentation":"Return repr(self).",
|
||||
\ "sortText":"z__repr__",
|
||||
\ "insertText":"__repr__"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"__setattr__(name, value)",
|
||||
\ "kind":3,
|
||||
\ "detail":"object",
|
||||
\ "documentation":"Implement setattr(self, name, value).",
|
||||
\ "sortText":"z__setattr__",
|
||||
\ "insertText":"__setattr__"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"__sizeof__()",
|
||||
\ "kind":3,
|
||||
\ "detail":"object",
|
||||
\ "documentation":"__sizeof__() -> int\nsize of object in memory, in bytes",
|
||||
\ "sortText":"z__sizeof__",
|
||||
\ "insertText":"__sizeof__"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"__str__()",
|
||||
\ "kind":3,
|
||||
\ "detail":"object",
|
||||
\ "documentation":"Return str(self).",
|
||||
\ "sortText":"z__str__",
|
||||
\ "insertText":"__str__"
|
||||
\ },
|
||||
\ {
|
||||
\ "label":"__subclasshook__()",
|
||||
\ "kind":3,
|
||||
\ "detail":"object",
|
||||
\ "documentation":"Abstract classes can override this to customize issubclass().\n\nThis is invoked early on by abc.ABCMeta.__subclasscheck__().\nIt should return True, False or NotImplemented.\u00a0\u00a0If it returns\nNotImplemented, the normal algorithm is used.\u00a0\u00a0Otherwise, it\noverrides the normal algorithm (and the outcome is cached).",
|
||||
\ "sortText":"z__subclasshook__",
|
||||
\ "insertText":"__subclasshook__"
|
||||
\ }
|
||||
\ ]
|
||||
\ }
|
||||
\ })
|
||||
|
||||
Execute(Should handle extra Python completion results correctly):
|
||||
let g:ale_completion_autoimport = 0
|
||||
|
||||
let b:ale_completion_info = {
|
||||
\ 'completion_filter': 'ale#completion#python#CompletionItemFilter',
|
||||
\ 'prefix': 'mig',
|
||||
\}
|
||||
|
||||
AssertEqual
|
||||
\ [
|
||||
\ {'word': 'migrations', 'dup': 0, 'menu': 'xxx', 'info': 'migrations', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ {'word': 'MigEngine', 'dup': 0, 'menu': 'xxx', 'info': 'mig engine', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ ],
|
||||
\ ale#completion#ParseLSPCompletions({
|
||||
\ 'jsonrpc': '2.0',
|
||||
\ 'id': 6,
|
||||
\ 'result': {
|
||||
\ 'isIncomplete': v:false,
|
||||
\ 'items': [
|
||||
\ {
|
||||
\ 'label': 'migrations',
|
||||
\ 'kind': 3,
|
||||
\ 'detail': 'xxx',
|
||||
\ 'documentation': 'migrations',
|
||||
\ },
|
||||
\ {
|
||||
\ 'label': 'MigEngine',
|
||||
\ 'kind': 3,
|
||||
\ 'detail': 'xxx',
|
||||
\ 'documentation': 'mig engine',
|
||||
\ },
|
||||
\ {
|
||||
\ 'label': 'ignore me',
|
||||
\ 'kind': 3,
|
||||
\ 'detail': 'nope',
|
||||
\ 'documentation': 'nope',
|
||||
\ },
|
||||
\ ]
|
||||
\ }
|
||||
\ })
|
||||
|
||||
Execute(Should handle missing keys):
|
||||
let g:ale_completion_autoimport = 0
|
||||
|
||||
AssertEqual
|
||||
\ [
|
||||
\ {'word': 'x', 'dup': 0, 'menu': '', 'info': '', 'kind': 'v', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ ],
|
||||
\ ale#completion#ParseLSPCompletions({
|
||||
\ 'jsonrpc': '2.0',
|
||||
\ 'id': 6,
|
||||
\ 'result': {
|
||||
\ 'isIncomplete': v:false,
|
||||
\ 'items': [
|
||||
\ {
|
||||
\ 'label': 'x',
|
||||
\ },
|
||||
\ ]
|
||||
\ }
|
||||
\ })
|
||||
|
||||
Execute(Should handle documentation in the markdown format):
|
||||
let g:ale_completion_autoimport = 0
|
||||
|
||||
AssertEqual
|
||||
\ [
|
||||
\ {'word': 'migrations', 'dup': 0, 'menu': 'xxx', 'info': 'Markdown documentation', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ ],
|
||||
\ ale#completion#ParseLSPCompletions({
|
||||
\ 'jsonrpc': '2.0',
|
||||
\ 'id': 6,
|
||||
\ 'result': {
|
||||
\ 'isIncomplete': v:false,
|
||||
\ 'items': [
|
||||
\ {
|
||||
\ 'label': 'migrations',
|
||||
\ 'kind': 3,
|
||||
\ 'detail': 'xxx',
|
||||
\ 'documentation': {
|
||||
\ 'kind': 'markdown',
|
||||
\ 'value': 'Markdown documentation',
|
||||
\ },
|
||||
\ },
|
||||
\ ],
|
||||
\ },
|
||||
\ })
|
||||
|
||||
Execute(Should handle completion messages with textEdit objects):
|
||||
let g:ale_completion_autoimport = 0
|
||||
|
||||
AssertEqual
|
||||
\ [
|
||||
\ {'word': 'next_callback', 'dup': 0, 'menu': 'PlayTimeCallback', 'info': '', 'kind': 'v', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ ],
|
||||
\ ale#completion#ParseLSPCompletions({
|
||||
\ 'id': 226,
|
||||
\ 'jsonrpc': '2.0',
|
||||
\ 'result': {
|
||||
\ 'isIncomplete': v:false,
|
||||
\ 'items': [
|
||||
\ {
|
||||
\ 'detail': 'PlayTimeCallback',
|
||||
\ 'filterText': 'next_callback',
|
||||
\ 'insertText': 'ignoreme',
|
||||
\ 'insertTextFormat': 1,
|
||||
\ 'kind': 6,
|
||||
\ 'label': ' next_callback',
|
||||
\ 'sortText': '3ee19999next_callback',
|
||||
\ 'textEdit': {
|
||||
\ 'newText': 'next_callback',
|
||||
\ 'range': {
|
||||
\ 'end': {'character': 13, 'line': 12},
|
||||
\ 'start': {'character': 4, 'line': 12},
|
||||
\ },
|
||||
\ },
|
||||
\ },
|
||||
\ ],
|
||||
\ },
|
||||
\ })
|
||||
|
||||
Execute(Should handle completion messages with textEdit objects and no insertTextFormat key):
|
||||
let g:ale_completion_autoimport = 0
|
||||
|
||||
AssertEqual
|
||||
\ [
|
||||
\ {'word': 'next_callback', 'dup': 0, 'menu': 'PlayTimeCallback', 'info': '', 'kind': 'v', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ ],
|
||||
\ ale#completion#ParseLSPCompletions({
|
||||
\ 'id': 226,
|
||||
\ 'jsonrpc': '2.0',
|
||||
\ 'result': {
|
||||
\ 'isIncomplete': v:false,
|
||||
\ 'items': [
|
||||
\ {
|
||||
\ 'detail': 'PlayTimeCallback',
|
||||
\ 'filterText': 'next_callback',
|
||||
\ 'insertText': 'ignoreme',
|
||||
\ 'kind': 6,
|
||||
\ 'label': ' next_callback',
|
||||
\ 'sortText': '3ee19999next_callback',
|
||||
\ 'textEdit': {
|
||||
\ 'newText': 'next_callback',
|
||||
\ 'range': {
|
||||
\ 'end': {'character': 13, 'line': 12},
|
||||
\ 'start': {'character': 4, 'line': 12},
|
||||
\ },
|
||||
\ },
|
||||
\ },
|
||||
\ ],
|
||||
\ },
|
||||
\ })
|
||||
|
||||
Execute(Should handle completion messages with the deprecated insertText attribute):
|
||||
let g:ale_completion_autoimport = 0
|
||||
|
||||
AssertEqual
|
||||
\ [
|
||||
\ {'word': 'next_callback', 'dup': 0, 'menu': 'PlayTimeCallback', 'info': '', 'kind': 'v', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
|
||||
\ ],
|
||||
\ ale#completion#ParseLSPCompletions({
|
||||
\ 'id': 226,
|
||||
\ 'jsonrpc': '2.0',
|
||||
\ 'result': {
|
||||
\ 'isIncomplete': v:false,
|
||||
\ 'items': [
|
||||
\ {
|
||||
\ 'detail': 'PlayTimeCallback',
|
||||
\ 'filterText': 'next_callback',
|
||||
\ 'insertText': 'next_callback',
|
||||
\ 'insertTextFormat': 1,
|
||||
\ 'kind': 6,
|
||||
\ 'label': ' next_callback',
|
||||
\ 'sortText': '3ee19999next_callback',
|
||||
\ },
|
||||
\ ],
|
||||
\ },
|
||||
\ })
|
||||
|
||||
Execute(Should handle completion messages with additionalTextEdits when ale_completion_autoimport is turned on):
|
||||
let g:ale_completion_autoimport = 1
|
||||
|
||||
AssertEqual
|
||||
\ [
|
||||
\ {
|
||||
\ 'word': 'next_callback',
|
||||
\ 'dup': 1,
|
||||
\ 'menu': 'PlayTimeCallback',
|
||||
\ 'info': '',
|
||||
\ 'kind': 'v',
|
||||
\ 'icase': 1,
|
||||
\ 'user_data': json_encode({
|
||||
\ '_ale_completion_item': 1,
|
||||
\ 'code_actions': [
|
||||
\ {
|
||||
\ 'description': 'completion',
|
||||
\ 'changes': [
|
||||
\ {
|
||||
\ 'fileName': expand('#' . bufnr('') . ':p'),
|
||||
\ 'textChanges': [
|
||||
\ {
|
||||
\ 'start': {
|
||||
\ 'line': 11,
|
||||
\ 'offset': 2,
|
||||
\ },
|
||||
\ 'end': {
|
||||
\ 'line': 13,
|
||||
\ 'offset': 4,
|
||||
\ },
|
||||
\ 'newText': 'from "module" import next_callback',
|
||||
\ },
|
||||
\ ],
|
||||
\ },
|
||||
\ ],
|
||||
\ },
|
||||
\ ],
|
||||
\ }),
|
||||
\ },
|
||||
\ ],
|
||||
\ ale#completion#ParseLSPCompletions({
|
||||
\ 'id': 226,
|
||||
\ 'jsonrpc': '2.0',
|
||||
\ 'result': {
|
||||
\ 'isIncomplete': v:false,
|
||||
\ 'items': [
|
||||
\ {
|
||||
\ 'detail': 'PlayTimeCallback',
|
||||
\ 'filterText': 'next_callback',
|
||||
\ 'insertText': 'next_callback',
|
||||
\ 'insertTextFormat': 1,
|
||||
\ 'kind': 6,
|
||||
\ 'label': ' next_callback',
|
||||
\ 'sortText': '3ee19999next_callback',
|
||||
\ 'additionalTextEdits': [
|
||||
\ {
|
||||
\ 'range': {
|
||||
\ 'start': {
|
||||
\ 'line': 10,
|
||||
\ 'character': 1,
|
||||
\ },
|
||||
\ 'end': {
|
||||
\ 'line': 12,
|
||||
\ 'character': 3,
|
||||
\ },
|
||||
\ },
|
||||
\ 'newText': 'from "module" import next_callback',
|
||||
\ },
|
||||
\ ],
|
||||
\ },
|
||||
\ ],
|
||||
\ },
|
||||
\ })
|
||||
|
||||
Execute(Should not handle completion messages with additionalTextEdits when ale_completion_autoimport is turned off):
|
||||
let g:ale_completion_autoimport = 0
|
||||
let b:ale_completion_info = {'line': 30}
|
||||
|
||||
AssertEqual
|
||||
\ [],
|
||||
\ ale#completion#ParseLSPCompletions({
|
||||
\ 'id': 226,
|
||||
\ 'jsonrpc': '2.0',
|
||||
\ 'result': {
|
||||
\ 'isIncomplete': v:false,
|
||||
\ 'items': [
|
||||
\ {
|
||||
\ 'detail': 'PlayTimeCallback',
|
||||
\ 'filterText': 'next_callback',
|
||||
\ 'insertText': 'next_callback',
|
||||
\ 'insertTextFormat': 1,
|
||||
\ 'kind': 6,
|
||||
\ 'label': ' next_callback',
|
||||
\ 'sortText': '3ee19999next_callback',
|
||||
\ 'additionalTextEdits': [
|
||||
\ {
|
||||
\ 'range': {
|
||||
\ 'start': {
|
||||
\ 'line': 10,
|
||||
\ 'character': 1,
|
||||
\ },
|
||||
\ 'end': {
|
||||
\ 'line': 12,
|
||||
\ 'character': 3,
|
||||
\ },
|
||||
\ },
|
||||
\ 'newText': 'from "module" import next_callback',
|
||||
\ },
|
||||
\ ],
|
||||
\ },
|
||||
\ ],
|
||||
\ },
|
||||
\ })
|
||||
|
||||
Execute(Should still handle completion messages with empty additionalTextEdits with ale_completion_autoimport turned off):
|
||||
let g:ale_completion_autoimport = 0
|
||||
|
||||
AssertEqual
|
||||
\ [
|
||||
\ {
|
||||
\ 'word': 'next_callback',
|
||||
\ 'dup': 0,
|
||||
\ 'menu': 'PlayTimeCallback',
|
||||
\ 'info': '',
|
||||
\ 'kind': 'v',
|
||||
\ 'icase': 1,
|
||||
\ 'user_data': json_encode({'_ale_completion_item': 1}),
|
||||
\ }
|
||||
\ ],
|
||||
\ ale#completion#ParseLSPCompletions({
|
||||
\ 'id': 226,
|
||||
\ 'jsonrpc': '2.0',
|
||||
\ 'result': {
|
||||
\ 'isIncomplete': v:false,
|
||||
\ 'items': [
|
||||
\ {
|
||||
\ 'detail': 'PlayTimeCallback',
|
||||
\ 'filterText': 'next_callback',
|
||||
\ 'insertText': 'next_callback',
|
||||
\ 'insertTextFormat': 1,
|
||||
\ 'kind': 6,
|
||||
\ 'label': ' next_callback',
|
||||
\ 'sortText': '3ee19999next_callback',
|
||||
\ 'additionalTextEdits': [],
|
||||
\ },
|
||||
\ ],
|
||||
\ },
|
||||
\ })
|
@ -0,0 +1,60 @@
|
||||
Before:
|
||||
unlet! b:ale_completion_info
|
||||
unlet! b:ale_completion_result
|
||||
|
||||
let b:lsp_started = 0
|
||||
|
||||
runtime autoload/ale/lsp_linter.vim
|
||||
|
||||
function! ale#lsp_linter#StartLSP(buffer, linter, Callback) abort
|
||||
return b:lsp_started
|
||||
endfunction
|
||||
|
||||
function! SetCompletionResult(...) abort
|
||||
let b:ale_completion_result = ['foo']
|
||||
endfunction
|
||||
|
||||
function! SetCompletionResponse(...) abort
|
||||
let b:ale_completion_result = ['foo']
|
||||
endfunction
|
||||
|
||||
After:
|
||||
unlet! b:ale_completion_info
|
||||
unlet! b:ale_completion_result
|
||||
unlet! b:lsp_started
|
||||
|
||||
delfunction SetCompletionResult
|
||||
delfunction SetCompletionResponse
|
||||
|
||||
runtime autoload/ale/lsp_linter.vim
|
||||
|
||||
call ale#linter#Reset()
|
||||
|
||||
Given typescript():
|
||||
let abc = y.
|
||||
let foo = ab
|
||||
let foo = (ab)
|
||||
|
||||
Execute(-3 should be returned when completion results cannot be requested):
|
||||
AssertEqual -3, ale#completion#OmniFunc(1, '')
|
||||
|
||||
Execute(The start position should be returned when results can be requested):
|
||||
let b:lsp_started = 1
|
||||
call setpos('.', [bufnr(''), 3, 14, 0])
|
||||
|
||||
AssertEqual 11, ale#completion#OmniFunc(1, '')
|
||||
|
||||
Execute(The omnifunc function should return async results):
|
||||
" Neovim 0.2.0 and 0.4.4 struggles at running these tests.
|
||||
if !has('nvim')
|
||||
call timer_start(0, function('SetCompletionResult'))
|
||||
|
||||
AssertEqual ['foo'], ale#completion#OmniFunc(0, '')
|
||||
endif
|
||||
|
||||
Execute(The omnifunc function should parse and return async responses):
|
||||
if !has('nvim')
|
||||
call timer_start(0, function('SetCompletionResponse'))
|
||||
|
||||
AssertEqual ['foo'], ale#completion#OmniFunc(0, '')
|
||||
endif
|
@ -0,0 +1,47 @@
|
||||
Before:
|
||||
call ale#linter#Reset()
|
||||
|
||||
unlet! b:ale_linters
|
||||
unlet! b:ale_completion_info
|
||||
unlet! b:ale_completion_result
|
||||
|
||||
After:
|
||||
call ale#linter#Reset()
|
||||
|
||||
unlet! b:ale_linters
|
||||
unlet! b:ale_completion_info
|
||||
unlet! b:ale_completion_result
|
||||
|
||||
Execute(ale#completion#GetCompletionResult() should return v:null when there are no results):
|
||||
AssertEqual v:null, ale#completion#GetCompletionResult()
|
||||
|
||||
Execute(ale#completion#GetCompletionResult() should return a result computed previously):
|
||||
let b:ale_completion_result = [1]
|
||||
|
||||
AssertEqual [1], ale#completion#GetCompletionResult()
|
||||
|
||||
Execute(ale#completion#GetCompletionPosition() should return 0 when there is no completion information):
|
||||
AssertEqual 0, ale#completion#GetCompletionPosition()
|
||||
|
||||
Given python(Some Python file):
|
||||
foo bar
|
||||
|
||||
Execute(ale#completion#GetCompletionPosition() should return the position in the file when information is available):
|
||||
let b:ale_completion_info = {'line': 1, 'column': 6}
|
||||
|
||||
" This is the first character of 'bar'
|
||||
AssertEqual 4, ale#completion#GetCompletionPosition()
|
||||
|
||||
Execute(ale#completion#GetCompletionPositionForDeoplete() should return the position on the given input string):
|
||||
" This is the first character of 'bar'
|
||||
AssertEqual 4, ale#completion#GetCompletionPositionForDeoplete('foo bar')
|
||||
|
||||
Execute(ale#completion#CanProvideCompletions should return 0 when no completion sources are available):
|
||||
let b:ale_linters = ['flake8']
|
||||
AssertEqual 0, ale#completion#CanProvideCompletions()
|
||||
|
||||
Execute(ale#completion#CanProvideCompletions should return 1 when at least one completion source is available):
|
||||
runtime ale_linters/python/pylsp.vim
|
||||
let b:ale_linters = ['pylsp']
|
||||
|
||||
AssertEqual 1, ale#completion#CanProvideCompletions()
|
@ -0,0 +1,309 @@
|
||||
Before:
|
||||
Save g:ale_completion_tsserver_remove_warnings
|
||||
|
||||
let g:ale_completion_tsserver_remove_warnings = 0
|
||||
|
||||
After:
|
||||
Restore
|
||||
|
||||
unlet! b:ale_tsserver_completion_names
|
||||
|
||||
Execute(TypeScript completions responses should be parsed correctly):
|
||||
AssertEqual [],
|
||||
\ ale#completion#ParseTSServerCompletions({
|
||||
\ 'body': [],
|
||||
\})
|
||||
AssertEqual
|
||||
\ [
|
||||
\ {
|
||||
\ 'word': 'foo',
|
||||
\ 'source': '/path/to/foo.ts',
|
||||
\ },
|
||||
\ {
|
||||
\ 'word': 'bar',
|
||||
\ 'source': '',
|
||||
\ },
|
||||
\ {
|
||||
\ 'word': 'baz',
|
||||
\ 'source': '',
|
||||
\ }
|
||||
\ ],
|
||||
\ ale#completion#ParseTSServerCompletions({
|
||||
\ 'body': [
|
||||
\ {'name': 'foo', 'source': '/path/to/foo.ts'},
|
||||
\ {'name': 'bar'},
|
||||
\ {'name': 'baz'},
|
||||
\ ],
|
||||
\})
|
||||
|
||||
Execute(TypeScript completions responses should include warnings):
|
||||
AssertEqual
|
||||
\ [
|
||||
\ {
|
||||
\ 'word': 'foo',
|
||||
\ 'source': '/path/to/foo.ts',
|
||||
\ },
|
||||
\ {
|
||||
\ 'word': 'bar',
|
||||
\ 'source': '',
|
||||
\ },
|
||||
\ {
|
||||
\ 'word': 'baz',
|
||||
\ 'source': '',
|
||||
\ }
|
||||
\ ],
|
||||
\ ale#completion#ParseTSServerCompletions({
|
||||
\ 'body': [
|
||||
\ {'name': 'foo', 'source': '/path/to/foo.ts'},
|
||||
\ {'name': 'bar', 'kind': 'warning'},
|
||||
\ {'name': 'baz'},
|
||||
\ ],
|
||||
\})
|
||||
|
||||
Execute(TypeScript completions responses should not include warnings if excluded):
|
||||
let g:ale_completion_tsserver_remove_warnings = 1
|
||||
AssertEqual
|
||||
\ [
|
||||
\ {
|
||||
\ 'word': 'foo',
|
||||
\ 'source': '/path/to/foo.ts',
|
||||
\ },
|
||||
\ {
|
||||
\ 'word': 'baz',
|
||||
\ 'source': '',
|
||||
\ }
|
||||
\ ],
|
||||
\ ale#completion#ParseTSServerCompletions({
|
||||
\ 'body': [
|
||||
\ {'name': 'foo', 'source': '/path/to/foo.ts'},
|
||||
\ {'name': 'bar', 'kind': 'warning'},
|
||||
\ {'name': 'baz'},
|
||||
\ ],
|
||||
\})
|
||||
|
||||
Execute(TypeScript completion details responses should be parsed correctly):
|
||||
AssertEqual
|
||||
\ [
|
||||
\ {
|
||||
\ 'word': 'abc',
|
||||
\ 'menu': '(property) Foo.abc: number',
|
||||
\ 'info': '',
|
||||
\ 'kind': 'v',
|
||||
\ 'icase': 1,
|
||||
\ 'user_data': json_encode({'_ale_completion_item': 1}),
|
||||
\ 'dup': g:ale_completion_autoimport,
|
||||
\ },
|
||||
\ {
|
||||
\ 'word': 'def',
|
||||
\ 'menu': '(property) Foo.def: number',
|
||||
\ 'info': 'foo bar baz',
|
||||
\ 'kind': 'v',
|
||||
\ 'icase': 1,
|
||||
\ 'user_data': json_encode({'_ale_completion_item': 1}),
|
||||
\ 'dup': g:ale_completion_autoimport,
|
||||
\ },
|
||||
\ {
|
||||
\ 'word': 'ghi',
|
||||
\ 'menu': '(class) Foo',
|
||||
\ 'info': '',
|
||||
\ 'kind': 'v',
|
||||
\ 'icase': 1,
|
||||
\ 'user_data': json_encode({'_ale_completion_item': 1}),
|
||||
\ 'dup': g:ale_completion_autoimport,
|
||||
\ },
|
||||
\ ],
|
||||
\ 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'},
|
||||
\ ],
|
||||
\ },
|
||||
\ {
|
||||
\ 'name': 'ghi',
|
||||
\ 'kind': 'className',
|
||||
\ 'displayParts': [
|
||||
\ {'text': '('},
|
||||
\ {'text': 'class'},
|
||||
\ {'text': ')'},
|
||||
\ {'text': ' '},
|
||||
\ {'text': 'Foo'},
|
||||
\ ],
|
||||
\ },
|
||||
\ ],
|
||||
\})
|
||||
|
||||
Execute(Entries without details should be included in the responses):
|
||||
let b:ale_tsserver_completion_names = [{
|
||||
\ 'word': 'xyz',
|
||||
\ 'source': '/path/to/xyz.ts',
|
||||
\ }]
|
||||
|
||||
AssertEqual
|
||||
\ [
|
||||
\ {
|
||||
\ 'word': 'abc',
|
||||
\ 'menu': 'import { def } from "./Foo"; (property) Foo.abc: number',
|
||||
\ 'info': '',
|
||||
\ 'kind': 'v',
|
||||
\ 'icase': 1,
|
||||
\ 'user_data': json_encode({
|
||||
\ '_ale_completion_item': 1,
|
||||
\ 'code_actions': [{
|
||||
\ 'description': 'import { def } from "./Foo";',
|
||||
\ 'changes': [],
|
||||
\ }],
|
||||
\ }),
|
||||
\ 'dup': g:ale_completion_autoimport,
|
||||
\ },
|
||||
\ {
|
||||
\ 'word': 'def',
|
||||
\ 'menu': '(property) Foo.def: number',
|
||||
\ 'info': 'foo bar baz',
|
||||
\ 'kind': 'v',
|
||||
\ 'icase': 1,
|
||||
\ 'user_data': json_encode({'_ale_completion_item': 1}),
|
||||
\ 'dup': g:ale_completion_autoimport,
|
||||
\ },
|
||||
\ {
|
||||
\ 'word': 'xyz',
|
||||
\ 'menu': '',
|
||||
\ 'info': '',
|
||||
\ 'kind': 'v',
|
||||
\ 'user_data': json_encode({'_ale_completion_item': 1}),
|
||||
\ 'icase': 1,
|
||||
\ },
|
||||
\ ],
|
||||
\ ale#completion#ParseTSServerCompletionEntryDetails({
|
||||
\ 'body': [
|
||||
\ {
|
||||
\ 'name': 'abc',
|
||||
\ 'kind': 'parameterName',
|
||||
\ 'displayParts': [
|
||||
\ {'text': '('},
|
||||
\ {'text': 'property'},
|
||||
\ {'text': ')'},
|
||||
\ {'text': ' '},
|
||||
\ {'text': 'Foo'},
|
||||
\ {'text': '.'},
|
||||
\ {'text': 'abc'},
|
||||
\ {'text': ':'},
|
||||
\ {'text': ' '},
|
||||
\ {'text': 'number'},
|
||||
\ ],
|
||||
\ 'codeActions': [{
|
||||
\ 'description': 'import { def } from "./Foo";',
|
||||
\ 'changes': [],
|
||||
\ }],
|
||||
\ },
|
||||
\ {
|
||||
\ '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'},
|
||||
\ ],
|
||||
\ },
|
||||
\ ],
|
||||
\})
|
||||
|
||||
Execute(Default imports should be handled correctly):
|
||||
AssertEqual
|
||||
\ [
|
||||
\ {
|
||||
\ 'word': 'abcd',
|
||||
\ 'menu': 'Import default ''abcd'' from module "./foo" (alias) const abcd: 3',
|
||||
\ 'info': '',
|
||||
\ 'kind': 't',
|
||||
\ 'icase': 1,
|
||||
\ 'user_data': json_encode({
|
||||
\ '_ale_completion_item': 1,
|
||||
\ 'code_actions': [{
|
||||
\ 'description': 'Import default ''abcd'' from module "./foo"',
|
||||
\ 'changes': [],
|
||||
\ }],
|
||||
\ }),
|
||||
\ 'dup': g:ale_completion_autoimport,
|
||||
\ },
|
||||
\ ],
|
||||
\ ale#completion#ParseTSServerCompletionEntryDetails({
|
||||
\ 'body': [
|
||||
\ {
|
||||
\ 'name': 'default',
|
||||
\ 'kind': 'alias',
|
||||
\ 'displayParts': [
|
||||
\ {'kind': 'punctuation', 'text': '('},
|
||||
\ {'kind': 'text', 'text': 'alias'},
|
||||
\ {'kind': 'punctuation', 'text': ')'},
|
||||
\ {'kind': 'space', 'text': ' '},
|
||||
\ {'kind': 'keyword', 'text': 'const'},
|
||||
\ {'kind': 'space', 'text': ' '},
|
||||
\ {'kind': 'localName', 'text': 'abcd'},
|
||||
\ {'kind': 'punctuation', 'text': ':'},
|
||||
\ {'kind': 'space', 'text': ' '},
|
||||
\ {'kind': 'stringLiteral', 'text': '3'},
|
||||
\ {'kind': 'lineBreak', 'text': '^@'},
|
||||
\ {'kind': 'keyword', 'text': 'export'},
|
||||
\ {'kind': 'space', 'text': ' '},
|
||||
\ {'kind': 'keyword', 'text': 'default'},
|
||||
\ {'kind': 'space', 'text': ' '},
|
||||
\ {'kind': 'aliasName', 'text': 'abcd'}
|
||||
\ ],
|
||||
\ 'codeActions': [
|
||||
\ {
|
||||
\ 'description': 'Import default ''abcd'' from module "./foo"',
|
||||
\ 'changes': [],
|
||||
\ },
|
||||
\ ],
|
||||
\ },
|
||||
\ ],
|
||||
\ })
|
Reference in New Issue
Block a user