#2132 Use an on-init callback for all LSP logic

This commit is contained in:
w0rp 2019-02-13 00:31:33 +00:00
parent e88243687a
commit 1ee56713b8
No known key found for this signature in database
GPG key ID: 0FC1ECAA8C81CD83
14 changed files with 181 additions and 192 deletions

View file

@ -446,10 +446,15 @@ function! ale#completion#HandleLSPResponse(conn_id, response) abort
\) \)
endfunction endfunction
function! s:OnReady(linter, lsp_details, ...) abort function! s:OnReady(linter, lsp_details) abort
let l:buffer = a:lsp_details.buffer
let l:id = a:lsp_details.connection_id let l:id = a:lsp_details.connection_id
if !ale#lsp#HasCapability(l:id, 'completion')
return
endif
let l:buffer = a:lsp_details.buffer
" If we have sent a completion request already, don't send another. " If we have sent a completion request already, don't send another.
if b:ale_completion_info.request_id if b:ale_completion_info.request_id
return return
@ -498,21 +503,6 @@ function! s:OnReady(linter, lsp_details, ...) abort
endif endif
endfunction endfunction
function! s:GetLSPCompletions(linter) abort
let l:buffer = bufnr('')
let l:lsp_details = ale#lsp_linter#StartLSP(l:buffer, a:linter)
if empty(l:lsp_details)
return 0
endif
let l:id = l:lsp_details.connection_id
let l:OnReady = function('s:OnReady', [a:linter, l:lsp_details])
call ale#lsp#WaitForCapability(l:id, 'completion', l:OnReady)
endfunction
function! ale#completion#GetCompletions() abort function! ale#completion#GetCompletions() abort
if !g:ale_completion_enabled if !g:ale_completion_enabled
return return
@ -543,9 +533,12 @@ function! ale#completion#AlwaysGetCompletions(need_prefix) abort
\ 'request_id': 0, \ 'request_id': 0,
\} \}
let l:buffer = bufnr('')
let l:Callback = function('s:OnReady')
for l:linter in ale#linter#Get(&filetype) for l:linter in ale#linter#Get(&filetype)
if !empty(l:linter.lsp) if !empty(l:linter.lsp)
call s:GetLSPCompletions(l:linter) call ale#lsp_linter#StartLSP(l:buffer, l:linter, l:Callback)
endif endif
endfor endfor
endfunction endfunction

View file

@ -57,10 +57,15 @@ function! ale#definition#HandleLSPResponse(conn_id, response) abort
endif endif
endfunction endfunction
function! s:OnReady(linter, lsp_details, line, column, options, capability, ...) abort function! s:OnReady(line, column, options, capability, linter, lsp_details) abort
let l:buffer = a:lsp_details.buffer
let l:id = a:lsp_details.connection_id let l:id = a:lsp_details.connection_id
if !ale#lsp#HasCapability(l:id, a:capability)
return
endif
let l:buffer = a:lsp_details.buffer
let l:Callback = a:linter.lsp is# 'tsserver' let l:Callback = a:linter.lsp is# 'tsserver'
\ ? function('ale#definition#HandleTSServerResponse') \ ? function('ale#definition#HandleTSServerResponse')
\ : function('ale#definition#HandleLSPResponse') \ : function('ale#definition#HandleLSPResponse')
@ -100,21 +105,13 @@ endfunction
function! s:GoToLSPDefinition(linter, options, capability) abort function! s:GoToLSPDefinition(linter, options, capability) abort
let l:buffer = bufnr('') let l:buffer = bufnr('')
let [l:line, l:column] = getcurpos()[1:2] let [l:line, l:column] = getcurpos()[1:2]
let l:lsp_details = ale#lsp_linter#StartLSP(l:buffer, a:linter)
if a:linter.lsp isnot# 'tsserver'
let l:column = min([l:column, len(getline(l:line))]) let l:column = min([l:column, len(getline(l:line))])
endif
if empty(l:lsp_details) let l:Callback = function(
return 0 \ 's:OnReady',
endif \ [l:line, l:column, a:options, a:capability]
\)
let l:id = l:lsp_details.connection_id call ale#lsp_linter#StartLSP(l:buffer, a:linter, l:Callback)
call ale#lsp#WaitForCapability(l:id, a:capability, function('s:OnReady', [
\ a:linter, l:lsp_details, l:line, l:column, a:options, a:capability
\]))
endfunction endfunction
function! ale#definition#GoTo(options) abort function! ale#definition#GoTo(options) abort

View file

