From 29b1a4761a9fadfa9de05cfd9c8aad281fc29791 Mon Sep 17 00:00:00 2001 From: butwerenotthereyet <58348703+butwerenotthereyet@users.noreply.github.com> Date: Thu, 9 Jan 2020 07:31:16 -0800 Subject: [PATCH] tabpage: disallow go-to-previous in cmdline-win #11692 After cbc8d72fde4b19176028490934ff7a447afe523c when editing the command in the command editing window (q:, q/, q?) it was possible to switch to the previous tab. Doing so put Nvim in a bad state. Moreover, switching tabs via the other available mechanisms (gt, gT, gt, gT) is not possible when in the command editing window. Here, the behavior is prevented. It is no longer possible to switch to the previous tab when editing the command in the command editing window. The solution is to share code between gt, gT, and g. Specifically, goto_tabpage_lastused now calls through goto_tabpage rather than directly calling goto_tabpage_tp. Doing so works well because all the validation enjoyed by gt and gT is present in goto_tabpage. --- src/nvim/window.c | 5 +- .../functional/autocmd/tabnewentered_spec.lua | 76 ++++++++++++++----- 2 files changed, 59 insertions(+), 22 deletions(-) diff --git a/src/nvim/window.c b/src/nvim/window.c index 8feedf2de6..e913d33de0 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -4113,8 +4113,9 @@ void goto_tabpage_tp(tabpage_T *tp, int trigger_enter_autocmds, int trigger_leav // Go to the last accessed tab page, if there is one. void goto_tabpage_lastused(void) { - if (valid_tabpage(lastused_tabpage)) { - goto_tabpage_tp(lastused_tabpage, true, true); + int index = tabpage_index(lastused_tabpage); + if (index < tabpage_index(NULL)) { + goto_tabpage(index); } } diff --git a/test/functional/autocmd/tabnewentered_spec.lua b/test/functional/autocmd/tabnewentered_spec.lua index 6240db2042..949786d8ff 100644 --- a/test/functional/autocmd/tabnewentered_spec.lua +++ b/test/functional/autocmd/tabnewentered_spec.lua @@ -439,32 +439,32 @@ describe('tabpage/previous', function() does_not_switch_to_previous_after_closing_current_tab('')) local function does_not_switch_to_previous_after_entering_operator_pending(characters) - return function() - -- Add three tabs for a total of four - command('tabnew') - command('tabnew') - command('tabnew') + return function() + -- Add three tabs for a total of four + command('tabnew') + command('tabnew') + command('tabnew') - -- The previous tab is now the third. - eq(3, eval('tabpagenr(\'#\')')) + -- The previous tab is now the third. + eq(3, eval('tabpagenr(\'#\')')) - -- Enter operator pending mode. - feed('d') - eq('no', eval('mode(1)')) + -- Enter operator pending mode. + feed('d') + eq('no', eval('mode(1)')) - -- At this point switching to the previous tab should have no effect - -- other than leaving operator pending mode. - feed(characters) + -- At this point switching to the previous tab should have no effect + -- other than leaving operator pending mode. + feed(characters) - -- Attempting to switch tabs returns us to normal mode. - eq('n', eval('mode()')) + -- Attempting to switch tabs returns us to normal mode. + eq('n', eval('mode()')) - -- The current tab is still the fourth. - eq(4, eval('tabpagenr()')) + -- The current tab is still the fourth. + eq(4, eval('tabpagenr()')) - -- The previous tab is still the third. - eq(3, eval('tabpagenr(\'#\')')) - end + -- The previous tab is still the third. + eq(3, eval('tabpagenr(\'#\')')) + end end it('does not switch to previous via g after entering operator pending', does_not_switch_to_previous_after_entering_operator_pending('g')) @@ -480,4 +480,40 @@ describe('tabpage/previous', function() -- does_not_switch_to_previous_after_entering_operator_pending('g')) it('does not switch to previous via after entering operator pending', does_not_switch_to_previous_after_entering_operator_pending('')) + + local function cmdline_win_prevents_tab_switch(characters, completion_visible) + return function() + -- Add three tabs for a total of four + command('tabnew') + command('tabnew') + command('tabnew') + + -- The previous tab is now the third. + eq(3, eval('tabpagenr(\'#\')')) + + -- Edit : command line in command-line window + feed('q:') + + local cmdline_win_id = eval('win_getid()') + + -- At this point switching to the previous tab should have no effect. + feed(characters) + + -- Attempting to switch tabs maintains the current window. + eq(cmdline_win_id, eval('win_getid()')) + eq(completion_visible, eval('complete_info().pum_visible')) + + -- The current tab is still the fourth. + eq(4, eval('tabpagenr()')) + + -- The previous tab is still the third. + eq(3, eval('tabpagenr(\'#\')')) + end + end + it('cmdline-win prevents tab switch via g', + cmdline_win_prevents_tab_switch('g', 0)) + it('cmdline-win prevents tab switch via g', + cmdline_win_prevents_tab_switch('g', 1)) + it('cmdline-win prevents tab switch via ', + cmdline_win_prevents_tab_switch('', 0)) end)