feat(server): allow embed with listen (#25709)

connection from any channel or stdio will unblock
remote_ui_wait_for_attach.  Wait on stdio only if
only —embed specified, if both —embed and
—listen then wait on any channel.
This commit is contained in:
George Harker 2023-10-31 20:04:53 -07:00 committed by GitHub
parent 746a153bc1
commit 4e6096a67f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 82 additions and 11 deletions

View File

@ -390,6 +390,10 @@ argument.
< Then startup will continue without waiting for `nvim_ui_attach`.
This is equivalent to: >
nvim --headless --cmd "call stdioopen({'rpc': v:true})"
<
Embedders that use the UI protocol on a socket connection must
pass |--listen| as well as |--embed|: >
nvim --embed --listen addr
< See also: |ui-startup| |channel-stdio|

View File

@ -126,18 +126,24 @@ void remote_ui_disconnect(uint64_t channel_id)
xfree(ui);
}
/// Wait until ui has connected on stdio channel.
void remote_ui_wait_for_attach(void)
/// Wait until ui has connected on stdio channel if only_stdio
/// is true, otherwise any channel.
void remote_ui_wait_for_attach(bool only_stdio)
{
Channel *channel = find_channel(CHAN_STDIO);
if (!channel) {
// this function should only be called in --embed mode, stdio channel
// can be assumed.
abort();
}
if (only_stdio) {
Channel *channel = find_channel(CHAN_STDIO);
if (!channel) {
// this function should only be called in --embed mode, stdio channel
// can be assumed.
abort();
}
LOOP_PROCESS_EVENTS_UNTIL(&main_loop, channel->events, -1,
map_has(uint64_t, &connected_uis, CHAN_STDIO));
LOOP_PROCESS_EVENTS_UNTIL(&main_loop, channel->events, -1,
map_has(uint64_t, &connected_uis, CHAN_STDIO));
} else {
LOOP_PROCESS_EVENTS_UNTIL(&main_loop, main_loop.events, -1,
ui_active());
}
}
/// Activates UI events on the channel.

View File

@ -392,9 +392,10 @@ int main(int argc, char **argv)
// Wait for UIs to set up Nvim or show early messages
// and prompts (--cmd, swapfile dialog, …).
bool use_remote_ui = (embedded_mode && !headless_mode);
bool listen_and_embed = params.listen_addr != NULL;
if (use_remote_ui) {
TIME_MSG("waiting for UI");
remote_ui_wait_for_attach();
remote_ui_wait_for_attach(!listen_and_embed);
TIME_MSG("done waiting for UI");
firstwin->w_prev_height = firstwin->w_height; // may have changed
}

View File

@ -2,10 +2,13 @@ local uv = require'luv'
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local thelpers = require('test.functional.terminal.helpers')
local feed = helpers.feed
local eq = helpers.eq
local clear = helpers.clear
local ok = helpers.ok
local function test_embed(ext_linegrid)
local screen
@ -133,3 +136,60 @@ describe('--embed UI', function()
]]}
end)
end)
describe('--embed --listen UI', function()
it('waits for connection on listening address', function()
helpers.skip(helpers.is_os('win'))
clear()
local child_server = assert(helpers.new_pipename())
local screen = thelpers.screen_setup(0,
string.format(
[=[["%s", "--embed", "--listen", "%s", "-u", "NONE", "-i", "NONE", "--cmd", "%s"]]=],
helpers.nvim_prog, child_server, helpers.nvim_set))
screen:expect{grid=[[
{1: } |
|
|
|
|
|
{3:-- TERMINAL --} |
]]}
local child_session = helpers.connect(child_server)
local info_ok, apiinfo = child_session:request('nvim_get_api_info')
assert(info_ok)
assert(#apiinfo == 2)
child_session:request('nvim_exec2', [[
let g:vim_entered=0
autocmd VimEnter * call execute("let g:vim_entered=1")
]], {})
-- g:vim_entered shouldn't be set to 1 until after attach
local var_ok, var = child_session:request('nvim_get_var', 'vim_entered')
assert(var_ok)
ok(var == 0)
local child_screen = Screen.new(40, 6)
child_screen:attach(nil, child_session)
child_screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
|
]], attr_ids={
[1] = {foreground = Screen.colors.Blue, bold = true};
}}
-- g:vim_entered should now be set to 1
var_ok, var = child_session:request('nvim_get_var', 'vim_entered')
assert(var_ok)
ok(var == 1)
end)
end)