@ -106,10 +106,15 @@ function! ale#hover#HandleLSPResponse(conn_id, response) abort
endif endif
endfunction endfunction
function! s:OnReady(linter, lsp_details, line, column, opt, ...) abort function! s:OnReady(line, column, opt, linter, lsp_details) abort
let l:buffer = a:lsp_details.buffer
let l:id = a:lsp_details.connection_id let l:id = a:lsp_details.connection_id
if !ale#lsp#HasCapability(l:id, 'hover')
return
endif
let l:buffer = a:lsp_details.buffer
let l:Callback = a:linter.lsp is# 'tsserver' let l:Callback = a:linter.lsp is# 'tsserver'
\ ? function('ale#hover#HandleTSServerResponse') \ ? function('ale#hover#HandleTSServerResponse')
\ : function('ale#hover#HandleLSPResponse') \ : function('ale#hover#HandleLSPResponse')
@ -144,20 +149,6 @@ function! s:OnReady(linter, lsp_details, line, column, opt, ...) abort
\} \}
endfunction endfunction
function! s:ShowDetails(linter, buffer, line, column, opt, ...) abort
let l:lsp_details = ale#lsp_linter#StartLSP(a:buffer, a:linter)
if empty(l:lsp_details)
return 0
endif
let l:id = l:lsp_details.connection_id
call ale#lsp#WaitForCapability(l:id, 'hover', function('s:OnReady', [
\ a:linter, l:lsp_details, a:line, a:column, a:opt
\]))
endfunction
" Obtain Hover information for the specified position " Obtain Hover information for the specified position
" Pass optional arguments in the dictionary opt. " Pass optional arguments in the dictionary opt.
" Currently, only one key/value is useful: " Currently, only one key/value is useful:
@ -169,12 +160,13 @@ endfunction
" - as status message otherwise " - as status message otherwise
function! ale#hover#Show(buffer, line, col, opt) abort function! ale#hover#Show(buffer, line, col, opt) abort
let l:show_documentation = get(a:opt, 'show_documentation', 0) let l:show_documentation = get(a:opt, 'show_documentation', 0)
let l:Callback = function('s:OnReady', [a:line, a:col, a:opt])
for l:linter in ale#linter#Get(getbufvar(a:buffer, '&filetype')) for l:linter in ale#linter#Get(getbufvar(a:buffer, '&filetype'))
" Only tsserver supports documentation requests at the moment. " Only tsserver supports documentation requests at the moment.
if !empty(l:linter.lsp) if !empty(l:linter.lsp)
\&& (!l:show_documentation || l:linter.lsp is# 'tsserver') \&& (!l:show_documentation || l:linter.lsp is# 'tsserver')
call s:ShowDetails(l:linter, a:buffer, a:line, a:col, a:opt) call ale#lsp_linter#StartLSP(a:buffer, l:linter, l:Callback)
endif endif
endfor endfor
endfunction endfunction

View file

@ -36,7 +36,7 @@ function! ale#lsp#Register(executable_or_address, project, init_options) abort
\ 'config': {}, \ 'config': {},
\ 'callback_list': [], \ 'callback_list': [],
\ 'message_queue': [], \ 'message_queue': [],
\ 'capabilities_queue': [], \ 'init_queue': [],
\ 'capabilities': { \ 'capabilities': {
\ 'hover': 0, \ 'hover': 0,
\ 'references': 0, \ 'references': 0,
@ -259,13 +259,11 @@ function! ale#lsp#HandleInitResponse(conn, response) abort
let a:conn.message_queue = [] let a:conn.message_queue = []
" Call capabilities callbacks queued for the project. " Call capabilities callbacks queued for the project.
for [l:capability, l:Callback] in a:conn.capabilities_queue for [l:Callback] in a:conn.init_queue
if a:conn.capabilities[l:capability] call l:Callback()
call call(l:Callback, [a:conn.id])
endif
endfor endfor
let a:conn.capabilities_queue = [] let a:conn.init_queue = []
endfunction endfunction
function! ale#lsp#HandleMessage(conn_id, message) abort function! ale#lsp#HandleMessage(conn_id, message) abort
@ -501,26 +499,32 @@ function! ale#lsp#NotifyForChanges(conn_id, buffer) abort
return l:notified return l:notified
endfunction endfunction
" Given some LSP details that must contain at least `connection_id` and " Wait for an LSP server to be initialized.
" `project_root` keys, function! ale#lsp#OnInit(conn_id, Callback) abort
function! ale#lsp#WaitForCapability(conn_id, capability, callback) abort
let l:conn = get(s:connections, a:conn_id, {}) let l:conn = get(s:connections, a:conn_id, {})
if empty(l:conn) if empty(l:conn)
return return
endif endif
if l:conn.initialized
call a:Callback()
else
call add(l:conn.init_queue, a:Callback)
endif
endfunction
" Check if an LSP has a given capability.
function! ale#lsp#HasCapability(conn_id, capability) abort
let l:conn = get(s:connections, a:conn_id, {})
if empty(l:conn)
return 0
endif
if type(get(l:conn.capabilities, a:capability, v:null)) isnot v:t_number if type(get(l:conn.capabilities, a:capability, v:null)) isnot v:t_number
throw 'Invalid capability ' . a:capability throw 'Invalid capability ' . a:capability
endif endif
if l:conn.initialized return l:conn.capabilities[a:capability]
if l:conn.capabilities[a:capability]
" The project has been initialized, so call the callback now.
call call(a:callback, [a:conn_id])
endif
else
" Call the callback later, once we have the information we need.
call add(l:conn.capabilities_queue, [a:capability, a:callback])
endif
endfunction endfunction

View file

@ -187,7 +187,7 @@ endfunction
" Given a buffer, an LSP linter, start up an LSP linter and get ready to " Given a buffer, an LSP linter, start up an LSP linter and get ready to
" receive messages for the document. " receive messages for the document.
function! ale#lsp_linter#StartLSP(buffer, linter) abort function! ale#lsp_linter#StartLSP(buffer, linter, Callback) abort
let l:command = '' let l:command = ''
let l:address = '' let l:address = ''
let l:root = ale#lsp_linter#FindProjectRoot(a:buffer, a:linter) let l:root = ale#lsp_linter#FindProjectRoot(a:buffer, a:linter)
@ -195,7 +195,7 @@ function! ale#lsp_linter#StartLSP(buffer, linter) abort
if empty(l:root) && a:linter.lsp isnot# 'tsserver' if empty(l:root) && a:linter.lsp isnot# 'tsserver'
" If there's no project root, then we can't check files with LSP, " If there's no project root, then we can't check files with LSP,
" unless we are using tsserver, which doesn't use project roots. " unless we are using tsserver, which doesn't use project roots.
return {} return 0
endif endif
let l:init_options = ale#lsp_linter#GetOptions(a:buffer, a:linter) let l:init_options = ale#lsp_linter#GetOptions(a:buffer, a:linter)
@ -208,7 +208,7 @@ function! ale#lsp_linter#StartLSP(buffer, linter) abort
let l:executable = ale#linter#GetExecutable(a:buffer, a:linter) let l:executable = ale#linter#GetExecutable(a:buffer, a:linter)
if empty(l:executable) || !executable(l:executable) if empty(l:executable) || !executable(l:executable)
return {} return 0
endif endif
let l:conn_id = ale#lsp#Register(l:executable, l:root, l:init_options) let l:conn_id = ale#lsp#Register(l:executable, l:root, l:init_options)
@ -225,7 +225,7 @@ function! ale#lsp_linter#StartLSP(buffer, linter) abort
call ale#history#Add(a:buffer, 'failed', l:conn_id, l:command) call ale#history#Add(a:buffer, 'failed', l:conn_id, l:command)
endif endif
return {} return 0
endif endif
" tsserver behaves differently, so tell the LSP API that it is tsserver. " tsserver behaves differently, so tell the LSP API that it is tsserver.
@ -257,18 +257,20 @@ function! ale#lsp_linter#StartLSP(buffer, linter) abort
call ale#lsp#NotifyForChanges(l:conn_id, a:buffer) call ale#lsp#NotifyForChanges(l:conn_id, a:buffer)
endif endif
return l:details call ale#lsp#OnInit(l:conn_id, {-> a:Callback(a:linter, l:details)})
return 1
endfunction endfunction
function! ale#lsp_linter#CheckWithLSP(buffer, linter) abort function! s:CheckWithLSP(linter, details) abort
let l:info = g:ale_buffer_info[a:buffer] let l:buffer = a:details.buffer
let l:lsp_details = ale#lsp_linter#StartLSP(a:buffer, a:linter) let l:info = get(g:ale_buffer_info, l:buffer)
if empty(l:lsp_details) if empty(l:info)
return 0 return
endif endif
let l:id = l:lsp_details.connection_id let l:id = a:details.connection_id
" Register a callback now for handling errors now. " Register a callback now for handling errors now.
let l:Callback = function('ale#lsp_linter#HandleLSPResponse') let l:Callback = function('ale#lsp_linter#HandleLSPResponse')
@ -278,16 +280,16 @@ function! ale#lsp_linter#CheckWithLSP(buffer, linter) abort
let s:lsp_linter_map[l:id] = a:linter.name let s:lsp_linter_map[l:id] = a:linter.name
if a:linter.lsp is# 'tsserver' if a:linter.lsp is# 'tsserver'
let l:message = ale#lsp#tsserver_message#Geterr(a:buffer) let l:message = ale#lsp#tsserver_message#Geterr(l:buffer)
let l:notified = ale#lsp#Send(l:id, l:message) != 0 let l:notified = ale#lsp#Send(l:id, l:message) != 0
else else
let l:notified = ale#lsp#NotifyForChanges(l:id, a:buffer) let l:notified = ale#lsp#NotifyForChanges(l:id, l:buffer)
endif endif
" If this was a file save event, also notify the server of that. " If this was a file save event, also notify the server of that.
if a:linter.lsp isnot# 'tsserver' if a:linter.lsp isnot# 'tsserver'
\&& getbufvar(a:buffer, 'ale_save_event_fired', 0) \&& getbufvar(l:buffer, 'ale_save_event_fired', 0)
let l:save_message = ale#lsp#message#DidSave(a:buffer) let l:save_message = ale#lsp#message#DidSave(l:buffer)
let l:notified = ale#lsp#Send(l:id, l:save_message) != 0 let l:notified = ale#lsp#Send(l:id, l:save_message) != 0
endif endif
@ -305,8 +307,10 @@ function! ale#lsp_linter#CheckWithLSP(buffer, linter) abort
call add(l:info.active_linter_list, a:linter) call add(l:info.active_linter_list, a:linter)
endif endif
endif endif
endfunction
return l:notified function! ale#lsp_linter#CheckWithLSP(buffer, linter) abort
return ale#lsp_linter#StartLSP(a:buffer, a:linter, function('s:CheckWithLSP'))
endfunction endfunction
" Clear LSP linter data for the linting engine. " Clear LSP linter data for the linting engine.

View file

@ -65,10 +65,15 @@ function! ale#references#HandleLSPResponse(conn_id, response) abort
endif endif
endfunction endfunction
function! s:OnReady(linter, lsp_details, line, column, options, ...) abort function! s:OnReady(line, column, options, linter, lsp_details) abort
let l:buffer = a:lsp_details.buffer
let l:id = a:lsp_details.connection_id let l:id = a:lsp_details.connection_id
if !ale#lsp#HasCapability(l:id, 'references')
return
endif
let l:buffer = a:lsp_details.buffer
let l:Callback = a:linter.lsp is# 'tsserver' let l:Callback = a:linter.lsp is# 'tsserver'
\ ? function('ale#references#HandleTSServerResponse') \ ? function('ale#references#HandleTSServerResponse')
\ : function('ale#references#HandleLSPResponse') \ : function('ale#references#HandleLSPResponse')
@ -96,27 +101,6 @@ function! s:OnReady(linter, lsp_details, line, column, options, ...) abort
\} \}
endfunction endfunction
function! s:FindReferences(linter, options) abort
let l:buffer = bufnr('')
let [l:line, l:column] = getcurpos()[1:2]
if a:linter.lsp isnot# 'tsserver'
let l:column = min([l:column, len(getline(l:line))])
endif
let l:lsp_details = ale#lsp_linter#StartLSP(l:buffer, a:linter)
if empty(l:lsp_details)
return 0
endif
let l:id = l:lsp_details.connection_id
call ale#lsp#WaitForCapability(l:id, 'references', function('s:OnReady', [
\ a:linter, l:lsp_details, l:line, l:column, a:options
\]))
endfunction
function! ale#references#Find(...) abort function! ale#references#Find(...) abort
let l:options = {} let l:options = {}
@ -128,9 +112,14 @@ function! ale#references#Find(...) abort
endfor endfor
endif endif
let l:buffer = bufnr('')
let [l:line, l:column] = getcurpos()[1:2]
let l:column = min([l:column, len(getline(l:line))])
let l:Callback = function('s:OnReady', [l:line, l:column, l:options])
for l:linter in ale#linter#Get(&filetype) for l:linter in ale#linter#Get(&filetype)
if !empty(l:linter.lsp) if !empty(l:linter.lsp)
call s:FindReferences(l:linter, l:options) call ale#lsp_linter#StartLSP(l:buffer, l:linter, l:Callback)
endif endif
endfor endfor
endfunction endfunction

