mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-04 01:34:25 +00:00 
			
		
		
		
	refactor(lsp): merge rpc.domain_socket_connect into rpc.connect (#28398)
See discussion in https://github.com/neovim/neovim/pull/26850
This commit is contained in:
		
				
					committed by
					
						
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							206475d791
						
					
				
				
					commit
					97323d821b
				
			@@ -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`)
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -621,22 +621,33 @@ 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)
 | 
			
		||||
        handle:write(msg)
 | 
			
		||||
      end,
 | 
			
		||||
      is_closing = function()
 | 
			
		||||
        return closing
 | 
			
		||||
@@ -644,18 +655,19 @@ function M.connect(host, port)
 | 
			
		||||
      terminate = function()
 | 
			
		||||
        if not closing then
 | 
			
		||||
          closing = true
 | 
			
		||||
          tcp:shutdown()
 | 
			
		||||
          tcp:close()
 | 
			
		||||
          handle:shutdown()
 | 
			
		||||
          handle:close()
 | 
			
		||||
          dispatchers.on_exit(0, 0)
 | 
			
		||||
        end
 | 
			
		||||
      end,
 | 
			
		||||
    }
 | 
			
		||||
    local client = new_client(dispatchers, transport)
 | 
			
		||||
    tcp:connect(host, port, 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:%s, reason: %s', host, port, vim.inspect(err)),
 | 
			
		||||
            string.format('Could not connect to %s, reason: %s', address, vim.inspect(err)),
 | 
			
		||||
            vim.log.levels.WARN
 | 
			
		||||
          )
 | 
			
		||||
        end)
 | 
			
		||||
@@ -664,64 +676,15 @@ function M.connect(host, port)
 | 
			
		||||
      local handle_body = function(body)
 | 
			
		||||
        client:handle_body(body)
 | 
			
		||||
      end
 | 
			
		||||
      tcp: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)
 | 
			
		||||
 | 
			
		||||
    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()
 | 
			
		||||
          dispatchers.on_exit(0, 0)
 | 
			
		||||
        end
 | 
			
		||||
      end,
 | 
			
		||||
    }
 | 
			
		||||
    local client = new_client(dispatchers, transport)
 | 
			
		||||
    pipe:connect(pipe_path, function(err)
 | 
			
		||||
      if err then
 | 
			
		||||
        vim.schedule(function()
 | 
			
		||||
          vim.notify(
 | 
			
		||||
            string.format('Could not connect to :%s, reason: %s', pipe_path, vim.inspect(err)),
 | 
			
		||||
            vim.log.levels.WARN
 | 
			
		||||
          )
 | 
			
		||||
        end)
 | 
			
		||||
        return
 | 
			
		||||
      end
 | 
			
		||||
      local handle_body = function(body)
 | 
			
		||||
        client:handle_body(body)
 | 
			
		||||
      end
 | 
			
		||||
      pipe: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
 | 
			
		||||
 
 | 
			
		||||
@@ -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()
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user