diff options
-rw-r--r-- | CONTRIBUTING.md | 2 | ||||
-rw-r--r-- | runtime/doc/api.txt | 4 | ||||
-rw-r--r-- | runtime/doc/gui.txt | 19 | ||||
-rw-r--r-- | runtime/doc/news.txt | 2 | ||||
-rw-r--r-- | src/nvim/api/ui.c | 2 | ||||
-rw-r--r-- | src/nvim/api/vim.c | 7 | ||||
-rw-r--r-- | src/nvim/channel.c | 1 | ||||
-rw-r--r-- | src/nvim/channel.h | 3 | ||||
-rw-r--r-- | src/nvim/event/proc.c | 16 | ||||
-rw-r--r-- | src/nvim/event/stream.c | 3 | ||||
-rw-r--r-- | src/nvim/ex_cmds.lua | 6 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 53 | ||||
-rw-r--r-- | src/nvim/globals.h | 2 | ||||
-rw-r--r-- | src/nvim/msgpack_rpc/channel.c | 20 | ||||
-rw-r--r-- | src/nvim/os/input.c | 4 | ||||
-rw-r--r-- | src/nvim/ui_client.c | 8 | ||||
-rw-r--r-- | test/functional/core/job_spec.lua | 16 | ||||
-rw-r--r-- | test/functional/editor/put_spec.lua | 2 | ||||
-rw-r--r-- | test/functional/terminal/tui_spec.lua | 258 | ||||
-rw-r--r-- | test/functional/testnvim.lua | 6 |
20 files changed, 300 insertions, 134 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 324cb3e13a..2cf93e74ed 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -129,7 +129,7 @@ Each pull request must pass the automated builds on [Cirrus CI] and [GitHub Acti passes various linter checks. - CI for FreeBSD runs on [Cirrus CI]. - To see CI results faster in your PR, you can temporarily set `TEST_FILE` in - [test.yml](https://github.com/neovim/neovim/blob/e35b9020b16985eee26e942f9a3f6b045bc3809b/.github/workflows/test.yml#L29). + [test.yml](https://github.com/neovim/neovim/blob/ad8e0cfc1dfd937c2577dc032e524c799a772693/.github/workflows/test.yml#L26). ### Coverity diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index 92f5a261ee..4f76e7e058 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -1208,8 +1208,8 @@ nvim_select_popupmenu_item({item}, {insert}, {finish}, {opts}) *nvim_set_client_info()* nvim_set_client_info({name}, {version}, {type}, {methods}, {attributes}) - Self-identifies the client. Sets the `client` object returned by - |nvim_get_chan_info()|. + Self-identifies the client, and sets optional flags on the channel. + Defines the `client` object returned by |nvim_get_chan_info()|. Clients should call this just after connecting, to provide hints for debugging and orchestration. (Note: Something is better than nothing! diff --git a/runtime/doc/gui.txt b/runtime/doc/gui.txt index ecb4de09bb..780712df6c 100644 --- a/runtime/doc/gui.txt +++ b/runtime/doc/gui.txt @@ -47,6 +47,25 @@ can connect to any Nvim instance). Example: this sets "g:gui" to the value of the UI's "rgb" field: > :autocmd UIEnter * let g:gui = filter(nvim_list_uis(),{k,v-> v.chan==v:event.chan})[0].rgb < +------------------------------------------------------------------------------ +Stop or detach the current UI + + *:detach* +:detach + Detaches the current UI. Other UIs (if any) remain attached. + The server (typically `nvim --embed`) continues running as + a background process, and you can reattach to it later. + Before detaching, you may want to note the server address: + >vim + :echo v:servername +< + Note: The server closes the UI RPC channel, so :detach + inherently "works" for all UIs. But if a UI isn't expecting + the channel to be closed, it may be (incorrectly) reported as + an error. + +------------------------------------------------------------------------------ +GUI commands *:winp* *:winpos* *E188* :winp[os] diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index 1f1ad84a02..90a020bb4d 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -400,6 +400,8 @@ TUI UI +• |:detach| the current UI, let the Nvim server continue running as a background + process. Works with the builtin TUI, and all GUIs. • |vim.ui.open()| (by default bound to |gx|) accepts an `opt.cmd` parameter which controls the tool used to open the given path or URL. If you want to globally set this, you can override vim.ui.open using the same approach diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index f6f32a73ed..41a09999d0 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -189,6 +189,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dict opt ui->wildmenu_active = false; pmap_put(uint64_t)(&connected_uis, channel_id, ui); + current_ui = channel_id; ui_attach_impl(ui, channel_id); may_trigger_vim_suspend_resume(false); @@ -214,6 +215,7 @@ void nvim_ui_set_focus(uint64_t channel_id, Boolean gained, Error *error) } if (gained) { + current_ui = channel_id; may_trigger_vim_suspend_resume(false); } diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index c103a56032..02aa73d98d 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -359,11 +359,11 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_ks) /// @param keys to be typed /// @return Number of bytes actually written (can be fewer than /// requested if the buffer becomes full). -Integer nvim_input(String keys) +Integer nvim_input(uint64_t channel_id, String keys) FUNC_API_SINCE(1) FUNC_API_FAST { may_trigger_vim_suspend_resume(false); - return (Integer)input_enqueue(keys); + return (Integer)input_enqueue(channel_id, keys); } /// Send mouse event from GUI. @@ -1485,7 +1485,8 @@ Array nvim_get_api_info(uint64_t channel_id, Arena *arena) return rv; } -/// Self-identifies the client. Sets the `client` object returned by |nvim_get_chan_info()|. +/// Self-identifies the client, and sets optional flags on the channel. Defines the `client` object +/// returned by |nvim_get_chan_info()|. /// /// Clients should call this just after connecting, to provide hints for debugging and /// orchestration. (Note: Something is better than nothing! Fields are optional, but at least set diff --git a/src/nvim/channel.c b/src/nvim/channel.c index 912d515f84..c964748a20 100644 --- a/src/nvim/channel.c +++ b/src/nvim/channel.c @@ -219,6 +219,7 @@ Channel *channel_alloc(ChannelStreamType type) chan->refcount = 1; chan->exit_status = -1; chan->streamtype = type; + chan->detach = false; assert(chan->id <= VARNUMBER_MAX); pmap_put(uint64_t)(&channels, chan->id, chan); return chan; diff --git a/src/nvim/channel.h b/src/nvim/channel.h index 2327216826..81d67ceb66 100644 --- a/src/nvim/channel.h +++ b/src/nvim/channel.h @@ -31,6 +31,9 @@ struct Channel { } stream; bool is_rpc; + bool detach; ///< Prevents self-exit on channel-close. Normally, Nvim self-exits if its primary + ///< RPC channel is closed, unless detach=true. Note: currently, detach=false does + ///< not FORCE self-exit. RpcState rpc; Terminal *term; diff --git a/src/nvim/event/proc.c b/src/nvim/event/proc.c index 37cb102d11..e32bbbc29a 100644 --- a/src/nvim/event/proc.c +++ b/src/nvim/event/proc.c @@ -315,10 +315,8 @@ static void decref(Proc *proc) static void proc_close(Proc *proc) FUNC_ATTR_NONNULL_ARG(1) { - if (proc_is_tearing_down && (proc->detach || proc->type == kProcTypePty) - && proc->closed) { - // If a detached/pty process dies while tearing down it might get closed - // twice. + if (proc_is_tearing_down && proc->closed && (proc->detach || proc->type == kProcTypePty)) { + // If a detached/pty process dies while tearing down it might get closed twice. return; } assert(!proc->closed); @@ -427,19 +425,21 @@ static void exit_event(void **argv) } } -void exit_from_channel(int status) +/// Performs self-exit because the primary RPC channel was closed. +void exit_on_closed_chan(int status) { + DLOG("self-exit triggered by closed RPC channel..."); multiqueue_put(main_loop.fast_events, exit_event, (void *)(intptr_t)status); } static void on_proc_exit(Proc *proc) { Loop *loop = proc->loop; - ILOG("exited: pid=%d status=%d stoptime=%" PRIu64, proc->pid, proc->status, - proc->stopped_time); + ILOG("child exited: pid=%d status=%d" PRIu64, proc->pid, proc->status); + // XXX: This assumes the TUI never spawns any other processes...? if (ui_client_channel_id) { - exit_from_channel(proc->status); + exit_on_closed_chan(proc->status); } // Process has terminated, but there could still be data to be read from the diff --git a/src/nvim/event/stream.c b/src/nvim/event/stream.c index 9c155b55ea..3e32813e1c 100644 --- a/src/nvim/event/stream.c +++ b/src/nvim/event/stream.c @@ -104,9 +104,10 @@ void stream_may_close(Stream *stream, bool rstream) if (stream->closed) { return; } - assert(!stream->closed); DLOG("closing Stream: %p", (void *)stream); stream->closed = true; + // TODO(justinmk): stream->close_cb is never actually invoked. Either remove it, or see if it can + // be used somewhere... stream->close_cb = NULL; stream->close_cb_data = NULL; diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index 0cdc397e9c..d118c808d3 100644 --- a/src/nvim/ex_cmds.lua +++ b/src/nvim/ex_cmds.lua @@ -733,6 +733,12 @@ M.cmds = { func = 'ex_delfunction', }, { + command = 'detach', + flags = bit.bor(BANG, FILES, CMDARG, ARGOPT, TRLBAR, CMDWIN, LOCK_OK), + addr_type = 'ADDR_NONE', + func = 'ex_detach', + }, + { command = 'display', flags = bit.bor(EXTRA, NOTRLCOM, TRLBAR, SBOXOK, CMDWIN, LOCK_OK), addr_type = 'ADDR_NONE', diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index ceb17a995d..3b78092daf 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -14,6 +14,7 @@ #include "auto/config.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" +#include "nvim/api/ui.h" #include "nvim/arglist.h" #include "nvim/ascii_defs.h" #include "nvim/autocmd.h" @@ -21,6 +22,7 @@ #include "nvim/buffer.h" #include "nvim/buffer_defs.h" #include "nvim/change.h" +#include "nvim/channel.h" #include "nvim/charset.h" #include "nvim/cmdexpand.h" #include "nvim/cmdexpand_defs.h" @@ -67,6 +69,7 @@ #include "nvim/message.h" #include "nvim/mouse.h" #include "nvim/move.h" +#include "nvim/msgpack_rpc/server.h" #include "nvim/normal.h" #include "nvim/normal_defs.h" #include "nvim/ops.h" @@ -5530,6 +5533,56 @@ static void ex_tabs(exarg_T *eap) } } +/// ":detach" +/// +/// Detaches the current UI. +/// +/// ":detach!" with bang (!) detaches all UIs _except_ the current UI. +static void ex_detach(exarg_T *eap) +{ + // come on pooky let's burn this mf down + if (eap && eap->forceit) { + emsg("bang (!) not supported yet"); + } else { + // 1. (TODO) Send "detach" UI-event (notification only). + // 2. Perform server-side `nvim_ui_detach`. + // 3. Close server-side channel without self-exit. + + if (!current_ui) { + emsg("UI not attached"); + return; + } + + Channel *chan = find_channel(current_ui); + if (!chan) { + emsg(e_invchan); + return; + } + chan->detach = true; // Prevent self-exit on channel-close. + + // Server-side UI detach. Doesn't close the channel. + Error err2 = ERROR_INIT; + nvim_ui_detach(chan->id, &err2); + if (ERROR_SET(&err2)) { + emsg(err2.msg); // UI disappeared already? + api_clear_error(&err2); + return; + } + + // Server-side channel close. + const char *err = NULL; + bool rv = channel_close(chan->id, kChannelPartAll, &err); + if (!rv && err) { + emsg(err); // UI disappeared already? + return; + } + // XXX: Can't do this, channel_decref() is async... + // assert(!find_channel(chan->id)); + + ILOG("detach current_ui=%" PRId64, chan->id); + } +} + /// ":mode": /// If no argument given, get the screen size and redraw. static void ex_mode(exarg_T *eap) diff --git a/src/nvim/globals.h b/src/nvim/globals.h index a473180349..ea349352a8 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -301,6 +301,8 @@ EXTERN bool garbage_collect_at_exit INIT( = false); EXTERN sctx_T current_sctx INIT( = { 0, 0, 0 }); // ID of the current channel making a client API call EXTERN uint64_t current_channel_id INIT( = 0); +/// Last channel that invoked 'nvim_input` or got FocusGained. +EXTERN uint64_t current_ui INIT( = 0); EXTERN bool did_source_packages INIT( = false); diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index e38bc1896d..fa50afd83b 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -224,8 +224,7 @@ static size_t receive_msgpack(RStream *stream, const char *rbuf, size_t c, void if (eof) { channel_close(channel->id, kChannelPartRpc, NULL); char buf[256]; - snprintf(buf, sizeof(buf), "ch %" PRIu64 " was closed by the client", - channel->id); + snprintf(buf, sizeof(buf), "ch %" PRIu64 " was closed by the peer", channel->id); chan_close_with_error(channel, buf, LOGLVL_INF); } @@ -293,7 +292,7 @@ static void parse_msgpack(Channel *channel) Object res = p->result; if (p->result.type != kObjectTypeArray) { - chan_close_with_error(channel, "msgpack-rpc request args has to be an array", LOGLVL_ERR); + chan_close_with_error(channel, "msgpack-rpc request args must be an array", LOGLVL_ERR); return; } Array arg = res.data.array; @@ -487,13 +486,16 @@ void rpc_close(Channel *channel) channel->rpc.closed = true; channel_decref(channel); - if (channel->streamtype == kChannelStreamStdio - || (channel->id == ui_client_channel_id && channel->streamtype != kChannelStreamProc)) { - if (channel->streamtype == kChannelStreamStdio) { - // Avoid hanging when there are no other UIs and a prompt is triggered on exit. - remote_ui_disconnect(channel->id); + if (ui_client_channel_id && channel->id == ui_client_channel_id) { + assert(!channel->detach); // `Channel.detach` is not currently used by the UI client. + exit_on_closed_chan(0); + } else if (channel->streamtype == kChannelStreamStdio) { + // Avoid hanging when there are no other UIs and a prompt is triggered on exit. + remote_ui_disconnect(channel->id); + + if (!channel->detach) { + exit_on_closed_chan(0); } - exit_from_channel(0); } } diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 3259fb500b..f510c67753 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -274,8 +274,10 @@ void input_enqueue_raw(const char *data, size_t size) input_write_pos += to_write; } -size_t input_enqueue(String keys) +size_t input_enqueue(uint64_t chan_id, String keys) { + current_ui = chan_id; + const char *ptr = keys.data; const char *end = ptr + keys.size; diff --git a/src/nvim/ui_client.c b/src/nvim/ui_client.c index af946d799a..44fc645a04 100644 --- a/src/nvim/ui_client.c +++ b/src/nvim/ui_client.c @@ -61,9 +61,15 @@ uint64_t ui_client_start_server(int argc, char **argv) CallbackReader on_err = CALLBACK_READER_INIT; on_err.fwd_err = true; +#ifdef MSWIN + // TODO(justinmk): detach breaks `tt.setup_child_nvim` tests on Windows? + bool detach = os_env_exists("__NVIM_DETACH"); +#else + bool detach = true; +#endif Channel *channel = channel_job_start(args, get_vim_var_str(VV_PROGPATH), CALLBACK_READER_INIT, on_err, CALLBACK_NONE, - false, true, true, false, kChannelStdinPipe, + false, true, true, detach, kChannelStdinPipe, NULL, 0, 0, NULL, &exit_status); if (!channel) { return 0; diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua index e833b5127d..75e09f3455 100644 --- a/test/functional/core/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -1265,12 +1265,16 @@ describe('jobs', function() ]]) feed(':q<CR>') - screen:expect([[ - | - [Process exited 0]^ | - |*4 - {3:-- TERMINAL --} | - ]]) + if is_os('freebsd') then + screen:expect { any = vim.pesc('[Process exited 0]') } + else + screen:expect([[ + | + [Process exited 0]^ | + |*4 + {3:-- TERMINAL --} | + ]]) + end end) end) diff --git a/test/functional/editor/put_spec.lua b/test/functional/editor/put_spec.lua index 79f9d97bc5..aeb9c75e42 100644 --- a/test/functional/editor/put_spec.lua +++ b/test/functional/editor/put_spec.lua @@ -931,6 +931,8 @@ describe('put command', function() end) it('should ring the bell when deleting if not appropriate', function() + t.skip(t.is_os('bsd'), 'crashes on freebsd') + command('goto 2') feed('i<bs><esc>') expect([[ diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 147a8675cb..e2adcb66df 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -33,6 +33,133 @@ local assert_log = t.assert_log local testlog = 'Xtest-tui-log' +describe('TUI :detach', function() + before_each(function() + os.remove(testlog) + end) + teardown(function() + os.remove(testlog) + end) + + it('does not stop server', function() + local job_opts = { + env = { + NVIM_LOG_FILE = testlog, + }, + } + + if is_os('win') then + -- TODO(justinmk): on Windows, + -- - tt.setup_child_nvim() is broken. + -- - session.lua is broken after the pipe closes. + -- So this test currently just exercises __NVIM_DETACH + :detach, without asserting anything. + + -- TODO(justinmk): temporary hack for Windows. + job_opts.env['__NVIM_DETACH'] = '1' + n.clear(job_opts) + + local screen = Screen.new(50, 10) + n.feed('iHello, World') + screen:expect([[ + Hello, World^ | + {1:~ }|*8 + {5:-- INSERT --} | + ]]) + + -- local addr = api.nvim_get_vvar('servername') + eq(1, #n.api.nvim_list_uis()) + + -- TODO(justinmk): test util should not freak out when the pipe closes. + n.expect_exit(n.command, 'detach') + + -- n.get_session():close() -- XXX: hangs + -- n.set_session(n.connect(addr)) -- XXX: hangs + -- eq(0, #n.api.nvim_list_uis()) -- XXX: hangs + + -- Avoid a dangling process. + n.get_session():close('kill') + -- n.expect_exit(n.command, 'qall!') + + return + end + + local server_super = n.clear() + local client_super = n.new_session(true) + finally(function() + server_super:close() + client_super:close() + end) + + local child_server = new_pipename() + local screen = tt.setup_child_nvim({ + '--listen', + child_server, + '-u', + 'NONE', + '-i', + 'NONE', + '--cmd', + 'colorscheme vim', + '--cmd', + nvim_set .. ' notermguicolors laststatus=2 background=dark', + }, job_opts) + + tt.feed_data('iHello, World') + screen:expect { + grid = [[ + Hello, World^ | + {4:~ }|*3 + {MATCH:No Name} + {3:-- INSERT --} | + {3:-- TERMINAL --} | + ]], + } + + local child_session = n.connect(child_server) + finally(function() + child_session:request('nvim_command', 'qall!') + end) + local status, child_uis = child_session:request('nvim_list_uis') + assert(status) + eq(1, #child_uis) + + tt.feed_data('\027\027:detach\013') + -- Note: "Process exited" message is misleading; tt.setup_child_nvim() sees the foreground + -- process (client) exited, and doesn't know the server is still running? + screen:expect { + any = [[Process exited 0]], + } + + child_uis --[[@type any[] ]] = ({ child_session:request('nvim_list_uis') })[2] + eq(0, #child_uis) + + -- NOTE: The tt.setup_child_nvim() screen just wraps :terminal, it's not connected to the child. + -- To use it again, we need to detach the old one. + screen:detach() + + -- Edit some text on the headless server. + status = (child_session:request('nvim_input', 'ddiWe did it, pooky.<Esc><Esc>')) + assert(status) + + -- Test reattach by connecting a new TUI. + local screen_reattached = tt.setup_child_nvim({ + '--remote-ui', + '--server', + child_server, + }, job_opts) + + screen_reattached:expect { + grid = [[ + We did it, pooky^. | + {4:~ }|*3 + {5:[No Name] [+] }| + | + {3:-- TERMINAL --} | + ]], + } + end) +end) + if t.skip(is_os('win')) then return end @@ -48,10 +175,7 @@ describe('TUI', function() screen = tt.setup_child_nvim({ '--listen', child_server, - '-u', - 'NONE', - '-i', - 'NONE', + '--clean', '--cmd', nvim_set .. ' notermguicolors laststatus=2 background=dark', '--cmd', @@ -2222,7 +2346,7 @@ describe('TUI', function() end) local screen = tt.setup_screen( 0, - ('"%s" -u NONE -i NONE --cmd "set noswapfile noshowcmd noruler" --cmd "normal iabc" > /dev/null 2>&1 && cat testF && rm testF'):format( + ('"%s" --clean --cmd "set noswapfile noshowcmd noruler" --cmd "normal iabc" > /dev/null 2>&1 && cat testF && rm testF'):format( nvim_prog ), nil, @@ -2242,10 +2366,7 @@ describe('TUI', function() it('<C-h> #10134', function() local screen = tt.setup_child_nvim({ - '-u', - 'NONE', - '-i', - 'NONE', + '--clean', '--cmd', 'colorscheme vim', '--cmd', @@ -2275,10 +2396,7 @@ describe('TUI', function() it('draws line with many trailing spaces correctly #24955', function() local screen = tt.setup_child_nvim({ - '-u', - 'NONE', - '-i', - 'NONE', + '--clean', '--cmd', 'set notermguicolors', '--cmd', @@ -2312,10 +2430,7 @@ describe('TUI', function() it('draws screen lines with leading spaces correctly #29711', function() local screen = tt.setup_child_nvim({ - '-u', - 'NONE', - '-i', - 'NONE', + '--clean', '--cmd', 'set foldcolumn=6 | call setline(1, ["", repeat("aabb", 1000)]) | echo 42', }, { extra_rows = 10, cols = 66 }) @@ -2355,10 +2470,7 @@ describe('TUI', function() -- Set a different bg colour and change $TERM to something dumber so the `print_spaces()` -- codepath in `clear_region()` is hit. local screen = tt.setup_child_nvim({ - '-u', - 'NONE', - '-i', - 'NONE', + '--clean', '--cmd', 'set notermguicolors | highlight Normal ctermbg=red', '--cmd', @@ -2399,10 +2511,7 @@ describe('TUI UIEnter/UILeave', function() it('fires exactly once, after VimEnter', function() clear() local screen = tt.setup_child_nvim({ - '-u', - 'NONE', - '-i', - 'NONE', + '--clean', '--cmd', 'colorscheme vim', '--cmd', @@ -2665,10 +2774,7 @@ describe("TUI 't_Co' (terminal colors)", function() local function assert_term_colors(term, colorterm, maxcolors) clear({ env = { TERM = term }, args = {} }) screen = tt.setup_child_nvim({ - '-u', - 'NONE', - '-i', - 'NONE', + '--clean', '--cmd', 'colorscheme vim', '--cmd', @@ -2948,10 +3054,7 @@ describe("TUI 'term' option", function() local function assert_term(term_envvar, term_expected) clear() screen = tt.setup_child_nvim({ - '-u', - 'NONE', - '-i', - 'NONE', + '--clean', '--cmd', nvim_set .. ' notermguicolors', }, { @@ -3008,10 +3111,7 @@ describe('TUI', function() local function nvim_tui(extra_args) clear() screen = tt.setup_child_nvim({ - '-u', - 'NONE', - '-i', - 'NONE', + '--clean', '--cmd', 'colorscheme vim', '--cmd', @@ -3089,12 +3189,9 @@ describe('TUI', function() local child_server = new_pipename() screen = tt.setup_child_nvim({ + '--clean', '--listen', child_server, - '-u', - 'NONE', - '-i', - 'NONE', }, { env = { VIMRUNTIME = os.getenv('VIMRUNTIME'), @@ -3146,12 +3243,9 @@ describe('TUI', function() local child_server = new_pipename() screen = tt.setup_child_nvim({ + '--clean', '--listen', child_server, - '-u', - 'NONE', - '-i', - 'NONE', }, { env = { VIMRUNTIME = os.getenv('VIMRUNTIME'), @@ -3220,12 +3314,9 @@ describe('TUI bg color', function() command('set background=dark') -- set outer Nvim background local child_server = new_pipename() local screen = tt.setup_child_nvim({ + '--clean', '--listen', child_server, - '-u', - 'NONE', - '-i', - 'NONE', '--cmd', 'colorscheme vim', '--cmd', @@ -3243,12 +3334,9 @@ describe('TUI bg color', function() command('set background=light') -- set outer Nvim background local child_server = new_pipename() local screen = tt.setup_child_nvim({ + '--clean', '--listen', child_server, - '-u', - 'NONE', - '-i', - 'NONE', '--cmd', 'colorscheme vim', '--cmd', @@ -3274,10 +3362,7 @@ describe('TUI bg color', function() }) ]]) tt.setup_child_nvim({ - '-u', - 'NONE', - '-i', - 'NONE', + '--clean', '--cmd', 'colorscheme vim', '--cmd', @@ -3290,10 +3375,7 @@ describe('TUI bg color', function() it('triggers OptionSet from automatic background processing', function() local screen = tt.setup_child_nvim({ - '-u', - 'NONE', - '-i', - 'NONE', + '--clean', '--cmd', 'colorscheme vim', '--cmd', @@ -3314,12 +3396,9 @@ describe('TUI bg color', function() command('set background=dark') -- set outer Nvim background local child_server = new_pipename() local screen = tt.setup_child_nvim({ + '--clean', '--listen', child_server, - '-u', - 'NONE', - '-i', - 'NONE', '--cmd', 'colorscheme vim', '--cmd', @@ -3349,12 +3428,9 @@ describe('TUI client', function() set_session(server_super) local server_pipe = new_pipename() local screen_server = tt.setup_child_nvim({ + '--clean', '--listen', server_pipe, - '-u', - 'NONE', - '-i', - 'NONE', '--cmd', 'colorscheme vim', '--cmd', @@ -3384,9 +3460,9 @@ describe('TUI client', function() set_session(client_super) local screen_client = tt.setup_child_nvim({ + '--remote-ui', '--server', server_pipe, - '--remote-ui', }) screen_client:expect { @@ -3428,9 +3504,9 @@ describe('TUI client', function() set_session(client_super) local screen_client = tt.setup_child_nvim({ + '--remote-ui', '--server', server_pipe, - '--remote-ui', }) screen_client:expect { @@ -3457,7 +3533,7 @@ describe('TUI client', function() eq(0, api.nvim_get_vvar('shell_error')) -- exits on input eof #22244 - fn.system({ nvim_prog, '--server', server_pipe, '--remote-ui' }) + fn.system({ nvim_prog, '--remote-ui', '--server', server_pipe }) eq(1, api.nvim_get_vvar('shell_error')) client_super:close() @@ -3470,9 +3546,9 @@ describe('TUI client', function() it('throws error when no server exists', function() clear() local screen = tt.setup_child_nvim({ + '--remote-ui', '--server', '127.0.0.1:2436546', - '--remote-ui', }, { cols = 60 }) screen:expect([[ @@ -3485,18 +3561,18 @@ describe('TUI client', function() end) local function test_remote_tui_quit(status) - local server_super = n.new_session(false) + local server_super = n.clear() local client_super = n.new_session(true) + finally(function() + server_super:close() + client_super:close() + end) - set_session(server_super) local server_pipe = new_pipename() local screen_server = tt.setup_child_nvim({ + '--clean', '--listen', server_pipe, - '-u', - 'NONE', - '-i', - 'NONE', '--cmd', 'colorscheme vim', '--cmd', @@ -3535,9 +3611,9 @@ describe('TUI client', function() set_session(client_super) local screen_client = tt.setup_child_nvim({ + '--remote-ui', '--server', server_pipe, - '--remote-ui', }) screen_client:expect { @@ -3554,26 +3630,8 @@ describe('TUI client', function() set_session(server_super) feed_data(status and ':' .. status .. 'cquit!\n' or ':quit!\n') status = status and status or 0 - screen_server:expect { - grid = [[ - | - [Process exited ]] .. status .. [[]^ {MATCH:%s+}| - |*4 - {3:-- TERMINAL --} | - ]], - } - -- assert that client has exited - screen_client:expect { - grid = [[ - | - [Process exited ]] .. status .. [[]^ {MATCH:%s+}| - |*4 - {3:-- TERMINAL --} | - ]], - } - - server_super:close() - client_super:close() + screen_server:expect({ any = 'Process exited ' .. status }) + screen_client:expect({ any = 'Process exited ' .. status }) end describe('exits when server quits', function() diff --git a/test/functional/testnvim.lua b/test/functional/testnvim.lua index 59cb593cf7..9b7ece3c21 100644 --- a/test/functional/testnvim.lua +++ b/test/functional/testnvim.lua @@ -908,8 +908,10 @@ function M.is_asan() return version:match('-fsanitize=[a-z,]*address') end --- Returns a valid, platform-independent Nvim listen address. --- Useful for communicating with child instances. +--- Returns a valid, platform-independent Nvim listen address. +--- Useful for communicating with child instances. +--- +--- @return string function M.new_pipename() -- HACK: Start a server temporarily, get the name, then stop it. local pipename = M.eval('serverstart()') |