patch 8.2.1967: the session file does not restore the alternate file

Problem:    The session file does not restore the alternate file.
Solution:   Add ":balt".  Works like ":badd" and also sets the buffer as the
            alternate file.  Use it in the session file. (closes #7269,
            closes #6714)
diff --git a/src/ex_cmdidxs.h b/src/ex_cmdidxs.h
index 2e59d2c..290e9fa 100644
--- a/src/ex_cmdidxs.h
+++ b/src/ex_cmdidxs.h
@@ -7,30 +7,30 @@
 {
   /* a */ 0,
   /* b */ 19,
-  /* c */ 42,
-  /* d */ 108,
-  /* e */ 133,
-  /* f */ 156,
-  /* g */ 173,
-  /* h */ 179,
-  /* i */ 188,
-  /* j */ 207,
-  /* k */ 209,
-  /* l */ 214,
-  /* m */ 276,
-  /* n */ 294,
-  /* o */ 314,
-  /* p */ 326,
-  /* q */ 365,
-  /* r */ 368,
-  /* s */ 388,
-  /* t */ 457,
-  /* u */ 502,
-  /* v */ 513,
-  /* w */ 533,
-  /* x */ 547,
-  /* y */ 557,
-  /* z */ 558
+  /* c */ 43,
+  /* d */ 109,
+  /* e */ 134,
+  /* f */ 157,
+  /* g */ 174,
+  /* h */ 180,
+  /* i */ 189,
+  /* j */ 208,
+  /* k */ 210,
+  /* l */ 215,
+  /* m */ 277,
+  /* n */ 295,
+  /* o */ 315,
+  /* p */ 327,
+  /* q */ 366,
+  /* r */ 369,
+  /* s */ 389,
+  /* t */ 458,
+  /* u */ 503,
+  /* v */ 514,
+  /* w */ 534,
+  /* x */ 548,
+  /* y */ 558,
+  /* z */ 559
 };
 
 /*
@@ -42,7 +42,7 @@
 static const unsigned char cmdidxs2[26][26] =
 { /*         a   b   c   d   e   f   g   h   i   j   k   l   m   n   o   p   q   r   s   t   u   v   w   x   y   z */
   /* a */ {  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  4,  5,  6,  0,  0,  0,  7, 15,  0, 16,  0,  0,  0,  0,  0 },
-  /* b */ {  2,  0,  0,  4,  5,  7,  0,  0,  0,  0,  0,  8,  9, 10, 11, 12,  0, 13,  0,  0,  0,  0, 22,  0,  0,  0 },
+  /* b */ {  2,  0,  0,  5,  6,  8,  0,  0,  0,  0,  0,  9, 10, 11, 12, 13,  0, 14,  0,  0,  0,  0, 23,  0,  0,  0 },
   /* c */ {  3, 12, 16, 18, 20, 22, 25,  0,  0,  0,  0, 33, 37, 40, 46, 56, 58, 59, 60,  0, 62,  0, 65,  0,  0,  0 },
   /* d */ {  0,  0,  0,  0,  0,  0,  0,  0,  8, 18,  0, 19,  0,  0, 20,  0,  0, 22, 23,  0,  0,  0,  0,  0,  0,  0 },
   /* e */ {  1,  0,  2,  0,  0,  0,  0,  0,  0,  0,  0,  7,  9, 10,  0,  0,  0,  0,  0,  0,  0, 17,  0, 18,  0,  0 },
@@ -69,4 +69,4 @@
   /* z */ {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 }
 };
 
-static const int command_count = 573;
+static const int command_count = 574;
diff --git a/src/ex_cmds.c b/src/ex_cmds.c
index 185033f..aa9fe9b 100644
--- a/src/ex_cmds.c
+++ b/src/ex_cmds.c
@@ -2459,6 +2459,7 @@
  *	 ECMD_OLDBUF: use existing buffer if it exists
  *	ECMD_FORCEIT: ! used for Ex command
  *	 ECMD_ADDBUF: don't edit, just add to buffer list
+ *	 ECMD_ALTBUF: like ECMD_ADDBUF and also set the alternate file
  *   oldwin: Should be "curwin" when editing a new buffer in the current
  *	     window, NULL when splitting the window first.  When not NULL info
  *	     of the previous buffer for "oldwin" is stored.
@@ -2555,7 +2556,8 @@
 	    fname_case(sfname, 0);   // set correct case for sfname
 #endif
 
-	if ((flags & ECMD_ADDBUF) && (ffname == NULL || *ffname == NUL))
+	if ((flags & (ECMD_ADDBUF | ECMD_ALTBUF))
+					 && (ffname == NULL || *ffname == NUL))
 	    goto theend;
 
 	if (ffname == NULL)
