diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/eval.c | 7 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 4 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 29 | ||||
-rw-r--r-- | src/nvim/ex_getln.c | 2 | ||||
-rw-r--r-- | src/nvim/globals.h | 5 | ||||
-rw-r--r-- | src/nvim/normal.c | 11 | ||||
-rw-r--r-- | src/nvim/testdir/check.vim | 8 | ||||
-rw-r--r-- | src/nvim/testdir/test_cmdline.vim | 12 | ||||
-rw-r--r-- | src/nvim/testdir/test_exit.vim | 22 | ||||
-rw-r--r-- | src/nvim/testdir/test_tabpage.vim | 71 | ||||
-rw-r--r-- | src/nvim/window.c | 45 |
11 files changed, 186 insertions, 30 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 18b9039d60..b2ce15fd87 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -3257,9 +3257,7 @@ char_u *get_user_var_name(expand_T *xp, int idx) } // b: variables - // In cmdwin, the alternative buffer should be used. - hashtab_T *ht - = is_in_cmdwin() ? &prevwin->w_buffer->b_vars->dv_hashtab : &curbuf->b_vars->dv_hashtab; + const hashtab_T *ht = &prevwin_curwin()->w_buffer->b_vars->dv_hashtab; if (bdone < ht->ht_used) { if (bdone++ == 0) { hi = ht->ht_array; @@ -3273,8 +3271,7 @@ char_u *get_user_var_name(expand_T *xp, int idx) } // w: variables - // In cmdwin, the alternative window should be used. - ht = is_in_cmdwin() ? &prevwin->w_vars->dv_hashtab : &curwin->w_vars->dv_hashtab; + ht = &prevwin_curwin()->w_vars->dv_hashtab; if (wdone < ht->ht_used) { if (wdone++ == 0) { hi = ht->ht_array; diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index b249dffe11..b74f9759ac 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -11213,9 +11213,7 @@ static void f_tabpagenr(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (strcmp(arg, "$") == 0) { nr = tabpage_index(NULL) - 1; } else if (strcmp(arg, "#") == 0) { - nr = valid_tabpage(lastused_tabpage) - ? tabpage_index(lastused_tabpage) - : nr; + nr = valid_tabpage(lastused_tabpage) ? tabpage_index(lastused_tabpage) : 0; } else { semsg(_(e_invexpr2), arg); } diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 63dc1e539e..09cf6601ee 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -2036,6 +2036,18 @@ doend: return ea.nextcmd; } +static char ex_error_buf[MSG_BUF_LEN]; + +/// @return an error message with argument included. +/// Uses a static buffer, only the last error will be kept. +/// "msg" will be translated, caller should use N_(). +char *ex_errmsg(const char *const msg, const char_u *const arg) + FUNC_ATTR_NONNULL_ALL +{ + vim_snprintf(ex_error_buf, MSG_BUF_LEN, _(msg), arg); + return ex_error_buf; +} + // Parse and skip over command modifiers: // - update eap->cmd // - store flags in "cmdmod". @@ -2704,7 +2716,7 @@ static char_u *find_ucmd(exarg_T *eap, char_u *p, int *full, expand_T *xp, int * // only full match global is accepted. // Look for buffer-local user commands first, then global ones. - gap = is_in_cmdwin() ? &prevwin->w_buffer->b_ucmds : &curbuf->b_ucmds; + gap = &prevwin_curwin()->w_buffer->b_ucmds; for (;;) { for (j = 0; j < gap->ga_len; j++) { uc = USER_CMD_GA(gap, j); @@ -4861,7 +4873,13 @@ static int get_tabpage_arg(exarg_T *eap) if (STRCMP(p, "$") == 0) { tab_number = LAST_TAB_NR; } else if (STRCMP(p, "#") == 0) { - tab_number = tabpage_index(lastused_tabpage); + if (valid_tabpage(lastused_tabpage)) { + tab_number = tabpage_index(lastused_tabpage); + } else { + eap->errmsg = ex_errmsg(e_invargval, eap->arg); + tab_number = 0; + goto theend; + } } else if (p == p_save || *p_save == '-' || *p != NUL || tab_number > LAST_TAB_NR) { // No numbers as argument. @@ -5378,7 +5396,7 @@ static void uc_list(char_u *name, size_t name_len) uint32_t a; // In cmdwin, the alternative buffer should be used. - garray_T *gap = is_in_cmdwin() ? &prevwin->w_buffer->b_ucmds : &curbuf->b_ucmds; + const garray_T *gap = &prevwin_curwin()->w_buffer->b_ucmds; for (;;) { for (i = 0; i < gap->ga_len; i++) { cmd = USER_CMD_GA(gap, i); @@ -6357,7 +6375,7 @@ char_u *get_user_commands(expand_T *xp FUNC_ATTR_UNUSED, int idx) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { // In cmdwin, the alternative buffer should be used. - const buf_T *const buf = is_in_cmdwin() ? prevwin->w_buffer : curbuf; + const buf_T *const buf = prevwin_curwin()->w_buffer; if (idx < buf->b_ucmds.ga_len) { return USER_CMD_GA(&buf->b_ucmds, idx)->uc_name; @@ -6379,7 +6397,8 @@ static char_u *get_user_command_name(int idx, int cmdidx) } if (cmdidx == CMD_USER_BUF) { // In cmdwin, the alternative buffer should be used. - buf_T *buf = is_in_cmdwin() ? prevwin->w_buffer : curbuf; + const buf_T *const buf = prevwin_curwin()->w_buffer; + if (idx < buf->b_ucmds.ga_len) { return USER_CMD_GA(&buf->b_ucmds, idx)->uc_name; } diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 30287cd6f2..f52f3afe7d 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -6589,7 +6589,7 @@ static int open_cmdwin(void) /// @return true if in the cmdwin, not editing the command line. bool is_in_cmdwin(void) - FUNC_ATTR_PURE + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { return cmdwin_type != 0 && get_cmdline_type() == NUL; } diff --git a/src/nvim/globals.h b/src/nvim/globals.h index b64ed7c758..cbd67afb09 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -448,10 +448,11 @@ EXTERN int aucmd_win_used INIT(= false); // aucmd_win is being used EXTERN frame_T *topframe; // top of the window frame tree // Tab pages are alternative topframes. "first_tabpage" points to the first -// one in the list, "curtab" is the current one. +// one in the list, "curtab" is the current one. "lastused_tabpage" is the +// last used one. EXTERN tabpage_T *first_tabpage; -EXTERN tabpage_T *lastused_tabpage; EXTERN tabpage_T *curtab; +EXTERN tabpage_T *lastused_tabpage; EXTERN bool redraw_tabline INIT(= false); // need to redraw tabline // Iterates over all tabs in the tab list diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 0e5e0ab403..f402865d2d 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -5869,7 +5869,7 @@ static void nv_gomark(cmdarg_T *cap) } } -// Handle CTRL-O, CTRL-I, "g;", "g,", and "CTRL-Tab" commands. +/// Handle CTRL-O, CTRL-I, "g;", "g,", and "CTRL-Tab" commands. static void nv_pcmark(cmdarg_T *cap) { pos_T *pos; @@ -5878,7 +5878,9 @@ static void nv_pcmark(cmdarg_T *cap) if (!checkclearopq(cap->oap)) { if (cap->cmdchar == TAB && mod_mask == MOD_MASK_CTRL) { - goto_tabpage_lastused(); + if (!goto_tabpage_lastused()) { + clearopbeep(cap->oap); + } return; } if (cap->cmdchar == 'g') { @@ -6642,9 +6644,10 @@ static void nv_g_cmd(cmdarg_T *cap) goto_tabpage(-(int)cap->count1); } break; + case TAB: - if (!checkclearop(oap)) { - goto_tabpage_lastused(); + if (!checkclearop(oap) && !goto_tabpage_lastused()) { + clearopbeep(oap); } break; diff --git a/src/nvim/testdir/check.vim b/src/nvim/testdir/check.vim index 883f036fe1..8f97d959ce 100644 --- a/src/nvim/testdir/check.vim +++ b/src/nvim/testdir/check.vim @@ -137,6 +137,14 @@ func CheckNotMSWindows() endif endfunc +" Command to check for not running under ASAN +command CheckNotAsan call CheckNotAsan() +func CheckNotAsan() + if execute('version') =~# '-fsanitize=[a-z,]*\<address\>' + throw 'Skipped: does not work with ASAN' + endif +endfunc + " Command to check for satisfying any of the conditions. " e.g. CheckAnyOf Feature:bsd Feature:sun Linux command -nargs=+ CheckAnyOf call CheckAnyOf(<f-args>) diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim index ff4cbe544c..c589d941da 100644 --- a/src/nvim/testdir/test_cmdline.vim +++ b/src/nvim/testdir/test_cmdline.vim @@ -1123,6 +1123,18 @@ func Test_cmdlineclear_tabenter() call delete('XtestCmdlineClearTabenter') endfunc +func Test_cmdwin_tabpage() + tabedit + " v8.2.1919 isn't ported yet, so E492 is thrown after E11 here. + " v8.2.1183 also isn't ported yet, so we also can't assert E11 directly. + " For now, assert E11 and E492 seperately. When v8.2.1183 is ported, the + " assert for E492 will fail and this workaround should be removed. + " call assert_fails("silent norm q/g :I\<Esc>", 'E11:') + call assert_fails("silent norm q/g ", 'E11:') + call assert_fails("silent norm q/g :I\<Esc>", 'E492:') + tabclose! +endfunc + " test that ";" works to find a match at the start of the first line func Test_zero_line_search() new diff --git a/src/nvim/testdir/test_exit.vim b/src/nvim/testdir/test_exit.vim index bd3e9eb4d4..befcaec2b2 100644 --- a/src/nvim/testdir/test_exit.vim +++ b/src/nvim/testdir/test_exit.vim @@ -1,6 +1,7 @@ " Tests for exiting Vim. source shared.vim +source check.vim func Test_exiting() let after =<< trim [CODE] @@ -109,4 +110,25 @@ func Test_exit_code() call delete('Xtestout') endfunc +func Test_exit_error_reading_input() + throw 'Skipped: Nvim does not exit after stdin is read' + + CheckNotGui + CheckNotMSWindows + " The early exit causes memory not to be freed somehow + CheckNotAsan + + call writefile([":au VimLeave * call writefile(['l = ' .. v:exiting], 'Xtestout')", ":tabnew", "q:"], 'Xscript', 'b') + + " Nvim requires "-s -" to read stdin as Normal mode input + " if RunVim([], [], '<Xscript') + if RunVim([], [], '-s - <Xscript') + call assert_equal(1, v:shell_error) + call assert_equal(['l = 1'], readfile('Xtestout')) + endif + call delete('Xscript') + call delete('Xtestout') +endfun + + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_tabpage.vim b/src/nvim/testdir/test_tabpage.vim index 9869dc7590..51ab5c1022 100644 --- a/src/nvim/testdir/test_tabpage.vim +++ b/src/nvim/testdir/test_tabpage.vim @@ -128,6 +128,8 @@ function Test_tabpage() 1tabmove call assert_equal(2, tabpagenr()) + call assert_fails('let t = tabpagenr("@")', 'E15:') + call assert_equal(0, tabpagewinnr(-1)) call assert_fails("99tabmove", 'E16:') call assert_fails("+99tabmove", 'E16:') call assert_fails("-99tabmove", 'E16:') @@ -683,4 +685,73 @@ func Test_tabline_tabmenu() %bw! endfunc +" Test for jumping to last accessed tabpage +func Test_lastused_tabpage() + tabonly! + call assert_equal(0, tabpagenr('#')) + call assert_beeps('call feedkeys("g\<Tab>", "xt")') + call assert_beeps('call feedkeys("\<C-Tab>", "xt")') + call assert_beeps('call feedkeys("\<C-W>g\<Tab>", "xt")') + call assert_fails('tabnext #', 'E475:') + + " open four tab pages + tabnew + tabnew + tabnew + + 2tabnext + + " Test for g<Tab> + call assert_equal(4, tabpagenr('#')) + call feedkeys("g\<Tab>", "xt") + call assert_equal(4, tabpagenr()) + call assert_equal(2, tabpagenr('#')) + + " Test for <C-Tab> + call feedkeys("\<C-Tab>", "xt") + call assert_equal(2, tabpagenr()) + call assert_equal(4, tabpagenr('#')) + + " Test for <C-W>g<Tab> + call feedkeys("\<C-W>g\<Tab>", "xt") + call assert_equal(4, tabpagenr()) + call assert_equal(2, tabpagenr('#')) + + " Test for :tabnext # + tabnext # + call assert_equal(2, tabpagenr()) + call assert_equal(4, tabpagenr('#')) + + " Try to jump to a closed tab page + tabclose # + call assert_equal(0, tabpagenr('#')) + call feedkeys("g\<Tab>", "xt") + call assert_equal(2, tabpagenr()) + call feedkeys("\<C-Tab>", "xt") + call assert_equal(2, tabpagenr()) + call feedkeys("\<C-W>g\<Tab>", "xt") + call assert_equal(2, tabpagenr()) + call assert_fails('tabnext #', 'E475:') + call assert_equal(2, tabpagenr()) + + " Test for :tabonly # + let wnum = win_getid() + $tabnew + tabonly # + call assert_equal(wnum, win_getid()) + call assert_equal(1, tabpagenr('$')) + + " Test for :tabmove # + tabnew + let wnum = win_getid() + tabnew + tabnew + tabnext 2 + tabmove # + call assert_equal(4, tabpagenr()) + call assert_equal(wnum, win_getid()) + + tabonly! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/window.c b/src/nvim/window.c index d659f60e66..a235b07b47 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -73,6 +73,15 @@ typedef enum { static char *m_onlyone = N_("Already only one window"); +/// @return the current window, unless in the cmdline window and "prevwin" is +/// set, then return "prevwin". +win_T *prevwin_curwin(void) + FUNC_ATTR_WARN_UNUSED_RESULT +{ + // In cmdwin, the alternative buffer should be used. + return is_in_cmdwin() && prevwin != NULL ? prevwin : curwin; +} + /// all CTRL-W window commands are handled here, called from normal_cmd(). /// /// @param xchar extra char from ":wincmd gx" or NUL @@ -521,10 +530,6 @@ wingotofile: do_nv_ident('g', xchar); break; - case TAB: - goto_tabpage_lastused(); - break; - case 'f': // CTRL-W gf: "gf" in a new tab page case 'F': // CTRL-W gF: "gF" in a new tab page cmdmod.tab = tabpage_index(curtab) + 1; @@ -538,6 +543,12 @@ wingotofile: goto_tabpage(-(int)Prenum1); break; + case TAB: // CTRL-W g<Tab>: go to last used tab page + if (!goto_tabpage_lastused()) { + beep_flush(); + } + break; + case 'e': if (curwin->w_floating || !ui_has(kUIMultigrid)) { beep_flush(); @@ -2895,6 +2906,9 @@ void win_free_all(void) { int dummy; + // avoid an error for switching tabpage with the cmdline window open + cmdwin_type = 0; + while (first_tabpage->tp_next != NULL) { tabpage_close(TRUE); } @@ -3857,6 +3871,11 @@ int win_new_tabpage(int after, char_u *filename) tabpage_T *newtp; int n; + if (cmdwin_type != 0) { + emsg(_(e_cmdwin)); + return FAIL; + } + newtp = alloc_tabpage(); // Remember the current windows in this Tab page. @@ -4102,8 +4121,8 @@ static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, bool trigger_enter_a { int old_off = tp->tp_firstwin->w_winrow; win_T *next_prevwin = tp->tp_prevwin; - tabpage_T *old_curtab = curtab; + curtab = tp; firstwin = tp->tp_firstwin; lastwin = tp->tp_lastwin; @@ -4255,6 +4274,10 @@ void goto_tabpage(int n) /// @param trigger_leave_autocmds when true trigger *Leave autocommands. void goto_tabpage_tp(tabpage_T *tp, bool trigger_enter_autocmds, bool trigger_leave_autocmds) { + if (trigger_enter_autocmds || trigger_leave_autocmds) { + CHECK_CMDWIN; + } + // Don't repeat a message in another tab page. set_keep_msg(NULL, 0); @@ -4270,13 +4293,15 @@ void goto_tabpage_tp(tabpage_T *tp, bool trigger_enter_autocmds, bool trigger_le } } -// Go to the last accessed tab page, if there is one. -void goto_tabpage_lastused(void) +/// Go to the last accessed tab page, if there is one. +/// @return true if the tab page is valid, false otherwise. +bool goto_tabpage_lastused(void) { - int index = tabpage_index(lastused_tabpage); - if (index < tabpage_index(NULL)) { - goto_tabpage(index); + if (valid_tabpage(lastused_tabpage)) { + goto_tabpage_tp(lastused_tabpage, true, true); + return true; } + return false; } /* |