View file

@ -57,7 +57,13 @@ function! ale#symbol#HandleLSPResponse(conn_id, response) abort
endif endif
endfunction endfunction
function! s:OnReady(linter, lsp_details, query, options, ...) abort function! s:OnReady(query, options, linter, lsp_details) abort
let l:id = a:lsp_details.connection_id
if !ale#lsp#HasCapability(l:id, 'symbol_search')
return
endif
let l:buffer = a:lsp_details.buffer let l:buffer = a:lsp_details.buffer
" If we already made a request, stop here. " If we already made a request, stop here.
@ -65,8 +71,6 @@ function! s:OnReady(linter, lsp_details, query, options, ...) abort
return return
endif endif
let l:id = a:lsp_details.connection_id
let l:Callback = function('ale#symbol#HandleLSPResponse') let l:Callback = function('ale#symbol#HandleLSPResponse')
call ale#lsp#RegisterCallback(l:id, l:Callback) call ale#lsp#RegisterCallback(l:id, l:Callback)
@ -80,18 +84,6 @@ function! s:OnReady(linter, lsp_details, query, options, ...) abort
\} \}
endfunction endfunction
function! s:Search(linter, buffer, query, options) abort
let l:lsp_details = ale#lsp_linter#StartLSP(a:buffer, a:linter)
if !empty(l:lsp_details)
call ale#lsp#WaitForCapability(
\ l:lsp_details.connection_id,
\ 'symbol_search',
\ function('s:OnReady', [a:linter, l:lsp_details, a:query, a:options]),
\)
endif
endfunction
function! ale#symbol#Search(args) abort function! ale#symbol#Search(args) abort
let [l:opts, l:query] = ale#args#Parse(['relative'], a:args) let [l:opts, l:query] = ale#args#Parse(['relative'], a:args)
@ -108,10 +100,11 @@ function! ale#symbol#Search(args) abort
" Set a flag so we only make one request. " Set a flag so we only make one request.
call setbufvar(l:buffer, 'ale_symbol_request_made', 0) call setbufvar(l:buffer, 'ale_symbol_request_made', 0)
let l:Callback = function('s:OnReady', [l:query, l:options])
for l:linter in ale#linter#Get(getbufvar(l:buffer, '&filetype')) for l:linter in ale#linter#Get(getbufvar(l:buffer, '&filetype'))
if !empty(l:linter.lsp) && l:linter.lsp isnot# 'tsserver' if !empty(l:linter.lsp) && l:linter.lsp isnot# 'tsserver'
call s:Search(l:linter, l:buffer, l:query, l:options) call ale#lsp_linter#StartLSP(l:buffer, l:linter, l:Callback)
endif endif
endfor endfor
endfunction endfunction

