changeset 28652:27dcbe70e1f0 v8.2.4850

patch 8.2.4850: mksession mixes up "tabpages" and "curdir" arguments Commit: https://github.com/vim/vim/commit/d7c9564d8d24343f2e27205633032dd6ebe5232c Author: LemonBoy <thatlemon@gmail.com> Date: Sat Apr 30 16:10:27 2022 +0100 patch 8.2.4850: mksession mixes up "tabpages" and "curdir" arguments Problem: Mksession mixes up "tabpages" and "curdir" arguments. Solution: Correct logic for storing tabpage in session. (closes https://github.com/vim/vim/issues/10312)
author Bram Moolenaar <Bram@vim.org>
date Sat, 30 Apr 2022 17:15:02 +0200
parents f3e46158f0dd
children 94f2550a1af1
files src/session.c src/testdir/test_mksession.vim src/version.c
diffstat 3 files changed, 52 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/src/session.c
+++ b/src/session.c
@@ -623,13 +623,13 @@ makeopens(
     win_T	*wp;
     char_u	*sname;
     win_T	*edited_win = NULL;
-    int		tabnr;
     int		restore_stal = FALSE;
     win_T	*tab_firstwin;
     frame_T	*tab_topframe;
     int		cur_arg_idx = 0;
     int		next_arg_idx = 0;
     int		ret = FAIL;
+    tabpage_T	*tp;
 #ifdef FEAT_TERMINAL
     hashtab_T	terminal_bufs;
 
@@ -755,18 +755,11 @@ makeopens(
 	restore_stal = TRUE;
     }
 
-    // May repeat putting Windows for each tab, when "tabpages" is in
-    // 'sessionoptions'.
-    // Don't use goto_tabpage(), it may change directory and trigger
-    // autocommands.
-    tab_firstwin = firstwin;	// first window in tab page "tabnr"
-    tab_topframe = topframe;
     if ((ssop_flags & SSOP_TABPAGES))
     {
-	tabpage_T *tp;
-
-	// Similar to ses_win_rec() below, populate the tab pages first so
-	// later local options won't be copied to the new tabs.
+	// "tabpages" is in 'sessionoptions': Similar to ses_win_rec() below,
+	// populate the tab pages first so later local options won't be copied
+	// to the new tabs.
 	FOR_ALL_TABPAGES(tp)
 	    // Use `bufhidden=wipe` to remove empty "placeholder" buffers once
 	    // they are not needed. This prevents creating extra buffers (see
@@ -777,18 +770,20 @@ makeopens(
 	if (first_tabpage->tp_next != NULL && put_line(fd, "tabrewind") == FAIL)
 	    goto fail;
     }
-    for (tabnr = 1; ; ++tabnr)
+
+    // Assume "tabpages" is in 'sessionoptions'.  If not then we only do
+    // "curtab" and bail out of the loop.
+    FOR_ALL_TABPAGES(tp)
     {
-	tabpage_T *tp = NULL;
 	int	need_tabnext = FALSE;
 	int	cnr = 1;
 
+	// May repeat putting Windows for each tab, when "tabpages" is in
+	// 'sessionoptions'.
+	// Don't use goto_tabpage(), it may change directory and trigger
+	// autocommands.
 	if ((ssop_flags & SSOP_TABPAGES))
 	{
-	    tp = find_tabpage(tabnr);
-
-	    if (tp == NULL)
-		break;		// done all tab pages
 	    if (tp == curtab)
 	    {
 		tab_firstwin = firstwin;
@@ -799,9 +794,15 @@ makeopens(
 		tab_firstwin = tp->tp_firstwin;
 		tab_topframe = tp->tp_topframe;
 	    }
-	    if (tabnr > 1)
+	    if (tp != first_tabpage)
 		need_tabnext = TRUE;
 	}
+	else
+	{
+	    tp = curtab;
+	    tab_firstwin = firstwin;
+	    tab_topframe = topframe;
+	}
 
 	// Before creating the window layout, try loading one file.  If this
 	// is aborted we don't end up with a number of useless windows.
@@ -893,11 +894,11 @@ makeopens(
 	// Restore the tab-local working directory if specified
 	// Do this before the windows, so that the window-local directory can
 	// override the tab-local directory.
-	if (tp != NULL && tp->tp_localdir != NULL && ssop_flags & SSOP_CURDIR)
+	if ((ssop_flags & SSOP_CURDIR) && tp->tp_localdir != NULL)
 	{
 	    if (fputs("tcd ", fd) < 0
-		    || ses_put_fname(fd, tp->tp_localdir, &ssop_flags) == FAIL
-		    || put_eol(fd) == FAIL)
+		     || ses_put_fname(fd, tp->tp_localdir, &ssop_flags) == FAIL
+		     || put_eol(fd) == FAIL)
 		goto fail;
 	    did_lcd = TRUE;
 	}
--- a/src/testdir/test_mksession.vim
+++ b/src/testdir/test_mksession.vim
@@ -865,6 +865,34 @@ func Test_mksession_sesdir()
   call delete('Xproj', 'rf')
 endfunc
 
+" Test for saving and restoring the tab-local working directory when there is
+" only a single tab and 'tabpages' is not in 'sessionoptions'.
+func Test_mksession_tcd_single_tabs()
+  only | tabonly
+
+  let save_cwd = getcwd()
+  set sessionoptions-=tabpages
+  set sessionoptions+=curdir
+  call mkdir('Xtopdir1')
+  call mkdir('Xtopdir2')
+
+  " There are two tab pages, the current one has local cwd set to 'Xtopdir2'.
+  exec 'tcd ' .. save_cwd .. '/Xtopdir1'
+  tabnew
+  exec 'tcd ' .. save_cwd .. '/Xtopdir2'
+  mksession! Xtest_tcd_single
+
+  source Xtest_tcd_single
+  call assert_equal(2, haslocaldir())
+  call assert_equal('Xtopdir2', fnamemodify(getcwd(-1, 0), ':t'))
+  %bwipe
+
+  set sessionoptions&
+  call chdir(save_cwd)
+  call delete('Xtopdir1', 'rf')
+  call delete('Xtopdir2', 'rf')
+endfunc
+
 " Test for storing the 'lines' and 'columns' settings
 func Test_mksession_resize()
   mksession! Xtest_mks1.out
--- a/src/version.c
+++ b/src/version.c
@@ -747,6 +747,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    4850,
+/**/
     4849,
 /**/
     4848,