aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/starting.txt11
-rw-r--r--src/nvim/main.c24
-rw-r--r--src/nvim/msgpack_rpc/channel.c26
-rw-r--r--src/nvim/syntax.c3
-rw-r--r--test/functional/helpers.lua2
-rw-r--r--test/functional/plugin/helpers.lua2
-rw-r--r--test/functional/ui/embed_spec.lua71
7 files changed, 134 insertions, 5 deletions
diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt
index 3440131642..275b08b5dd 100644
--- a/runtime/doc/starting.txt
+++ b/runtime/doc/starting.txt
@@ -349,7 +349,16 @@ argument.
*--embed*
--embed Use stdin/stdout as a msgpack-RPC channel, so applications can
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})"
<
See also |channel-stdio|.
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 771074f189..b00f7947bd 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -344,6 +344,24 @@ int main(int argc, char **argv)
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.
exe_pre_commands(&params);
@@ -456,8 +474,10 @@ int main(int argc, char **argv)
setmouse(); // may start using the mouse
- if (exmode_active) {
- must_redraw = CLEAR; // Don't clear the screen when starting in Ex mode.
+ if (exmode_active || early_ui) {
+ // Don't clear the screen when starting in Ex mode, or when an
+ // embedding UI might have displayed messages
+ must_redraw = CLEAR;
} else {
screenclear(); // clear screen
TIME_MSG("clearing screen");
diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c
index bb4aea0986..c37dde341f 100644
--- a/src/nvim/msgpack_rpc/channel.c
+++ b/src/nvim/msgpack_rpc/channel.c
@@ -40,6 +40,8 @@
static PMap(cstr_t) *event_strings = NULL;
static msgpack_sbuffer out_buffer;
+static bool got_stdio_request = false;
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "msgpack_rpc/channel.c.generated.h"
#endif
@@ -329,6 +331,9 @@ static void handle_request(Channel *channel, msgpack_object *request)
send_error(channel, request_id, error.msg);
api_clear_error(&error);
api_free_array(args);
+ if (channel->id == CHAN_STDIO) {
+ got_stdio_request = true;
+ }
return;
}
@@ -344,6 +349,9 @@ static void handle_request(Channel *channel, msgpack_object *request)
if (is_get_mode && !input_blocking()) {
// Defer the event to a special queue used by os/input.c. #6247
multiqueue_put(ch_before_blocking_events, on_request_event, 1, evdata);
+ if (channel->id == CHAN_STDIO) {
+ got_stdio_request = true;
+ }
} else {
// Invoke immediately.
on_request_event((void **)&evdata);
@@ -378,6 +386,11 @@ static void on_request_event(void **argv)
channel_decref(channel);
xfree(e);
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)
@@ -744,3 +757,16 @@ static void log_msg_close(FILE *f, msgpack_object msg)
}
#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);
+}
+
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index 332c50129e..05f06d64c3 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -6332,7 +6332,6 @@ int load_colors(char_u *name)
apply_autocmds(EVENT_COLORSCHEME, name, curbuf->b_fname, FALSE, curbuf);
recursive = false;
- ui_refresh();
return retval;
}
@@ -6885,7 +6884,7 @@ void do_highlight(const char *line, const bool forceit, const bool init)
// "fg", which have been changed now.
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
// changed
ui_refresh();
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index 72e71a2cf2..8823a6e003 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -362,6 +362,8 @@ local function clear(...)
table.insert(args, arg)
end
set_session(spawn(args, nil, env))
+ -- Dummy request so that --embed continues past UI initialization
+ session:request('nvim_eval', "0")
end
local function insert(...)
diff --git a/test/functional/plugin/helpers.lua b/test/functional/plugin/helpers.lua
index 2024e6ebbf..bd482d2db7 100644
--- a/test/functional/plugin/helpers.lua
+++ b/test/functional/plugin/helpers.lua
@@ -3,6 +3,7 @@ local paths = require('test.config.paths')
local helpers = require('test.functional.helpers')(nil)
local spawn, set_session, nvim_prog, merge_args =
helpers.spawn, helpers.set_session, helpers.nvim_prog, helpers.merge_args
+local request = helpers.request
local additional_cmd = ''
@@ -29,6 +30,7 @@ local function reset(...)
end
session = spawn(nvim_argv(...))
set_session(session)
+ request('nvim_eval', "0")
end
local function set_additional_cmd(s)
diff --git a/test/functional/ui/embed_spec.lua b/test/functional/ui/embed_spec.lua
new file mode 100644
index 0000000000..7d41567fda
--- /dev/null
+++ b/test/functional/ui/embed_spec.lua
@@ -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)