summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--autoload/ale/assert.vim13
-rw-r--r--autoload/ale/linter.vim12
-rw-r--r--autoload/ale/lsp.vim21
-rw-r--r--autoload/ale/lsp_linter.vim21
-rw-r--r--doc/ale-development.txt1
-rw-r--r--doc/ale.txt13
-rw-r--r--test/command_callback/test_elixir_ls_command_callbacks.vader1
-rw-r--r--test/command_callback/test_golangserver_command_callback.vader3
-rw-r--r--test/command_callback/test_scala_sbtserver.vader2
-rw-r--r--test/lsp/test_other_initialize_message_handling.vader1
-rw-r--r--test/lsp/test_update_config.vader17
-rw-r--r--test/test_linter_defintion_processing.vader27
12 files changed, 122 insertions, 10 deletions
diff --git a/autoload/ale/assert.vim b/autoload/ale/assert.vim
index a1bfd0b7..ed08ed09 100644
--- a/autoload/ale/assert.vim
+++ b/autoload/ale/assert.vim
@@ -85,6 +85,14 @@ function! ale#assert#LSPOptions(expected_options) abort
AssertEqual a:expected_options, l:initialization_options
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
let l:buffer = bufnr('')
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=0 AssertLinterNotExecuted :call ale#assert#LinterNotExecuted()
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=+ AssertLSPProject :call ale#assert#LSPProject(<args>)
command! -nargs=+ AssertLSPAddress :call ale#assert#LSPAddress(<args>)
@@ -172,6 +181,10 @@ function! ale#assert#TearDownLinterTest() abort
delcommand AssertLSPOptions
endif
+ if exists(':AssertLSPConfig')
+ delcommand AssertLSPConfig
+ endif
+
if exists(':AssertLSPLanguage')
delcommand AssertLSPLanguage
endif
diff --git a/autoload/ale/linter.vim b/autoload/ale/linter.vim
index dbf9f221..114765e6 100644
--- a/autoload/ale/linter.vim
+++ b/autoload/ale/linter.vim
@@ -257,7 +257,17 @@ function! ale#linter#PreProcess(filetype, linter) abort
let l:obj.initialization_options = a:linter.initialization_options
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
throw '`lsp_config` must be a Dictionary'
endif
diff --git a/autoload/ale/lsp.vim b/autoload/ale/lsp.vim
index b7908e74..f55096c2 100644
--- a/autoload/ale/lsp.vim
+++ b/autoload/ale/lsp.vim
@@ -19,6 +19,7 @@ function! ale#lsp#Register(executable_or_address, project, init_options) abort
" initialized: 0 if the connection is ready, 1 otherwise.
" init_request_id: The ID for the init request.
" init_options: Options to send to the server.
+ " config: Configuration settings to send to the server.
" callback_list: A list of callbacks for handling LSP responses.
" message_queue: Messages queued for sending to callbacks.
" capabilities_queue: The list of callbacks to call with capabilities.
@@ -32,6 +33,7 @@ function! ale#lsp#Register(executable_or_address, project, init_options) abort
\ 'initialized': 0,
\ 'init_request_id': 0,
\ 'init_options': a:init_options,
+ \ 'config': {},
\ 'callback_list': [],
\ 'message_queue': [],
\ 'capabilities_queue': [],
@@ -210,6 +212,25 @@ function! s:UpdateCapabilities(conn, capabilities) abort
endif
endfunction
+" Update a connection's configuration dictionary and notify LSP servers
+" of any changes since the last update. Returns 1 if a configuration
+" update was sent; otherwise 0 will be returned.
+function! ale#lsp#UpdateConfig(conn_id, buffer, config) abort
+ let l:conn = get(s:connections, a:conn_id, {})
+
+ if empty(l:conn) || a:config ==# l:conn.config " no-custom-checks
+ return 0
+ endif
+
+ let l:conn.config = a:config
+ let l:message = ale#lsp#message#DidChangeConfiguration(a:buffer, a:config)
+
+ call ale#lsp#Send(a:conn_id, l:message)
+
+ return 1
+endfunction
+
+
function! ale#lsp#HandleInitResponse(conn, response) abort
if get(a:response, 'method', '') is# 'initialize'
let a:conn.initialized = 1
diff --git a/autoload/ale/lsp_linter.vim b/autoload/ale/lsp_linter.vim
index fa4d2f86..42d67398 100644
--- a/autoload/ale/lsp_linter.vim
+++ b/autoload/ale/lsp_linter.vim
@@ -140,6 +140,18 @@ function! ale#lsp_linter#GetOptions(buffer, linter) abort
return l:initialization_options
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
" receive messages for the document.
function! ale#lsp_linter#StartLSP(buffer, linter) abort
@@ -188,14 +200,9 @@ function! ale#lsp_linter#StartLSP(buffer, linter) abort
call ale#lsp#MarkConnectionAsTsserver(l:conn_id)
endif
+ let l:config = ale#lsp_linter#GetConfig(a:buffer, a:linter)
let l:language_id = ale#util#GetFunction(a:linter.language_callback)(a:buffer)
- if !empty(get(a:linter, 'lsp_config'))
- " set LSP configuration options (workspace/didChangeConfiguration)
- let l:config_message = ale#lsp#message#DidChangeConfiguration(a:buffer, a:linter.lsp_config)
- call ale#lsp#Send(l:conn_id, l:config_message)
- endif
-
let l:details = {
\ 'buffer': a:buffer,
\ 'connection_id': l:conn_id,
@@ -204,6 +211,8 @@ function! ale#lsp_linter#StartLSP(buffer, linter) abort
\ 'language_id': l:language_id,
\}
+ call ale#lsp#UpdateConfig(l:conn_id, a:buffer, l:config)
+
if ale#lsp#OpenDocument(l:conn_id, a:buffer, l:language_id)
if g:ale_history_enabled && !empty(l:command)
call ale#history#Add(a:buffer, 'started', l:conn_id, l:command)
diff --git a/doc/ale-development.txt b/doc/ale-development.txt
index ac72d615..1e168130 100644
--- a/doc/ale-development.txt
+++ b/doc/ale-development.txt
@@ -306,6 +306,7 @@ given the above setup are as follows.
`AssertLinterNotExecuted` - Check that linters will not be executed.
`AssertLSPLanguage language` - Check the language 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.
`AssertLSPAddress address` - Check the address to an LSP server.
diff --git a/doc/ale.txt b/doc/ale.txt
index 6340091c..59b9f352 100644
--- a/doc/ale.txt
+++ b/doc/ale.txt
@@ -2685,6 +2685,9 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
`initialization_options_callback` may be defined to
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
accepting a buffer number. A |String| should be
returned with an address to connect to.
@@ -2745,6 +2748,16 @@ 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.
+ 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
specified. `command_callback` is generally recommended when a command string
needs to be generated dynamically, or any global options are used.
diff --git a/test/command_callback/test_elixir_ls_command_callbacks.vader b/test/command_callback/test_elixir_ls_command_callbacks.vader
index 0d00354b..f79be9b4 100644
--- a/test/command_callback/test_elixir_ls_command_callbacks.vader
+++ b/test/command_callback/test_elixir_ls_command_callbacks.vader
@@ -26,4 +26,5 @@ Execute(should set correct LSP values):
AssertLSPLanguage 'elixir'
AssertLSPOptions {}
+ AssertLSPConfig {}
AssertLSPProject ale#path#Simplify(g:dir . '/mix_paths/wrapped_project')
diff --git a/test/command_callback/test_golangserver_command_callback.vader b/test/command_callback/test_golangserver_command_callback.vader
index ee88e1a4..90fdc26f 100644
--- a/test/command_callback/test_golangserver_command_callback.vader
+++ b/test/command_callback/test_golangserver_command_callback.vader
@@ -56,7 +56,7 @@ Execute(should set go-langserver for go app1):
call ale#test#SetFilename('go_paths/go1/prj1/file.go')
AssertLSPLanguage 'go'
- AssertLSPOptions {}
+ AssertLSPConfig {}
AssertLSPProject ale#path#Simplify(g:dir . '/go_paths/go1')
Execute(should set go-langserver for go app2):
@@ -64,4 +64,5 @@ Execute(should set go-langserver for go app2):
AssertLSPLanguage 'go'
AssertLSPOptions {}
+ AssertLSPConfig {}
AssertLSPProject ale#path#Simplify(g:dir . '/go_paths/go2')
diff --git a/test/command_callback/test_scala_sbtserver.vader b/test/command_callback/test_scala_sbtserver.vader
index 1b708bd9..1c7d8472 100644
--- a/test/command_callback/test_scala_sbtserver.vader
+++ b/test/command_callback/test_scala_sbtserver.vader
@@ -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')
AssertLSPLanguage 'scala'
AssertLSPOptions {}
+ AssertLSPConfig {}
AssertLSPProject ale#path#Simplify(g:dir . 'command_callback/../scala_fixtures/valid_sbt_project')
AssertLSPAddress '127.0.0.1:4273'
Execute(should not set sbtserver for sbt project without build.sbt):
call ale#test#SetFilename('../scala_fixtures/invalid_sbt_project/Main.scala')
AssertLSPLanguage 'scala'
AssertLSPOptions {}
+ AssertLSPConfig {}
AssertLSPProject ''
AssertLSPAddress '127.0.0.1:4273'
diff --git a/test/lsp/test_other_initialize_message_handling.vader b/test/lsp/test_other_initialize_message_handling.vader
index 072f8c4b..2f59535d 100644
--- a/test/lsp/test_other_initialize_message_handling.vader
+++ b/test/lsp/test_other_initialize_message_handling.vader
@@ -7,6 +7,7 @@ Before:
\ 'initialized': 0,
\ 'init_request_id': 0,
\ 'init_options': {},
+ \ 'config': {},
\ 'callback_list': [],
\ 'message_queue': [],
\ 'capabilities_queue': [],
diff --git a/test/lsp/test_update_config.vader b/test/lsp/test_update_config.vader
new file mode 100644
index 00000000..07068bc8
--- /dev/null
+++ b/test/lsp/test_update_config.vader
@@ -0,0 +1,17 @@
+Before:
+ runtime autoload/ale/lsp.vim
+
+ let g:conn_id = ale#lsp#Register('executable', '/foo/bar', {})
+
+After:
+ Restore
+
+ unlet! g:conn_id
+
+ runtime autoload/ale/lsp.vim
+
+Execute(Only send updates when the configuration dictionary changes):
+ AssertEqual 0, ale#lsp#UpdateConfig(g:conn_id, bufnr(''), {})
+ AssertEqual 1, ale#lsp#UpdateConfig(g:conn_id, bufnr(''), {'a': 1})
+ AssertEqual 0, ale#lsp#UpdateConfig(g:conn_id, bufnr(''), {'a': 1})
+ AssertEqual 1, ale#lsp#UpdateConfig(g:conn_id, bufnr(''), {})
diff --git a/test/test_linter_defintion_processing.vader b/test/test_linter_defintion_processing.vader
index a28edf9e..d967761d 100644
--- a/test/test_linter_defintion_processing.vader
+++ b/test/test_linter_defintion_processing.vader
@@ -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
+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):
let g:ale_lsp_configuration = {
\ '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
-
Execute(PreProcess should throw when lsp_config is not a Dictionary):
AssertThrows call ale#linter#PreProcess('testft', {
\ 'name': 'foo',
@@ -528,4 +552,3 @@ Execute(PreProcess should throw when lsp_config is not a Dictionary):
\ 'lsp_config': 'x',
\})
AssertEqual '`lsp_config` must be a Dictionary', g:vader_exception
-