View file

@ -16,18 +16,20 @@ Before:
let g:capability_checked = '' let g:capability_checked = ''
let g:conn_id = v:null let g:conn_id = v:null
let g:Callback = '' let g:Callback = ''
let g:wait_callback_list = [] let g:init_callback_list = []
function! ale#lsp_linter#StartLSP(buffer, linter) abort function! ale#lsp_linter#StartLSP(buffer, linter, Callback) abort
let g:conn_id = ale#lsp#Register('executable', '/foo/bar', {}) let g:conn_id = ale#lsp#Register('executable', '/foo/bar', {})
call ale#lsp#MarkDocumentAsOpen(g:conn_id, a:buffer) call ale#lsp#MarkDocumentAsOpen(g:conn_id, a:buffer)
return { let l:details = {
\ 'buffer': a:buffer, \ 'buffer': a:buffer,
\ 'connection_id': g:conn_id, \ 'connection_id': g:conn_id,
\ 'project_root': '/foo/bar', \ 'project_root': '/foo/bar',
\ 'language_id': 'python', \ 'language_id': 'python',
\} \}
call add(g:init_callback_list, {-> a:Callback(a:linter, l:details)})
endfunction endfunction
" Pretend we're in insert mode for most tests. " Pretend we're in insert mode for most tests.
@ -35,9 +37,10 @@ Before:
return 'i' return 'i'
endfunction endfunction
function! ale#lsp#WaitForCapability(conn_id, capability, callback) abort function! ale#lsp#HasCapability(conn_id, capability) abort
let g:capability_checked = a:capability let g:capability_checked = a:capability
call add(g:wait_callback_list, a:callback)
return 1
endfunction endfunction
function! ale#lsp#RegisterCallback(conn_id, callback) abort function! ale#lsp#RegisterCallback(conn_id, callback) abort
@ -60,7 +63,7 @@ After:
unlet! g:message_list unlet! g:message_list
unlet! g:capability_checked unlet! g:capability_checked
unlet! g:wait_callback_list unlet! g:init_callback_list
unlet! g:conn_id unlet! g:conn_id
unlet! g:Callback unlet! g:Callback
unlet! b:ale_old_omnifunc unlet! b:ale_old_omnifunc
@ -104,9 +107,10 @@ Execute(The right message should be sent for the initial tsserver request):
" We shouldn't register the callback yet. " We shouldn't register the callback yet.
AssertEqual '''''', string(g:Callback) AssertEqual '''''', string(g:Callback)
AssertEqual 1, len(g:wait_callback_list) AssertEqual 1, len(g:init_callback_list)
call map(g:init_callback_list, 'v:val()')
AssertEqual 'completion', g:capability_checked AssertEqual 'completion', g:capability_checked
call map(g:wait_callback_list, 'v:val([g:conn_id, ''/foo/bar''])')
" We should send the right callback. " We should send the right callback.
AssertEqual AssertEqual
@ -191,9 +195,10 @@ Execute(The right message should be sent for the initial LSP request):
" We shouldn't register the callback yet. " We shouldn't register the callback yet.
AssertEqual '''''', string(g:Callback) AssertEqual '''''', string(g:Callback)
AssertEqual 1, len(g:wait_callback_list) AssertEqual 1, len(g:init_callback_list)
call map(g:init_callback_list, 'v:val()')
AssertEqual 'completion', g:capability_checked AssertEqual 'completion', g:capability_checked
call map(g:wait_callback_list, 'v:val([g:conn_id, ''/foo/bar''])')
" We should send the right callback. " We should send the right callback.
AssertEqual AssertEqual
@ -258,9 +263,10 @@ Execute(Two completion requests shouldn't be sent in a row):
" We shouldn't register the callback yet. " We shouldn't register the callback yet.
AssertEqual '''''', string(g:Callback) AssertEqual '''''', string(g:Callback)
AssertEqual 2, len(g:wait_callback_list) AssertEqual 2, len(g:init_callback_list)
call map(g:init_callback_list, 'v:val()')
AssertEqual 'completion', g:capability_checked AssertEqual 'completion', g:capability_checked
call map(g:wait_callback_list, 'v:val([347, ''/foo/bar''])')
" We should only send one completion message for two LSP servers. " We should only send one completion message for two LSP servers.
AssertEqual AssertEqual

View file

@ -34,16 +34,19 @@ Before:
\ }) \ })
let g:ale_linters = {'foobar': ['dummy_linter']} let g:ale_linters = {'foobar': ['dummy_linter']}
function! ale#lsp_linter#StartLSP(buffer, linter) abort function! ale#lsp_linter#StartLSP(buffer, linter, Callback) abort
let g:conn_id = ale#lsp#Register('executable', '/foo/bar', {}) let g:conn_id = ale#lsp#Register('executable', '/foo/bar', {})
call ale#lsp#MarkDocumentAsOpen(g:conn_id, a:buffer) call ale#lsp#MarkDocumentAsOpen(g:conn_id, a:buffer)
let l:details = {
return {
\ 'buffer': a:buffer, \ 'buffer': a:buffer,
\ 'connection_id': g:conn_id, \ 'connection_id': g:conn_id,
\ 'project_root': '/foo/bar', \ 'project_root': '/foo/bar',
\ 'language_id': 'foobar', \ 'language_id': 'foobar',
\} \}
call a:Callback(a:linter, l:details)
return 1
endfunction endfunction
" Replace the Send function for LSP, so we can monitor calls to it. " Replace the Send function for LSP, so we can monitor calls to it.
@ -61,6 +64,7 @@ After:
unlet! b:ale_enabled unlet! b:ale_enabled
unlet! b:ale_linters unlet! b:ale_linters
unlet! g:message_list unlet! g:message_list
unlet! b:ale_save_event_fired
delfunction LanguageCallback delfunction LanguageCallback
delfunction ProjectRootCallback delfunction ProjectRootCallback