@@ -2584,7 +2586,7 @@
      */
     if (  ((!other_file && !(flags & ECMD_OLDBUF))
 	    || (curbuf->b_nwindows == 1
-		&& !(flags & (ECMD_HIDE | ECMD_ADDBUF))))
+		&& !(flags & (ECMD_HIDE | ECMD_ADDBUF | ECMD_ALTBUF))))
 	&& check_changed(curbuf, (p_awa ? CCGD_AW : 0)
 			       | (other_file ? 0 : CCGD_MULTWIN)
 			       | ((flags & ECMD_FORCEIT) ? CCGD_FORCEIT : 0)
@@ -2633,7 +2635,7 @@
      */
     if (other_file)
     {
-	if (!(flags & ECMD_ADDBUF))
+	if (!(flags & (ECMD_ADDBUF | ECMD_ALTBUF)))
 	{
 	    if ((cmdmod.cmod_flags & CMOD_KEEPALT) == 0)
 		curwin->w_alt_fnum = curbuf->b_fnum;
@@ -2645,11 +2647,12 @@
 	    buf = buflist_findnr(fnum);
 	else
 	{
-	    if (flags & ECMD_ADDBUF)
+	    if (flags & (ECMD_ADDBUF | ECMD_ALTBUF))
 	    {
 		// Default the line number to zero to avoid that a wininfo item
 		// is added for the current window.
 		linenr_T	tlnum = 0;
+		buf_T		*newbuf;
 
 		if (command != NULL)
 		{
@@ -2657,10 +2660,12 @@
 		    if (tlnum <= 0)
 			tlnum = 1L;
 		}
-		// Add BLN_NOCURWIN to avoid a new wininfo items is assocated
+		// Add BLN_NOCURWIN to avoid a new wininfo items are assocated
 		// with the current window.
-		(void)buflist_new(ffname, sfname, tlnum,
+		newbuf = buflist_new(ffname, sfname, tlnum,
 						    BLN_LISTED | BLN_NOCURWIN);
+		if (newbuf != NULL && (flags & ECMD_ALTBUF))
+		    curwin->w_alt_fnum = newbuf->b_fnum;
 		goto theend;
 	    }
 	    buf = buflist_new(ffname, sfname, 0L,
@@ -2818,7 +2823,7 @@
     }
     else // !other_file
     {
-	if ((flags & ECMD_ADDBUF) || check_fname() == FAIL)
+	if ((flags & (ECMD_ADDBUF | ECMD_ALTBUF)) || check_fname() == FAIL)
 	    goto theend;
 
 	oldbuf = (flags & ECMD_OLDBUF);
diff --git a/src/ex_cmds.h b/src/ex_cmds.h
index d53b6df..4fe62ca 100644
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -178,6 +178,9 @@
 EXCMD(CMD_badd,		"badd",		ex_edit,
 	EX_NEEDARG|EX_FILE1|EX_CMDARG|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
 	ADDR_NONE),
+EXCMD(CMD_balt,		"balt",		ex_edit,
+	EX_NEEDARG|EX_FILE1|EX_CMDARG|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
+	ADDR_NONE),
 EXCMD(CMD_bdelete,	"bdelete",	ex_bunload,
 	EX_BANG|EX_RANGE|EX_BUFNAME|EX_COUNT|EX_EXTRA|EX_TRLBAR,
 	ADDR_BUFFERS),
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 290dcee..627dae7 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -6506,7 +6506,7 @@
 }
 
 /*
- * ":edit", ":badd", ":visual".
+ * ":edit", ":badd", ":balt", ":visual".
  */
     static void
 ex_edit(exarg_T *eap)
@@ -6621,7 +6621,8 @@
 		    + (eap->forceit ? ECMD_FORCEIT : 0)
 		      // after a split we can use an existing buffer
 		    + (old_curwin != NULL ? ECMD_OLDBUF : 0)
-		    + (eap->cmdidx == CMD_badd ? ECMD_ADDBUF : 0 )
+		    + (eap->cmdidx == CMD_badd ? ECMD_ADDBUF : 0)
+		    + (eap->cmdidx == CMD_balt ? ECMD_ALTBUF : 0)
 		    , old_curwin == NULL ? curwin : NULL) == FAIL)
 	{
 	    // Editing the file failed.  If the window was split, close it.
@@ -8472,7 +8473,7 @@
  * Evaluate cmdline variables.
  *
  * change '%'	    to curbuf->b_ffname
- *	  '#'	    to curwin->w_altfile
+ *	  '#'	    to curwin->w_alt_fnum
  *	  '<cword>' to word under the cursor
  *	  '<cWORD>' to WORD under the cursor
  *	  '<cexpr>' to C-expression under the cursor
diff --git a/src/session.c b/src/session.c
index 44976e8..9731bd3 100644
--- a/src/session.c
+++ b/src/session.c
@@ -397,6 +397,19 @@
 	}
     }
 
+    if (wp->w_alt_fnum)
+    {
+	buf_T *alt = buflist_findnr(wp->w_alt_fnum);
+
+	// Set the alternate file.
+	if (alt != NULL
+		&& alt->b_fname != NULL
+		&& *alt->b_fname != NUL
+		&& (fputs("balt ", fd) < 0
+		|| ses_fname(fd, alt, flagp, TRUE) == FAIL))
+	    return FAIL;
+    }
+
     // Local mappings and abbreviations.
     if ((*flagp & (SSOP_OPTIONS | SSOP_LOCALOPTIONS))
 					 && makemap(fd, wp->w_buffer) == FAIL)
diff --git a/src/testdir/test_buffer.vim b/src/testdir/test_buffer.vim
index a743f18..4e8a79f 100644
--- a/src/testdir/test_buffer.vim
+++ b/src/testdir/test_buffer.vim
@@ -374,4 +374,11 @@
   bwipe! SomeNewBuffer
 endfunc
 
+func Test_balt()
+  new SomeNewBuffer
+  balt +3 OtherBuffer
+  e #
+  call assert_equal('OtherBuffer', bufname())
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index 1fbae19..fe89862 100644
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1967,
+/**/
     1966,
 /**/
     1965,
diff --git a/src/vim.h b/src/vim.h
index 289ef3c..d2e22fe 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -1029,6 +1029,7 @@
 #define ECMD_OLDBUF	0x04	// use existing buffer if it exists
 #define ECMD_FORCEIT	0x08	// ! used in Ex command
 #define ECMD_ADDBUF	0x10	// don't edit, just add to buffer list
+#define ECMD_ALTBUF	0x20	// like ECMD_ADDBUF and set the alternate file
 
 // for lnum argument in do_ecmd()
 #define ECMD_LASTL	(linenr_T)0	// use last position in loaded file