diff options
author | w0rp <devw0rp@gmail.com> | 2019-02-27 23:26:32 +0000 |
---|---|---|
committer | w0rp <devw0rp@gmail.com> | 2019-02-27 23:26:32 +0000 |
commit | c4328f2a31a8acac96ca8d7615231812bad700bf (patch) | |
tree | 62e382a04342fda2deed82364ef4ade2ce03f7a7 /autoload | |
parent | 37a1d24a36399338a3238f94a92d4db97b8255f3 (diff) | |
download | ale-c4328f2a31a8acac96ca8d7615231812bad700bf.zip |
#2132 - Support deferred execution for LSP executables, commands, and addresses
Diffstat (limited to 'autoload')
-rw-r--r-- | autoload/ale/lsp.vim | 9 | ||||
-rw-r--r-- | autoload/ale/lsp_linter.vim | 139 |
2 files changed, 111 insertions, 37 deletions
diff --git a/autoload/ale/lsp.vim b/autoload/ale/lsp.vim index 8da95ef6..7186d2a9 100644 --- a/autoload/ale/lsp.vim +++ b/autoload/ale/lsp.vim @@ -57,6 +57,15 @@ function! ale#lsp#RemoveConnectionWithID(id) abort endif endfunction +function! ale#lsp#ResetConnections() abort + let s:connections = {} +endfunction + +" Used only in tests. +function! ale#lsp#GetConnections() abort + return s:connections +endfunction + " This is only needed for tests function! ale#lsp#MarkDocumentAsOpen(id, buffer) abort let l:conn = get(s:connections, a:id, {}) diff --git a/autoload/ale/lsp_linter.vim b/autoload/ale/lsp_linter.vim index d0f66bf7..d544916a 100644 --- a/autoload/ale/lsp_linter.vim +++ b/autoload/ale/lsp_linter.vim @@ -228,69 +228,134 @@ function! ale#lsp_linter#OnInit(linter, details, Callback) abort call a:Callback(a:linter, a:details) endfunction -" Given a buffer, an LSP linter, start up an LSP linter and get ready to -" receive messages for the document. -function! ale#lsp_linter#StartLSP(buffer, linter, Callback) abort - let l:command = '' - let l:address = '' - let l:root = ale#lsp_linter#FindProjectRoot(a:buffer, a:linter) - - if empty(l:root) && a:linter.lsp isnot# 'tsserver' - " 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. - return 0 - endif - - let l:init_options = ale#lsp_linter#GetOptions(a:buffer, a:linter) - - if a:linter.lsp is# 'socket' - let l:address = ale#linter#GetAddress(a:buffer, a:linter) - let l:conn_id = ale#lsp#Register(l:address, l:root, l:init_options) - let l:ready = ale#lsp#ConnectToAddress(l:conn_id, l:address) +function! s:StartLSP(options, address, executable, command) abort + let l:buffer = a:options.buffer + let l:linter = a:options.linter + let l:root = a:options.root + let l:Callback = a:options.callback + + let l:init_options = ale#lsp_linter#GetOptions(l:buffer, l:linter) + + if l:linter.lsp is# 'socket' + let l:conn_id = ale#lsp#Register(a:address, l:root, l:init_options) + let l:ready = ale#lsp#ConnectToAddress(l:conn_id, a:address) + let l:command = '' else - let l:executable = ale#linter#GetExecutable(a:buffer, a:linter) - - if !ale#engine#IsExecutable(a:buffer, l:executable) - return 0 - endif - - let l:conn_id = ale#lsp#Register(l:executable, l:root, l:init_options) + let l:conn_id = ale#lsp#Register(a:executable, l:root, l:init_options) " tsserver behaves differently, so tell the LSP API that it is tsserver. - if a:linter.lsp is# 'tsserver' + if l:linter.lsp is# 'tsserver' call ale#lsp#MarkConnectionAsTsserver(l:conn_id) endif - let l:command = ale#linter#GetCommand(a:buffer, a:linter) - " Format the command, so %e can be formatted into it. - let l:command = ale#command#FormatCommand(a:buffer, l:executable, l:command, 0, v:false)[1] - let l:command = ale#job#PrepareCommand(a:buffer, l:command) - let l:ready = ale#lsp#StartProgram(l:conn_id, l:executable, l:command) + let l:command = ale#command#FormatCommand(l:buffer, a:executable, a:command, 0, v:false)[1] + let l:command = ale#job#PrepareCommand(l:buffer, l:command) + let l:ready = ale#lsp#StartProgram(l:conn_id, a:executable, l:command) endif if !l:ready - if g:ale_history_enabled && !empty(l:command) - call ale#history#Add(a:buffer, 'failed', l:conn_id, l:command) + if g:ale_history_enabled && !empty(a:command) + call ale#history#Add(l:buffer, 'failed', l:conn_id, a:command) endif return 0 endif - let l:details = { - \ 'buffer': a:buffer, + \ 'buffer': l:buffer, \ 'connection_id': l:conn_id, \ 'command': l:command, \ 'project_root': l:root, \} call ale#lsp#OnInit(l:conn_id, {-> - \ ale#lsp_linter#OnInit(a:linter, l:details, a:Callback) + \ ale#lsp_linter#OnInit(l:linter, l:details, l:Callback) \}) return 1 endfunction +function! s:StartWithAddress(options, address) abort + if ale#command#IsDeferred(a:address) + let a:address.result_callback = { + \ address -> s:StartWithAddress(a:options, address) + \} + + return 1 + endif + + if empty(a:address) + return 0 + endif + + return s:StartLSP(a:options, a:address, '', '') +endfunction + +function! s:StartWithCommand(options, executable, command) abort + if ale#command#IsDeferred(a:command) + let a:command.result_callback = { + \ command -> s:StartWithCommand(a:options, a:executable, command) + \} + + return 1 + endif + + if empty(a:command) + return 0 + endif + + return s:StartLSP(a:options, '', a:executable, a:command) +endfunction + +function! s:StartIfExecutable(options, executable) abort + if ale#command#IsDeferred(a:executable) + let a:executable.result_callback = { + \ executable -> s:StartIfExecutable(a:options, executable) + \} + + return 1 + endif + + if !ale#engine#IsExecutable(a:options.buffer, a:executable) + return 0 + endif + + let l:command = ale#linter#GetCommand(a:options.buffer, a:options.linter) + + return s:StartWithCommand(a:options, a:executable, l:command) +endfunction + +" Given a buffer, an LSP linter, start up an LSP linter and get ready to +" receive messages for the document. +function! ale#lsp_linter#StartLSP(buffer, linter, Callback) abort + let l:command = '' + let l:address = '' + let l:root = ale#lsp_linter#FindProjectRoot(a:buffer, a:linter) + + if empty(l:root) && a:linter.lsp isnot# 'tsserver' + " 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. + return 0 + endif + + let l:options = { + \ 'buffer': a:buffer, + \ 'linter': a:linter, + \ 'callback': a:Callback, + \ 'root': l:root, + \} + + if a:linter.lsp is# 'socket' + let l:address = ale#linter#GetAddress(a:buffer, a:linter) + + return s:StartWithAddress(l:options, l:address) + endif + + let l:executable = ale#linter#GetExecutable(a:buffer, a:linter) + + return s:StartIfExecutable(l:options, l:executable) +endfunction + function! s:CheckWithLSP(linter, details) abort let l:buffer = a:details.buffer let l:info = get(g:ale_buffer_info, l:buffer) |