From 28134f4e78819c2bbf0344326b9d44f21eb0d736 Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Sun, 3 Oct 2021 13:57:01 +0100 Subject: [PATCH 01/10] vim-patch:8.1.0035: not easy to switch between prompt buffer and other windows Problem: Not easy to switch between prompt buffer and other windows. Solution: Accept CTRL-W commands in Insert mode. Start and stop Insert mode as one would expect. https://github.com/vim/vim/commit/6d41c78e353b630bc1a72cbff9160311d2a81e8c Cherry-pick channel.txt change from: https://github.com/vim/vim/commit/d2f3a8b8787333abf2300d38836b196955f10c00 b_prompt_insert was already ported. --- runtime/doc/channel.txt | 5 ++++ src/nvim/edit.c | 29 +++++++++++++++++- src/nvim/testdir/test_prompt_buffer.vim | 7 ++--- src/nvim/window.c | 39 ++++++++++++++++++++++--- 4 files changed, 71 insertions(+), 9 deletions(-) diff --git a/runtime/doc/channel.txt b/runtime/doc/channel.txt index 656bb10c45..5f376a600e 100644 --- a/runtime/doc/channel.txt +++ b/runtime/doc/channel.txt @@ -210,6 +210,11 @@ effective prompt text for a buffer, with |prompt_getprompt()|. The user can go to Normal mode and navigate through the buffer. This can be useful to see older output or copy text. +The CTRL-W key can be used to start a window command, such as CTRL-W w to +switch to the next window. This also works in Insert mode (use Shift-CTRL-W +to delete a word). When leaving the window Insert mode will be stopped. When +coming back to the prompt window Insert mode will be restored. + Any command that starts Insert mode, such as "a", "i", "A" and "I", will move the cursor to the last line. "A" will move to the end of the line, "I" to the start of the line. diff --git a/src/nvim/edit.c b/src/nvim/edit.c index fe69da7fcb..16601d327d 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -655,10 +655,17 @@ static int insert_check(VimState *state) static int insert_execute(VimState *state, int key) { + InsertState *const s = (InsertState *)state; + if (stop_insert_mode) { + // Insert mode ended, possibly from a callback. + s->count = 0; + s->nomove = true; + return 0; + } + if (key == K_IGNORE || key == K_NOP) { return -1; // get another key } - InsertState *s = (InsertState *)state; s->c = key; // Don't want K_EVENT with cursorhold for the second key, e.g., after CTRL-V. @@ -984,6 +991,15 @@ static int insert_handle_key(InsertState *s) break; case Ctrl_W: // delete word before the cursor + if (bt_prompt(curbuf) && (mod_mask & MOD_MASK_SHIFT) == 0) { + // In a prompt window CTRL-W is used for window commands. + // Use Shift-CTRL-W to delete a word. + stuffcharReadbuff(Ctrl_W); + restart_edit = 'i'; + s->nomove = true; + s->count = 0; + return 0; + } s->did_backspace = ins_bs(s->c, BACKSPACE_WORD, &s->inserted_space); auto_format(false, true); break; @@ -1653,6 +1669,17 @@ static void init_prompt(int cmdchar_todo) coladvance(MAXCOL); changed_bytes(curbuf->b_ml.ml_line_count, 0); } + + // Insert always starts after the prompt, allow editing text after it. + if (Insstart_orig.lnum != curwin->w_cursor.lnum || Insstart_orig.col != (colnr_T)STRLEN(prompt)) { + Insstart.lnum = curwin->w_cursor.lnum; + Insstart.col = STRLEN(prompt); + Insstart_orig = Insstart; + Insstart_textlen = Insstart.col; + Insstart_blank_vcol = MAXCOL; + arrow_used = false; + } + if (cmdchar_todo == 'A') { coladvance(MAXCOL); } diff --git a/src/nvim/testdir/test_prompt_buffer.vim b/src/nvim/testdir/test_prompt_buffer.vim index c59a00afcc..fde97a66a8 100644 --- a/src/nvim/testdir/test_prompt_buffer.vim +++ b/src/nvim/testdir/test_prompt_buffer.vim @@ -145,10 +145,9 @@ func Test_prompt_buffer_edit() call assert_beeps("normal! \") " pressing CTRL-W in the prompt buffer should trigger the window commands call assert_equal(1, winnr()) - " In Nvim, CTRL-W commands aren't usable from insert mode in a prompt buffer - " exe "normal A\\" - " call assert_equal(2, winnr()) - " wincmd w + exe "normal A\\" + call assert_equal(2, winnr()) + wincmd w close! call assert_equal(0, prompt_setprompt([], '')) endfunc diff --git a/src/nvim/window.c b/src/nvim/window.c index 3e6e42dec2..1da6c3704f 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -2229,6 +2229,28 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int } } +static void leaving_window(win_T *const win) + FUNC_ATTR_NONNULL_ALL +{ + // When leaving a prompt window stop Insert mode and perhaps restart + // it when entering that window again. + win->w_buffer->b_prompt_insert = restart_edit; + restart_edit = NUL; + + // When leaving the window (or closing the window) was done from a + // callback we need to break out of the Insert mode loop. + if (State & INSERT) { + stop_insert_mode = true; + } +} + +static void entering_window(win_T *const win) + FUNC_ATTR_NONNULL_ALL +{ + // When entering the prompt window may restart Insert mode. + restart_edit = win->w_buffer->b_prompt_insert; +} + /// Closes all windows for buffer `buf`. /// /// @param keep_curwin don't close `curwin` @@ -2367,6 +2389,7 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev shell_new_rows(); } } + entering_window(curwin); // Since goto_tabpage_tp above did not trigger *Enter autocommands, do // that now. @@ -2434,10 +2457,10 @@ int win_close(win_T *win, bool free_buf) } if (win == curwin) { - /* - * Guess which window is going to be the new current window. - * This may change because of the autocommands (sigh). - */ + leaving_window(curwin); + + // Guess which window is going to be the new current window. + // This may change because of the autocommands (sigh). if (!win->w_floating) { wp = frame2win(win_altframe(win, NULL)); } else { @@ -3801,6 +3824,8 @@ int win_new_tabpage(int after, char_u *filename) lastused_tabpage = old_curtab; + entering_window(curwin); + apply_autocmds(EVENT_WINNEW, NULL, NULL, false, curbuf); apply_autocmds(EVENT_WINENTER, NULL, NULL, false, curbuf); apply_autocmds(EVENT_TABNEW, filename, filename, false, curbuf); @@ -3956,6 +3981,7 @@ static int leave_tabpage(buf_T *new_curbuf, bool trigger_leave_autocmds) { tabpage_T *tp = curtab; + leaving_window(curwin); reset_VIsual_and_resel(); // stop Visual mode if (trigger_leave_autocmds) { if (new_curbuf != curbuf) { @@ -4478,6 +4504,10 @@ static void win_enter_ext(win_T *const wp, const int flags) return; } + if (!curwin_invalid) { + leaving_window(curwin); + } + if (!curwin_invalid && (flags & WEE_TRIGGER_LEAVE_AUTOCMDS)) { // Be careful: If autocommands delete the window, return now. if (wp->w_buffer != curbuf) { @@ -4525,6 +4555,7 @@ static void win_enter_ext(win_T *const wp, const int flags) fix_current_dir(); + entering_window(curwin); // Careful: autocommands may close the window and make "wp" invalid if (flags & WEE_TRIGGER_NEW_AUTOCMDS) { apply_autocmds(EVENT_WINNEW, NULL, NULL, false, curbuf); From d6ea0741c92e39e4f6c3ec639117d9f39ec08094 Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Sun, 3 Oct 2021 14:00:24 +0100 Subject: [PATCH 02/10] fix(prompt): add missing changes from v8.1.0036 v8.1.0036 is already marked as ported, but missed out changes that depended on v8.1.0035. --- src/nvim/window.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/nvim/window.c b/src/nvim/window.c index 1da6c3704f..9f4c5c68f6 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -2241,12 +2241,21 @@ static void leaving_window(win_T *const win) // callback we need to break out of the Insert mode loop. if (State & INSERT) { stop_insert_mode = true; + if (bt_prompt(win->w_buffer) && win->w_buffer->b_prompt_insert == NUL) { + win->w_buffer->b_prompt_insert = 'A'; + } } } static void entering_window(win_T *const win) FUNC_ATTR_NONNULL_ALL { + // When switching to a prompt buffer that was in Insert mode, don't stop + // Insert mode, it may have been set in leaving_window(). + if (bt_prompt(win->w_buffer) && win->w_buffer->b_prompt_insert != NUL) { + stop_insert_mode = false; + } + // When entering the prompt window may restart Insert mode. restart_edit = win->w_buffer->b_prompt_insert; } From b9ab4c1dea0ee65950f8c1ec374ccab744a81acb Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Sun, 7 Nov 2021 14:50:01 +0000 Subject: [PATCH 03/10] vim-patch:8.1.0042: if omni completion opens a window Insert mode is stopped Problem: If omni completion opens a window Insert mode is stopped. (Hirohito Higashi) Solution: Only set stop_insert_mode in a prompt buffer window. https://github.com/vim/vim/commit/f98b845dd185dfadfa7a622a42452bfa6809d4e0 popupmenu_spec.lua fails without this. --- src/nvim/window.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/nvim/window.c b/src/nvim/window.c index 9f4c5c68f6..e0d05e1d47 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -2232,16 +2232,22 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int static void leaving_window(win_T *const win) FUNC_ATTR_NONNULL_ALL { + // Only matters for a prompt window. + if (!bt_prompt(win->w_buffer)) { + return; + } + // When leaving a prompt window stop Insert mode and perhaps restart // it when entering that window again. win->w_buffer->b_prompt_insert = restart_edit; restart_edit = NUL; // When leaving the window (or closing the window) was done from a - // callback we need to break out of the Insert mode loop. + // callback we need to break out of the Insert mode loop and restart Insert + // mode when entering the window again. if (State & INSERT) { stop_insert_mode = true; - if (bt_prompt(win->w_buffer) && win->w_buffer->b_prompt_insert == NUL) { + if (win->w_buffer->b_prompt_insert == NUL) { win->w_buffer->b_prompt_insert = 'A'; } } @@ -2250,13 +2256,19 @@ static void leaving_window(win_T *const win) static void entering_window(win_T *const win) FUNC_ATTR_NONNULL_ALL { + // Only matters for a prompt window. + if (!bt_prompt(win->w_buffer)) { + return; + } + // When switching to a prompt buffer that was in Insert mode, don't stop // Insert mode, it may have been set in leaving_window(). - if (bt_prompt(win->w_buffer) && win->w_buffer->b_prompt_insert != NUL) { + if (win->w_buffer->b_prompt_insert != NUL) { stop_insert_mode = false; } - // When entering the prompt window may restart Insert mode. + // When entering the prompt window restart Insert mode if we were in Insert + // mode when we left it. restart_edit = win->w_buffer->b_prompt_insert; } From 1fffccc5d62e4fa01c1ce52405da359723defb1c Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Sun, 7 Nov 2021 20:57:09 +0000 Subject: [PATCH 04/10] vim-patch:8.1.0064: typing CTRL-W in a prompt buffer shows mode "-- --" Problem: Typing CTRL-W in a prompt buffer shows mode "-- --". Solution: Set restart_edit to 'A' and check for it. https://github.com/vim/vim/commit/942b4541a2d8e8df8369ab70e112dbbbe0c7c0aa Nvim already checked for 'i' in showmode(), so this bug was fixed with (though this patch now changes to use 'A'). However, the missing changes I ported for v8.1.0036 use 'A' when a callback leaves the window in insert mode and edit gets restarted, so this bug was possible there. Modify showmode() restart_edit condition to match v8.2.1978: https://github.com/vim/vim/commit/957cf67d50516ba98716f59c9e1cb6412ec1535d --- src/nvim/edit.c | 2 +- src/nvim/screen.c | 4 ++-- src/nvim/window.c | 3 +++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 16601d327d..6e3efe8bba 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -995,7 +995,7 @@ static int insert_handle_key(InsertState *s) // In a prompt window CTRL-W is used for window commands. // Use Shift-CTRL-W to delete a word. stuffcharReadbuff(Ctrl_W); - restart_edit = 'i'; + restart_edit = 'A'; s->nomove = true; s->count = 0; return 0; diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 2ce2be0bfd..d015ef110e 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -6930,7 +6930,7 @@ int showmode(void) do_mode = ((p_smd && msg_silent == 0) && ((State & TERM_FOCUS) || (State & INSERT) - || restart_edit + || restart_edit != NUL || VIsual_active)); if (do_mode || reg_recording != 0) { // Don't show mode right now, when not redrawing or inside a mapping. @@ -7010,7 +7010,7 @@ int showmode(void) } msg_puts_attr(_(" INSERT"), attr); } else if (restart_edit == 'I' || restart_edit == 'i' - || restart_edit == 'a') { + || restart_edit == 'a' || restart_edit == 'A') { msg_puts_attr(_(" (insert)"), attr); } else if (restart_edit == 'R') { msg_puts_attr(_(" (replace)"), attr); diff --git a/src/nvim/window.c b/src/nvim/window.c index e0d05e1d47..ddf50b47a7 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -2240,6 +2240,9 @@ static void leaving_window(win_T *const win) // When leaving a prompt window stop Insert mode and perhaps restart // it when entering that window again. win->w_buffer->b_prompt_insert = restart_edit; + if (restart_edit != NUL && mode_displayed) { + clear_cmdline = true; // unshow mode later + } restart_edit = NUL; // When leaving the window (or closing the window) was done from a From 38cd91de5f0f89daccdcbac16508af830d8001d7 Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Sun, 7 Nov 2021 21:28:11 +0000 Subject: [PATCH 05/10] vim-patch:8.2.1781: writing to prompt buffer interferes with insert mode Problem: Writing to prompt buffer interferes with insert mode. Solution: Use win_enter() instead of just setting "curwin". (Ben Jackson, closes vim/vim#7035) https://github.com/vim/vim/commit/4537bcc88956f86267c25edf8008e0dbde598652 Vim test will be skipped, so add a Lua test. The problem boils down to the use of aucmd_restbuf in a callback, so just test that (via nvim_buf_set_lines). --- src/nvim/autocmd.c | 2 +- src/nvim/testdir/test_prompt_buffer.vim | 34 +++++++++++++++++++ test/functional/legacy/prompt_buffer_spec.lua | 14 +++++++- 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index 490fe5a0ac..e274d00a77 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -1208,7 +1208,7 @@ win_found: win_T *const save_curwin = win_find_by_handle(aco->save_curwin_handle); if (save_curwin != NULL) { - curwin = save_curwin; + win_enter(save_curwin, true); } else { // Hmm, original window disappeared. Just use the first one. curwin = firstwin; diff --git a/src/nvim/testdir/test_prompt_buffer.vim b/src/nvim/testdir/test_prompt_buffer.vim index fde97a66a8..72b037dd37 100644 --- a/src/nvim/testdir/test_prompt_buffer.vim +++ b/src/nvim/testdir/test_prompt_buffer.vim @@ -186,4 +186,38 @@ func Test_prompt_buffer_getbufinfo() %bwipe! endfunc +function! Test_prompt_while_writing_to_hidden_buffer() + throw 'skipped: TODO' + call CanTestPromptBuffer() + CheckUnix + + " Make a job continuously write to a hidden buffer, check that the prompt + " buffer is not affected. + let scriptName = 'XpromptscriptHiddenBuf' + let script =<< trim END + set buftype=prompt + call prompt_setprompt( bufnr(), 'cmd:' ) + let job = job_start(['/bin/sh', '-c', + \ 'while true; + \ do echo line; + \ sleep 0.1; + \ done'], #{out_io: 'buffer', out_name: ''}) + startinsert + END + eval script->writefile(scriptName) + + let buf = RunVimInTerminal('-S ' .. scriptName, {}) + call WaitForAssert({-> assert_equal('cmd:', term_getline(buf, 1))}) + + call term_sendkeys(buf, 'test') + call WaitForAssert({-> assert_equal('cmd:test', term_getline(buf, 1))}) + call term_sendkeys(buf, 'test') + call WaitForAssert({-> assert_equal('cmd:testtest', term_getline(buf, 1))}) + call term_sendkeys(buf, 'test') + call WaitForAssert({-> assert_equal('cmd:testtesttest', term_getline(buf, 1))}) + + call StopVimInTerminal(buf) + call delete(scriptName) +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/functional/legacy/prompt_buffer_spec.lua b/test/functional/legacy/prompt_buffer_spec.lua index 513be807be..a987eaf12c 100644 --- a/test/functional/legacy/prompt_buffer_spec.lua +++ b/test/functional/legacy/prompt_buffer_spec.lua @@ -1,9 +1,12 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') -local feed= helpers.feed +local feed = helpers.feed local source = helpers.source local clear = helpers.clear local feed_command = helpers.feed_command +local poke_eventloop = helpers.poke_eventloop +local meths = helpers.meths +local eq = helpers.eq describe('prompt buffer', function() local screen @@ -150,4 +153,13 @@ describe('prompt buffer', function() ]]) end) + it('keeps insert mode after aucmd_restbuf in callback', function() + source [[ + let s:buf = nvim_create_buf(1, 1) + call timer_start(0, {-> nvim_buf_set_lines(s:buf, -1, -1, 0, ['walrus'])}) + startinsert + ]] + poke_eventloop() + eq({ mode = "i", blocking = false }, meths.get_mode()) + end) end) From a128b64e73322a41b175811dc88a7f7046278de3 Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Sun, 7 Nov 2021 21:46:06 +0000 Subject: [PATCH 06/10] vim-patch:8.2.1783: try-catch test fails Problem: Try-catch test fails. Solution: Don't call win_enter(), only call enterering_window(). https://github.com/vim/vim/commit/bdf931c25b4fe78877106ca529baee7899d0f6a4 v8.2.1781 caused Test_reload_in_try_catch() from v8.2.0004 to fail in Vim, but it has not been ported yet. --- src/nvim/autocmd.c | 7 +++++-- src/nvim/testdir/runtest.vim | 5 +++++ src/nvim/window.c | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index e274d00a77..9044657358 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -1208,15 +1208,18 @@ win_found: win_T *const save_curwin = win_find_by_handle(aco->save_curwin_handle); if (save_curwin != NULL) { - win_enter(save_curwin, true); + curwin = save_curwin; } else { // Hmm, original window disappeared. Just use the first one. curwin = firstwin; } + curbuf = curwin->w_buffer; + // May need to restore insert mode for a prompt buffer. + entering_window(curwin); + prevwin = win_find_by_handle(aco->save_prevwin_handle); vars_clear(&aucmd_win->w_vars->dv_hashtab); // free all w: variables hash_init(&aucmd_win->w_vars->dv_hashtab); // re-use the hashtab - curbuf = curwin->w_buffer; xfree(globaldir); globaldir = aco->globaldir; diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim index 49993c03aa..ab047fd2a8 100644 --- a/src/nvim/testdir/runtest.vim +++ b/src/nvim/testdir/runtest.vim @@ -197,7 +197,12 @@ func RunTheTest(test) " Close any extra tab pages and windows and make the current one not modified. while tabpagenr('$') > 1 + let winid = win_getid() quit! + if winid == win_getid() + echoerr 'Could not quit window' + break + endif endwhile while 1 diff --git a/src/nvim/window.c b/src/nvim/window.c index ddf50b47a7..e0ba4b72f3 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -2256,7 +2256,7 @@ static void leaving_window(win_T *const win) } } -static void entering_window(win_T *const win) +void entering_window(win_T *const win) FUNC_ATTR_NONNULL_ALL { // Only matters for a prompt window. From c2d0a1041e215634be316c4e824c1b1b2f242e76 Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Sun, 7 Nov 2021 21:14:36 +0000 Subject: [PATCH 07/10] vim-patch:8.2.1976: cannot backspace in prompt buffer after using cursor-left Problem: Cannot backspace in prompt buffer after using cursor-left. (Maxim Kim) Solution: Ignore "arrow_used" in a prompt buffer. (closes vim/vim#7281) https://github.com/vim/vim/commit/6f6244855fbce5aaa718cd5001a29aac3c5c15d6 cmdchar_todo wasn't adapted properly for Nvim's state system, which caused it to be a dead store and such was removed in #11900. Re-introduce cmdchar_todo properly. --- src/nvim/edit.c | 7 +++++-- src/nvim/testdir/test_prompt_buffer.vim | 8 ++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 6e3efe8bba..dfdefddc20 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -227,6 +227,7 @@ typedef struct insert_state { cmdarg_T *ca; int mincol; int cmdchar; + int cmdchar_todo; // cmdchar to handle once in init_prompt int startln; long count; int c; @@ -290,6 +291,7 @@ static void insert_enter(InsertState *s) s->did_backspace = true; s->old_topfill = -1; s->replaceState = REPLACE; + s->cmdchar_todo = s->cmdchar; // Remember whether editing was restarted after CTRL-O did_restart_edit = restart_edit; // sleep before redrawing, needed for "CTRL-O :" that results in an @@ -585,7 +587,8 @@ static int insert_check(VimState *state) } if (bt_prompt(curbuf)) { - init_prompt(s->cmdchar); + init_prompt(s->cmdchar_todo); + s->cmdchar_todo = NUL; } // If we inserted a character at the last position of the last line in the @@ -8268,7 +8271,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) || (!revins_on && ((curwin->w_cursor.lnum == 1 && curwin->w_cursor.col == 0) || (!can_bs(BS_START) - && (arrow_used + && ((arrow_used && !bt_prompt(curbuf)) || (curwin->w_cursor.lnum == Insstart_orig.lnum && curwin->w_cursor.col <= Insstart_orig.col))) || (!can_bs(BS_INDENT) && !arrow_used && ai_col > 0 diff --git a/src/nvim/testdir/test_prompt_buffer.vim b/src/nvim/testdir/test_prompt_buffer.vim index 72b037dd37..af7231c9c0 100644 --- a/src/nvim/testdir/test_prompt_buffer.vim +++ b/src/nvim/testdir/test_prompt_buffer.vim @@ -126,6 +126,14 @@ func Test_prompt_garbage_collect() bwipe! endfunc +func Test_prompt_backspace() + new + set buftype=prompt + call feedkeys("A123456\\\", 'xt') + call assert_equal('% 12346', getline(1)) + bwipe! +endfunc + " Test for editing the prompt buffer func Test_prompt_buffer_edit() new From d6258a9bad10e97d2582a102750e0e931bb9321a Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Sun, 7 Nov 2021 13:12:17 +0000 Subject: [PATCH 08/10] vim-patch:8.2.2014: using CTRL-O in a prompt buffer moves cursor to start Problem: Using CTRL-O in a prompt buffer moves cursor to start of the line. Solution: Do not move the cursor when restarting edit. (closes vim/vim#7330) https://github.com/vim/vim/commit/ee8b787bcd15f63a938243770065e704c9b5c85f Test_prompt_editing is skipped, so edit the Lua test in prompt_buffer_spec. --- src/nvim/edit.c | 2 +- src/nvim/testdir/test_prompt_buffer.vim | 5 ++++- test/functional/legacy/prompt_buffer_spec.lua | 15 ++++++++++++++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/nvim/edit.c b/src/nvim/edit.c index dfdefddc20..9bfb8a9d4a 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -1686,7 +1686,7 @@ static void init_prompt(int cmdchar_todo) if (cmdchar_todo == 'A') { coladvance(MAXCOL); } - if (cmdchar_todo == 'I' || curwin->w_cursor.col <= (int)STRLEN(prompt)) { + if (curwin->w_cursor.col < (colnr_T)STRLEN(prompt)) { curwin->w_cursor.col = STRLEN(prompt); } // Make sure the cursor is in a valid position. diff --git a/src/nvim/testdir/test_prompt_buffer.vim b/src/nvim/testdir/test_prompt_buffer.vim index af7231c9c0..4212dcb36e 100644 --- a/src/nvim/testdir/test_prompt_buffer.vim +++ b/src/nvim/testdir/test_prompt_buffer.vim @@ -89,9 +89,12 @@ func Test_prompt_editing() call term_sendkeys(buf, left . left . left . bs . '-') call WaitForAssert({-> assert_equal('cmd: -hel', term_getline(buf, 1))}) + call term_sendkeys(buf, "\lz") + call WaitForAssert({-> assert_equal('cmd: -hzel', term_getline(buf, 1))}) + let end = "\" call term_sendkeys(buf, end . "x") - call WaitForAssert({-> assert_equal('cmd: -helx', term_getline(buf, 1))}) + call WaitForAssert({-> assert_equal('cmd: -hzelx', term_getline(buf, 1))}) call term_sendkeys(buf, "\exit\") call WaitForAssert({-> assert_equal('other buffer', term_getline(buf, 1))}) diff --git a/test/functional/legacy/prompt_buffer_spec.lua b/test/functional/legacy/prompt_buffer_spec.lua index a987eaf12c..5c077e3f7d 100644 --- a/test/functional/legacy/prompt_buffer_spec.lua +++ b/test/functional/legacy/prompt_buffer_spec.lua @@ -125,9 +125,22 @@ describe('prompt buffer', function() ~ | | ]]) + feed("lz") + screen:expect([[ + % -hz^el | + ~ | + ~ | + ~ | + [Prompt] [+] | + other buffer | + ~ | + ~ | + ~ | + | + ]]) feed("x") screen:expect([[ - % -helx^ | + % -hzelx^ | ~ | ~ | ~ | From 0f792b284fbb924d46020a31162a7660fa6dc077 Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Fri, 26 Nov 2021 03:34:41 +0000 Subject: [PATCH 09/10] test(prompt_buffer_spec): include changes from v8.1.1984 I already ported v8.1.1984 previously, but hadn't updated prompt_buffer_spec to match test_prompt_buffer (which we have but due to Vim features such as term_sendkeys it's mostly skipped). Required for v8.2.3671. --- test/functional/legacy/prompt_buffer_spec.lua | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test/functional/legacy/prompt_buffer_spec.lua b/test/functional/legacy/prompt_buffer_spec.lua index 5c077e3f7d..e689c29dfd 100644 --- a/test/functional/legacy/prompt_buffer_spec.lua +++ b/test/functional/legacy/prompt_buffer_spec.lua @@ -37,6 +37,7 @@ describe('prompt buffer', function() feed_command("new") feed_command("set buftype=prompt") feed_command("call prompt_setcallback(bufnr(''), function('TextEntered'))") + feed_command("eval bufnr('')->prompt_setprompt('cmd: ')") end) after_each(function() @@ -59,10 +60,10 @@ describe('prompt buffer', function() feed("i") feed("hello\n") screen:expect([[ - % hello | + cmd: hello | Command: "hello" | Result: "hello" | - % ^ | + cmd: ^ | [Prompt] [+] | other buffer | ~ | @@ -101,7 +102,7 @@ describe('prompt buffer', function() feed("i") feed("hello") screen:expect([[ - % hel^ | + cmd: hel^ | ~ | ~ | ~ | @@ -114,7 +115,7 @@ describe('prompt buffer', function() ]]) feed("-") screen:expect([[ - % -^hel | + cmd: -^hel | ~ | ~ | ~ | @@ -127,7 +128,7 @@ describe('prompt buffer', function() ]]) feed("lz") screen:expect([[ - % -hz^el | + cmd: -hz^el | ~ | ~ | ~ | @@ -140,7 +141,7 @@ describe('prompt buffer', function() ]]) feed("x") screen:expect([[ - % -hzelx^ | + cmd: -hzelx^ | ~ | ~ | ~ | From 361f548437a0a9b620db620356fdd405d24a7b34 Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Thu, 25 Nov 2021 22:53:14 +0000 Subject: [PATCH 10/10] vim-patch:8.2.3671: restarting Insert mode in prompt buffer too often Problem: Restarting Insert mode in prompt buffer too often when a callback switches windows and comes back. (Sean Dewar) Solution: Do not set "restart_edit" when already in Insert mode. https://github.com/vim/vim/commit/34c20ff85b87be587ea5d0398812441b502ee6a5 As Test_prompt_switch_windows is skipped, implement it in prompt_buffer_spec. Replace the 50ms term_wait calls with poke_eventloop (test seems to work anyway without them, so maybe they're not required?) The new test does include a duplicate screen test that may generate a "screen test succeeded immediately" warning, but this is done to match the Vim test. --- src/nvim/testdir/test_prompt_buffer.vim | 26 ++++++++++ src/nvim/window.c | 6 ++- test/functional/legacy/prompt_buffer_spec.lua | 49 +++++++++++++++++++ 3 files changed, 79 insertions(+), 2 deletions(-) diff --git a/src/nvim/testdir/test_prompt_buffer.vim b/src/nvim/testdir/test_prompt_buffer.vim index 4212dcb36e..8f94a8572b 100644 --- a/src/nvim/testdir/test_prompt_buffer.vim +++ b/src/nvim/testdir/test_prompt_buffer.vim @@ -41,6 +41,10 @@ func WriteScript(name) \ ' set nomodified', \ 'endfunc', \ '', + \ 'func SwitchWindows()', + \ ' call timer_start(0, {-> execute("wincmd p|wincmd p", "")})', + \ 'endfunc', + \ '', \ 'call setline(1, "other buffer")', \ 'set nomodified', \ 'new', @@ -103,6 +107,28 @@ func Test_prompt_editing() call delete(scriptName) endfunc +func Test_prompt_switch_windows() + throw 'skipped: TODO' + call CanTestPromptBuffer() + let scriptName = 'XpromptSwitchWindows' + call WriteScript(scriptName) + + let buf = RunVimInTerminal('-S ' . scriptName, {'rows': 12}) + call WaitForAssert({-> assert_equal('cmd:', term_getline(buf, 1))}) + call WaitForAssert({-> assert_match('-- INSERT --', term_getline(buf, 12))}) + + call term_sendkeys(buf, "\:call SwitchWindows()\") + call term_wait(buf, 50) + call WaitForAssert({-> assert_match('-- INSERT --', term_getline(buf, 12))}) + + call term_sendkeys(buf, "\") + call term_wait(buf, 50) + call WaitForAssert({-> assert_match('^ *$', term_getline(buf, 12))}) + + call StopVimInTerminal(buf) + call delete(scriptName) +endfunc + func Test_prompt_garbage_collect() func MyPromptCallback(x, text) " NOP diff --git a/src/nvim/window.c b/src/nvim/window.c index e0ba4b72f3..be963d8374 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -2271,8 +2271,10 @@ void entering_window(win_T *const win) } // When entering the prompt window restart Insert mode if we were in Insert - // mode when we left it. - restart_edit = win->w_buffer->b_prompt_insert; + // mode when we left it and not already in Insert mode. + if ((State & INSERT) == 0) { + restart_edit = win->w_buffer->b_prompt_insert; + } } /// Closes all windows for buffer `buf`. diff --git a/test/functional/legacy/prompt_buffer_spec.lua b/test/functional/legacy/prompt_buffer_spec.lua index e689c29dfd..47eca19de3 100644 --- a/test/functional/legacy/prompt_buffer_spec.lua +++ b/test/functional/legacy/prompt_buffer_spec.lua @@ -31,6 +31,10 @@ describe('prompt buffer', function() func TimerFunc(text) call append(line("$") - 1, 'Result: "' . a:text .'"') endfunc + + func SwitchWindows() + call timer_start(0, {-> execute("wincmd p|wincmd p", "")}) + endfunc ]]) feed_command("set noshowmode | set laststatus=0") feed_command("call setline(1, 'other buffer')") @@ -167,6 +171,51 @@ describe('prompt buffer', function() ]]) end) + it('switch windows', function() + feed_command("set showmode") + feed("i") + screen:expect([[ + cmd: ^ | + ~ | + ~ | + ~ | + [Prompt] [+] | + other buffer | + ~ | + ~ | + ~ | + -- INSERT -- | + ]]) + feed(":call SwitchWindows()") + poke_eventloop() + screen:expect([[ + cmd: ^ | + ~ | + ~ | + ~ | + [Prompt] [+] | + other buffer | + ~ | + ~ | + ~ | + -- INSERT -- | + ]]) + feed("") + poke_eventloop() + screen:expect([[ + cmd:^ | + ~ | + ~ | + ~ | + [Prompt] [+] | + other buffer | + ~ | + ~ | + ~ | + | + ]]) + end) + it('keeps insert mode after aucmd_restbuf in callback', function() source [[ let s:buf = nvim_create_buf(1, 1)