diff options
author | Björn Linse <bjorn.linse@gmail.com> | 2018-09-18 20:52:13 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-09-18 20:52:13 +0200 |
commit | 809fff94e6786875cc852b98550cc73e65b33a87 (patch) | |
tree | 1798c2487a0a84ae7e98ac5d61906ca21742601e | |
parent | 32ad52ae04d3fea1fa84594b9b13ee1442a410ca (diff) | |
parent | bd8d43c6fef868ad5ed50a79deb0f7adc1f5e53a (diff) | |
download | rneovim-809fff94e6786875cc852b98550cc73e65b33a87.tar.gz rneovim-809fff94e6786875cc852b98550cc73e65b33a87.tar.bz2 rneovim-809fff94e6786875cc852b98550cc73e65b33a87.zip |
Merge pull request #8754 from bfredl/embed_ui
startup: make --embed wait for first request so embedding UI can display startup messages
-rw-r--r-- | runtime/doc/starting.txt | 11 | ||||
-rw-r--r-- | src/nvim/main.c | 24 | ||||
-rw-r--r-- | src/nvim/msgpack_rpc/channel.c | 26 | ||||
-rw-r--r-- | src/nvim/syntax.c | 3 | ||||
-rw-r--r-- | test/functional/helpers.lua | 2 | ||||
-rw-r--r-- | test/functional/plugin/helpers.lua | 2 | ||||
-rw-r--r-- | test/functional/ui/embed_spec.lua | 71 |
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(¶ms); @@ -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) |