#2132 - Make most foo_callback options work as foo
This commit is contained in:
parent
ffa45fa3fb
commit
f8aeb5c5a4
4 changed files with 198 additions and 41 deletions
|
@ -195,9 +195,16 @@ function! ale#linter#PreProcess(filetype, linter) abort
|
|||
endif
|
||||
|
||||
if !l:needs_address
|
||||
if has_key(a:linter, 'address_callback')
|
||||
throw '`address_callback` cannot be used when lsp != ''socket'''
|
||||
if has_key(a:linter, 'address') || has_key(a:linter, 'address_callback')
|
||||
throw '`address` or `address_callback` cannot be used when lsp != ''socket'''
|
||||
endif
|
||||
elseif has_key(a:linter, 'address')
|
||||
if type(a:linter.address) isnot v:t_string
|
||||
\&& type(a:linter.address) isnot v:t_func
|
||||
throw '`address` must be a String or Function if defined'
|
||||
endif
|
||||
|
||||
let l:obj.address = a:linter.address
|
||||
elseif has_key(a:linter, 'address_callback')
|
||||
let l:obj.address_callback = a:linter.address_callback
|
||||
|
||||
|
@ -205,7 +212,7 @@ function! ale#linter#PreProcess(filetype, linter) abort
|
|||
throw '`address_callback` must be a callback if defined'
|
||||
endif
|
||||
else
|
||||
throw '`address_callback` must be defined for getting the LSP address'
|
||||
throw '`address` or `address_callback` must be defined for getting the LSP address'
|
||||
endif
|
||||
|
||||
if l:needs_lsp_details
|
||||
|
@ -222,14 +229,17 @@ function! ale#linter#PreProcess(filetype, linter) abort
|
|||
endif
|
||||
else
|
||||
" Default to using the filetype as the language.
|
||||
let l:obj.language = get(a:linter, 'language', a:filetype)
|
||||
let l:Language = get(a:linter, 'language', a:filetype)
|
||||
|
||||
if type(l:obj.language) isnot v:t_string
|
||||
throw '`language` must be a string'
|
||||
if type(l:Language) is v:t_string
|
||||
" Make 'language_callback' return the 'language' value.
|
||||
let l:obj.language = l:Language
|
||||
let l:obj.language_callback = function('s:LanguageGetter')
|
||||
elseif type(l:Language) is v:t_func
|
||||
let l:obj.language_callback = l:Language
|
||||
else
|
||||
throw '`language` must be a String or Funcref'
|
||||
endif
|
||||
|
||||
" Make 'language_callback' return the 'language' value.
|
||||
let l:obj.language_callback = function('s:LanguageGetter')
|
||||
endif
|
||||
|
||||
let l:obj.project_root_callback = get(a:linter, 'project_root_callback')
|
||||
|
@ -259,6 +269,11 @@ function! ale#linter#PreProcess(filetype, linter) abort
|
|||
endif
|
||||
elseif has_key(a:linter, 'initialization_options')
|
||||
let l:obj.initialization_options = a:linter.initialization_options
|
||||
|
||||
if type(l:obj.initialization_options) isnot v:t_dict
|
||||
\&& type(l:obj.initialization_options) isnot v:t_func
|
||||
throw '`initialization_options` must be a String or Function if defined'
|
||||
endif
|
||||
endif
|
||||
|
||||
if has_key(a:linter, 'lsp_config_callback')
|
||||
|
@ -273,7 +288,8 @@ function! ale#linter#PreProcess(filetype, linter) abort
|
|||
endif
|
||||
elseif has_key(a:linter, 'lsp_config')
|
||||
if type(a:linter.lsp_config) isnot v:t_dict
|
||||
throw '`lsp_config` must be a Dictionary'
|
||||
\&& type(a:linter.lsp_config) isnot v:t_func
|
||||
throw '`lsp_config` must be a Dictionary or Function if defined'
|
||||
endif
|
||||
|
||||
let l:obj.lsp_config = a:linter.lsp_config
|
||||
|
@ -501,7 +517,11 @@ endfunction
|
|||
|
||||
" Given a buffer and linter, get the address for connecting to the server.
|
||||
function! ale#linter#GetAddress(buffer, linter) abort
|
||||
return has_key(a:linter, 'address_callback')
|
||||
\ ? ale#util#GetFunction(a:linter.address_callback)(a:buffer)
|
||||
let l:Address = has_key(a:linter, 'address_callback')
|
||||
\ ? function(a:linter.address_callback)
|
||||
\ : a:linter.address
|
||||
|
||||
return type(l:Address) is v:t_func
|
||||
\ ? l:Address(a:buffer)
|
||||
\ : l:Address
|
||||
endfunction
|
||||
|
|
|
@ -129,27 +129,39 @@ function! ale#lsp_linter#HandleLSPResponse(conn_id, response) abort
|
|||
endfunction
|
||||
|
||||
function! ale#lsp_linter#GetOptions(buffer, linter) abort
|
||||
let l:initialization_options = {}
|
||||
|
||||
if has_key(a:linter, 'initialization_options_callback')
|
||||
let l:initialization_options = ale#util#GetFunction(a:linter.initialization_options_callback)(a:buffer)
|
||||
elseif has_key(a:linter, 'initialization_options')
|
||||
let l:initialization_options = a:linter.initialization_options
|
||||
return ale#util#GetFunction(a:linter.initialization_options_callback)(a:buffer)
|
||||
endif
|
||||
|
||||
return l:initialization_options
|
||||
if has_key(a:linter, 'initialization_options')
|
||||
let l:Options = a:linter.initialization_options
|
||||
|
||||
if type(l:Options) is v:t_func
|
||||
let l:Options = l:Options(a:buffer)
|
||||
endif
|
||||
|
||||
return l:Options
|
||||
endif
|
||||
|
||||
return {}
|
||||
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
|
||||
return ale#util#GetFunction(a:linter.lsp_config_callback)(a:buffer)
|
||||
endif
|
||||
|
||||
return l:config
|
||||
if has_key(a:linter, 'lsp_config')
|
||||
let l:Config = a:linter.lsp_config
|
||||
|
||||
if type(l:Config) is v:t_func
|
||||
let l:Config = l:Config(a:buffer)
|
||||
endif
|
||||
|
||||
return l:Config
|
||||
endif
|
||||
|
||||
return {}
|
||||
endfunction
|
||||
|
||||
function! ale#lsp_linter#FindProjectRoot(buffer, linter) abort
|
||||
|
|
30
doc/ale.txt
30
doc/ale.txt
|
@ -3231,8 +3231,9 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
|
|||
|
||||
When this argument is set to `'socket'`, then the
|
||||
linter will be defined as an LSP linter via a TCP
|
||||
socket connection. `address_callback` must be set
|
||||
with a callback returning an address to connect to.
|
||||
socket connection. Either `address` or
|
||||
`address_callback` must be set.
|
||||
|
||||
ALE will not start a server automatically.
|
||||
|
||||
When this argument is not empty
|
||||
|
@ -3255,6 +3256,13 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
|
|||
An optional `lsp_config` or `lsp_config_callback` may
|
||||
be defined to pass configuration settings to the LSP.
|
||||
|
||||
`address` A |String| representing an address to connect to,
|
||||
or a |Funcref| accepting a buffer number and
|
||||
returning the |String|.
|
||||
|
||||
This argument must only be set if the `lsp` argument
|
||||
is set to `'socket'`.
|
||||
|
||||
`address_callback` A |String| or |Funcref| for a callback function
|
||||
accepting a buffer number. A |String| should be
|
||||
returned with an address to connect to.
|
||||
|
@ -3273,8 +3281,10 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
|
|||
is also set to a non-empty string.
|
||||
|
||||
`language` A |String| representing the name of the language
|
||||
being checked. This string will be sent to the LSP to
|
||||
tell it what type of language is being checked.
|
||||
being checked, or a |Funcref| accepting a buffer
|
||||
number and returning the |String|. This string will
|
||||
be sent to the LSP to tell it what type of language
|
||||
is being checked.
|
||||
|
||||
If this or `language_callback` isn't set, the
|
||||
language will default to the value of the filetype
|
||||
|
@ -3304,7 +3314,10 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
|
|||
setting can make it easier to guess the linter name
|
||||
by offering a few alternatives.
|
||||
|
||||
`initialization_options` A |Dictionary| of initialization options for LSPs.
|
||||
`initialization_options` A |Dictionary| of initialization options for LSPs,
|
||||
or a |Funcref| for a callback function accepting
|
||||
a buffer number and returning the |Dictionary|.
|
||||
|
||||
This will be fed (as JSON) to the LSP in the
|
||||
initialize command.
|
||||
|
||||
|
@ -3315,11 +3328,14 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
|
|||
This can be used in place of `initialization_options`
|
||||
when more complicated processing is needed.
|
||||
|
||||
`lsp_config` A |Dictionary| of configuration settings for LSPs.
|
||||
`lsp_config` A |Dictionary| for configuring a language server,
|
||||
or a |Funcref| for a callback function accepting
|
||||
a buffer number and returning the |Dictionary|.
|
||||
|
||||
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
|
||||
`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
|
||||
|
|
|
@ -461,6 +461,18 @@ Execute(PreProcess should complain about using language and language_callback to
|
|||
AssertThrows call ale#linter#PreProcess('testft', g:linter)
|
||||
AssertEqual 'Only one of `language` or `language_callback` should be set', g:vader_exception
|
||||
|
||||
Execute(PreProcess should complain about invalid language values):
|
||||
let g:linter = {
|
||||
\ 'name': 'x',
|
||||
\ 'lsp': 'socket',
|
||||
\ 'address_callback': 'X',
|
||||
\ 'language': 0,
|
||||
\ 'project_root_callback': 'x',
|
||||
\}
|
||||
|
||||
AssertThrows call ale#linter#PreProcess('testft', g:linter)
|
||||
AssertEqual '`language` must be a String or Funcref', g:vader_exception
|
||||
|
||||
Execute(PreProcess should use the filetype as the language string by default):
|
||||
let g:linter = {
|
||||
\ 'name': 'x',
|
||||
|
@ -471,6 +483,17 @@ Execute(PreProcess should use the filetype as the language string by default):
|
|||
|
||||
AssertEqual 'testft', ale#linter#PreProcess('testft', g:linter).language_callback(0)
|
||||
|
||||
Execute(PreProcess should allow language to be set to a callback):
|
||||
let g:linter = {
|
||||
\ 'name': 'x',
|
||||
\ 'lsp': 'socket',
|
||||
\ 'address_callback': 'X',
|
||||
\ 'language': {-> 'foo'},
|
||||
\ 'project_root_callback': 'x',
|
||||
\}
|
||||
|
||||
AssertEqual 'foo', ale#linter#PreProcess('testft', g:linter).language_callback(0)
|
||||
|
||||
Execute(PreProcess should require an address_callback for LSP socket configurations):
|
||||
let g:linter = {
|
||||
\ 'name': 'x',
|
||||
|
@ -478,7 +501,7 @@ Execute(PreProcess should require an address_callback for LSP socket configurati
|
|||
\}
|
||||
|
||||
AssertThrows call ale#linter#PreProcess('testft', g:linter)
|
||||
AssertEqual '`address_callback` must be defined for getting the LSP address', g:vader_exception
|
||||
AssertEqual '`address` or `address_callback` must be defined for getting the LSP address', g:vader_exception
|
||||
|
||||
Execute(PreProcess should complain about address_callback for non-LSP linters):
|
||||
let g:linter = {
|
||||
|
@ -490,7 +513,50 @@ Execute(PreProcess should complain about address_callback for non-LSP linters):
|
|||
\}
|
||||
|
||||
AssertThrows call ale#linter#PreProcess('testft', g:linter)
|
||||
AssertEqual '`address_callback` cannot be used when lsp != ''socket''', g:vader_exception
|
||||
AssertEqual '`address` or `address_callback` cannot be used when lsp != ''socket''', g:vader_exception
|
||||
|
||||
Execute(PreProcess accept valid address_callback values):
|
||||
let g:linter = ale#linter#PreProcess('testft', {
|
||||
\ 'name': 'x',
|
||||
\ 'lsp': 'socket',
|
||||
\ 'address_callback': {-> 'foo:123'},
|
||||
\ 'language': 'x',
|
||||
\ 'project_root_callback': 'x',
|
||||
\})
|
||||
|
||||
AssertEqual 'foo:123', ale#linter#GetAddress(0, g:linter)
|
||||
|
||||
Execute(PreProcess accept address as a String):
|
||||
let g:linter = ale#linter#PreProcess('testft', {
|
||||
\ 'name': 'x',
|
||||
\ 'lsp': 'socket',
|
||||
\ 'address': 'foo:123',
|
||||
\ 'language': 'x',
|
||||
\ 'project_root_callback': 'x',
|
||||
\})
|
||||
|
||||
AssertEqual 'foo:123', ale#linter#GetAddress(0, g:linter)
|
||||
|
||||
Execute(PreProcess accept address as a Function):
|
||||
let g:linter = ale#linter#PreProcess('testft', {
|
||||
\ 'name': 'x',
|
||||
\ 'lsp': 'socket',
|
||||
\ 'address': {-> 'foo:123'},
|
||||
\ 'language': 'x',
|
||||
\ 'project_root_callback': 'x',
|
||||
\})
|
||||
|
||||
AssertEqual 'foo:123', ale#linter#GetAddress(0, g:linter)
|
||||
|
||||
Execute(PreProcess should complain about invalid address values):
|
||||
AssertThrows call ale#linter#PreProcess('testft', {
|
||||
\ 'name': 'x',
|
||||
\ 'lsp': 'socket',
|
||||
\ 'address': 0,
|
||||
\ 'language': 'x',
|
||||
\ 'project_root_callback': 'x',
|
||||
\})
|
||||
AssertEqual '`address` must be a String or Function if defined', g:vader_exception
|
||||
|
||||
Execute(PreProcess should complain about using initialization_options and initialization_options_callback together):
|
||||
let g:linter = {
|
||||
|
@ -517,6 +583,41 @@ 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
|
||||
|
||||
Execute(PreProcess should throw when initialization_options is not a Dictionary or callback):
|
||||
AssertThrows call ale#linter#PreProcess('testft', {
|
||||
\ 'name': 'foo',
|
||||
\ 'lsp': 'socket',
|
||||
\ 'address_callback': 'X',
|
||||
\ 'language': 'x',
|
||||
\ 'project_root_callback': 'x',
|
||||
\ 'initialization_options': 0,
|
||||
\})
|
||||
AssertEqual '`initialization_options` must be a String or Function if defined', g:vader_exception
|
||||
|
||||
Execute(PreProcess should accept initialization_options as a Dictionary):
|
||||
let g:linter = ale#linter#PreProcess('testft', {
|
||||
\ 'name': 'foo',
|
||||
\ 'lsp': 'socket',
|
||||
\ 'address_callback': 'X',
|
||||
\ 'language': 'x',
|
||||
\ 'project_root_callback': 'x',
|
||||
\ 'initialization_options': {'foo': v:true},
|
||||
\})
|
||||
|
||||
AssertEqual {'foo': v:true}, ale#lsp_linter#GetOptions(0, g:linter)
|
||||
|
||||
Execute(PreProcess should accept initialization_options as a Funcref):
|
||||
let g:linter = ale#linter#PreProcess('testft', {
|
||||
\ 'name': 'foo',
|
||||
\ 'lsp': 'socket',
|
||||
\ 'address_callback': 'X',
|
||||
\ 'language': 'x',
|
||||
\ 'project_root_callback': 'x',
|
||||
\ 'initialization_options': {-> {'foo': v:true}},
|
||||
\})
|
||||
|
||||
AssertEqual {'foo': v:true}, ale#lsp_linter#GetOptions(0, g:linter)
|
||||
|
||||
Execute(PreProcess should complain about using lsp_config and lsp_config_callback together):
|
||||
let g:linter = {
|
||||
\ 'name': 'x',
|
||||
|
@ -543,22 +644,30 @@ Execute(PreProcess should throw when lsp_config_callback is not a callback):
|
|||
AssertEqual '`lsp_config_callback` must be a callback if defined', g:vader_exception
|
||||
|
||||
Execute(PreProcess should accept LSP configuration options via lsp_config):
|
||||
let g:ale_lsp_configuration = {
|
||||
\ 'foo': 'bar'
|
||||
\}
|
||||
|
||||
let g:linter = {
|
||||
\ 'name': 'x',
|
||||
\ 'lsp': 'socket',
|
||||
\ 'address_callback': 'X',
|
||||
\ 'language_callback': 'x',
|
||||
\ 'project_root_callback': 'x',
|
||||
\ 'lsp_config': g:ale_lsp_configuration,
|
||||
\ 'lsp_config': {'foo': 'bar'},
|
||||
\}
|
||||
|
||||
AssertEqual {'foo': 'bar'}, ale#linter#PreProcess('testft', g:linter).lsp_config
|
||||
AssertEqual {'foo': 'bar'}, ale#lsp_linter#GetConfig(0, g:linter)
|
||||
|
||||
Execute(PreProcess should throw when lsp_config is not a Dictionary):
|
||||
Execute(PreProcess should accept LSP configuration options via lsp_config as a function):
|
||||
let g:linter = {
|
||||
\ 'name': 'x',
|
||||
\ 'lsp': 'socket',
|
||||
\ 'address_callback': 'X',
|
||||
\ 'language_callback': 'x',
|
||||
\ 'project_root_callback': 'x',
|
||||
\ 'lsp_config': {-> {'foo': 'bar'}},
|
||||
\}
|
||||
|
||||
AssertEqual {'foo': 'bar'}, ale#lsp_linter#GetConfig(0, g:linter)
|
||||
|
||||
Execute(PreProcess should throw when lsp_config is not a Dictionary or Function):
|
||||
AssertThrows call ale#linter#PreProcess('testft', {
|
||||
\ 'name': 'foo',
|
||||
\ 'lsp': 'socket',
|
||||
|
@ -567,4 +676,4 @@ Execute(PreProcess should throw when lsp_config is not a Dictionary):
|
|||
\ 'project_root_callback': 'x',
|
||||
\ 'lsp_config': 'x',
|
||||
\})
|
||||
AssertEqual '`lsp_config` must be a Dictionary', g:vader_exception
|
||||
AssertEqual '`lsp_config` must be a Dictionary or Function if defined', g:vader_exception
|
||||
|
|
Reference in a new issue