aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/lsp.txt30
-rw-r--r--runtime/doc/news.txt2
-rw-r--r--runtime/lua/vim/lsp/rpc.lua95
-rw-r--r--test/functional/plugin/lsp_spec.lua4
4 files changed, 41 insertions, 90 deletions
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index 70b8878837..0ca5240da0 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -2229,32 +2229,20 @@ Lua module: vim.lsp.rpc *lsp-rpc*
• {terminate} (`fun()`)
-connect({host}, {port}) *vim.lsp.rpc.connect()*
- Create a LSP RPC client factory that connects via TCP to the given host
- and port.
+connect({host_or_path}, {port}) *vim.lsp.rpc.connect()*
+ Create a LSP RPC client factory that connects to either:
+ • a named pipe (windows)
+ • a domain socket (unix)
+ • a host and port via TCP
Return a function that can be passed to the `cmd` field for
|vim.lsp.start_client()| or |vim.lsp.start()|.
Parameters: ~
- • {host} (`string`) host to connect to
- • {port} (`integer`) port to connect to
-
- Return: ~
- (`fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient`)
-
- *vim.lsp.rpc.domain_socket_connect()*
-domain_socket_connect({pipe_path})
- Create a LSP RPC client factory that connects via named pipes (Windows) or
- unix domain sockets (Unix) to the given pipe_path (file path on Unix and
- name on Windows).
-
- Return a function that can be passed to the `cmd` field for
- |vim.lsp.start_client()| or |vim.lsp.start()|.
-
- Parameters: ~
- • {pipe_path} (`string`) file path of the domain socket (Unix) or name
- of the named pipe (Windows) to connect to
+ • {host_or_path} (`string`) host to connect to or path to a pipe/domain
+ socket
+ • {port} (`integer?`) TCP port to connect to. If absent the
+ first argument must be a pipe
Return: ~
(`fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient`)
diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt
index 966d50c382..8d51d9d849 100644
--- a/runtime/doc/news.txt
+++ b/runtime/doc/news.txt
@@ -225,7 +225,7 @@ The following new APIs and features were added.
• |vim.lsp.util.locations_to_items()| sets the `user_data` of each item to
the original LSP `Location` or `LocationLink`.
• Added support for connecting to servers using named pipes (Windows) or
- unix domain sockets (Unix) via |vim.lsp.rpc.domain_socket_connect()|.
+ unix domain sockets (Unix) via |vim.lsp.rpc.connect()|.
• Added support for `completionList.itemDefaults`, reducing overhead when
computing completion items where properties often share the same value
(e.g. `commitCharacters`). Note that this might affect plugins and
diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua
index 984e4f040a..6748b32ec0 100644
--- a/runtime/lua/vim/lsp/rpc.lua
+++ b/runtime/lua/vim/lsp/rpc.lua
@@ -621,95 +621,53 @@ local function merge_dispatchers(dispatchers)
return merged
end
---- Create a LSP RPC client factory that connects via TCP to the given host and port.
+--- Create a LSP RPC client factory that connects to either:
+---
+--- - a named pipe (windows)
+--- - a domain socket (unix)
+--- - a host and port via TCP
---
--- Return a function that can be passed to the `cmd` field for
--- |vim.lsp.start_client()| or |vim.lsp.start()|.
---
----@param host string host to connect to
----@param port integer port to connect to
+---@param host_or_path string host to connect to or path to a pipe/domain socket
+---@param port integer? TCP port to connect to. If absent the first argument must be a pipe
---@return fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient
-function M.connect(host, port)
+function M.connect(host_or_path, port)
return function(dispatchers)
dispatchers = merge_dispatchers(dispatchers)
- local tcp = assert(uv.new_tcp())
+ local handle = (
+ port == nil
+ and assert(
+ uv.new_pipe(false),
+ string.format('Pipe with name %s could not be opened.', host_or_path)
+ )
+ or assert(uv.new_tcp(), 'Could not create new TCP socket')
+ )
local closing = false
local transport = {
write = function(msg)
- tcp:write(msg)
- end,
- is_closing = function()
- return closing
- end,
- terminate = function()
- if not closing then
- closing = true
- tcp:shutdown()
- tcp:close()
- dispatchers.on_exit(0, 0)
- end
+ handle:write(msg)
end,
- }
- local client = new_client(dispatchers, transport)
- tcp:connect(host, port, function(err)
- if err then
- vim.schedule(function()
- vim.notify(
- string.format('Could not connect to %s:%s, reason: %s', host, port, vim.inspect(err)),
- vim.log.levels.WARN
- )
- end)
- return
- end
- local handle_body = function(body)
- client:handle_body(body)
- end
- tcp:read_start(M.create_read_loop(handle_body, transport.terminate, function(read_err)
- client:on_error(M.client_errors.READ_ERROR, read_err)
- end))
- end)
-
- return public_client(client)
- end
-end
-
---- Create a LSP RPC client factory that connects via named pipes (Windows)
---- or unix domain sockets (Unix) to the given pipe_path (file path on
---- Unix and name on Windows).
----
---- Return a function that can be passed to the `cmd` field for
---- |vim.lsp.start_client()| or |vim.lsp.start()|.
----
----@param pipe_path string file path of the domain socket (Unix) or name of the named pipe (Windows) to connect to
----@return fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient
-function M.domain_socket_connect(pipe_path)
- return function(dispatchers)
- dispatchers = merge_dispatchers(dispatchers)
- local pipe =
- assert(uv.new_pipe(false), string.format('pipe with name %s could not be opened.', pipe_path))
- local closing = false
- local transport = {
- write = vim.schedule_wrap(function(msg)
- pipe:write(msg)
- end),
is_closing = function()
return closing
end,
terminate = function()
if not closing then
closing = true
- pipe:shutdown()
- pipe:close()
+ handle:shutdown()
+ handle:close()
dispatchers.on_exit(0, 0)
end
end,
}
local client = new_client(dispatchers, transport)
- pipe:connect(pipe_path, function(err)
+ local function on_connect(err)
if err then
+ local address = port == nil and host_or_path or (host_or_path .. ':' .. port)
vim.schedule(function()
vim.notify(
- string.format('Could not connect to :%s, reason: %s', pipe_path, vim.inspect(err)),
+ string.format('Could not connect to %s, reason: %s', address, vim.inspect(err)),
vim.log.levels.WARN
)
end)
@@ -718,10 +676,15 @@ function M.domain_socket_connect(pipe_path)
local handle_body = function(body)
client:handle_body(body)
end
- pipe:read_start(M.create_read_loop(handle_body, transport.terminate, function(read_err)
+ handle:read_start(M.create_read_loop(handle_body, transport.terminate, function(read_err)
client:on_error(M.client_errors.READ_ERROR, read_err)
end))
- end)
+ end
+ if port == nil then
+ handle:connect(host_or_path, on_connect)
+ else
+ handle:connect(host_or_path, port, on_connect)
+ end
return public_client(client)
end
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index 1ff29bf74f..feca31c01b 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -4311,7 +4311,7 @@ describe('LSP', function()
]]
eq('initialize', result.method)
end)
- it('can connect to lsp server via rpc.domain_socket_connect', function()
+ it('can connect to lsp server via pipe or domain_socket', function()
local tmpfile --- @type string
if is_os('win') then
tmpfile = '\\\\.\\\\pipe\\pipe.test'
@@ -4336,7 +4336,7 @@ describe('LSP', function()
client:close()
end))
end)
- vim.lsp.start({ name = "dummy", cmd = vim.lsp.rpc.domain_socket_connect(SOCK) })
+ vim.lsp.start({ name = "dummy", cmd = vim.lsp.rpc.connect(SOCK) })
vim.wait(1000, function() return init ~= nil end)
assert(init, "server must receive `initialize` request")
server:close()