mirror of
https://github.com/dense-analysis/ale.git
synced 2025-12-06 12:44:23 +08:00
Add Neovim TCP connections to language servers
Support TCP connections to language servers through Neovim's built in client. In all but what is currently the nightly builds of Neovim connections via a hostname will fail, but connections via an IP address should function. We will still enable the built in Neovim client by default anyway, as LSP clients very rarely connect over TCP.
This commit is contained in:
@@ -569,6 +569,21 @@ function! ale#lsp#StartProgram(conn_id, executable, command) abort
|
||||
return l:job_id > 0
|
||||
endfunction
|
||||
|
||||
" Split an address into [host, port].
|
||||
" The port will either be a number or v:null.
|
||||
function! ale#lsp#SplitAddress(address) abort
|
||||
let l:port_match = matchlist(a:address, '\v:(\d+)$')
|
||||
|
||||
if !empty(l:port_match)
|
||||
let l:host = a:address[:-len(l:port_match[1]) - 2]
|
||||
let l:port = l:port_match[1] + 0
|
||||
|
||||
return [l:host, l:port ? l:port : v:null]
|
||||
endif
|
||||
|
||||
return [a:address, v:null]
|
||||
endfunction
|
||||
|
||||
" Connect to an LSP server via TCP.
|
||||
"
|
||||
" 1 will be returned if the connection is running, or 0 if the connection could
|
||||
@@ -577,8 +592,23 @@ function! ale#lsp#ConnectToAddress(conn_id, address) abort
|
||||
let l:conn = s:connections[a:conn_id]
|
||||
let l:started = 0
|
||||
|
||||
" TODO: Start Neovim client here.
|
||||
if !has_key(l:conn, 'channel_id') || !ale#socket#IsOpen(l:conn.channel_id)
|
||||
if g:ale_use_neovim_lsp_api && !l:conn.is_tsserver
|
||||
let [l:host, l:port] = ale#lsp#SplitAddress(a:address)
|
||||
|
||||
let l:client_id = luaeval('require("ale.lsp").start(_A)', {
|
||||
\ 'name': a:conn_id,
|
||||
\ 'host': l:host,
|
||||
\ 'port': l:port,
|
||||
\ 'root_dir': l:conn.root,
|
||||
\ 'init_options': l:conn.init_options,
|
||||
\})
|
||||
|
||||
if l:client_id > 0
|
||||
let l:conn.client_id = l:client_id
|
||||
endif
|
||||
|
||||
return l:client_id > 0
|
||||
elseif !has_key(l:conn, 'channel_id') || !ale#socket#IsOpen(l:conn.channel_id)
|
||||
let l:channel_id = ale#socket#Open(a:address, {
|
||||
\ 'callback': {_, mess -> ale#lsp#HandleMessage(a:conn_id, mess)},
|
||||
\})
|
||||
|
||||
@@ -476,6 +476,11 @@ functionality for Neovim's LSP client should work as expected, and this
|
||||
ensures ALE integrates well with other plugins that rely on Neovim's LSP
|
||||
client.
|
||||
|
||||
NOTE: Neovim versions below `0.11.0` do not support socket connections to
|
||||
language servers when the `address` defined in ALE uses a hostname instead of
|
||||
an IP address. To work around this, configure language clients with an IP
|
||||
address instead of a hostname, or revert back to ALE's custom LSP client.
|
||||
|
||||
See |lsp| for information on Neovim's built in LSP client.
|
||||
|
||||
For diagnostics, for computing problems to show via ALE, ALE overrides the
|
||||
|
||||
@@ -6,6 +6,31 @@ module.start = function(config)
|
||||
config.init_options[true] = nil
|
||||
end
|
||||
|
||||
-- If configuring LSP via a socket connection, then generate the cmd
|
||||
-- using vim.lsp.rpc.connect(), as defined in Neovim documentation.
|
||||
if config.host then
|
||||
local cmd_func = vim.lsp.rpc.connect(config.host, config.port)
|
||||
config.host = nil
|
||||
config.port = nil
|
||||
|
||||
-- Wrap the cmd function so we don't throw errors back to the user
|
||||
-- if the connection to an address fails to start.
|
||||
--
|
||||
-- We will separately log in ALE that we failed to start a connection.
|
||||
--
|
||||
-- In older Neovim versions TCP connections do not function if supplied
|
||||
-- a hostname instead of an address.
|
||||
config.cmd = function(dispatch)
|
||||
local success, result = pcall(cmd_func, dispatch)
|
||||
|
||||
if success then
|
||||
return result
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
config.handlers = {
|
||||
-- Override Neovim's handling of diagnostics to run through ALE's
|
||||
-- functions so all of the functionality in ALE works.
|
||||
|
||||
9
test/lsp/test_lsp_address_split.vader
Normal file
9
test/lsp/test_lsp_address_split.vader
Normal file
@@ -0,0 +1,9 @@
|
||||
Execute(Address splitting should function as intended):
|
||||
AssertEqual ['foo', v:null], ale#lsp#SplitAddress('foo')
|
||||
AssertEqual ['foo:', v:null], ale#lsp#SplitAddress('foo:')
|
||||
AssertEqual ['foo', v:null], ale#lsp#SplitAddress('foo:0')
|
||||
AssertEqual ['foo', 123], ale#lsp#SplitAddress('foo:123')
|
||||
AssertEqual ['protocol:/foo:', v:null], ale#lsp#SplitAddress('protocol:/foo:')
|
||||
AssertEqual ['protocol:/foo', v:null], ale#lsp#SplitAddress('protocol:/foo:0')
|
||||
AssertEqual ['protocol:/foo', 123], ale#lsp#SplitAddress('protocol:/foo:123')
|
||||
AssertEqual ['protocol:foo', v:null], ale#lsp#SplitAddress('protocol:foo')
|
||||
Reference in New Issue
Block a user