mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge pull request #8754 from bfredl/embed_ui
startup: make --embed wait for first request so embedding UI can display startup messages
This commit is contained in:
commit
809fff94e6
@ -349,7 +349,16 @@ argument.
|
|||||||
*--embed*
|
*--embed*
|
||||||
--embed Use stdin/stdout as a msgpack-RPC channel, so applications can
|
--embed Use stdin/stdout as a msgpack-RPC channel, so applications can
|
||||||
embed and control Nvim via the |rpc-api|. Implies |--headless|.
|
embed and control Nvim via the |rpc-api|. Implies |--headless|.
|
||||||
Equivalent to: >
|
|
||||||
|
Nvim will wait for a single request before sourcing startup
|
||||||
|
files and reading buffers. This is mainly so that UIs can call
|
||||||
|
`nvim_ui_attach` so that the UI can show startup messages
|
||||||
|
and possible swap file dialog for the first loaded file. In
|
||||||
|
addition, a `nvim_get_api_info` call before the `nvim_ui_attach`
|
||||||
|
call is also allowed, so that UI features can be safely
|
||||||
|
detected by the UI.
|
||||||
|
|
||||||
|
To avoid this behavior, this alterative could be used instead: >
|
||||||
nvim --headless --cmd "call stdioopen({'rpc': v:true})"
|
nvim --headless --cmd "call stdioopen({'rpc': v:true})"
|
||||||
<
|
<
|
||||||
See also |channel-stdio|.
|
See also |channel-stdio|.
|
||||||
|
@ -344,6 +344,24 @@ int main(int argc, char **argv)
|
|||||||
p_lpl = false;
|
p_lpl = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// give embedders a chance to set up nvim, by processing a request before
|
||||||
|
// startup. This allows an external UI to show messages and prompts from
|
||||||
|
// --cmd and buffer loading (e.g. swap files)
|
||||||
|
bool early_ui = false;
|
||||||
|
if (embedded_mode) {
|
||||||
|
TIME_MSG("waiting for embedder to make request");
|
||||||
|
rpc_wait_for_request();
|
||||||
|
TIME_MSG("done waiting for embedder");
|
||||||
|
|
||||||
|
if (ui_active()) {
|
||||||
|
// prepare screen now, so external UIs can display messages
|
||||||
|
starting = NO_BUFFERS;
|
||||||
|
screenclear();
|
||||||
|
early_ui = true;
|
||||||
|
TIME_MSG("initialized screen early for embedder");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Execute --cmd arguments.
|
// Execute --cmd arguments.
|
||||||
exe_pre_commands(¶ms);
|
exe_pre_commands(¶ms);
|
||||||
|
|
||||||
@ -456,8 +474,10 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
setmouse(); // may start using the mouse
|
setmouse(); // may start using the mouse
|
||||||
|
|
||||||
if (exmode_active) {
|
if (exmode_active || early_ui) {
|
||||||
must_redraw = CLEAR; // Don't clear the screen when starting in Ex mode.
|
// Don't clear the screen when starting in Ex mode, or when an
|
||||||
|
// embedding UI might have displayed messages
|
||||||
|
must_redraw = CLEAR;
|
||||||
} else {
|
} else {
|
||||||
screenclear(); // clear screen
|
screenclear(); // clear screen
|
||||||
TIME_MSG("clearing screen");
|
TIME_MSG("clearing screen");
|
||||||
|
@ -40,6 +40,8 @@
|
|||||||
static PMap(cstr_t) *event_strings = NULL;
|
static PMap(cstr_t) *event_strings = NULL;
|
||||||
static msgpack_sbuffer out_buffer;
|
static msgpack_sbuffer out_buffer;
|
||||||
|
|
||||||
|
static bool got_stdio_request = false;
|
||||||
|
|
||||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
# include "msgpack_rpc/channel.c.generated.h"
|
# include "msgpack_rpc/channel.c.generated.h"
|
||||||
#endif
|
#endif
|
||||||
@ -329,6 +331,9 @@ static void handle_request(Channel *channel, msgpack_object *request)
|
|||||||
send_error(channel, request_id, error.msg);
|
send_error(channel, request_id, error.msg);
|
||||||
api_clear_error(&error);
|
api_clear_error(&error);
|
||||||
api_free_array(args);
|
api_free_array(args);
|
||||||
|
if (channel->id == CHAN_STDIO) {
|
||||||
|
got_stdio_request = true;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,6 +349,9 @@ static void handle_request(Channel *channel, msgpack_object *request)
|
|||||||
if (is_get_mode && !input_blocking()) {
|
if (is_get_mode && !input_blocking()) {
|
||||||
// Defer the event to a special queue used by os/input.c. #6247
|
// Defer the event to a special queue used by os/input.c. #6247
|
||||||
multiqueue_put(ch_before_blocking_events, on_request_event, 1, evdata);
|
multiqueue_put(ch_before_blocking_events, on_request_event, 1, evdata);
|
||||||
|
if (channel->id == CHAN_STDIO) {
|
||||||
|
got_stdio_request = true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Invoke immediately.
|
// Invoke immediately.
|
||||||
on_request_event((void **)&evdata);
|
on_request_event((void **)&evdata);
|
||||||
@ -378,6 +386,11 @@ static void on_request_event(void **argv)
|
|||||||
channel_decref(channel);
|
channel_decref(channel);
|
||||||
xfree(e);
|
xfree(e);
|
||||||
api_clear_error(&error);
|
api_clear_error(&error);
|
||||||
|
bool is_api_info = handler.fn == handle_nvim_get_api_info;
|
||||||
|
// api info is used to initiate client library, ignore it
|
||||||
|
if (channel->id == CHAN_STDIO && !is_api_info) {
|
||||||
|
got_stdio_request = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool channel_write(Channel *channel, WBuffer *buffer)
|
static bool channel_write(Channel *channel, WBuffer *buffer)
|
||||||
@ -744,3 +757,16 @@ static void log_msg_close(FILE *f, msgpack_object msg)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/// Wait until embedder has done a request
|
||||||
|
void rpc_wait_for_request(void)
|
||||||
|
{
|
||||||
|
Channel *channel = find_rpc_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, got_stdio_request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -6332,7 +6332,6 @@ int load_colors(char_u *name)
|
|||||||
apply_autocmds(EVENT_COLORSCHEME, name, curbuf->b_fname, FALSE, curbuf);
|
apply_autocmds(EVENT_COLORSCHEME, name, curbuf->b_fname, FALSE, curbuf);
|
||||||
|
|
||||||
recursive = false;
|
recursive = false;
|
||||||
ui_refresh();
|
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@ -6885,7 +6884,7 @@ void do_highlight(const char *line, const bool forceit, const bool init)
|
|||||||
// "fg", which have been changed now.
|
// "fg", which have been changed now.
|
||||||
highlight_attr_set_all();
|
highlight_attr_set_all();
|
||||||
|
|
||||||
if (!ui_is_external(kUINewgrid)) {
|
if (!ui_is_external(kUINewgrid) && starting != NO_SCREEN) {
|
||||||
// Older UIs assume that we clear the screen after normal group is
|
// Older UIs assume that we clear the screen after normal group is
|
||||||
// changed
|
// changed
|
||||||
ui_refresh();
|
ui_refresh();
|
||||||
|
@ -362,6 +362,8 @@ local function clear(...)
|
|||||||
table.insert(args, arg)
|
table.insert(args, arg)
|
||||||
end
|
end
|
||||||
set_session(spawn(args, nil, env))
|
set_session(spawn(args, nil, env))
|
||||||
|
-- Dummy request so that --embed continues past UI initialization
|
||||||
|
session:request('nvim_eval', "0")
|
||||||
end
|
end
|
||||||
|
|
||||||
local function insert(...)
|
local function insert(...)
|
||||||
|
@ -3,6 +3,7 @@ local paths = require('test.config.paths')
|
|||||||
local helpers = require('test.functional.helpers')(nil)
|
local helpers = require('test.functional.helpers')(nil)
|
||||||
local spawn, set_session, nvim_prog, merge_args =
|
local spawn, set_session, nvim_prog, merge_args =
|
||||||
helpers.spawn, helpers.set_session, helpers.nvim_prog, helpers.merge_args
|
helpers.spawn, helpers.set_session, helpers.nvim_prog, helpers.merge_args
|
||||||
|
local request = helpers.request
|
||||||
|
|
||||||
local additional_cmd = ''
|
local additional_cmd = ''
|
||||||
|
|
||||||
@ -29,6 +30,7 @@ local function reset(...)
|
|||||||
end
|
end
|
||||||
session = spawn(nvim_argv(...))
|
session = spawn(nvim_argv(...))
|
||||||
set_session(session)
|
set_session(session)
|
||||||
|
request('nvim_eval', "0")
|
||||||
end
|
end
|
||||||
|
|
||||||
local function set_additional_cmd(s)
|
local function set_additional_cmd(s)
|
||||||
|
71
test/functional/ui/embed_spec.lua
Normal file
71
test/functional/ui/embed_spec.lua
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
local helpers = require('test.functional.helpers')(after_each)
|
||||||
|
local Screen = require('test.functional.ui.screen')
|
||||||
|
|
||||||
|
local feed = helpers.feed
|
||||||
|
local spawn, set_session = helpers.spawn, helpers.set_session
|
||||||
|
local nvim_prog, nvim_set = helpers.nvim_prog, helpers.nvim_set
|
||||||
|
local merge_args, prepend_argv = helpers.merge_args, helpers.prepend_argv
|
||||||
|
|
||||||
|
describe('--embed UI on startup', function()
|
||||||
|
local session, screen
|
||||||
|
local function startup(...)
|
||||||
|
local nvim_argv = {nvim_prog, '-u', 'NONE', '-i', 'NONE',
|
||||||
|
'--cmd', nvim_set, '--embed'}
|
||||||
|
nvim_argv = merge_args(prepend_argv, nvim_argv, {...})
|
||||||
|
session = spawn(nvim_argv)
|
||||||
|
set_session(session)
|
||||||
|
|
||||||
|
-- attach immediately after startup, for early UI
|
||||||
|
screen = Screen.new(60, 8)
|
||||||
|
screen:attach()
|
||||||
|
screen:set_default_attr_ids({
|
||||||
|
[1] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
|
||||||
|
[2] = {bold = true, foreground = Screen.colors.SeaGreen4},
|
||||||
|
[3] = {bold = true, foreground = Screen.colors.Blue1},
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
after_each(function()
|
||||||
|
session:close()
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('can display errors', function()
|
||||||
|
startup('--cmd', 'echoerr invalid+')
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
Error detected while processing pre-vimrc command line: |
|
||||||
|
E121: Undefined variable: invalid |
|
||||||
|
E15: Invalid expression: invalid+ |
|
||||||
|
Press ENTER or type command to continue^ |
|
||||||
|
]])
|
||||||
|
|
||||||
|
feed('<cr>')
|
||||||
|
screen:expect([[
|
||||||
|
^ |
|
||||||
|
{3:~ }|
|
||||||
|
{3:~ }|
|
||||||
|
{3:~ }|
|
||||||
|
{3:~ }|
|
||||||
|
{3:~ }|
|
||||||
|
{3:~ }|
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("doesn't erase output when setting colors", function()
|
||||||
|
startup('--cmd', 'echoerr "foo"', '--cmd', 'color default', '--cmd', 'echoerr "bar"')
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
Error detected while processing pre-vimrc command line: |
|
||||||
|
foo |
|
||||||
|
{1:bar} |
|
||||||
|
{2:Press ENTER or type command to continue}^ |
|
||||||
|
]])
|
||||||
|
end)
|
||||||
|
end)
|
Loading…
Reference in New Issue
Block a user