diff options
author | Björn Linse <bjorn.linse@gmail.com> | 2018-09-20 19:19:38 +0200 |
---|---|---|
committer | Björn Linse <bjorn.linse@gmail.com> | 2018-09-22 10:18:28 +0200 |
commit | 4da5cb38d396d76d8072815d150725f7c9a85078 (patch) | |
tree | 426eb0f7525621d9760bb2cbf394d5c42b691775 | |
parent | 7f990741f7018b5e52833f2da6913b97c6d2d5ee (diff) | |
download | rneovim-4da5cb38d396d76d8072815d150725f7c9a85078.tar.gz rneovim-4da5cb38d396d76d8072815d150725f7c9a85078.tar.bz2 rneovim-4da5cb38d396d76d8072815d150725f7c9a85078.zip |
startup: always wait for UI with --embed, unless --headless also is supplied
-rw-r--r-- | runtime/doc/starting.txt | 33 | ||||
-rw-r--r-- | src/nvim/api/ui.c | 15 | ||||
-rw-r--r-- | src/nvim/channel.c | 2 | ||||
-rw-r--r-- | src/nvim/main.c | 21 | ||||
-rw-r--r-- | src/nvim/msgpack_rpc/channel.c | 27 | ||||
-rw-r--r-- | test/functional/api/server_requests_spec.lua | 7 | ||||
-rw-r--r-- | test/functional/ex_cmds/oldfiles_spec.lua | 2 | ||||
-rw-r--r-- | test/functional/helpers.lua | 9 | ||||
-rw-r--r-- | test/functional/plugin/helpers.lua | 4 | ||||
-rw-r--r-- | test/functional/shada/helpers.lua | 5 | ||||
-rw-r--r-- | test/functional/shada/marks_spec.lua | 4 | ||||
-rw-r--r-- | test/functional/shada/shada_spec.lua | 6 | ||||
-rw-r--r-- | test/functional/ui/embed_spec.lua | 16 |
13 files changed, 70 insertions, 81 deletions
diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt index 275b08b5dd..dd9f9ad0f3 100644 --- a/runtime/doc/starting.txt +++ b/runtime/doc/starting.txt @@ -348,30 +348,35 @@ argument. *--embed* --embed Use stdin/stdout as a msgpack-RPC channel, so applications can - embed and control Nvim via the |rpc-api|. Implies |--headless|. - - 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: > + embed and control Nvim via the |rpc-api|. + + By default nvim will wait for the embedding process to call + `nvim_ui_attach` before sourcing startup files and reading + buffers. This is so that UI can show startup messages and + possible swap file dialog for the first loaded file. The + process can do requests before the `nvim_ui_attach`, for + instance a `nvim_get_api_info` call so that UI features can be + safely detected by the UI before attaching. + + To embed nvim without using the UI protocol, `--headless` should + be supplied together with `--embed`. Then initialization is + performed without waiting for an UI. This is also equivalent + to the following alternative: > nvim --headless --cmd "call stdioopen({'rpc': v:true})" < See also |channel-stdio|. *--headless* ---headless Do not start the default UI, so stdio can be used as an - arbitrary communication channel. |channel-stdio| +--headless Start nvim without an UI. The TUI is not used, so stdio + can be used as an arbitrary communication channel. + |channel-stdio| When used together with `--embed`, do not wait + for the embedder to attach an UI. Also useful for scripting (tests) to see messages that would not be printed by |-es|. To detect if a UI is available, check if |nvim_list_uis()| is - empty after |VimEnter|. + empty in or after |VimEnter|. To read stdin as text, "-" must be given explicitly: --headless cannot assume that stdin is just text. > diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 509032892b..4971753854 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -58,6 +58,21 @@ 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) + FUNC_API_NOEXPORT +{ + 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, + pmap_has(uint64_t)(connected_uis, CHAN_STDIO)); +} + void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dictionary options, Error *err) FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY diff --git a/src/nvim/channel.c b/src/nvim/channel.c index 36423d0aa1..259f1cc600 100644 --- a/src/nvim/channel.c +++ b/src/nvim/channel.c @@ -432,7 +432,7 @@ uint64_t channel_from_stdio(bool rpc, CallbackReader on_output, const char **error) FUNC_ATTR_NONNULL_ALL { - if (!headless_mode) { + if (!headless_mode && !embedded_mode) { *error = _("can only be opened in headless mode"); return 0; } diff --git a/src/nvim/main.c b/src/nvim/main.c index 192e7d2907..4b838a837c 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -65,6 +65,7 @@ #include "nvim/msgpack_rpc/helpers.h" #include "nvim/msgpack_rpc/server.h" #include "nvim/msgpack_rpc/channel.h" +#include "nvim/api/ui.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #include "nvim/api/private/handle.h" @@ -304,6 +305,7 @@ int main(int argc, char **argv) // Read ex-commands if invoked with "-es". // bool reading_tty = !headless_mode + && !embedded_mode && !silent_mode && (params.input_isatty || params.output_isatty || params.err_isatty); @@ -348,18 +350,16 @@ int main(int argc, char **argv) // 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) { + if (embedded_mode && !headless_mode) { TIME_MSG("waiting for embedder to make request"); - rpc_wait_for_request(); + remote_ui_wait_for_attach(); 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"); - } + // 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. @@ -467,7 +467,7 @@ int main(int argc, char **argv) wait_return(true); } - if (!headless_mode && !silent_mode) { + if (!headless_mode && !embedded_mode && !silent_mode) { input_stop(); // Stop reading input, let the UI take over. ui_builtin_start(); } @@ -848,7 +848,6 @@ static void command_line_scan(mparm_T *parmp) headless_mode = true; } else if (STRICMP(argv[0] + argv_idx, "embed") == 0) { embedded_mode = true; - headless_mode = true; const char *err; if (!channel_from_stdio(true, CALLBACK_READER_INIT, &err)) { abort(); diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index c6cfb1a9ce..3356cdc61e 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -40,8 +40,6 @@ 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 @@ -331,9 +329,6 @@ 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; } @@ -349,9 +344,6 @@ 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); @@ -387,11 +379,6 @@ 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) @@ -757,17 +744,3 @@ static void log_msg_close(FILE *f, msgpack_object msg) log_unlock(); } #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/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua index 856e5ca4d2..4d25ba0819 100644 --- a/test/functional/api/server_requests_spec.lua +++ b/test/functional/api/server_requests_spec.lua @@ -9,7 +9,7 @@ local nvim_prog, command, funcs = helpers.nvim_prog, helpers.command, helpers.fu local source, next_msg = helpers.source, helpers.next_msg local ok = helpers.ok local meths = helpers.meths -local spawn, nvim_argv = helpers.spawn, helpers.nvim_argv +local spawn, merge_args = helpers.spawn, helpers.merge_args local set_session = helpers.set_session local expect_err = helpers.expect_err @@ -23,7 +23,7 @@ describe('server -> client', function() it('handles unexpected closed stream while preparing RPC response', function() source([[ - let g:_nvim_args = [v:progpath, '--embed', '-n', '-u', 'NONE', '-i', 'NONE', ] + let g:_nvim_args = [v:progpath, '--embed', '--headless', '-n', '-u', 'NONE', '-i', 'NONE', ] let ch1 = jobstart(g:_nvim_args, {'rpc': v:true}) let child1_ch = rpcrequest(ch1, "nvim_get_api_info")[0] call rpcnotify(ch1, 'nvim_eval', 'rpcrequest('.child1_ch.', "nvim_get_api_info")') @@ -189,7 +189,7 @@ describe('server -> client', function() end before_each(function() - command("let vim = rpcstart('"..nvim_prog.."', ['-u', 'NONE', '-i', 'NONE', '--cmd', 'set noswapfile', '--embed'])") + command("let vim = rpcstart('"..nvim_prog.."', ['-u', 'NONE', '-i', 'NONE', '--cmd', 'set noswapfile', '--embed', '--headless'])") neq(0, eval('vim')) end) @@ -268,6 +268,7 @@ describe('server -> client', function() end) describe('connecting to another (peer) nvim', function() + local nvim_argv = merge_args(helpers.nvim_argv, {'--headless'}) local function connect_test(server, mode, address) local serverpid = funcs.getpid() local client = spawn(nvim_argv) diff --git a/test/functional/ex_cmds/oldfiles_spec.lua b/test/functional/ex_cmds/oldfiles_spec.lua index 448326cdfb..e2958c2924 100644 --- a/test/functional/ex_cmds/oldfiles_spec.lua +++ b/test/functional/ex_cmds/oldfiles_spec.lua @@ -9,7 +9,7 @@ local eval = helpers.eval local shada_file = 'Xtest.shada' local function _clear() - set_session(spawn({nvim_prog, '--embed', '-u', 'NONE', + set_session(spawn({nvim_prog, '--embed', '--headless', '-u', 'NONE', -- Need shada for these tests. '-i', shada_file, '--cmd', 'set noswapfile undodir=. directory=. viewdir=. backupdir=. belloff= noshowcmd noruler'})) diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 8823a6e003..a51eca7fdc 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -330,6 +330,7 @@ local function clear(...) local new_args local env = nil local opts = select(1, ...) + local headless = true if type(opts) == 'table' then if opts.env then local env_tbl = {} @@ -355,15 +356,19 @@ local function clear(...) end end new_args = opts.args or {} + if opts.headless == false then + headless = false + end else new_args = {...} end + if headless then + table.insert(args, '--headless') + end for _, arg in ipairs(new_args) do 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 bd482d2db7..4359380bd7 100644 --- a/test/functional/plugin/helpers.lua +++ b/test/functional/plugin/helpers.lua @@ -3,7 +3,6 @@ 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 = '' @@ -14,7 +13,7 @@ local function nvim_argv(shada_file) '--cmd', 'set shortmess+=I background=light noswapfile belloff= noshowcmd noruler', '--cmd', 'let &runtimepath=' .. rtp_value, '--cmd', additional_cmd, - '--embed'} + '--embed', '--headless'} if helpers.prepend_argv then return merge_args(helpers.prepend_argv, nvim_args) else @@ -30,7 +29,6 @@ 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/shada/helpers.lua b/test/functional/shada/helpers.lua index 1312d762d8..d5e061bb50 100644 --- a/test/functional/shada/helpers.lua +++ b/test/functional/shada/helpers.lua @@ -9,9 +9,12 @@ local tmpname = helpers.tmpname() local append_argv = nil local function nvim_argv(shada_file, embed) + if embed == nil then + embed = true + end local argv = {nvim_prog, '-u', 'NONE', '-i', shada_file or tmpname, '-N', '--cmd', 'set shortmess+=I background=light noswapfile', - embed or '--embed'} + '--headless', embed and '--embed' or nil} if helpers.prepend_argv or append_argv then return merge_args(helpers.prepend_argv, argv, append_argv) else diff --git a/test/functional/shada/marks_spec.lua b/test/functional/shada/marks_spec.lua index 4cceae1aa3..c2f6351e00 100644 --- a/test/functional/shada/marks_spec.lua +++ b/test/functional/shada/marks_spec.lua @@ -224,7 +224,7 @@ describe('ShaDa support code', function() it('does not create incorrect file for non-existent buffers when writing from -c', function() add_argv('--cmd', 'silent edit ' .. non_existent_testfilename, '-c', 'qall') - local argv = nvim_argv(nil, '--headless') + local argv = nvim_argv(nil, false) -- no --embed eq('', funcs.system(argv)) eq(0, exc_exec('rshada')) end) @@ -233,7 +233,7 @@ describe('ShaDa support code', function() function() add_argv('-c', 'silent edit ' .. non_existent_testfilename, '-c', 'autocmd VimEnter * qall') - local argv = nvim_argv(nil, '--headless') + local argv = nvim_argv(nil, false) -- no --embed eq('', funcs.system(argv)) eq(0, exc_exec('rshada')) end) diff --git a/test/functional/shada/shada_spec.lua b/test/functional/shada/shada_spec.lua index 720855860a..5f7daf73e5 100644 --- a/test/functional/shada/shada_spec.lua +++ b/test/functional/shada/shada_spec.lua @@ -137,7 +137,7 @@ describe('ShaDa support code', function() it('does not write NONE file', function() local session = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed', - '--cmd', 'qall'}, true) + '--headless', '--cmd', 'qall'}, true) session:close() eq(nil, lfs.attributes('NONE')) eq(nil, lfs.attributes('NONE.tmp.a')) @@ -145,8 +145,8 @@ describe('ShaDa support code', function() it('does not read NONE file', function() write_file('NONE', '\005\001\015\131\161na\162rX\194\162rc\145\196\001-') - local session = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed'}, - true) + local session = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed', + '--headless'}, true) set_session(session) eq('', funcs.getreg('a')) session:close() diff --git a/test/functional/ui/embed_spec.lua b/test/functional/ui/embed_spec.lua index afe4db66b3..6a5227803d 100644 --- a/test/functional/ui/embed_spec.lua +++ b/test/functional/ui/embed_spec.lua @@ -3,18 +3,12 @@ local Screen = require('test.functional.ui.screen') local feed = helpers.feed local eq = helpers.eq -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 +local clear = helpers.clear local function test_embed(ext_newgrid) - local session, screen + local 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) + clear{headless=false, args={...}} -- attach immediately after startup, for early UI screen = Screen.new(60, 8) @@ -26,10 +20,6 @@ local function test_embed(ext_newgrid) }) end - after_each(function() - session:close() - end) - it('can display errors', function() startup('--cmd', 'echoerr invalid+') screen:expect([[ |