View file

@ -24,6 +24,7 @@ Execute(Command formatting should be applied correctly for LSP linters):
\ 'executable': has('win32') ? 'cmd': 'true', \ 'executable': has('win32') ? 'cmd': 'true',
\ 'command': '%e --foo', \ 'command': '%e --foo',
\ }, \ },
\ {-> 0}
\) \)
if has('win32') if has('win32')

View file

@ -10,7 +10,7 @@ Before:
\ 'config': {}, \ 'config': {},
\ 'callback_list': [], \ 'callback_list': [],
\ 'message_queue': [], \ 'message_queue': [],
\ 'capabilities_queue': [], \ 'init_queue': [],
\ 'capabilities': { \ 'capabilities': {
\ 'hover': 0, \ 'hover': 0,
\ 'references': 0, \ 'references': 0,

View file

@ -11,28 +11,30 @@ Before:
let g:options = {} let g:options = {}
let g:capability_checked = '' let g:capability_checked = ''
let g:conn_id = v:null let g:conn_id = v:null
let g:WaitCallback = v:null let g:InitCallback = v:null
runtime autoload/ale/linter.vim runtime autoload/ale/linter.vim
runtime autoload/ale/lsp.vim runtime autoload/ale/lsp.vim
runtime autoload/ale/util.vim runtime autoload/ale/util.vim
runtime autoload/ale/preview.vim runtime autoload/ale/preview.vim
function! ale#lsp_linter#StartLSP(buffer, linter) abort function! ale#lsp_linter#StartLSP(buffer, linter, Callback) abort
let g:conn_id = ale#lsp#Register('executable', '/foo/bar', {}) let g:conn_id = ale#lsp#Register('executable', '/foo/bar', {})
call ale#lsp#MarkDocumentAsOpen(g:conn_id, a:buffer) call ale#lsp#MarkDocumentAsOpen(g:conn_id, a:buffer)
let l:details = {
return {
\ 'buffer': a:buffer, \ 'buffer': a:buffer,
\ 'connection_id': g:conn_id, \ 'connection_id': g:conn_id,
\ 'project_root': '/foo/bar', \ 'project_root': '/foo/bar',
\ 'language_id': 'python', \ 'language_id': 'python',
\} \}
let g:InitCallback = {-> a:Callback(a:linter, l:details)}
endfunction endfunction
function! ale#lsp#WaitForCapability(conn_id, capability, callback) abort function! ale#lsp#HasCapability(conn_id, capability) abort
let g:capability_checked = a:capability let g:capability_checked = a:capability
let g:WaitCallback = a:callback
return 1
endfunction endfunction
function! ale#lsp#RegisterCallback(conn_id, callback) abort function! ale#lsp#RegisterCallback(conn_id, callback) abort
@ -65,7 +67,7 @@ After:
call ale#linter#Reset() call ale#linter#Reset()
unlet! g:capability_checked unlet! g:capability_checked
unlet! g:WaitCallback unlet! g:InitCallback
unlet! g:old_filename unlet! g:old_filename
unlet! g:conn_id unlet! g:conn_id
unlet! g:Callback unlet! g:Callback
@ -173,10 +175,10 @@ Execute(tsserver reference requests should be sent):
" We shouldn't register the callback yet. " We shouldn't register the callback yet.
AssertEqual '''''', string(g:Callback) AssertEqual '''''', string(g:Callback)
AssertEqual type(function('type')), type(g:WaitCallback) AssertEqual type(function('type')), type(g:InitCallback)
AssertEqual 'references', g:capability_checked call g:InitCallback()
call call(g:WaitCallback, [g:conn_id, '/foo/bar'])
AssertEqual 'references', g:capability_checked
AssertEqual AssertEqual
\ 'function(''ale#references#HandleTSServerResponse'')', \ 'function(''ale#references#HandleTSServerResponse'')',
\ string(g:Callback) \ string(g:Callback)
@ -191,7 +193,7 @@ Execute('-relative' argument should enable 'use_relative_paths' in HandleTSServe
ALEFindReferences -relative ALEFindReferences -relative
call call(g:WaitCallback, [g:conn_id, '/foo/bar']) call g:InitCallback()
AssertEqual {'42': {'use_relative_paths': 1}}, ale#references#GetMap() AssertEqual {'42': {'use_relative_paths': 1}}, ale#references#GetMap()
@ -264,10 +266,10 @@ Execute(LSP reference requests should be sent):
" We shouldn't register the callback yet. " We shouldn't register the callback yet.
AssertEqual '''''', string(g:Callback) AssertEqual '''''', string(g:Callback)
AssertEqual type(function('type')), type(g:WaitCallback) AssertEqual type(function('type')), type(g:InitCallback)
AssertEqual 'references', g:capability_checked call g:InitCallback()
call call(g:WaitCallback, [g:conn_id, '/foo/bar'])
AssertEqual 'references', g:capability_checked
AssertEqual AssertEqual
\ 'function(''ale#references#HandleLSPResponse'')', \ 'function(''ale#references#HandleLSPResponse'')',
\ string(g:Callback) \ string(g:Callback)
@ -298,6 +300,6 @@ Execute('-relative' argument should enable 'use_relative_paths' in HandleLSPResp
ALEFindReferences -relative ALEFindReferences -relative
call call(g:WaitCallback, [g:conn_id, '/foo/bar']) call g:InitCallback()
AssertEqual {'42': {'use_relative_paths': 1}}, ale#references#GetMap() AssertEqual {'42': {'use_relative_paths': 1}}, ale#references#GetMap()

View file

@ -8,27 +8,29 @@ Before:
let g:expr_list = [] let g:expr_list = []
let g:capability_checked = '' let g:capability_checked = ''
let g:conn_id = v:null let g:conn_id = v:null
let g:WaitCallback = v:null let g:InitCallback = v:null
runtime autoload/ale/linter.vim runtime autoload/ale/linter.vim
runtime autoload/ale/lsp.vim runtime autoload/ale/lsp.vim
runtime autoload/ale/util.vim runtime autoload/ale/util.vim
function! ale#lsp_linter#StartLSP(buffer, linter) abort function! ale#lsp_linter#StartLSP(buffer, linter, Callback) abort
let g:conn_id = ale#lsp#Register('executable', '/foo/bar', {}) let g:conn_id = ale#lsp#Register('executable', '/foo/bar', {})
call ale#lsp#MarkDocumentAsOpen(g:conn_id, a:buffer) call ale#lsp#MarkDocumentAsOpen(g:conn_id, a:buffer)
let l:details = {
return {
\ 'buffer': a:buffer, \ 'buffer': a:buffer,
\ 'connection_id': g:conn_id, \ 'connection_id': g:conn_id,
\ 'project_root': '/foo/bar', \ 'project_root': '/foo/bar',
\ 'language_id': 'python', \ 'language_id': 'python',
\} \}
let g:InitCallback = {-> a:Callback(a:linter, l:details)}
endfunction endfunction
function! ale#lsp#WaitForCapability(conn_id, capability, callback) abort function! ale#lsp#HasCapability(conn_id, capability) abort
let g:capability_checked = a:capability let g:capability_checked = a:capability
let g:WaitCallback = a:callback
return 1
endfunction endfunction
function! ale#lsp#RegisterCallback(conn_id, callback) abort function! ale#lsp#RegisterCallback(conn_id, callback) abort
@ -55,7 +57,7 @@ After:
call ale#linter#Reset() call ale#linter#Reset()
unlet! g:capability_checked unlet! g:capability_checked
unlet! g:WaitCallback unlet! g:InitCallback
unlet! g:old_filename unlet! g:old_filename
unlet! g:conn_id unlet! g:conn_id
unlet! g:Callback unlet! g:Callback
@ -205,10 +207,10 @@ Execute(tsserver definition requests should be sent):
" We shouldn't register the callback yet. " We shouldn't register the callback yet.
AssertEqual '''''', string(g:Callback) AssertEqual '''''', string(g:Callback)
AssertEqual type(function('type')), type(g:WaitCallback) AssertEqual type(function('type')), type(g:InitCallback)
AssertEqual 'definition', g:capability_checked call g:InitCallback()
call call(g:WaitCallback, [g:conn_id, '/foo/bar'])
AssertEqual 'definition', g:capability_checked
AssertEqual AssertEqual
\ 'function(''ale#definition#HandleTSServerResponse'')', \ 'function(''ale#definition#HandleTSServerResponse'')',
\ string(g:Callback) \ string(g:Callback)
@ -226,10 +228,10 @@ Execute(tsserver tab definition requests should be sent):
" We shouldn't register the callback yet. " We shouldn't register the callback yet.
AssertEqual '''''', string(g:Callback) AssertEqual '''''', string(g:Callback)
AssertEqual type(function('type')), type(g:WaitCallback) AssertEqual type(function('type')), type(g:InitCallback)
AssertEqual 'definition', g:capability_checked call g:InitCallback()
call call(g:WaitCallback, [g:conn_id, '/foo/bar'])
AssertEqual 'definition', g:capability_checked
AssertEqual AssertEqual
\ 'function(''ale#definition#HandleTSServerResponse'')', \ 'function(''ale#definition#HandleTSServerResponse'')',
\ string(g:Callback) \ string(g:Callback)
@ -358,10 +360,10 @@ Execute(LSP definition requests should be sent):
" We shouldn't register the callback yet. " We shouldn't register the callback yet.
AssertEqual '''''', string(g:Callback) AssertEqual '''''', string(g:Callback)
AssertEqual type(function('type')), type(g:WaitCallback) AssertEqual type(function('type')), type(g:InitCallback)
AssertEqual 'definition', g:capability_checked call g:InitCallback()
call call(g:WaitCallback, [g:conn_id, '/foo/bar'])
AssertEqual 'definition', g:capability_checked
AssertEqual AssertEqual
\ 'function(''ale#definition#HandleLSPResponse'')', \ 'function(''ale#definition#HandleLSPResponse'')',
\ string(g:Callback) \ string(g:Callback)
@ -394,10 +396,10 @@ Execute(LSP type definition requests should be sent):
" We shouldn't register the callback yet. " We shouldn't register the callback yet.
AssertEqual '''''', string(g:Callback) AssertEqual '''''', string(g:Callback)
AssertEqual type(function('type')), type(g:WaitCallback) AssertEqual type(function('type')), type(g:InitCallback)
AssertEqual 'typeDefinition', g:capability_checked call g:InitCallback()
call call(g:WaitCallback, [g:conn_id, '/foo/bar'])
AssertEqual 'typeDefinition', g:capability_checked
AssertEqual AssertEqual
\ 'function(''ale#definition#HandleLSPResponse'')', \ 'function(''ale#definition#HandleLSPResponse'')',
\ string(g:Callback) \ string(g:Callback)
@ -430,10 +432,10 @@ Execute(LSP tab definition requests should be sent):
" We shouldn't register the callback yet. " We shouldn't register the callback yet.
AssertEqual '''''', string(g:Callback) AssertEqual '''''', string(g:Callback)
AssertEqual type(function('type')), type(g:WaitCallback) AssertEqual type(function('type')), type(g:InitCallback)
AssertEqual 'definition', g:capability_checked call g:InitCallback()
call call(g:WaitCallback, [g:conn_id, '/foo/bar'])
AssertEqual 'definition', g:capability_checked
AssertEqual AssertEqual
\ 'function(''ale#definition#HandleLSPResponse'')', \ 'function(''ale#definition#HandleLSPResponse'')',
\ string(g:Callback) \ string(g:Callback)
@ -466,10 +468,10 @@ Execute(LSP tab type definition requests should be sent):
" We shouldn't register the callback yet. " We shouldn't register the callback yet.
AssertEqual '''''', string(g:Callback) AssertEqual '''''', string(g:Callback)
AssertEqual type(function('type')), type(g:WaitCallback) AssertEqual type(function('type')), type(g:InitCallback)
AssertEqual 'typeDefinition', g:capability_checked call g:InitCallback()
call call(g:WaitCallback, [g:conn_id, '/foo/bar'])
AssertEqual 'typeDefinition', g:capability_checked
AssertEqual AssertEqual
\ 'function(''ale#definition#HandleLSPResponse'')', \ 'function(''ale#definition#HandleLSPResponse'')',
\ string(g:Callback) \ string(g:Callback)

View file

@ -10,28 +10,30 @@ Before:
let g:options = {} let g:options = {}
let g:capability_checked = '' let g:capability_checked = ''
let g:conn_id = v:null let g:conn_id = v:null
let g:WaitCallback = v:null let g:InitCallback = v:null
runtime autoload/ale/lsp_linter.vim runtime autoload/ale/lsp_linter.vim
runtime autoload/ale/lsp.vim runtime autoload/ale/lsp.vim
runtime autoload/ale/util.vim runtime autoload/ale/util.vim
runtime autoload/ale/preview.vim runtime autoload/ale/preview.vim
function! ale#lsp_linter#StartLSP(buffer, linter) abort function! ale#lsp_linter#StartLSP(buffer, linter, Callback) abort
let g:conn_id = ale#lsp#Register('executable', '/foo/bar', {}) let g:conn_id = ale#lsp#Register('executable', '/foo/bar', {})
call ale#lsp#MarkDocumentAsOpen(g:conn_id, a:buffer) call ale#lsp#MarkDocumentAsOpen(g:conn_id, a:buffer)
let l:details = {
return {
\ 'buffer': a:buffer, \ 'buffer': a:buffer,
\ 'connection_id': g:conn_id, \ 'connection_id': g:conn_id,
\ 'project_root': '/foo/bar', \ 'project_root': '/foo/bar',
\ 'language_id': 'python', \ 'language_id': 'python',
\} \}
let g:InitCallback = {-> a:Callback(a:linter, l:details)}
endfunction endfunction
function! ale#lsp#WaitForCapability(conn_id, capability, callback) abort function! ale#lsp#HasCapability(conn_id, capability) abort
let g:capability_checked = a:capability let g:capability_checked = a:capability
let g:WaitCallback = a:callback
return 1
endfunction endfunction
function! ale#lsp#RegisterCallback(conn_id, callback) abort function! ale#lsp#RegisterCallback(conn_id, callback) abort
@ -59,7 +61,7 @@ After:
call ale#linter#Reset() call ale#linter#Reset()
unlet! g:capability_checked unlet! g:capability_checked
unlet! g:WaitCallback unlet! g:InitCallback
unlet! g:conn_id unlet! g:conn_id
unlet! g:Callback unlet! g:Callback
unlet! g:message_list unlet! g:message_list
@ -159,10 +161,10 @@ Execute(LSP symbol requests should be sent):
" We shouldn't register the callback yet. " We shouldn't register the callback yet.
AssertEqual '''''', string(g:Callback) AssertEqual '''''', string(g:Callback)
AssertEqual 'symbol_search', g:capability_checked AssertEqual type(function('type')), type(g:InitCallback)
AssertEqual type(function('type')), type(g:WaitCallback) call g:InitCallback()
call call(g:WaitCallback, [g:conn_id, '/foo/bar'])
AssertEqual 'symbol_search', g:capability_checked
AssertEqual AssertEqual
\ 'function(''ale#symbol#HandleLSPResponse'')', \ 'function(''ale#symbol#HandleLSPResponse'')',
\ string(g:Callback) \ string(g:Callback)
@ -182,6 +184,6 @@ Execute('-relative' argument should enable 'use_relative_paths' in HandleLSPResp
ALESymbolSearch -relative foo bar ALESymbolSearch -relative foo bar
call call(g:WaitCallback, [g:conn_id, '/foo/bar']) call g:InitCallback()
AssertEqual {'42': {'buffer': bufnr(''), 'use_relative_paths': 1}}, ale#symbol#GetMap() AssertEqual {'42': {'buffer': bufnr(''), 'use_relative_paths': 1}}, ale#symbol#GetMap()