mirror of
https://github.com/neovim/neovim.git
synced 2025-09-29 06:28:35 +00:00
feat: serverlist({peer=true}) returns peer addresses #34806
Problem: serverlist() only lists servers that were started by the current Nvim. Solution: Look for other Nvim servers in stdpath("run").
This commit is contained in:
@@ -8736,13 +8736,23 @@ searchpos({pattern} [, {flags} [, {stopline} [, {timeout} [, {skip}]]]])
|
|||||||
Return: ~
|
Return: ~
|
||||||
(`any`)
|
(`any`)
|
||||||
|
|
||||||
serverlist() *serverlist()*
|
serverlist([{opts}]) *serverlist()*
|
||||||
Returns a list of server addresses, or empty if all servers
|
Returns a list of server addresses, or empty if all servers
|
||||||
were stopped. |serverstart()| |serverstop()|
|
were stopped. |serverstart()| |serverstop()|
|
||||||
|
|
||||||
|
The optional argument {opts} is a Dict and supports the following items:
|
||||||
|
|
||||||
|
peer : If |TRUE|, servers not started by |serverstart()|
|
||||||
|
will also be returned. (default: |FALSE|)
|
||||||
|
Not supported on Windows yet.
|
||||||
|
|
||||||
Example: >vim
|
Example: >vim
|
||||||
echo serverlist()
|
echo serverlist()
|
||||||
<
|
<
|
||||||
|
|
||||||
|
Parameters: ~
|
||||||
|
• {opts} (`table?`)
|
||||||
|
|
||||||
Return: ~
|
Return: ~
|
||||||
(`string[]`)
|
(`string[]`)
|
||||||
|
|
||||||
|
33
runtime/lua/vim/_core/server.lua
Normal file
33
runtime/lua/vim/_core/server.lua
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
local M = {}
|
||||||
|
|
||||||
|
--- Called by builtin serverlist(). Returns all running servers.
|
||||||
|
--- in stdpath("run"). Does not include named pipes or TCP servers.
|
||||||
|
---
|
||||||
|
--- @param listed string[] Already listed servers
|
||||||
|
--- @return string[] A list of currently running servers in stdpath("run")
|
||||||
|
function M.serverlist(listed)
|
||||||
|
-- TODO: also get named pipes on Windows
|
||||||
|
local socket_paths = vim.fs.find(function(name, _)
|
||||||
|
return name:match('nvim.*')
|
||||||
|
end, { path = vim.fn.stdpath('run'), type = 'socket', limit = math.huge })
|
||||||
|
|
||||||
|
local running_sockets = {}
|
||||||
|
for _, socket in ipairs(socket_paths) do
|
||||||
|
-- Don't list servers twice
|
||||||
|
if not vim.list_contains(listed, socket) then
|
||||||
|
local ok, chan = pcall(vim.fn.sockconnect, 'pipe', socket, { rpc = true })
|
||||||
|
if ok and chan then
|
||||||
|
-- Check that the server is responding
|
||||||
|
-- TODO: do we need a timeout or error handling here?
|
||||||
|
if vim.fn.rpcrequest(chan, 'nvim_get_chan_info', 0).id then
|
||||||
|
table.insert(running_sockets, socket)
|
||||||
|
end
|
||||||
|
vim.fn.chanclose(chan)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return running_sockets
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
10
runtime/lua/vim/_meta/vimfn.lua
generated
10
runtime/lua/vim/_meta/vimfn.lua
generated
@@ -7964,12 +7964,20 @@ function vim.fn.searchpos(pattern, flags, stopline, timeout, skip) end
|
|||||||
|
|
||||||
--- Returns a list of server addresses, or empty if all servers
|
--- Returns a list of server addresses, or empty if all servers
|
||||||
--- were stopped. |serverstart()| |serverstop()|
|
--- were stopped. |serverstart()| |serverstop()|
|
||||||
|
---
|
||||||
|
--- The optional argument {opts} is a Dict and supports the following items:
|
||||||
|
---
|
||||||
|
--- peer : If |TRUE|, servers not started by |serverstart()|
|
||||||
|
--- will also be returned. (default: |FALSE|)
|
||||||
|
--- Not supported on Windows yet.
|
||||||
|
---
|
||||||
--- Example: >vim
|
--- Example: >vim
|
||||||
--- echo serverlist()
|
--- echo serverlist()
|
||||||
--- <
|
--- <
|
||||||
---
|
---
|
||||||
|
--- @param opts? table
|
||||||
--- @return string[]
|
--- @return string[]
|
||||||
function vim.fn.serverlist() end
|
function vim.fn.serverlist(opts) end
|
||||||
|
|
||||||
--- Opens a socket or named pipe at {address} and listens for
|
--- Opens a socket or named pipe at {address} and listens for
|
||||||
--- |RPC| messages. Clients can send |API| commands to the
|
--- |RPC| messages. Clients can send |API| commands to the
|
||||||
|
@@ -9655,17 +9655,25 @@ M.funcs = {
|
|||||||
signature = 'searchpos({pattern} [, {flags} [, {stopline} [, {timeout} [, {skip}]]]])',
|
signature = 'searchpos({pattern} [, {flags} [, {stopline} [, {timeout} [, {skip}]]]])',
|
||||||
},
|
},
|
||||||
serverlist = {
|
serverlist = {
|
||||||
|
args = { 0, 1 },
|
||||||
desc = [=[
|
desc = [=[
|
||||||
Returns a list of server addresses, or empty if all servers
|
Returns a list of server addresses, or empty if all servers
|
||||||
were stopped. |serverstart()| |serverstop()|
|
were stopped. |serverstart()| |serverstop()|
|
||||||
|
|
||||||
|
The optional argument {opts} is a Dict and supports the following items:
|
||||||
|
|
||||||
|
peer : If |TRUE|, servers not started by |serverstart()|
|
||||||
|
will also be returned. (default: |FALSE|)
|
||||||
|
Not supported on Windows yet.
|
||||||
|
|
||||||
Example: >vim
|
Example: >vim
|
||||||
echo serverlist()
|
echo serverlist()
|
||||||
<
|
<
|
||||||
]=],
|
]=],
|
||||||
name = 'serverlist',
|
name = 'serverlist',
|
||||||
params = {},
|
params = { { 'opts', 'table' } },
|
||||||
returns = 'string[]',
|
returns = 'string[]',
|
||||||
signature = 'serverlist()',
|
signature = 'serverlist([{opts}])',
|
||||||
},
|
},
|
||||||
serverstart = {
|
serverstart = {
|
||||||
args = { 0, 1 },
|
args = { 0, 1 },
|
||||||
|
@@ -6724,12 +6724,42 @@ static void f_serverlist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
|||||||
size_t n;
|
size_t n;
|
||||||
char **addrs = server_address_list(&n);
|
char **addrs = server_address_list(&n);
|
||||||
|
|
||||||
|
Arena arena = ARENA_EMPTY;
|
||||||
|
// Passed to vim._core.server.serverlist() to avoid duplicates
|
||||||
|
Array addrs_arr = arena_array(&arena, n);
|
||||||
|
|
||||||
// Copy addrs into a linked list.
|
// Copy addrs into a linked list.
|
||||||
list_T *const l = tv_list_alloc_ret(rettv, (ptrdiff_t)n);
|
list_T *const l = tv_list_alloc_ret(rettv, (ptrdiff_t)n);
|
||||||
for (size_t i = 0; i < n; i++) {
|
for (size_t i = 0; i < n; i++) {
|
||||||
tv_list_append_allocated_string(l, addrs[i]);
|
tv_list_append_allocated_string(l, addrs[i]);
|
||||||
|
ADD_C(addrs_arr, CSTR_AS_OBJ(addrs[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(argvars[0].v_type == VAR_DICT && tv_dict_get_bool(argvars[0].vval.v_dict, "peer", false))) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
MAXSIZE_TEMP_ARRAY(args, 1);
|
||||||
|
ADD_C(args, ARRAY_OBJ(addrs_arr));
|
||||||
|
|
||||||
|
Error err = ERROR_INIT;
|
||||||
|
Object rv = NLUA_EXEC_STATIC("return require('vim._core.server').serverlist(...)",
|
||||||
|
args, kRetObject,
|
||||||
|
&arena, &err);
|
||||||
|
|
||||||
|
if (ERROR_SET(&err)) {
|
||||||
|
ELOG("vim._core.serverlist failed: %s", err.msg);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < rv.data.array.size; i++) {
|
||||||
|
char *curr_server = rv.data.array.items[i].data.string.data;
|
||||||
|
tv_list_append_string(l, curr_server, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
xfree(addrs);
|
xfree(addrs);
|
||||||
|
arena_mem_free(arena_finish(&arena));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// "serverstart()" function
|
/// "serverstart()" function
|
||||||
|
@@ -162,7 +162,7 @@ describe('server', function()
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
it('serverlist() returns the list of servers', function()
|
it('serverlist() returns the list of servers', function()
|
||||||
clear()
|
local current_server = clear()
|
||||||
-- There should already be at least one server.
|
-- There should already be at least one server.
|
||||||
local _n = eval('len(serverlist())')
|
local _n = eval('len(serverlist())')
|
||||||
|
|
||||||
@@ -186,6 +186,24 @@ describe('server', function()
|
|||||||
end
|
end
|
||||||
-- After serverstop() the servers should NOT be in the list.
|
-- After serverstop() the servers should NOT be in the list.
|
||||||
eq(_n, eval('len(serverlist())'))
|
eq(_n, eval('len(serverlist())'))
|
||||||
|
|
||||||
|
-- serverlist({ peer = true }) returns servers from other Nvim sessions.
|
||||||
|
if t.is_os('win') then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local client_address = n.new_pipename()
|
||||||
|
local client = n.new_session(
|
||||||
|
true,
|
||||||
|
{ args = { '-u', 'NONE', '--listen', client_address, '--embed' }, merge = false }
|
||||||
|
)
|
||||||
|
n.set_session(client)
|
||||||
|
eq(client_address, fn.serverlist()[1])
|
||||||
|
|
||||||
|
n.set_session(current_server)
|
||||||
|
|
||||||
|
new_servs = fn.serverlist({ peer = true })
|
||||||
|
eq(true, vim.list_contains(new_servs, client_address))
|
||||||
|
client:close()
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user