From 857ca941d214a65b2168429bcd3b12df26f13a67 Mon Sep 17 00:00:00 2001 From: w0rp Date: Sun, 2 Jul 2017 13:17:24 +0100 Subject: [PATCH] Support an 'stdio' type for linter defintions, and require a command for LSP connections via programs --- ale_linters/typescript/tsserver.vim | 1 + autoload/ale/completion.vim | 9 ++-- autoload/ale/engine.vim | 13 ++---- autoload/ale/linter.vim | 36 +++++++++------ test/test_linter_defintion_processing.vader | 51 +++++++++++---------- 5 files changed, 59 insertions(+), 51 deletions(-) diff --git a/ale_linters/typescript/tsserver.vim b/ale_linters/typescript/tsserver.vim index 332e32e5..df979c6b 100644 --- a/ale_linters/typescript/tsserver.vim +++ b/ale_linters/typescript/tsserver.vim @@ -19,5 +19,6 @@ call ale#linter#Define('typescript', { \ 'name': 'tsserver', \ 'lsp': 'tsserver', \ 'executable_callback': 'ale_linters#typescript#tsserver#GetExecutable', +\ 'command_callback': 'ale_linters#typescript#tsserver#GetExecutable', \ 'callback': 'ale_linters#typescript#tsserver#Handle', \}) diff --git a/autoload/ale/completion.vim b/autoload/ale/completion.vim index 5f2346ea..c14dcd14 100644 --- a/autoload/ale/completion.vim +++ b/autoload/ale/completion.vim @@ -171,11 +171,10 @@ endfunction function! s:GetCompletionsForTSServer(linter) abort let l:buffer = bufnr('') - let l:executable = has_key(a:linter, 'executable_callback') - \ ? ale#util#GetFunction(a:linter.executable_callback)(l:buffer) - \ : a:linter.executable - let l:command = ale#job#PrepareCommand(l:executable) - + let l:executable = ale#linter#GetExecutable(l:buffer, a:linter) + let l:command = ale#job#PrepareCommand( + \ ale#linter#GetCommand(l:buffer, a:linter), + \) let l:id = ale#lsp#StartProgram( \ l:executable, \ l:command, diff --git a/autoload/ale/engine.vim b/autoload/ale/engine.vim index cee74911..acfc030a 100644 --- a/autoload/ale/engine.vim +++ b/autoload/ale/engine.vim @@ -502,11 +502,8 @@ function! ale#engine#ProcessChain(buffer, linter, chain_index, input) abort let l:input = [] let l:chain_index += 1 endwhile - elseif has_key(a:linter, 'command_callback') - " If there is a callback for generating a command, call that instead. - let l:command = ale#util#GetFunction(a:linter.command_callback)(a:buffer) else - let l:command = a:linter.command + let l:command = ale#linter#GetCommand(a:buffer, a:linter) endif if empty(l:command) @@ -563,7 +560,9 @@ endfunction function! s:CheckWithTSServer(buffer, linter, executable) abort let l:info = g:ale_buffer_info[a:buffer] - let l:command = ale#job#PrepareCommand(a:executable) + let l:command = ale#job#PrepareCommand( + \ ale#linter#GetCommand(a:buffer, a:linter), + \) let l:id = ale#lsp#StartProgram( \ a:executable, \ l:command, @@ -598,9 +597,7 @@ endfunction function! ale#engine#Invoke(buffer, linter) abort if empty(a:linter.lsp) || a:linter.lsp ==# 'tsserver' - let l:executable = has_key(a:linter, 'executable_callback') - \ ? ale#util#GetFunction(a:linter.executable_callback)(a:buffer) - \ : a:linter.executable + let l:executable = ale#linter#GetExecutable(a:buffer, a:linter) " Run this program if it can be executed. if s:IsExecutable(l:executable) diff --git a/autoload/ale/linter.vim b/autoload/ale/linter.vim index 3c2ddd35..3419f5af 100644 --- a/autoload/ale/linter.vim +++ b/autoload/ale/linter.vim @@ -63,25 +63,18 @@ function! ale#linter#PreProcess(linter) abort throw '`callback` must be defined with a callback to accept output' endif - let l:needs_executable = 0 - let l:needs_address = 0 - let l:needs_command = 0 + let l:needs_address = l:obj.lsp ==# 'socket' + let l:needs_executable = l:obj.lsp !=# 'socket' + let l:needs_command = l:obj.lsp !=# 'socket' - if l:obj.lsp ==# 'tsserver' - let l:needs_executable = 1 - elseif l:obj.lsp ==# 'lsp' - let l:needs_address = 1 - elseif !empty(l:obj.lsp) + if index(['', 'socket', 'stdio', 'tsserver'], l:obj.lsp) < 0 throw '`lsp` must be either `''lsp''` or `''tsserver''` if defined' - else - let l:needs_executable = 1 - let l:needs_command = 1 endif if !l:needs_executable if has_key(a:linter, 'executable') \|| has_key(a:linter, 'executable_callback') - throw '`executable` and `executable_callback` cannot be used when lsp == ''lsp''' + throw '`executable` and `executable_callback` cannot be used when lsp == ''socket''' endif elseif has_key(a:linter, 'executable_callback') let l:obj.executable_callback = a:linter.executable_callback @@ -103,7 +96,7 @@ function! ale#linter#PreProcess(linter) abort if has_key(a:linter, 'command') \|| has_key(a:linter, 'command_callback') \|| has_key(a:linter, 'command_chain') - throw '`command` and `command_callback` and `command_chain` cannot be used when `lsp` is set' + throw '`command` and `command_callback` and `command_chain` cannot be used when lsp == ''socket''' endif elseif has_key(a:linter, 'command_chain') let l:obj.command_chain = a:linter.command_chain @@ -167,7 +160,7 @@ function! ale#linter#PreProcess(linter) abort if !l:needs_address if has_key(a:linter, 'address_callback') - throw '`address_callback` cannot be used when lsp != ''lsp''' + throw '`address_callback` cannot be used when lsp != ''socket''' endif elseif has_key(a:linter, 'address_callback') let l:obj.address_callback = a:linter.address_callback @@ -334,3 +327,18 @@ function! ale#linter#Get(original_filetypes) abort return reverse(l:combined_linters) endfunction + +" Given a buffer and linter, get the executable String for the linter. +function! ale#linter#GetExecutable(buffer, linter) abort + return has_key(a:linter, 'executable_callback') + \ ? ale#util#GetFunction(a:linter.executable_callback)(a:buffer) + \ : a:linter.executable +endfunction + +" Given a buffer and linter, get the command String for the linter. +" The command_chain key is not supported. +function! ale#linter#GetCommand(buffer, linter) abort + return has_key(a:linter, 'command_callback') + \ ? ale#util#GetFunction(a:linter.command_callback)(a:buffer) + \ : a:linter.command +endfunction diff --git a/test/test_linter_defintion_processing.vader b/test/test_linter_defintion_processing.vader index 9c880c20..7ff8ddbf 100644 --- a/test/test_linter_defintion_processing.vader +++ b/test/test_linter_defintion_processing.vader @@ -370,6 +370,7 @@ Execute(PreProcess should accept tsserver LSP configuration): let g:linter = { \ 'name': 'x', \ 'executable': 'x', + \ 'command': 'x', \ 'lsp': 'tsserver', \ 'callback': 'x', \} @@ -379,46 +380,48 @@ Execute(PreProcess should accept tsserver LSP configuration): call remove(g:linter, 'executable') let g:linter.executable_callback = 'X' - call ale#linter#PreProcess(g:linter).lsp - -Execute(PreProcess should complain about commands being set for LSP configurations): - let g:linter = { - \ 'name': 'x', - \ 'executable': 'x', - \ 'lsp': 'tsserver', - \ 'command': 'x', - \ 'callback': 'x', - \} - - AssertThrows call ale#linter#PreProcess(g:linter) - AssertEqual '`command` and `command_callback` and `command_chain` cannot be used when `lsp` is set', g:vader_exception + call ale#linter#PreProcess(g:linter) call remove(g:linter, 'command') let g:linter.command_callback = 'X' - AssertThrows call ale#linter#PreProcess(g:linter) - AssertEqual '`command` and `command_callback` and `command_chain` cannot be used when `lsp` is set', g:vader_exception + call ale#linter#PreProcess(g:linter) - call remove(g:linter, 'command_callback') - let g:linter.command_chain = [] +Execute(PreProcess should accept stdio LSP configuration): + let g:linter = { + \ 'name': 'x', + \ 'executable': 'x', + \ 'command': 'x', + \ 'lsp': 'stdio', + \ 'callback': 'x', + \} - AssertThrows call ale#linter#PreProcess(g:linter) - AssertEqual '`command` and `command_callback` and `command_chain` cannot be used when `lsp` is set', g:vader_exception + AssertEqual 'stdio', ale#linter#PreProcess(g:linter).lsp + + call remove(g:linter, 'executable') + let g:linter.executable_callback = 'X' + + call ale#linter#PreProcess(g:linter) + + call remove(g:linter, 'command') + let g:linter.command_callback = 'X' + + call ale#linter#PreProcess(g:linter) Execute(PreProcess should accept LSP server configurations): let g:linter = { \ 'name': 'x', - \ 'lsp': 'lsp', + \ 'lsp': 'socket', \ 'callback': 'x', \ 'address_callback': 'X', \} - AssertEqual 'lsp', ale#linter#PreProcess(g:linter).lsp + AssertEqual 'socket', ale#linter#PreProcess(g:linter).lsp -Execute(PreProcess should require an address_callback for LSP server configurations): +Execute(PreProcess should require an address_callback for LSP socket configurations): let g:linter = { \ 'name': 'x', - \ 'lsp': 'lsp', + \ 'lsp': 'socket', \ 'callback': 'x', \} @@ -435,4 +438,4 @@ Execute(PreProcess should complain about address_callback for non-LSP linters): \} AssertThrows call ale#linter#PreProcess(g:linter) - AssertEqual '`address_callback` cannot be used when lsp != ''lsp''', g:vader_exception + AssertEqual '`address_callback` cannot be used when lsp != ''socket''', g:vader_exception