patch 8.2.1401: cannot jump to the last used tabpage

Problem:    Cannot jump to the last used tabpage.
Solution:   Add g<Tab> and tabpagnr('#'). (Yegappan Lakshmanan, closes #6661,
            neovim #11626)
diff --git a/src/evalwindow.c b/src/evalwindow.c
index 0b3052c..b50776d 100644
--- a/src/evalwindow.c
+++ b/src/evalwindow.c
@@ -616,6 +616,9 @@
 	{
 	    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
index cc01ac2..72b8a1e 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -725,10 +725,12 @@
 
 /*
  * 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
index dd79a43..cb8e736 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -5442,7 +5442,7 @@
 }
 
 /*
- * 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 @@
 
     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 @@
 	    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
index ab62c0a..4c9bddd 100644
--- a/src/proto/window.pro
+++ b/src/proto/window.pro
@@ -32,6 +32,7 @@
 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
index bbcafa8..6746971 100644
--- a/src/testdir/test_tabpage.vim
+++ b/src/testdir/test_tabpage.vim
@@ -130,7 +130,7 @@
   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 @@
   %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")')
+
+  " 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('#'))
+
+  " Try to jump to a closed tab page
+  tabclose 2
+  call assert_equal(0, tabpagenr('#'))
+  call feedkeys("g\<Tab>", "xt")
+  call assert_equal(3, tabpagenr())
+  call feedkeys("\<C-Tab>", "xt")
+  call assert_equal(3, tabpagenr())
+  call feedkeys("\<C-W>g\<Tab>", "xt")
+  call assert_equal(3, tabpagenr())
+
+  tabclose!
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index 20e8b36..15f4c06 100644
--- a/src/version.c
+++ b/src/version.c
@@ -755,6 +755,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1401,
+/**/
     1400,
 /**/
     1399,
diff --git a/src/window.c b/src/window.c
index 4b2ff4b..7d8122e 100644
--- a/src/window.c
+++ b/src/window.c
@@ -627,6 +627,11 @@
 			goto_tabpage(-(int)Prenum1);
 			break;
 
+		    case TAB:	    // CTRL-W g<Tab>: go to last used tab page
+			if (goto_tabpage_lastused() == FAIL)
+			    beep_flush();
+			break;
+
 		    default:
 			beep_flush();
 			break;
@@ -3809,6 +3814,9 @@
     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 @@
 	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 @@
     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 @@
     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 @@
 }
 
 /*
+ * 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.
  */