# HG changeset patch # User Bram Moolenaar # Date 1596975304 -7200 # Node ID 22583b9d4efd45e71aa1b0332d51f6c7fdaeffed # Parent b63fb341c0dac2f9fc6f597af29d3d1bb8e4bf4a patch 8.2.1401: cannot jump to the last used tabpage Commit: https://github.com/vim/vim/commit/62a232506d06f6d1b3b7271801c907d6294dfe84 Author: Bram Moolenaar Date: Sun Aug 9 14:04:42 2020 +0200 patch 8.2.1401: cannot jump to the last used tabpage Problem: Cannot jump to the last used tabpage. Solution: Add g and tabpagnr('#'). (Yegappan Lakshmanan, closes https://github.com/vim/vim/issues/6661, neovim #11626) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -10357,8 +10357,13 @@ tabpagebuflist([{arg}]) *tabpagebufl tabpagenr([{arg}]) *tabpagenr()* The result is a Number, which is the number of the current tab page. The first tab page has number 1. - When the optional argument is "$", the number of the last tab - page is returned (the tab page count). + + The optional argument {arg} supports the following values: + $ the number of the last tab page (the tab page + count). + # the number of the last accessed tab page + (where |g| goes to). if there is no + previous tab page 0 is returned. The number can be used with the |:tab| command. diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt --- a/runtime/doc/index.txt +++ b/runtime/doc/index.txt @@ -440,6 +440,7 @@ tag char note action in Normal mo || ":ta" to the keyword at the mouse click || 1 same as "w" || same as "CTRL-T" +|| same as "g" || ["x] 2 same as "x" |N| {count} remove the last digit from {count} || 1 same as "j" @@ -587,6 +588,8 @@ tag command action in Normal mode ~ following the file name. |CTRL-W_gt| CTRL-W g t same as `gt`: go to next tab page |CTRL-W_gT| CTRL-W g T same as `gT`: go to previous tab page +|CTRL-W_g| CTRL-W g same as |g|: go to last accessed tab + page. |CTRL-W_h| CTRL-W h go to Nth left window (stop at first window) |CTRL-W_i| CTRL-W i split window and jump to declaration of identifier under the cursor @@ -805,6 +808,7 @@ tag char note action in Normal mo |g| g same as g same as |g| g same as +|g| g go to the last accessed tab page. |g| g 1 same as "gk" ============================================================================== diff --git a/runtime/doc/tabpage.txt b/runtime/doc/tabpage.txt --- a/runtime/doc/tabpage.txt +++ b/runtime/doc/tabpage.txt @@ -221,6 +221,8 @@ gT Go to the previous tab page. Wraps *:tabl* *:tablast* :tabl[ast] Go to the last tab page. + *g* *CTRL-W_g* ** +g Go to the last accessed tab page. Other commands: *:tabs* diff --git a/src/evalwindow.c b/src/evalwindow.c --- a/src/evalwindow.c +++ b/src/evalwindow.c @@ -616,6 +616,9 @@ f_tabpagenr(typval_T *argvars UNUSED, ty { if (STRCMP(arg, "$") == 0) nr = tabpage_index(NULL) - 1; + else if (STRCMP(arg, "#") == 0) + nr = valid_tabpage(lastused_tabpage) ? + tabpage_index(lastused_tabpage) : 0; else semsg(_(e_invexpr2), arg); } diff --git a/src/globals.h b/src/globals.h --- a/src/globals.h +++ b/src/globals.h @@ -725,10 +725,12 @@ EXTERN frame_T *topframe; // top of the /* * 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 *curtab; +EXTERN tabpage_T *lastused_tabpage; EXTERN int redraw_tabline INIT(= FALSE); // need to redraw tabline /* diff --git a/src/normal.c b/src/normal.c --- a/src/normal.c +++ b/src/normal.c @@ -5442,7 +5442,7 @@ nv_gomark(cmdarg_T *cap) } /* - * Handle CTRL-O, CTRL-I, "g;" and "g," commands. + * Handle CTRL-O, CTRL-I, "g;", "g," and "CTRL-Tab" commands. */ static void nv_pcmark(cmdarg_T *cap) @@ -5456,6 +5456,12 @@ nv_pcmark(cmdarg_T *cap) if (!checkclearopq(cap->oap)) { + if (cap->cmdchar == TAB && mod_mask == MOD_MASK_CTRL) + { + if (goto_tabpage_lastused() == FAIL) + clearopbeep(cap->oap); + return; + } if (cap->cmdchar == 'g') pos = movechangelist((int)cap->count1); else @@ -6310,6 +6316,11 @@ nv_g_cmd(cmdarg_T *cap) goto_tabpage(-(int)cap->count1); break; + case TAB: + if (!checkclearop(oap) && goto_tabpage_lastused() == FAIL) + clearopbeep(oap); + break; + case '+': case '-': // "g+" and "g-": undo or redo along the timeline if (!checkclearopq(oap)) diff --git a/src/proto/window.pro b/src/proto/window.pro --- a/src/proto/window.pro +++ b/src/proto/window.pro @@ -32,6 +32,7 @@ tabpage_T *find_tabpage(int n); int tabpage_index(tabpage_T *ftp); void goto_tabpage(int n); void goto_tabpage_tp(tabpage_T *tp, int trigger_enter_autocmds, int trigger_leave_autocmds); +int goto_tabpage_lastused(void); void goto_tabpage_win(tabpage_T *tp, win_T *wp); void tabpage_move(int nr); void win_goto(win_T *wp); diff --git a/src/testdir/test_tabpage.vim b/src/testdir/test_tabpage.vim --- a/src/testdir/test_tabpage.vim +++ b/src/testdir/test_tabpage.vim @@ -130,7 +130,7 @@ function Test_tabpage() 1tabmove call assert_equal(2, tabpagenr()) - call assert_fails('let t = tabpagenr("#")', 'E15:') + call assert_fails('let t = tabpagenr("@")', 'E15:') call assert_equal(0, tabpagewinnr(-1)) call assert_fails("99tabmove", 'E16:') call assert_fails("+99tabmove", 'E16:') @@ -777,4 +777,48 @@ func Test_tabpage_close_on_switch() %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\", "xt")') + call assert_beeps('call feedkeys("\", "xt")') + call assert_beeps('call feedkeys("\g\", "xt")') + + " open four tab pages + tabnew + tabnew + tabnew + + 2tabnext + + " Test for g + call assert_equal(4, tabpagenr('#')) + call feedkeys("g\", "xt") + call assert_equal(4, tabpagenr()) + call assert_equal(2, tabpagenr('#')) + + " Test for + call feedkeys("\", "xt") + call assert_equal(2, tabpagenr()) + call assert_equal(4, tabpagenr('#')) + + " Test for g + call feedkeys("\g\", "xt") + call assert_equal(4, tabpagenr()) + call assert_equal(2, tabpagenr('#')) + + " Try to jump to a closed tab page + tabclose 2 + call assert_equal(0, tabpagenr('#')) + call feedkeys("g\", "xt") + call assert_equal(3, tabpagenr()) + call feedkeys("\", "xt") + call assert_equal(3, tabpagenr()) + call feedkeys("\g\", "xt") + call assert_equal(3, tabpagenr()) + + tabclose! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1401, +/**/ 1400, /**/ 1399, diff --git a/src/window.c b/src/window.c --- a/src/window.c +++ b/src/window.c @@ -627,6 +627,11 @@ wingotofile: goto_tabpage(-(int)Prenum1); break; + case TAB: // CTRL-W g: go to last used tab page + if (goto_tabpage_lastused() == FAIL) + beep_flush(); + break; + default: beep_flush(); break; @@ -3809,6 +3814,9 @@ free_tabpage(tabpage_T *tp) unref_var_dict(tp->tp_vars); #endif + if (tp == lastused_tabpage) + lastused_tabpage = NULL; + vim_free(tp->tp_localdir); vim_free(tp->tp_prevdir); @@ -3883,6 +3891,8 @@ win_new_tabpage(int after) newtp->tp_topframe = topframe; last_status(FALSE); + lastused_tabpage = tp; + #if defined(FEAT_GUI) // When 'guioptions' includes 'L' or 'R' may have to remove or add // scrollbars. Have to update them anyway. @@ -4118,6 +4128,7 @@ enter_tabpage( int row; int old_off = tp->tp_firstwin->w_winrow; win_T *next_prevwin = tp->tp_prevwin; + tabpage_T *last_tab = curtab; curtab = tp; firstwin = tp->tp_firstwin; @@ -4160,6 +4171,8 @@ enter_tabpage( if (curtab->tp_old_Columns != Columns && starting == 0) shell_new_columns(); // update window widths + lastused_tabpage = last_tab; + #if defined(FEAT_GUI) // When 'guioptions' includes 'L' or 'R' may have to remove or add // scrollbars. Have to update them anyway. @@ -4278,6 +4291,21 @@ goto_tabpage_tp( } /* + * Go to the last accessed tab page, if there is one. + * Return OK or FAIL + */ + int +goto_tabpage_lastused(void) +{ + if (valid_tabpage(lastused_tabpage)) + { + goto_tabpage_tp(lastused_tabpage, TRUE, TRUE); + return OK; + } + return FAIL; +} + +/* * Enter window "wp" in tab page "tp". * Also updates the GUI tab. */