summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorw0rp <devw0rp@gmail.com>2019-02-22 00:35:53 +0000
committerw0rp <devw0rp@gmail.com>2019-02-22 00:35:53 +0000
commitf8aeb5c5a45b57a35d1572176e345173c6e4de61 (patch)
tree15fb106b46f94d16f90e73fabd6fc7ac03ccbb03
parentffa45fa3fb44ade28c64aa8f0a21acd71c903a2a (diff)
downloadale-f8aeb5c5a45b57a35d1572176e345173c6e4de61.zip
#2132 - Make most foo_callback options work as foo
-rw-r--r--autoload/ale/linter.vim46
-rw-r--r--autoload/ale/lsp_linter.vim36
-rw-r--r--doc/ale.txt30
-rw-r--r--test/test_linter_defintion_processing.vader125
4 files changed, 197 insertions, 40 deletions
diff --git a/autoload/ale/linter.vim b/autoload/ale/linter.vim
index 8c9f83ad..dba59893 100644
--- a/autoload/ale/linter.vim
+++ b/autoload/ale/linter.vim
@@ -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)
-
- if type(l:obj.language) isnot v:t_string
- throw '`language` must be a string'
+ let l:Language = get(a:linter, 'language', a:filetype)
+
+ 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
diff --git a/autoload/ale/lsp_linter.vim b/autoload/ale/lsp_linter.vim
index 610d897f..b92f5104 100644
--- a/autoload/ale/lsp_linter.vim
+++ b/autoload/ale/lsp_linter.vim
@@ -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
+
+ 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 l:initialization_options
+ 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
+
+ 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 l:config
+ return {}
endfunction
function! ale#lsp_linter#FindProjectRoot(buffer, linter) abort
diff --git a/doc/ale.txt b/doc/ale.txt
index 083b0507..ca895fe0 100644
--- a/doc/ale.txt
+++ b/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
diff --git a/test/test_linter_defintion_processing.vader b/test/test_linter_defintion_processing.vader
index 0f54cf0e..a78b9838 100644
--- a/test/test_linter_defintion_processing.vader
+++ b/test/test_linter_defintion_processing.vader
@@ -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': {'foo': 'bar'},
\}
+ AssertEqual {'foo': 'bar'}, ale#lsp_linter#GetConfig(0, g:linter)
+
+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': 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 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