Add a lsp_config_callback
linter option
This is the callback-based variant of the existing `lsp_config` linter option. It serves the same purpose but can be used when more complicated processing is needed. `lsp_config` and `lsp_config_callback` are mutually exclusive options; if both an given, a linter preprocessing error will be raised. The runtime logic has been wrapped in `ale#lsp_linter#GetConfig` for convenience, similar to `ale#lsp_linter#GetOptions`. This also adds documentation and an `AssertLSPConfig` test function for completeness.
This commit is contained in:
parent
20e4e3f9db
commit
b5a7593577
9 changed files with 85 additions and 7 deletions
|
@ -85,6 +85,14 @@ function! ale#assert#LSPOptions(expected_options) abort
|
||||||
AssertEqual a:expected_options, l:initialization_options
|
AssertEqual a:expected_options, l:initialization_options
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! ale#assert#LSPConfig(expected_config) abort
|
||||||
|
let l:buffer = bufnr('')
|
||||||
|
let l:linter = s:GetLinter()
|
||||||
|
let l:config = ale#lsp_linter#GetConfig(l:buffer, l:linter)
|
||||||
|
|
||||||
|
AssertEqual a:expected_config, l:config
|
||||||
|
endfunction
|
||||||
|
|
||||||
function! ale#assert#LSPLanguage(expected_language) abort
|
function! ale#assert#LSPLanguage(expected_language) abort
|
||||||
let l:buffer = bufnr('')
|
let l:buffer = bufnr('')
|
||||||
let l:linter = s:GetLinter()
|
let l:linter = s:GetLinter()
|
||||||
|
@ -147,6 +155,7 @@ function! ale#assert#SetUpLinterTest(filetype, name) abort
|
||||||
command! -nargs=+ AssertLinter :call ale#assert#Linter(<args>)
|
command! -nargs=+ AssertLinter :call ale#assert#Linter(<args>)
|
||||||
command! -nargs=0 AssertLinterNotExecuted :call ale#assert#LinterNotExecuted()
|
command! -nargs=0 AssertLinterNotExecuted :call ale#assert#LinterNotExecuted()
|
||||||
command! -nargs=+ AssertLSPOptions :call ale#assert#LSPOptions(<args>)
|
command! -nargs=+ AssertLSPOptions :call ale#assert#LSPOptions(<args>)
|
||||||
|
command! -nargs=+ AssertLSPConfig :call ale#assert#LSPConfig(<args>)
|
||||||
command! -nargs=+ AssertLSPLanguage :call ale#assert#LSPLanguage(<args>)
|
command! -nargs=+ AssertLSPLanguage :call ale#assert#LSPLanguage(<args>)
|
||||||
command! -nargs=+ AssertLSPProject :call ale#assert#LSPProject(<args>)
|
command! -nargs=+ AssertLSPProject :call ale#assert#LSPProject(<args>)
|
||||||
command! -nargs=+ AssertLSPAddress :call ale#assert#LSPAddress(<args>)
|
command! -nargs=+ AssertLSPAddress :call ale#assert#LSPAddress(<args>)
|
||||||
|
@ -172,6 +181,10 @@ function! ale#assert#TearDownLinterTest() abort
|
||||||
delcommand AssertLSPOptions
|
delcommand AssertLSPOptions
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if exists(':AssertLSPConfig')
|
||||||
|
delcommand AssertLSPConfig
|
||||||
|
endif
|
||||||
|
|
||||||
if exists(':AssertLSPLanguage')
|
if exists(':AssertLSPLanguage')
|
||||||
delcommand AssertLSPLanguage
|
delcommand AssertLSPLanguage
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -257,7 +257,17 @@ function! ale#linter#PreProcess(filetype, linter) abort
|
||||||
let l:obj.initialization_options = a:linter.initialization_options
|
let l:obj.initialization_options = a:linter.initialization_options
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if has_key(a:linter, 'lsp_config')
|
if has_key(a:linter, 'lsp_config_callback')
|
||||||
|
if has_key(a:linter, 'lsp_config')
|
||||||
|
throw 'Only one of `lsp_config` or `lsp_config_callback` should be set'
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:obj.lsp_config_callback = a:linter.lsp_config_callback
|
||||||
|
|
||||||
|
if !s:IsCallback(l:obj.lsp_config_callback)
|
||||||
|
throw '`lsp_config_callback` must be a callback if defined'
|
||||||
|
endif
|
||||||
|
elseif has_key(a:linter, 'lsp_config')
|
||||||
if type(a:linter.lsp_config) isnot v:t_dict
|
if type(a:linter.lsp_config) isnot v:t_dict
|
||||||
throw '`lsp_config` must be a Dictionary'
|
throw '`lsp_config` must be a Dictionary'
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -140,6 +140,18 @@ function! ale#lsp_linter#GetOptions(buffer, linter) abort
|
||||||
return l:initialization_options
|
return l:initialization_options
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! ale#lsp_linter#GetConfig(buffer, linter) abort
|
||||||
|
let l:config = {}
|
||||||
|
|
||||||
|
if has_key(a:linter, 'lsp_config_callback')
|
||||||
|
let l:config = ale#util#GetFunction(a:linter.lsp_config_callback)(a:buffer)
|
||||||
|
elseif has_key(a:linter, 'lsp_config')
|
||||||
|
let l:config = a:linter.lsp_config
|
||||||
|
endif
|
||||||
|
|
||||||
|
return l:config
|
||||||
|
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) abort
|
||||||
|
@ -188,14 +200,16 @@ function! ale#lsp_linter#StartLSP(buffer, linter) abort
|
||||||
call ale#lsp#MarkConnectionAsTsserver(l:conn_id)
|
call ale#lsp#MarkConnectionAsTsserver(l:conn_id)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let l:language_id = ale#util#GetFunction(a:linter.language_callback)(a:buffer)
|
let l:config = ale#lsp_linter#GetConfig(a:buffer, a:linter)
|
||||||
|
|
||||||
if !empty(get(a:linter, 'lsp_config'))
|
if !empty(l:config)
|
||||||
" set LSP configuration options (workspace/didChangeConfiguration)
|
" set LSP configuration options (workspace/didChangeConfiguration)
|
||||||
let l:config_message = ale#lsp#message#DidChangeConfiguration(a:buffer, a:linter.lsp_config)
|
let l:config_message = ale#lsp#message#DidChangeConfiguration(a:buffer, l:config)
|
||||||
call ale#lsp#Send(l:conn_id, l:config_message)
|
call ale#lsp#Send(l:conn_id, l:config_message)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
let l:language_id = ale#util#GetFunction(a:linter.language_callback)(a:buffer)
|
||||||
|
|
||||||
let l:details = {
|
let l:details = {
|
||||||
\ 'buffer': a:buffer,
|
\ 'buffer': a:buffer,
|
||||||
\ 'connection_id': l:conn_id,
|
\ 'connection_id': l:conn_id,
|
||||||
|
|
|
@ -306,6 +306,7 @@ given the above setup are as follows.
|
||||||
`AssertLinterNotExecuted` - Check that linters will not be executed.
|
`AssertLinterNotExecuted` - Check that linters will not be executed.
|
||||||
`AssertLSPLanguage language` - Check the language given to an LSP server.
|
`AssertLSPLanguage language` - Check the language given to an LSP server.
|
||||||
`AssertLSPOptions options_dict` - Check the options given to an LSP server.
|
`AssertLSPOptions options_dict` - Check the options given to an LSP server.
|
||||||
|
`AssertLSPConfig config_dict` - Check the config given to an LSP server.
|
||||||
`AssertLSPProject project_root` - Check the root given to an LSP server.
|
`AssertLSPProject project_root` - Check the root given to an LSP server.
|
||||||
`AssertLSPAddress address` - Check the address to an LSP server.
|
`AssertLSPAddress address` - Check the address to an LSP server.
|
||||||
|
|
||||||
|
|
13
doc/ale.txt
13
doc/ale.txt
|
@ -2666,6 +2666,9 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
|
||||||
`initialization_options_callback` may be defined to
|
`initialization_options_callback` may be defined to
|
||||||
pass initialization options to the LSP.
|
pass initialization options to the LSP.
|
||||||
|
|
||||||
|
An optional `lsp_config` or `lsp_config_callback` may
|
||||||
|
be defined to pass configuration settings to the LSP.
|
||||||
|
|
||||||
`address_callback` A |String| or |Funcref| for a callback function
|
`address_callback` A |String| or |Funcref| for a callback function
|
||||||
accepting a buffer number. A |String| should be
|
accepting a buffer number. A |String| should be
|
||||||
returned with an address to connect to.
|
returned with an address to connect to.
|
||||||
|
@ -2726,6 +2729,16 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
|
||||||
This can be used in place of `initialization_options`
|
This can be used in place of `initialization_options`
|
||||||
when more complicated processing is needed.
|
when more complicated processing is needed.
|
||||||
|
|
||||||
|
`lsp_config` A |Dictionary| of configuration settings for LSPs.
|
||||||
|
This will be fed (as JSON) to the LSP in the
|
||||||
|
workspace/didChangeConfiguration command.
|
||||||
|
|
||||||
|
`lsp_config_callback` A |String| or |Funcref| for a callback function
|
||||||
|
accepting a buffer number. A |Dictionary| should be
|
||||||
|
returned for configuration settings to pass the LSP.
|
||||||
|
This can be used in place of `lsp_config` when more
|
||||||
|
complicated processing is needed.
|
||||||
|
|
||||||
Only one of `command`, `command_callback`, or `command_chain` should be
|
Only one of `command`, `command_callback`, or `command_chain` should be
|
||||||
specified. `command_callback` is generally recommended when a command string
|
specified. `command_callback` is generally recommended when a command string
|
||||||
needs to be generated dynamically, or any global options are used.
|
needs to be generated dynamically, or any global options are used.
|
||||||
|
|
|
@ -26,4 +26,5 @@ Execute(should set correct LSP values):
|
||||||
|
|
||||||
AssertLSPLanguage 'elixir'
|
AssertLSPLanguage 'elixir'
|
||||||
AssertLSPOptions {}
|
AssertLSPOptions {}
|
||||||
|
AssertLSPConfig {}
|
||||||
AssertLSPProject ale#path#Simplify(g:dir . '/mix_paths/wrapped_project')
|
AssertLSPProject ale#path#Simplify(g:dir . '/mix_paths/wrapped_project')
|
||||||
|
|
|
@ -56,7 +56,7 @@ Execute(should set go-langserver for go app1):
|
||||||
call ale#test#SetFilename('go_paths/go1/prj1/file.go')
|
call ale#test#SetFilename('go_paths/go1/prj1/file.go')
|
||||||
|
|
||||||
AssertLSPLanguage 'go'
|
AssertLSPLanguage 'go'
|
||||||
AssertLSPOptions {}
|
AssertLSPConfig {}
|
||||||
AssertLSPProject ale#path#Simplify(g:dir . '/go_paths/go1')
|
AssertLSPProject ale#path#Simplify(g:dir . '/go_paths/go1')
|
||||||
|
|
||||||
Execute(should set go-langserver for go app2):
|
Execute(should set go-langserver for go app2):
|
||||||
|
@ -64,4 +64,5 @@ Execute(should set go-langserver for go app2):
|
||||||
|
|
||||||
AssertLSPLanguage 'go'
|
AssertLSPLanguage 'go'
|
||||||
AssertLSPOptions {}
|
AssertLSPOptions {}
|
||||||
|
AssertLSPConfig {}
|
||||||
AssertLSPProject ale#path#Simplify(g:dir . '/go_paths/go2')
|
AssertLSPProject ale#path#Simplify(g:dir . '/go_paths/go2')
|
||||||
|
|
|
@ -9,11 +9,13 @@ Execute(should set sbtserver for sbt project with build.sbt):
|
||||||
call ale#test#SetFilename('../scala_fixtures/valid_sbt_project/Main.scala')
|
call ale#test#SetFilename('../scala_fixtures/valid_sbt_project/Main.scala')
|
||||||
AssertLSPLanguage 'scala'
|
AssertLSPLanguage 'scala'
|
||||||
AssertLSPOptions {}
|
AssertLSPOptions {}
|
||||||
|
AssertLSPConfig {}
|
||||||
AssertLSPProject ale#path#Simplify(g:dir . 'command_callback/../scala_fixtures/valid_sbt_project')
|
AssertLSPProject ale#path#Simplify(g:dir . 'command_callback/../scala_fixtures/valid_sbt_project')
|
||||||
AssertLSPAddress '127.0.0.1:4273'
|
AssertLSPAddress '127.0.0.1:4273'
|
||||||
Execute(should not set sbtserver for sbt project without build.sbt):
|
Execute(should not set sbtserver for sbt project without build.sbt):
|
||||||
call ale#test#SetFilename('../scala_fixtures/invalid_sbt_project/Main.scala')
|
call ale#test#SetFilename('../scala_fixtures/invalid_sbt_project/Main.scala')
|
||||||
AssertLSPLanguage 'scala'
|
AssertLSPLanguage 'scala'
|
||||||
AssertLSPOptions {}
|
AssertLSPOptions {}
|
||||||
|
AssertLSPConfig {}
|
||||||
AssertLSPProject ''
|
AssertLSPProject ''
|
||||||
AssertLSPAddress '127.0.0.1:4273'
|
AssertLSPAddress '127.0.0.1:4273'
|
||||||
|
|
|
@ -501,6 +501,31 @@ Execute(PreProcess should throw when initialization_options_callback is not a ca
|
||||||
\})
|
\})
|
||||||
AssertEqual '`initialization_options_callback` must be a callback if defined', g:vader_exception
|
AssertEqual '`initialization_options_callback` must be a callback if defined', g:vader_exception
|
||||||
|
|
||||||
|
Execute(PreProcess should complain about using lsp_config and lsp_config_callback together):
|
||||||
|
let g:linter = {
|
||||||
|
\ 'name': 'x',
|
||||||
|
\ 'lsp': 'socket',
|
||||||
|
\ 'address_callback': 'X',
|
||||||
|
\ 'language': 'x',
|
||||||
|
\ 'project_root_callback': 'x',
|
||||||
|
\ 'lsp_config': 'x',
|
||||||
|
\ 'lsp_config_callback': 'x',
|
||||||
|
\}
|
||||||
|
|
||||||
|
AssertThrows call ale#linter#PreProcess('testft', g:linter)
|
||||||
|
AssertEqual 'Only one of `lsp_config` or `lsp_config_callback` should be set', g:vader_exception
|
||||||
|
|
||||||
|
Execute(PreProcess should throw when lsp_config_callback is not a callback):
|
||||||
|
AssertThrows call ale#linter#PreProcess('testft', {
|
||||||
|
\ 'name': 'foo',
|
||||||
|
\ 'lsp': 'socket',
|
||||||
|
\ 'address_callback': 'X',
|
||||||
|
\ 'language': 'x',
|
||||||
|
\ 'project_root_callback': 'x',
|
||||||
|
\ 'lsp_config_callback': {},
|
||||||
|
\})
|
||||||
|
AssertEqual '`lsp_config_callback` must be a callback if defined', g:vader_exception
|
||||||
|
|
||||||
Execute(PreProcess should accept LSP configuration options via lsp_config):
|
Execute(PreProcess should accept LSP configuration options via lsp_config):
|
||||||
let g:ale_lsp_configuration = {
|
let g:ale_lsp_configuration = {
|
||||||
\ 'foo': 'bar'
|
\ 'foo': 'bar'
|
||||||
|
@ -517,7 +542,6 @@ Execute(PreProcess should accept LSP configuration options via lsp_config):
|
||||||
|
|
||||||
AssertEqual {'foo': 'bar'}, ale#linter#PreProcess('testft', g:linter).lsp_config
|
AssertEqual {'foo': 'bar'}, ale#linter#PreProcess('testft', g:linter).lsp_config
|
||||||
|
|
||||||
|
|
||||||
Execute(PreProcess should throw when lsp_config is not a Dictionary):
|
Execute(PreProcess should throw when lsp_config is not a Dictionary):
|
||||||
AssertThrows call ale#linter#PreProcess('testft', {
|
AssertThrows call ale#linter#PreProcess('testft', {
|
||||||
\ 'name': 'foo',
|
\ 'name': 'foo',
|
||||||
|
@ -528,4 +552,3 @@ Execute(PreProcess should throw when lsp_config is not a Dictionary):
|
||||||
\ 'lsp_config': 'x',
|
\ 'lsp_config': 'x',
|
||||||
\})
|
\})
|
||||||
AssertEqual '`lsp_config` must be a Dictionary', g:vader_exception
|
AssertEqual '`lsp_config` must be a Dictionary', g:vader_exception
|
||||||
|
|
||||||
|
|
Reference in a new issue