#2132 - Make most foo_callback options work as foo

This commit is contained in:
w0rp 2019-02-22 00:35:53 +00:00
parent ffa45fa3fb
commit f8aeb5c5a4
No known key found for this signature in database
GPG key ID: 0FC1ECAA8C81CD83
4 changed files with 198 additions and 41 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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