xref: /vim-8.2.3635/src/session.c (revision 21c1a0c2)
184538079SBram Moolenaar /* vi:set ts=8 sts=4 sw=4 noet:
284538079SBram Moolenaar  *
384538079SBram Moolenaar  * VIM - Vi IMproved	by Bram Moolenaar
484538079SBram Moolenaar  *
584538079SBram Moolenaar  * Do ":help uganda"  in Vim to read copying and usage conditions.
684538079SBram Moolenaar  * Do ":help credits" in Vim to see a list of people who contributed.
784538079SBram Moolenaar  * See README.txt for an overview of the Vim source code.
884538079SBram Moolenaar  */
984538079SBram Moolenaar 
1084538079SBram Moolenaar /*
1184538079SBram Moolenaar  * session.c: session related functions
1284538079SBram Moolenaar  */
1384538079SBram Moolenaar 
1484538079SBram Moolenaar #include "vim.h"
1584538079SBram Moolenaar 
1684538079SBram Moolenaar #if defined(FEAT_SESSION) || defined(PROTO)
1784538079SBram Moolenaar 
1884538079SBram Moolenaar static int did_lcd;	// whether ":lcd" was produced for a session
1984538079SBram Moolenaar 
2084538079SBram Moolenaar /*
2184538079SBram Moolenaar  * Write a file name to the session file.
2284538079SBram Moolenaar  * Takes care of the "slash" option in 'sessionoptions' and escapes special
2384538079SBram Moolenaar  * characters.
2484538079SBram Moolenaar  * Returns FAIL if writing fails or out of memory.
2584538079SBram Moolenaar  */
2684538079SBram Moolenaar     static int
ses_put_fname(FILE * fd,char_u * name,unsigned * flagp)2784538079SBram Moolenaar ses_put_fname(FILE *fd, char_u *name, unsigned *flagp)
2884538079SBram Moolenaar {
2984538079SBram Moolenaar     char_u	*sname;
3084538079SBram Moolenaar     char_u	*p;
3184538079SBram Moolenaar     int		retval = OK;
3284538079SBram Moolenaar 
3384538079SBram Moolenaar     sname = home_replace_save(NULL, name);
3484538079SBram Moolenaar     if (sname == NULL)
3584538079SBram Moolenaar 	return FAIL;
3684538079SBram Moolenaar 
3784538079SBram Moolenaar     if (*flagp & SSOP_SLASH)
3884538079SBram Moolenaar     {
3984538079SBram Moolenaar 	// change all backslashes to forward slashes
4084538079SBram Moolenaar 	for (p = sname; *p != NUL; MB_PTR_ADV(p))
4184538079SBram Moolenaar 	    if (*p == '\\')
4284538079SBram Moolenaar 		*p = '/';
4384538079SBram Moolenaar     }
4484538079SBram Moolenaar 
4584538079SBram Moolenaar     // escape special characters
46*21c1a0c2SBram Moolenaar     p = vim_strsave_fnameescape(sname, VSE_NONE);
4784538079SBram Moolenaar     vim_free(sname);
4884538079SBram Moolenaar     if (p == NULL)
4984538079SBram Moolenaar 	return FAIL;
5084538079SBram Moolenaar 
5184538079SBram Moolenaar     // write the result
5284538079SBram Moolenaar     if (fputs((char *)p, fd) < 0)
5384538079SBram Moolenaar 	retval = FAIL;
5484538079SBram Moolenaar 
5584538079SBram Moolenaar     vim_free(p);
5684538079SBram Moolenaar     return retval;
5784538079SBram Moolenaar }
5884538079SBram Moolenaar 
5984538079SBram Moolenaar /*
6084538079SBram Moolenaar  * Write a buffer name to the session file.
6184538079SBram Moolenaar  * Also ends the line, if "add_eol" is TRUE.
6284538079SBram Moolenaar  * Returns FAIL if writing fails.
6384538079SBram Moolenaar  */
6484538079SBram Moolenaar     static int
ses_fname(FILE * fd,buf_T * buf,unsigned * flagp,int add_eol)6584538079SBram Moolenaar ses_fname(FILE *fd, buf_T *buf, unsigned *flagp, int add_eol)
6684538079SBram Moolenaar {
6784538079SBram Moolenaar     char_u	*name;
6884538079SBram Moolenaar 
6984538079SBram Moolenaar     // Use the short file name if the current directory is known at the time
7084538079SBram Moolenaar     // the session file will be sourced.
7184538079SBram Moolenaar     // Don't do this for ":mkview", we don't know the current directory.
7284538079SBram Moolenaar     // Don't do this after ":lcd", we don't keep track of what the current
7384538079SBram Moolenaar     // directory is.
7484538079SBram Moolenaar     if (buf->b_sfname != NULL
7584538079SBram Moolenaar 	    && flagp == &ssop_flags
7684538079SBram Moolenaar 	    && (ssop_flags & (SSOP_CURDIR | SSOP_SESDIR))
7784538079SBram Moolenaar #ifdef FEAT_AUTOCHDIR
7884538079SBram Moolenaar 	    && !p_acd
7984538079SBram Moolenaar #endif
8084538079SBram Moolenaar 	    && !did_lcd)
8184538079SBram Moolenaar 	name = buf->b_sfname;
8284538079SBram Moolenaar     else
8384538079SBram Moolenaar 	name = buf->b_ffname;
8484538079SBram Moolenaar     if (ses_put_fname(fd, name, flagp) == FAIL
8584538079SBram Moolenaar 	    || (add_eol && put_eol(fd) == FAIL))
8684538079SBram Moolenaar 	return FAIL;
8784538079SBram Moolenaar     return OK;
8884538079SBram Moolenaar }
8984538079SBram Moolenaar 
9084538079SBram Moolenaar /*
9184538079SBram Moolenaar  * Write an argument list to the session file.
9284538079SBram Moolenaar  * Returns FAIL if writing fails.
9384538079SBram Moolenaar  */
9484538079SBram Moolenaar     static int
ses_arglist(FILE * fd,char * cmd,garray_T * gap,int fullname,unsigned * flagp)9584538079SBram Moolenaar ses_arglist(
9684538079SBram Moolenaar     FILE	*fd,
9784538079SBram Moolenaar     char	*cmd,
9884538079SBram Moolenaar     garray_T	*gap,
9984538079SBram Moolenaar     int		fullname,	// TRUE: use full path name
10084538079SBram Moolenaar     unsigned	*flagp)
10184538079SBram Moolenaar {
10284538079SBram Moolenaar     int		i;
10384538079SBram Moolenaar     char_u	*buf = NULL;
10484538079SBram Moolenaar     char_u	*s;
10584538079SBram Moolenaar 
10684538079SBram Moolenaar     if (fputs(cmd, fd) < 0 || put_eol(fd) == FAIL)
10784538079SBram Moolenaar 	return FAIL;
10884538079SBram Moolenaar     if (put_line(fd, "%argdel") == FAIL)
10984538079SBram Moolenaar 	return FAIL;
11084538079SBram Moolenaar     for (i = 0; i < gap->ga_len; ++i)
11184538079SBram Moolenaar     {
11284538079SBram Moolenaar 	// NULL file names are skipped (only happens when out of memory).
11384538079SBram Moolenaar 	s = alist_name(&((aentry_T *)gap->ga_data)[i]);
11484538079SBram Moolenaar 	if (s != NULL)
11584538079SBram Moolenaar 	{
11684538079SBram Moolenaar 	    if (fullname)
11784538079SBram Moolenaar 	    {
11884538079SBram Moolenaar 		buf = alloc(MAXPATHL);
11984538079SBram Moolenaar 		if (buf != NULL)
12084538079SBram Moolenaar 		{
12184538079SBram Moolenaar 		    (void)vim_FullName(s, buf, MAXPATHL, FALSE);
12284538079SBram Moolenaar 		    s = buf;
12384538079SBram Moolenaar 		}
12484538079SBram Moolenaar 	    }
12584538079SBram Moolenaar 	    if (fputs("$argadd ", fd) < 0
12684538079SBram Moolenaar 		    || ses_put_fname(fd, s, flagp) == FAIL
12784538079SBram Moolenaar 		    || put_eol(fd) == FAIL)
12884538079SBram Moolenaar 	    {
12984538079SBram Moolenaar 		vim_free(buf);
13084538079SBram Moolenaar 		return FAIL;
13184538079SBram Moolenaar 	    }
13284538079SBram Moolenaar 	    vim_free(buf);
13384538079SBram Moolenaar 	}
13484538079SBram Moolenaar     }
13584538079SBram Moolenaar     return OK;
13684538079SBram Moolenaar }
13784538079SBram Moolenaar 
13884538079SBram Moolenaar /*
13984538079SBram Moolenaar  * Return non-zero if window "wp" is to be stored in the Session.
14084538079SBram Moolenaar  */
14184538079SBram Moolenaar     static int
ses_do_win(win_T * wp)14284538079SBram Moolenaar ses_do_win(win_T *wp)
14384538079SBram Moolenaar {
14484538079SBram Moolenaar #ifdef FEAT_TERMINAL
14584538079SBram Moolenaar     if (bt_terminal(wp->w_buffer))
14684538079SBram Moolenaar 	return !term_is_finished(wp->w_buffer)
14784538079SBram Moolenaar 	    && (ssop_flags & SSOP_TERMINAL)
14884538079SBram Moolenaar 	    && term_should_restore(wp->w_buffer);
14984538079SBram Moolenaar #endif
15084538079SBram Moolenaar     if (wp->w_buffer->b_fname == NULL
15184538079SBram Moolenaar #ifdef FEAT_QUICKFIX
15284538079SBram Moolenaar 	    // When 'buftype' is "nofile" can't restore the window contents.
15384538079SBram Moolenaar 	    || bt_nofilename(wp->w_buffer)
15484538079SBram Moolenaar #endif
15584538079SBram Moolenaar        )
15684538079SBram Moolenaar 	return (ssop_flags & SSOP_BLANK);
15784538079SBram Moolenaar     if (bt_help(wp->w_buffer))
15884538079SBram Moolenaar 	return (ssop_flags & SSOP_HELP);
15984538079SBram Moolenaar     return TRUE;
16084538079SBram Moolenaar }
16184538079SBram Moolenaar 
16284538079SBram Moolenaar /*
16384538079SBram Moolenaar  * Return TRUE if frame "fr" has a window somewhere that we want to save in
16484538079SBram Moolenaar  * the Session.
16584538079SBram Moolenaar  */
16684538079SBram Moolenaar     static int
ses_do_frame(frame_T * fr)16784538079SBram Moolenaar ses_do_frame(frame_T *fr)
16884538079SBram Moolenaar {
16984538079SBram Moolenaar     frame_T	*frc;
17084538079SBram Moolenaar 
17184538079SBram Moolenaar     if (fr->fr_layout == FR_LEAF)
17284538079SBram Moolenaar 	return ses_do_win(fr->fr_win);
17384538079SBram Moolenaar     FOR_ALL_FRAMES(frc, fr->fr_child)
17484538079SBram Moolenaar 	if (ses_do_frame(frc))
17584538079SBram Moolenaar 	    return TRUE;
17684538079SBram Moolenaar     return FALSE;
17784538079SBram Moolenaar }
17884538079SBram Moolenaar 
17984538079SBram Moolenaar /*
18084538079SBram Moolenaar  * Skip frames that don't contain windows we want to save in the Session.
18184538079SBram Moolenaar  * Returns NULL when there none.
18284538079SBram Moolenaar  */
18384538079SBram Moolenaar     static frame_T *
ses_skipframe(frame_T * fr)18484538079SBram Moolenaar ses_skipframe(frame_T *fr)
18584538079SBram Moolenaar {
18684538079SBram Moolenaar     frame_T	*frc;
18784538079SBram Moolenaar 
18884538079SBram Moolenaar     FOR_ALL_FRAMES(frc, fr)
18984538079SBram Moolenaar 	if (ses_do_frame(frc))
19084538079SBram Moolenaar 	    break;
19184538079SBram Moolenaar     return frc;
19284538079SBram Moolenaar }
19384538079SBram Moolenaar 
19484538079SBram Moolenaar /*
19584538079SBram Moolenaar  * Write commands to "fd" to recursively create windows for frame "fr",
19684538079SBram Moolenaar  * horizontally and vertically split.
19784538079SBram Moolenaar  * After the commands the last window in the frame is the current window.
19884538079SBram Moolenaar  * Returns FAIL when writing the commands to "fd" fails.
19984538079SBram Moolenaar  */
20084538079SBram Moolenaar     static int
ses_win_rec(FILE * fd,frame_T * fr)20184538079SBram Moolenaar ses_win_rec(FILE *fd, frame_T *fr)
20284538079SBram Moolenaar {
20384538079SBram Moolenaar     frame_T	*frc;
20484538079SBram Moolenaar     int		count = 0;
20584538079SBram Moolenaar 
20684538079SBram Moolenaar     if (fr->fr_layout != FR_LEAF)
20784538079SBram Moolenaar     {
20884538079SBram Moolenaar 	// Find first frame that's not skipped and then create a window for
20984538079SBram Moolenaar 	// each following one (first frame is already there).
21084538079SBram Moolenaar 	frc = ses_skipframe(fr->fr_child);
21184538079SBram Moolenaar 	if (frc != NULL)
21284538079SBram Moolenaar 	    while ((frc = ses_skipframe(frc->fr_next)) != NULL)
21384538079SBram Moolenaar 	    {
21484538079SBram Moolenaar 		// Make window as big as possible so that we have lots of room
21584538079SBram Moolenaar 		// to split.
21684538079SBram Moolenaar 		if (put_line(fd, "wincmd _ | wincmd |") == FAIL
21784538079SBram Moolenaar 			|| put_line(fd, fr->fr_layout == FR_COL
21884538079SBram Moolenaar 						? "split" : "vsplit") == FAIL)
21984538079SBram Moolenaar 		    return FAIL;
22084538079SBram Moolenaar 		++count;
22184538079SBram Moolenaar 	    }
22284538079SBram Moolenaar 
22384538079SBram Moolenaar 	// Go back to the first window.
22484538079SBram Moolenaar 	if (count > 0 && (fprintf(fd, fr->fr_layout == FR_COL
22584538079SBram Moolenaar 			? "%dwincmd k" : "%dwincmd h", count) < 0
22684538079SBram Moolenaar 						      || put_eol(fd) == FAIL))
22784538079SBram Moolenaar 	    return FAIL;
22884538079SBram Moolenaar 
22984538079SBram Moolenaar 	// Recursively create frames/windows in each window of this column or
23084538079SBram Moolenaar 	// row.
23184538079SBram Moolenaar 	frc = ses_skipframe(fr->fr_child);
23284538079SBram Moolenaar 	while (frc != NULL)
23384538079SBram Moolenaar 	{
23484538079SBram Moolenaar 	    ses_win_rec(fd, frc);
23584538079SBram Moolenaar 	    frc = ses_skipframe(frc->fr_next);
23684538079SBram Moolenaar 	    // Go to next window.
23784538079SBram Moolenaar 	    if (frc != NULL && put_line(fd, "wincmd w") == FAIL)
23884538079SBram Moolenaar 		return FAIL;
23984538079SBram Moolenaar 	}
24084538079SBram Moolenaar     }
24184538079SBram Moolenaar     return OK;
24284538079SBram Moolenaar }
24384538079SBram Moolenaar 
24484538079SBram Moolenaar     static int
ses_winsizes(FILE * fd,int restore_size,win_T * tab_firstwin)24584538079SBram Moolenaar ses_winsizes(
24684538079SBram Moolenaar     FILE	*fd,
24784538079SBram Moolenaar     int		restore_size,
24884538079SBram Moolenaar     win_T	*tab_firstwin)
24984538079SBram Moolenaar {
25084538079SBram Moolenaar     int		n = 0;
25184538079SBram Moolenaar     win_T	*wp;
25284538079SBram Moolenaar 
25384538079SBram Moolenaar     if (restore_size && (ssop_flags & SSOP_WINSIZE))
25484538079SBram Moolenaar     {
25584538079SBram Moolenaar 	for (wp = tab_firstwin; wp != NULL; wp = wp->w_next)
25684538079SBram Moolenaar 	{
25784538079SBram Moolenaar 	    if (!ses_do_win(wp))
25884538079SBram Moolenaar 		continue;
25984538079SBram Moolenaar 	    ++n;
26084538079SBram Moolenaar 
26184538079SBram Moolenaar 	    // restore height when not full height
26284538079SBram Moolenaar 	    if (wp->w_height + wp->w_status_height < topframe->fr_height
26384538079SBram Moolenaar 		    && (fprintf(fd,
26484538079SBram Moolenaar 			  "exe '%dresize ' . ((&lines * %ld + %ld) / %ld)",
26584538079SBram Moolenaar 			    n, (long)wp->w_height, Rows / 2, Rows) < 0
26684538079SBram Moolenaar 						  || put_eol(fd) == FAIL))
26784538079SBram Moolenaar 		return FAIL;
26884538079SBram Moolenaar 
26984538079SBram Moolenaar 	    // restore width when not full width
27084538079SBram Moolenaar 	    if (wp->w_width < Columns && (fprintf(fd,
27184538079SBram Moolenaar 		   "exe 'vert %dresize ' . ((&columns * %ld + %ld) / %ld)",
27284538079SBram Moolenaar 			    n, (long)wp->w_width, Columns / 2, Columns) < 0
27384538079SBram Moolenaar 						  || put_eol(fd) == FAIL))
27484538079SBram Moolenaar 		return FAIL;
27584538079SBram Moolenaar 	}
27684538079SBram Moolenaar     }
27784538079SBram Moolenaar     else
27884538079SBram Moolenaar     {
27984538079SBram Moolenaar 	// Just equalise window sizes
28084538079SBram Moolenaar 	if (put_line(fd, "wincmd =") == FAIL)
28184538079SBram Moolenaar 	    return FAIL;
28284538079SBram Moolenaar     }
28384538079SBram Moolenaar     return OK;
28484538079SBram Moolenaar }
28584538079SBram Moolenaar 
28684538079SBram Moolenaar     static int
put_view_curpos(FILE * fd,win_T * wp,char * spaces)28784538079SBram Moolenaar put_view_curpos(FILE *fd, win_T *wp, char *spaces)
28884538079SBram Moolenaar {
28984538079SBram Moolenaar     int r;
29084538079SBram Moolenaar 
29184538079SBram Moolenaar     if (wp->w_curswant == MAXCOL)
29284538079SBram Moolenaar 	r = fprintf(fd, "%snormal! $", spaces);
29384538079SBram Moolenaar     else
29484538079SBram Moolenaar 	r = fprintf(fd, "%snormal! 0%d|", spaces, wp->w_virtcol + 1);
29584538079SBram Moolenaar     return r < 0 || put_eol(fd) == FAIL ? FALSE : OK;
29684538079SBram Moolenaar }
29784538079SBram Moolenaar 
29884538079SBram Moolenaar /*
29984538079SBram Moolenaar  * Write commands to "fd" to restore the view of a window.
30084538079SBram Moolenaar  * Caller must make sure 'scrolloff' is zero.
30184538079SBram Moolenaar  */
30284538079SBram Moolenaar     static int
put_view(FILE * fd,win_T * wp,int add_edit,unsigned * flagp,int current_arg_idx,hashtab_T * terminal_bufs UNUSED)30384538079SBram Moolenaar put_view(
30484538079SBram Moolenaar     FILE	*fd,
30584538079SBram Moolenaar     win_T	*wp,
30684538079SBram Moolenaar     int		add_edit,	     // add ":edit" command to view
30784538079SBram Moolenaar     unsigned	*flagp,		     // vop_flags or ssop_flags
308c2c82056SBram Moolenaar     int		current_arg_idx,     // current argument index of the window,
309c2c82056SBram Moolenaar 				     // use -1 if unknown
310c2c82056SBram Moolenaar     hashtab_T *terminal_bufs UNUSED) // already encountered terminal buffers,
311c2c82056SBram Moolenaar 				     // can be NULL
31284538079SBram Moolenaar {
31384538079SBram Moolenaar     win_T	*save_curwin;
31484538079SBram Moolenaar     int		f;
31584538079SBram Moolenaar     int		do_cursor;
31684538079SBram Moolenaar     int		did_next = FALSE;
31784538079SBram Moolenaar 
31884538079SBram Moolenaar     // Always restore cursor position for ":mksession".  For ":mkview" only
31984538079SBram Moolenaar     // when 'viewoptions' contains "cursor".
32084538079SBram Moolenaar     do_cursor = (flagp == &ssop_flags || *flagp & SSOP_CURSOR);
32184538079SBram Moolenaar 
32284538079SBram Moolenaar     // Local argument list.
32384538079SBram Moolenaar     if (wp->w_alist == &global_alist)
32484538079SBram Moolenaar     {
32584538079SBram Moolenaar 	if (put_line(fd, "argglobal") == FAIL)
32684538079SBram Moolenaar 	    return FAIL;
32784538079SBram Moolenaar     }
32884538079SBram Moolenaar     else
32984538079SBram Moolenaar     {
33084538079SBram Moolenaar 	if (ses_arglist(fd, "arglocal", &wp->w_alist->al_ga,
33184538079SBram Moolenaar 			flagp == &vop_flags
33284538079SBram Moolenaar 			|| !(*flagp & SSOP_CURDIR)
33384538079SBram Moolenaar 			|| wp->w_localdir != NULL, flagp) == FAIL)
33484538079SBram Moolenaar 	    return FAIL;
33584538079SBram Moolenaar     }
33684538079SBram Moolenaar 
33784538079SBram Moolenaar     // Only when part of a session: restore the argument index.  Some
33884538079SBram Moolenaar     // arguments may have been deleted, check if the index is valid.
33984538079SBram Moolenaar     if (wp->w_arg_idx != current_arg_idx && wp->w_arg_idx < WARGCOUNT(wp)
34084538079SBram Moolenaar 						      && flagp == &ssop_flags)
34184538079SBram Moolenaar     {
34284538079SBram Moolenaar 	if (fprintf(fd, "%ldargu", (long)wp->w_arg_idx + 1) < 0
34384538079SBram Moolenaar 		|| put_eol(fd) == FAIL)
34484538079SBram Moolenaar 	    return FAIL;
34584538079SBram Moolenaar 	did_next = TRUE;
34684538079SBram Moolenaar     }
34784538079SBram Moolenaar 
34884538079SBram Moolenaar     // Edit the file.  Skip this when ":next" already did it.
34984538079SBram Moolenaar     if (add_edit && (!did_next || wp->w_arg_idx_invalid))
35084538079SBram Moolenaar     {
35184538079SBram Moolenaar # ifdef FEAT_TERMINAL
35284538079SBram Moolenaar 	if (bt_terminal(wp->w_buffer))
35384538079SBram Moolenaar 	{
3540e655111SBram Moolenaar 	    if (term_write_session(fd, wp, terminal_bufs) == FAIL)
35584538079SBram Moolenaar 		return FAIL;
35684538079SBram Moolenaar 	}
35784538079SBram Moolenaar 	else
35884538079SBram Moolenaar # endif
35984538079SBram Moolenaar 	// Load the file.
36084538079SBram Moolenaar 	if (wp->w_buffer->b_ffname != NULL
36184538079SBram Moolenaar # ifdef FEAT_QUICKFIX
36284538079SBram Moolenaar 		&& !bt_nofilename(wp->w_buffer)
36384538079SBram Moolenaar # endif
36484538079SBram Moolenaar 		)
36584538079SBram Moolenaar 	{
36684538079SBram Moolenaar 	    // Editing a file in this buffer: use ":edit file".
36784538079SBram Moolenaar 	    // This may have side effects! (e.g., compressed or network file).
36884538079SBram Moolenaar 	    //
36984538079SBram Moolenaar 	    // Note, if a buffer for that file already exists, use :badd to
37084538079SBram Moolenaar 	    // edit that buffer, to not lose folding information (:edit resets
37184538079SBram Moolenaar 	    // folds in other buffers)
37284538079SBram Moolenaar 	    if (fputs("if bufexists(\"", fd) < 0
37384538079SBram Moolenaar 		    || ses_fname(fd, wp->w_buffer, flagp, FALSE) == FAIL
37484538079SBram Moolenaar 		    || fputs("\") | buffer ", fd) < 0
37584538079SBram Moolenaar 		    || ses_fname(fd, wp->w_buffer, flagp, FALSE) == FAIL
37684538079SBram Moolenaar 		    || fputs(" | else | edit ", fd) < 0
37784538079SBram Moolenaar 		    || ses_fname(fd, wp->w_buffer, flagp, FALSE) == FAIL
37884538079SBram Moolenaar 		    || fputs(" | endif", fd) < 0
37984538079SBram Moolenaar 		    || put_eol(fd) == FAIL)
38084538079SBram Moolenaar 		return FAIL;
38184538079SBram Moolenaar 	}
38284538079SBram Moolenaar 	else
38384538079SBram Moolenaar 	{
38484538079SBram Moolenaar 	    // No file in this buffer, just make it empty.
38584538079SBram Moolenaar 	    if (put_line(fd, "enew") == FAIL)
38684538079SBram Moolenaar 		return FAIL;
38784538079SBram Moolenaar #ifdef FEAT_QUICKFIX
38884538079SBram Moolenaar 	    if (wp->w_buffer->b_ffname != NULL)
38984538079SBram Moolenaar 	    {
39084538079SBram Moolenaar 		// The buffer does have a name, but it's not a file name.
39184538079SBram Moolenaar 		if (fputs("file ", fd) < 0
39284538079SBram Moolenaar 			|| ses_fname(fd, wp->w_buffer, flagp, TRUE) == FAIL)
39384538079SBram Moolenaar 		    return FAIL;
39484538079SBram Moolenaar 	    }
39584538079SBram Moolenaar #endif
39684538079SBram Moolenaar 	    do_cursor = FALSE;
39784538079SBram Moolenaar 	}
39884538079SBram Moolenaar     }
39984538079SBram Moolenaar 
40059d8e56eSBram Moolenaar     if (wp->w_alt_fnum)
40159d8e56eSBram Moolenaar     {
40259d8e56eSBram Moolenaar 	buf_T *alt = buflist_findnr(wp->w_alt_fnum);
40359d8e56eSBram Moolenaar 
4040756f757SBram Moolenaar 	// Set the alternate file if the buffer is listed.
405139348f3SBram Moolenaar 	if ((flagp == &ssop_flags)
406139348f3SBram Moolenaar 		&& alt != NULL
40759d8e56eSBram Moolenaar 		&& alt->b_fname != NULL
40859d8e56eSBram Moolenaar 		&& *alt->b_fname != NUL
4090756f757SBram Moolenaar 		&& alt->b_p_bl
41059d8e56eSBram Moolenaar 		&& (fputs("balt ", fd) < 0
41159d8e56eSBram Moolenaar 		|| ses_fname(fd, alt, flagp, TRUE) == FAIL))
41259d8e56eSBram Moolenaar 	    return FAIL;
41359d8e56eSBram Moolenaar     }
41459d8e56eSBram Moolenaar 
41584538079SBram Moolenaar     // Local mappings and abbreviations.
41684538079SBram Moolenaar     if ((*flagp & (SSOP_OPTIONS | SSOP_LOCALOPTIONS))
41784538079SBram Moolenaar 					 && makemap(fd, wp->w_buffer) == FAIL)
41884538079SBram Moolenaar 	return FAIL;
41984538079SBram Moolenaar 
42084538079SBram Moolenaar     // Local options.  Need to go to the window temporarily.
42184538079SBram Moolenaar     // Store only local values when using ":mkview" and when ":mksession" is
42284538079SBram Moolenaar     // used and 'sessionoptions' doesn't include "options".
42384538079SBram Moolenaar     // Some folding options are always stored when "folds" is included,
42484538079SBram Moolenaar     // otherwise the folds would not be restored correctly.
42584538079SBram Moolenaar     save_curwin = curwin;
42684538079SBram Moolenaar     curwin = wp;
42784538079SBram Moolenaar     curbuf = curwin->w_buffer;
42884538079SBram Moolenaar     if (*flagp & (SSOP_OPTIONS | SSOP_LOCALOPTIONS))
42984538079SBram Moolenaar 	f = makeset(fd, OPT_LOCAL,
43084538079SBram Moolenaar 			     flagp == &vop_flags || !(*flagp & SSOP_OPTIONS));
43184538079SBram Moolenaar #ifdef FEAT_FOLDING
43284538079SBram Moolenaar     else if (*flagp & SSOP_FOLDS)
43384538079SBram Moolenaar 	f = makefoldset(fd);
43484538079SBram Moolenaar #endif
43584538079SBram Moolenaar     else
43684538079SBram Moolenaar 	f = OK;
43784538079SBram Moolenaar     curwin = save_curwin;
43884538079SBram Moolenaar     curbuf = curwin->w_buffer;
43984538079SBram Moolenaar     if (f == FAIL)
44084538079SBram Moolenaar 	return FAIL;
44184538079SBram Moolenaar 
44284538079SBram Moolenaar #ifdef FEAT_FOLDING
44384538079SBram Moolenaar     // Save Folds when 'buftype' is empty and for help files.
44484538079SBram Moolenaar     if ((*flagp & SSOP_FOLDS)
44584538079SBram Moolenaar 	    && wp->w_buffer->b_ffname != NULL
44684538079SBram Moolenaar 	    && (bt_normal(wp->w_buffer) || bt_help(wp->w_buffer)))
44784538079SBram Moolenaar     {
44884538079SBram Moolenaar 	if (put_folds(fd, wp) == FAIL)
44984538079SBram Moolenaar 	    return FAIL;
45084538079SBram Moolenaar     }
45184538079SBram Moolenaar #endif
45284538079SBram Moolenaar 
45384538079SBram Moolenaar     // Set the cursor after creating folds, since that moves the cursor.
45484538079SBram Moolenaar     if (do_cursor)
45584538079SBram Moolenaar     {
45684538079SBram Moolenaar 
45784538079SBram Moolenaar 	// Restore the cursor line in the file and relatively in the
45884538079SBram Moolenaar 	// window.  Don't use "G", it changes the jumplist.
459b6c2e9a0SBram Moolenaar 	if (wp->w_height <= 0)
460b6c2e9a0SBram Moolenaar 	{
461b6c2e9a0SBram Moolenaar 	    if (fprintf(fd, "let s:l = %ld", (long)wp->w_cursor.lnum) < 0)
462b6c2e9a0SBram Moolenaar 		return FAIL;
463b6c2e9a0SBram Moolenaar 	}
464b6c2e9a0SBram Moolenaar 	else if (fprintf(fd,
465b6c2e9a0SBram Moolenaar 		    "let s:l = %ld - ((%ld * winheight(0) + %ld) / %ld)",
46684538079SBram Moolenaar 		    (long)wp->w_cursor.lnum,
46784538079SBram Moolenaar 		    (long)(wp->w_cursor.lnum - wp->w_topline),
468b6c2e9a0SBram Moolenaar 		    (long)wp->w_height / 2, (long)wp->w_height) < 0)
469b6c2e9a0SBram Moolenaar 	    return FAIL;
470b6c2e9a0SBram Moolenaar 
471b6c2e9a0SBram Moolenaar 	if (put_eol(fd) == FAIL
47284538079SBram Moolenaar 		|| put_line(fd, "if s:l < 1 | let s:l = 1 | endif") == FAIL
4733482be6aSBram Moolenaar 		|| put_line(fd, "keepjumps exe s:l") == FAIL
47484538079SBram Moolenaar 		|| put_line(fd, "normal! zt") == FAIL
4753482be6aSBram Moolenaar 		|| fprintf(fd, "keepjumps %ld", (long)wp->w_cursor.lnum) < 0
47684538079SBram Moolenaar 		|| put_eol(fd) == FAIL)
47784538079SBram Moolenaar 	    return FAIL;
47884538079SBram Moolenaar 	// Restore the cursor column and left offset when not wrapping.
47984538079SBram Moolenaar 	if (wp->w_cursor.col == 0)
48084538079SBram Moolenaar 	{
48184538079SBram Moolenaar 	    if (put_line(fd, "normal! 0") == FAIL)
48284538079SBram Moolenaar 		return FAIL;
48384538079SBram Moolenaar 	}
48484538079SBram Moolenaar 	else
48584538079SBram Moolenaar 	{
48684538079SBram Moolenaar 	    if (!wp->w_p_wrap && wp->w_leftcol > 0 && wp->w_width > 0)
48784538079SBram Moolenaar 	    {
48884538079SBram Moolenaar 		if (fprintf(fd,
48984538079SBram Moolenaar 			  "let s:c = %ld - ((%ld * winwidth(0) + %ld) / %ld)",
49084538079SBram Moolenaar 			    (long)wp->w_virtcol + 1,
49184538079SBram Moolenaar 			    (long)(wp->w_virtcol - wp->w_leftcol),
49284538079SBram Moolenaar 			    (long)wp->w_width / 2, (long)wp->w_width) < 0
49384538079SBram Moolenaar 			|| put_eol(fd) == FAIL
49484538079SBram Moolenaar 			|| put_line(fd, "if s:c > 0") == FAIL
49584538079SBram Moolenaar 			|| fprintf(fd,
49684538079SBram Moolenaar 			    "  exe 'normal! ' . s:c . '|zs' . %ld . '|'",
49784538079SBram Moolenaar 			    (long)wp->w_virtcol + 1) < 0
49884538079SBram Moolenaar 			|| put_eol(fd) == FAIL
49984538079SBram Moolenaar 			|| put_line(fd, "else") == FAIL
50084538079SBram Moolenaar 			|| put_view_curpos(fd, wp, "  ") == FAIL
50184538079SBram Moolenaar 			|| put_line(fd, "endif") == FAIL)
50284538079SBram Moolenaar 		    return FAIL;
50384538079SBram Moolenaar 	    }
50484538079SBram Moolenaar 	    else if (put_view_curpos(fd, wp, "") == FAIL)
50584538079SBram Moolenaar 		return FAIL;
50684538079SBram Moolenaar 	}
50784538079SBram Moolenaar     }
50884538079SBram Moolenaar 
50984538079SBram Moolenaar     // Local directory, if the current flag is not view options or the "curdir"
51084538079SBram Moolenaar     // option is included.
51184538079SBram Moolenaar     if (wp->w_localdir != NULL
51284538079SBram Moolenaar 			    && (flagp != &vop_flags || (*flagp & SSOP_CURDIR)))
51384538079SBram Moolenaar     {
51484538079SBram Moolenaar 	if (fputs("lcd ", fd) < 0
51584538079SBram Moolenaar 		|| ses_put_fname(fd, wp->w_localdir, flagp) == FAIL
51684538079SBram Moolenaar 		|| put_eol(fd) == FAIL)
51784538079SBram Moolenaar 	    return FAIL;
51884538079SBram Moolenaar 	did_lcd = TRUE;
51984538079SBram Moolenaar     }
52084538079SBram Moolenaar 
52184538079SBram Moolenaar     return OK;
52284538079SBram Moolenaar }
52384538079SBram Moolenaar 
52484538079SBram Moolenaar #ifdef FEAT_EVAL
52584538079SBram Moolenaar     static int
store_session_globals(FILE * fd)52684538079SBram Moolenaar store_session_globals(FILE *fd)
52784538079SBram Moolenaar {
528da6c0334SBram Moolenaar     hashtab_T	*gvht = get_globvar_ht();
52984538079SBram Moolenaar     hashitem_T	*hi;
53084538079SBram Moolenaar     dictitem_T	*this_var;
53184538079SBram Moolenaar     int		todo;
53284538079SBram Moolenaar     char_u	*p, *t;
53384538079SBram Moolenaar 
534da6c0334SBram Moolenaar     todo = (int)gvht->ht_used;
535da6c0334SBram Moolenaar     for (hi = gvht->ht_array; todo > 0; ++hi)
53684538079SBram Moolenaar     {
53784538079SBram Moolenaar 	if (!HASHITEM_EMPTY(hi))
53884538079SBram Moolenaar 	{
53984538079SBram Moolenaar 	    --todo;
54084538079SBram Moolenaar 	    this_var = HI2DI(hi);
54184538079SBram Moolenaar 	    if ((this_var->di_tv.v_type == VAR_NUMBER
54284538079SBram Moolenaar 			|| this_var->di_tv.v_type == VAR_STRING)
54384538079SBram Moolenaar 		    && var_flavour(this_var->di_key) == VAR_FLAVOUR_SESSION)
54484538079SBram Moolenaar 	    {
54584538079SBram Moolenaar 		// Escape special characters with a backslash.  Turn a LF and
54684538079SBram Moolenaar 		// CR into \n and \r.
54784538079SBram Moolenaar 		p = vim_strsave_escaped(tv_get_string(&this_var->di_tv),
54884538079SBram Moolenaar 							(char_u *)"\\\"\n\r");
54984538079SBram Moolenaar 		if (p == NULL)	    // out of memory
55084538079SBram Moolenaar 		    break;
55184538079SBram Moolenaar 		for (t = p; *t != NUL; ++t)
55284538079SBram Moolenaar 		    if (*t == '\n')
55384538079SBram Moolenaar 			*t = 'n';
55484538079SBram Moolenaar 		    else if (*t == '\r')
55584538079SBram Moolenaar 			*t = 'r';
55684538079SBram Moolenaar 		if ((fprintf(fd, "let %s = %c%s%c",
55784538079SBram Moolenaar 				this_var->di_key,
55884538079SBram Moolenaar 				(this_var->di_tv.v_type == VAR_STRING) ? '"'
55984538079SBram Moolenaar 									: ' ',
56084538079SBram Moolenaar 				p,
56184538079SBram Moolenaar 				(this_var->di_tv.v_type == VAR_STRING) ? '"'
56284538079SBram Moolenaar 								   : ' ') < 0)
56384538079SBram Moolenaar 			|| put_eol(fd) == FAIL)
56484538079SBram Moolenaar 		{
56584538079SBram Moolenaar 		    vim_free(p);
56684538079SBram Moolenaar 		    return FAIL;
56784538079SBram Moolenaar 		}
56884538079SBram Moolenaar 		vim_free(p);
56984538079SBram Moolenaar 	    }
57084538079SBram Moolenaar #ifdef FEAT_FLOAT
57184538079SBram Moolenaar 	    else if (this_var->di_tv.v_type == VAR_FLOAT
57284538079SBram Moolenaar 		    && var_flavour(this_var->di_key) == VAR_FLAVOUR_SESSION)
57384538079SBram Moolenaar 	    {
57484538079SBram Moolenaar 		float_T f = this_var->di_tv.vval.v_float;
57584538079SBram Moolenaar 		int sign = ' ';
57684538079SBram Moolenaar 
57784538079SBram Moolenaar 		if (f < 0)
57884538079SBram Moolenaar 		{
57984538079SBram Moolenaar 		    f = -f;
58084538079SBram Moolenaar 		    sign = '-';
58184538079SBram Moolenaar 		}
58284538079SBram Moolenaar 		if ((fprintf(fd, "let %s = %c%f",
58384538079SBram Moolenaar 					       this_var->di_key, sign, f) < 0)
58484538079SBram Moolenaar 			|| put_eol(fd) == FAIL)
58584538079SBram Moolenaar 		    return FAIL;
58684538079SBram Moolenaar 	    }
58784538079SBram Moolenaar #endif
58884538079SBram Moolenaar 	}
58984538079SBram Moolenaar     }
59084538079SBram Moolenaar     return OK;
59184538079SBram Moolenaar }
59284538079SBram Moolenaar #endif
59384538079SBram Moolenaar 
59484538079SBram Moolenaar /*
59584538079SBram Moolenaar  * Write openfile commands for the current buffers to an .exrc file.
59684538079SBram Moolenaar  * Return FAIL on error, OK otherwise.
59784538079SBram Moolenaar  */
59884538079SBram Moolenaar     static int
makeopens(FILE * fd,char_u * dirnow)59984538079SBram Moolenaar makeopens(
60084538079SBram Moolenaar     FILE	*fd,
60184538079SBram Moolenaar     char_u	*dirnow)	// Current directory name
60284538079SBram Moolenaar {
60384538079SBram Moolenaar     buf_T	*buf;
60484538079SBram Moolenaar     int		only_save_windows = TRUE;
60584538079SBram Moolenaar     int		nr;
60684538079SBram Moolenaar     int		restore_size = TRUE;
60784538079SBram Moolenaar     win_T	*wp;
60884538079SBram Moolenaar     char_u	*sname;
60984538079SBram Moolenaar     win_T	*edited_win = NULL;
61084538079SBram Moolenaar     int		tabnr;
61184538079SBram Moolenaar     int		restore_stal = FALSE;
61284538079SBram Moolenaar     win_T	*tab_firstwin;
61384538079SBram Moolenaar     frame_T	*tab_topframe;
61484538079SBram Moolenaar     int		cur_arg_idx = 0;
61584538079SBram Moolenaar     int		next_arg_idx = 0;
6160e655111SBram Moolenaar     int		ret = FAIL;
6170e655111SBram Moolenaar #ifdef FEAT_TERMINAL
6180e655111SBram Moolenaar     hashtab_T	terminal_bufs;
6190e655111SBram Moolenaar 
6200e655111SBram Moolenaar     hash_init(&terminal_bufs);
6210e655111SBram Moolenaar #endif
62284538079SBram Moolenaar 
62384538079SBram Moolenaar     if (ssop_flags & SSOP_BUFFERS)
62484538079SBram Moolenaar 	only_save_windows = FALSE;		// Save ALL buffers
62584538079SBram Moolenaar 
62684538079SBram Moolenaar     // Begin by setting the this_session variable, and then other
62784538079SBram Moolenaar     // sessionable variables.
62884538079SBram Moolenaar #ifdef FEAT_EVAL
62984538079SBram Moolenaar     if (put_line(fd, "let v:this_session=expand(\"<sfile>:p\")") == FAIL)
6300e655111SBram Moolenaar 	goto fail;
63184538079SBram Moolenaar     if (ssop_flags & SSOP_GLOBALS)
63284538079SBram Moolenaar 	if (store_session_globals(fd) == FAIL)
6330e655111SBram Moolenaar 	    goto fail;
63484538079SBram Moolenaar #endif
63584538079SBram Moolenaar 
63684538079SBram Moolenaar     // Close all windows and tabs but one.
63784538079SBram Moolenaar     if (put_line(fd, "silent only") == FAIL)
6380e655111SBram Moolenaar 	goto fail;
63984538079SBram Moolenaar     if ((ssop_flags & SSOP_TABPAGES)
64084538079SBram Moolenaar 	    && put_line(fd, "silent tabonly") == FAIL)
6410e655111SBram Moolenaar 	goto fail;
64284538079SBram Moolenaar 
64384538079SBram Moolenaar     // Now a :cd command to the session directory or the current directory
64484538079SBram Moolenaar     if (ssop_flags & SSOP_SESDIR)
64584538079SBram Moolenaar     {
64684538079SBram Moolenaar 	if (put_line(fd, "exe \"cd \" . escape(expand(\"<sfile>:p:h\"), ' ')")
64784538079SBram Moolenaar 								      == FAIL)
6480e655111SBram Moolenaar 	    goto fail;
64984538079SBram Moolenaar     }
65084538079SBram Moolenaar     else if (ssop_flags & SSOP_CURDIR)
65184538079SBram Moolenaar     {
65284538079SBram Moolenaar 	sname = home_replace_save(NULL, globaldir != NULL ? globaldir : dirnow);
65384538079SBram Moolenaar 	if (sname == NULL
65484538079SBram Moolenaar 		|| fputs("cd ", fd) < 0
65584538079SBram Moolenaar 		|| ses_put_fname(fd, sname, &ssop_flags) == FAIL
65684538079SBram Moolenaar 		|| put_eol(fd) == FAIL)
65784538079SBram Moolenaar 	{
65884538079SBram Moolenaar 	    vim_free(sname);
6590e655111SBram Moolenaar 	    goto fail;
66084538079SBram Moolenaar 	}
66184538079SBram Moolenaar 	vim_free(sname);
66284538079SBram Moolenaar     }
66384538079SBram Moolenaar 
66484538079SBram Moolenaar     // If there is an empty, unnamed buffer we will wipe it out later.
66584538079SBram Moolenaar     // Remember the buffer number.
66684538079SBram Moolenaar     if (put_line(fd, "if expand('%') == '' && !&modified && line('$') <= 1 && getline(1) == ''") == FAIL)
6670e655111SBram Moolenaar 	goto fail;
66884538079SBram Moolenaar     if (put_line(fd, "  let s:wipebuf = bufnr('%')") == FAIL)
6690e655111SBram Moolenaar 	goto fail;
67084538079SBram Moolenaar     if (put_line(fd, "endif") == FAIL)
6710e655111SBram Moolenaar 	goto fail;
67284538079SBram Moolenaar 
67384538079SBram Moolenaar     // Now save the current files, current buffer first.
67484538079SBram Moolenaar     if (put_line(fd, "set shortmess=aoO") == FAIL)
6750e655111SBram Moolenaar 	goto fail;
67684538079SBram Moolenaar 
67784538079SBram Moolenaar     // the global argument list
67884538079SBram Moolenaar     if (ses_arglist(fd, "argglobal", &global_alist.al_ga,
67984538079SBram Moolenaar 			    !(ssop_flags & SSOP_CURDIR), &ssop_flags) == FAIL)
6800e655111SBram Moolenaar 	goto fail;
68184538079SBram Moolenaar 
68284538079SBram Moolenaar     if (ssop_flags & SSOP_RESIZE)
68384538079SBram Moolenaar     {
68484538079SBram Moolenaar 	// Note: after the restore we still check it worked!
68584538079SBram Moolenaar 	if (fprintf(fd, "set lines=%ld columns=%ld" , Rows, Columns) < 0
68684538079SBram Moolenaar 		|| put_eol(fd) == FAIL)
6870e655111SBram Moolenaar 	    goto fail;
68884538079SBram Moolenaar     }
68984538079SBram Moolenaar 
69084538079SBram Moolenaar #ifdef FEAT_GUI
69184538079SBram Moolenaar     if (gui.in_use && (ssop_flags & SSOP_WINPOS))
69284538079SBram Moolenaar     {
69384538079SBram Moolenaar 	int	x, y;
69484538079SBram Moolenaar 
69584538079SBram Moolenaar 	if (gui_mch_get_winpos(&x, &y) == OK)
69684538079SBram Moolenaar 	{
69784538079SBram Moolenaar 	    // Note: after the restore we still check it worked!
69884538079SBram Moolenaar 	    if (fprintf(fd, "winpos %d %d", x, y) < 0 || put_eol(fd) == FAIL)
6990e655111SBram Moolenaar 		goto fail;
70084538079SBram Moolenaar 	}
70184538079SBram Moolenaar     }
70284538079SBram Moolenaar #endif
70384538079SBram Moolenaar 
70484538079SBram Moolenaar     // When there are two or more tabpages and 'showtabline' is 1 the tabline
70584538079SBram Moolenaar     // will be displayed when creating the next tab.  That resizes the windows
70684538079SBram Moolenaar     // in the first tab, which may cause problems.  Set 'showtabline' to 2
70784538079SBram Moolenaar     // temporarily to avoid that.
70884538079SBram Moolenaar     if (p_stal == 1 && first_tabpage->tp_next != NULL)
70984538079SBram Moolenaar     {
71084538079SBram Moolenaar 	if (put_line(fd, "set stal=2") == FAIL)
7110e655111SBram Moolenaar 	    goto fail;
71284538079SBram Moolenaar 	restore_stal = TRUE;
71384538079SBram Moolenaar     }
71484538079SBram Moolenaar 
71584538079SBram Moolenaar     // May repeat putting Windows for each tab, when "tabpages" is in
71684538079SBram Moolenaar     // 'sessionoptions'.
71784538079SBram Moolenaar     // Don't use goto_tabpage(), it may change directory and trigger
71884538079SBram Moolenaar     // autocommands.
71984538079SBram Moolenaar     tab_firstwin = firstwin;	// first window in tab page "tabnr"
72084538079SBram Moolenaar     tab_topframe = topframe;
72184538079SBram Moolenaar     if ((ssop_flags & SSOP_TABPAGES))
72284538079SBram Moolenaar     {
72384538079SBram Moolenaar 	tabpage_T *tp;
72484538079SBram Moolenaar 
72584538079SBram Moolenaar 	// Similar to ses_win_rec() below, populate the tab pages first so
72684538079SBram Moolenaar 	// later local options won't be copied to the new tabs.
72784538079SBram Moolenaar 	FOR_ALL_TABPAGES(tp)
72884538079SBram Moolenaar 	    if (tp->tp_next != NULL && put_line(fd, "tabnew") == FAIL)
7290e655111SBram Moolenaar 		goto fail;
73084538079SBram Moolenaar 	if (first_tabpage->tp_next != NULL && put_line(fd, "tabrewind") == FAIL)
7310e655111SBram Moolenaar 	    goto fail;
73284538079SBram Moolenaar     }
73384538079SBram Moolenaar     for (tabnr = 1; ; ++tabnr)
73484538079SBram Moolenaar     {
73584538079SBram Moolenaar 	tabpage_T *tp = NULL;
73684538079SBram Moolenaar 	int	need_tabnext = FALSE;
73784538079SBram Moolenaar 	int	cnr = 1;
73884538079SBram Moolenaar 
73984538079SBram Moolenaar 	if ((ssop_flags & SSOP_TABPAGES))
74084538079SBram Moolenaar 	{
74184538079SBram Moolenaar 	    tp = find_tabpage(tabnr);
74284538079SBram Moolenaar 
74384538079SBram Moolenaar 	    if (tp == NULL)
74484538079SBram Moolenaar 		break;		// done all tab pages
74584538079SBram Moolenaar 	    if (tp == curtab)
74684538079SBram Moolenaar 	    {
74784538079SBram Moolenaar 		tab_firstwin = firstwin;
74884538079SBram Moolenaar 		tab_topframe = topframe;
74984538079SBram Moolenaar 	    }
75084538079SBram Moolenaar 	    else
75184538079SBram Moolenaar 	    {
75284538079SBram Moolenaar 		tab_firstwin = tp->tp_firstwin;
75384538079SBram Moolenaar 		tab_topframe = tp->tp_topframe;
75484538079SBram Moolenaar 	    }
75584538079SBram Moolenaar 	    if (tabnr > 1)
75684538079SBram Moolenaar 		need_tabnext = TRUE;
75784538079SBram Moolenaar 	}
75884538079SBram Moolenaar 
75984538079SBram Moolenaar 	// Before creating the window layout, try loading one file.  If this
76084538079SBram Moolenaar 	// is aborted we don't end up with a number of useless windows.
76184538079SBram Moolenaar 	// This may have side effects! (e.g., compressed or network file).
76284538079SBram Moolenaar 	for (wp = tab_firstwin; wp != NULL; wp = wp->w_next)
76384538079SBram Moolenaar 	{
76484538079SBram Moolenaar 	    if (ses_do_win(wp)
76584538079SBram Moolenaar 		    && wp->w_buffer->b_ffname != NULL
76684538079SBram Moolenaar 		    && !bt_help(wp->w_buffer)
76784538079SBram Moolenaar #ifdef FEAT_QUICKFIX
76884538079SBram Moolenaar 		    && !bt_nofilename(wp->w_buffer)
76984538079SBram Moolenaar #endif
77084538079SBram Moolenaar 		    )
77184538079SBram Moolenaar 	    {
77284538079SBram Moolenaar 		if (need_tabnext && put_line(fd, "tabnext") == FAIL)
7730e655111SBram Moolenaar 		    goto fail;
77484538079SBram Moolenaar 		need_tabnext = FALSE;
77584538079SBram Moolenaar 
77684538079SBram Moolenaar 		if (fputs("edit ", fd) < 0
77784538079SBram Moolenaar 			      || ses_fname(fd, wp->w_buffer, &ssop_flags, TRUE)
77884538079SBram Moolenaar 								       == FAIL)
7790e655111SBram Moolenaar 		    goto fail;
78084538079SBram Moolenaar 		if (!wp->w_arg_idx_invalid)
78184538079SBram Moolenaar 		    edited_win = wp;
78284538079SBram Moolenaar 		break;
78384538079SBram Moolenaar 	    }
78484538079SBram Moolenaar 	}
78584538079SBram Moolenaar 
78684538079SBram Moolenaar 	// If no file got edited create an empty tab page.
78784538079SBram Moolenaar 	if (need_tabnext && put_line(fd, "tabnext") == FAIL)
7880e655111SBram Moolenaar 	    goto fail;
78984538079SBram Moolenaar 
7900995c81fSBram Moolenaar 	if (tab_topframe->fr_layout != FR_LEAF)
7910995c81fSBram Moolenaar 	{
79284538079SBram Moolenaar 	    // Save current window layout.
7930995c81fSBram Moolenaar 	    if (put_line(fd, "let s:save_splitbelow = &splitbelow") == FAIL
7940995c81fSBram Moolenaar 		    || put_line(fd, "let s:save_splitright = &splitright")
7950995c81fSBram Moolenaar 								       == FAIL)
7960995c81fSBram Moolenaar 		goto fail;
79784538079SBram Moolenaar 	    if (put_line(fd, "set splitbelow splitright") == FAIL)
7980e655111SBram Moolenaar 		goto fail;
79984538079SBram Moolenaar 	    if (ses_win_rec(fd, tab_topframe) == FAIL)
8000e655111SBram Moolenaar 		goto fail;
8010995c81fSBram Moolenaar 	    if (put_line(fd, "let &splitbelow = s:save_splitbelow") == FAIL
8020995c81fSBram Moolenaar 		    || put_line(fd, "let &splitright = s:save_splitright")
8030995c81fSBram Moolenaar 								       == FAIL)
8040e655111SBram Moolenaar 		goto fail;
8050995c81fSBram Moolenaar 	}
80684538079SBram Moolenaar 
80784538079SBram Moolenaar 	// Check if window sizes can be restored (no windows omitted).
80884538079SBram Moolenaar 	// Remember the window number of the current window after restoring.
80984538079SBram Moolenaar 	nr = 0;
81084538079SBram Moolenaar 	for (wp = tab_firstwin; wp != NULL; wp = W_NEXT(wp))
81184538079SBram Moolenaar 	{
81284538079SBram Moolenaar 	    if (ses_do_win(wp))
81384538079SBram Moolenaar 		++nr;
81484538079SBram Moolenaar 	    else
81584538079SBram Moolenaar 		restore_size = FALSE;
81684538079SBram Moolenaar 	    if (curwin == wp)
81784538079SBram Moolenaar 		cnr = nr;
81884538079SBram Moolenaar 	}
81984538079SBram Moolenaar 
8200995c81fSBram Moolenaar 	if (tab_firstwin->w_next != NULL)
8210995c81fSBram Moolenaar 	{
82284538079SBram Moolenaar 	    // Go to the first window.
82384538079SBram Moolenaar 	    if (put_line(fd, "wincmd t") == FAIL)
8240e655111SBram Moolenaar 		goto fail;
82584538079SBram Moolenaar 
82684538079SBram Moolenaar 	    // If more than one window, see if sizes can be restored.
8270995c81fSBram Moolenaar 	    // First set 'winheight' and 'winwidth' to 1 to avoid the windows
8280995c81fSBram Moolenaar 	    // being resized when moving between windows.
82984538079SBram Moolenaar 	    // Do this before restoring the view, so that the topline and the
83084538079SBram Moolenaar 	    // cursor can be set.  This is done again below.
8310995c81fSBram Moolenaar 	    // winminheight and winminwidth need to be set to avoid an error if
8320995c81fSBram Moolenaar 	    // the user has set winheight or winwidth.
8330995c81fSBram Moolenaar 	    if (put_line(fd, "let s:save_winminheight = &winminheight") == FAIL
8340995c81fSBram Moolenaar 		    || put_line(fd, "let s:save_winminwidth = &winminwidth")
8350995c81fSBram Moolenaar 								       == FAIL)
8360995c81fSBram Moolenaar 		goto fail;
83784538079SBram Moolenaar 	    if (put_line(fd, "set winminheight=0") == FAIL
83884538079SBram Moolenaar 		    || put_line(fd, "set winheight=1") == FAIL
83984538079SBram Moolenaar 		    || put_line(fd, "set winminwidth=0") == FAIL
84084538079SBram Moolenaar 		    || put_line(fd, "set winwidth=1") == FAIL)
8410e655111SBram Moolenaar 		goto fail;
8420995c81fSBram Moolenaar 	}
84384538079SBram Moolenaar 	if (nr > 1 && ses_winsizes(fd, restore_size, tab_firstwin) == FAIL)
8440e655111SBram Moolenaar 	    goto fail;
84584538079SBram Moolenaar 
84684538079SBram Moolenaar 	// Restore the tab-local working directory if specified
84784538079SBram Moolenaar 	// Do this before the windows, so that the window-local directory can
84884538079SBram Moolenaar 	// override the tab-local directory.
84984538079SBram Moolenaar 	if (tp != NULL && tp->tp_localdir != NULL && ssop_flags & SSOP_CURDIR)
85084538079SBram Moolenaar 	{
85184538079SBram Moolenaar 	    if (fputs("tcd ", fd) < 0
85284538079SBram Moolenaar 		    || ses_put_fname(fd, tp->tp_localdir, &ssop_flags) == FAIL
85384538079SBram Moolenaar 		    || put_eol(fd) == FAIL)
8540e655111SBram Moolenaar 		goto fail;
85584538079SBram Moolenaar 	    did_lcd = TRUE;
85684538079SBram Moolenaar 	}
85784538079SBram Moolenaar 
85884538079SBram Moolenaar 	// Restore the view of the window (options, file, cursor, etc.).
85984538079SBram Moolenaar 	for (wp = tab_firstwin; wp != NULL; wp = wp->w_next)
86084538079SBram Moolenaar 	{
86184538079SBram Moolenaar 	    if (!ses_do_win(wp))
86284538079SBram Moolenaar 		continue;
863c2c82056SBram Moolenaar 	    if (put_view(fd, wp, wp != edited_win, &ssop_flags, cur_arg_idx,
8640e655111SBram Moolenaar #ifdef FEAT_TERMINAL
865c2c82056SBram Moolenaar 							 &terminal_bufs
866c2c82056SBram Moolenaar #else
867c2c82056SBram Moolenaar 							 NULL
8680e655111SBram Moolenaar #endif
8690e655111SBram Moolenaar 		 ) == FAIL)
8700e655111SBram Moolenaar 		goto fail;
87184538079SBram Moolenaar 	    if (nr > 1 && put_line(fd, "wincmd w") == FAIL)
8720e655111SBram Moolenaar 		goto fail;
87384538079SBram Moolenaar 	    next_arg_idx = wp->w_arg_idx;
87484538079SBram Moolenaar 	}
87584538079SBram Moolenaar 
87684538079SBram Moolenaar 	// The argument index in the first tab page is zero, need to set it in
87784538079SBram Moolenaar 	// each window.  For further tab pages it's the window where we do
87884538079SBram Moolenaar 	// "tabedit".
87984538079SBram Moolenaar 	cur_arg_idx = next_arg_idx;
88084538079SBram Moolenaar 
88184538079SBram Moolenaar 	// Restore cursor to the current window if it's not the first one.
88284538079SBram Moolenaar 	if (cnr > 1 && (fprintf(fd, "%dwincmd w", cnr) < 0
88384538079SBram Moolenaar 						      || put_eol(fd) == FAIL))
8840e655111SBram Moolenaar 	    goto fail;
88584538079SBram Moolenaar 
88684538079SBram Moolenaar 	// Restore window sizes again after jumping around in windows, because
88784538079SBram Moolenaar 	// the current window has a minimum size while others may not.
88884538079SBram Moolenaar 	if (nr > 1 && ses_winsizes(fd, restore_size, tab_firstwin) == FAIL)
8890e655111SBram Moolenaar 	    goto fail;
89084538079SBram Moolenaar 
89184538079SBram Moolenaar 	// Don't continue in another tab page when doing only the current one
89284538079SBram Moolenaar 	// or when at the last tab page.
89384538079SBram Moolenaar 	if (!(ssop_flags & SSOP_TABPAGES))
89484538079SBram Moolenaar 	    break;
89584538079SBram Moolenaar     }
89684538079SBram Moolenaar 
89784538079SBram Moolenaar     if (ssop_flags & SSOP_TABPAGES)
89884538079SBram Moolenaar     {
89984538079SBram Moolenaar 	if (fprintf(fd, "tabnext %d", tabpage_index(curtab)) < 0
90084538079SBram Moolenaar 		|| put_eol(fd) == FAIL)
9010e655111SBram Moolenaar 	    goto fail;
90284538079SBram Moolenaar     }
90384538079SBram Moolenaar     if (restore_stal && put_line(fd, "set stal=1") == FAIL)
9040e655111SBram Moolenaar 	goto fail;
90584538079SBram Moolenaar 
90684538079SBram Moolenaar     // Now put the remaining buffers into the buffer list.
90784538079SBram Moolenaar     // This is near the end, so that when 'hidden' is set we don't create extra
90884538079SBram Moolenaar     // buffers.  If the buffer was already created with another command the
90984538079SBram Moolenaar     // ":badd" will have no effect.
91084538079SBram Moolenaar     FOR_ALL_BUFFERS(buf)
91184538079SBram Moolenaar     {
91284538079SBram Moolenaar 	if (!(only_save_windows && buf->b_nwindows == 0)
91384538079SBram Moolenaar 		&& !(buf->b_help && !(ssop_flags & SSOP_HELP))
91484538079SBram Moolenaar #ifdef FEAT_TERMINAL
91584538079SBram Moolenaar 		// Skip terminal buffers: finished ones are not useful, others
91684538079SBram Moolenaar 		// will be resurrected and result in a new buffer.
91784538079SBram Moolenaar 		&& !bt_terminal(buf)
91884538079SBram Moolenaar #endif
91984538079SBram Moolenaar 		&& buf->b_fname != NULL
92084538079SBram Moolenaar 		&& buf->b_p_bl)
92184538079SBram Moolenaar 	{
92284538079SBram Moolenaar 	    if (fprintf(fd, "badd +%ld ", buf->b_wininfo == NULL ? 1L
92384538079SBram Moolenaar 					   : buf->b_wininfo->wi_fpos.lnum) < 0
92484538079SBram Moolenaar 		    || ses_fname(fd, buf, &ssop_flags, TRUE) == FAIL)
9250e655111SBram Moolenaar 		goto fail;
92684538079SBram Moolenaar 	}
92784538079SBram Moolenaar     }
92884538079SBram Moolenaar 
92984538079SBram Moolenaar     // Wipe out an empty unnamed buffer we started in.
93084538079SBram Moolenaar     if (put_line(fd, "if exists('s:wipebuf') && len(win_findbuf(s:wipebuf)) == 0")
93184538079SBram Moolenaar 								       == FAIL)
9320e655111SBram Moolenaar 	goto fail;
93384538079SBram Moolenaar     if (put_line(fd, "  silent exe 'bwipe ' . s:wipebuf") == FAIL)
9340e655111SBram Moolenaar 	goto fail;
93584538079SBram Moolenaar     if (put_line(fd, "endif") == FAIL)
9360e655111SBram Moolenaar 	goto fail;
93784538079SBram Moolenaar     if (put_line(fd, "unlet! s:wipebuf") == FAIL)
9380e655111SBram Moolenaar 	goto fail;
93984538079SBram Moolenaar 
94084538079SBram Moolenaar     // Re-apply 'winheight', 'winwidth' and 'shortmess'.
94184538079SBram Moolenaar     if (fprintf(fd, "set winheight=%ld winwidth=%ld shortmess=%s",
94284538079SBram Moolenaar 			       p_wh, p_wiw, p_shm) < 0 || put_eol(fd) == FAIL)
9430e655111SBram Moolenaar 	goto fail;
9440995c81fSBram Moolenaar     if (tab_firstwin->w_next != NULL)
9450995c81fSBram Moolenaar     {
9460995c81fSBram Moolenaar 	// Restore 'winminheight' and 'winminwidth'.
9470995c81fSBram Moolenaar 	if (put_line(fd, "let &winminheight = s:save_winminheight") == FAIL
9480995c81fSBram Moolenaar 	      || put_line(fd, "let &winminwidth = s:save_winminwidth") == FAIL)
9490e655111SBram Moolenaar 	    goto fail;
9500995c81fSBram Moolenaar     }
95184538079SBram Moolenaar 
95284538079SBram Moolenaar     // Lastly, execute the x.vim file if it exists.
95384538079SBram Moolenaar     if (put_line(fd, "let s:sx = expand(\"<sfile>:p:r\").\"x.vim\"") == FAIL
954c5f33db8SBram Moolenaar 	    || put_line(fd, "if filereadable(s:sx)") == FAIL
95584538079SBram Moolenaar 	    || put_line(fd, "  exe \"source \" . fnameescape(s:sx)") == FAIL
95684538079SBram Moolenaar 	    || put_line(fd, "endif") == FAIL)
9570e655111SBram Moolenaar 	goto fail;
95884538079SBram Moolenaar 
9590e655111SBram Moolenaar     ret = OK;
9600e655111SBram Moolenaar fail:
9610e655111SBram Moolenaar #ifdef FEAT_TERMINAL
9620e655111SBram Moolenaar     hash_clear_all(&terminal_bufs, 0);
9630e655111SBram Moolenaar #endif
9640e655111SBram Moolenaar     return ret;
96584538079SBram Moolenaar }
96684538079SBram Moolenaar 
96784538079SBram Moolenaar /*
96884538079SBram Moolenaar  * Get the name of the view file for the current buffer.
96984538079SBram Moolenaar  */
97084538079SBram Moolenaar     static char_u *
get_view_file(int c)97184538079SBram Moolenaar get_view_file(int c)
97284538079SBram Moolenaar {
97384538079SBram Moolenaar     int		len = 0;
97484538079SBram Moolenaar     char_u	*p, *s;
97584538079SBram Moolenaar     char_u	*retval;
97684538079SBram Moolenaar     char_u	*sname;
97784538079SBram Moolenaar 
97884538079SBram Moolenaar     if (curbuf->b_ffname == NULL)
97984538079SBram Moolenaar     {
980e29a27f6SBram Moolenaar 	emsg(_(e_no_file_name));
98184538079SBram Moolenaar 	return NULL;
98284538079SBram Moolenaar     }
98384538079SBram Moolenaar     sname = home_replace_save(NULL, curbuf->b_ffname);
98484538079SBram Moolenaar     if (sname == NULL)
98584538079SBram Moolenaar 	return NULL;
98684538079SBram Moolenaar 
98784538079SBram Moolenaar     // We want a file name without separators, because we're not going to make
98884538079SBram Moolenaar     // a directory.
98984538079SBram Moolenaar     // "normal" path separator	-> "=+"
99084538079SBram Moolenaar     // "="			-> "=="
99184538079SBram Moolenaar     // ":" path separator	-> "=-"
99284538079SBram Moolenaar     for (p = sname; *p; ++p)
99384538079SBram Moolenaar 	if (*p == '=' || vim_ispathsep(*p))
99484538079SBram Moolenaar 	    ++len;
99584538079SBram Moolenaar     retval = alloc(STRLEN(sname) + len + STRLEN(p_vdir) + 9);
99684538079SBram Moolenaar     if (retval != NULL)
99784538079SBram Moolenaar     {
99884538079SBram Moolenaar 	STRCPY(retval, p_vdir);
99984538079SBram Moolenaar 	add_pathsep(retval);
100084538079SBram Moolenaar 	s = retval + STRLEN(retval);
100184538079SBram Moolenaar 	for (p = sname; *p; ++p)
100284538079SBram Moolenaar 	{
100384538079SBram Moolenaar 	    if (*p == '=')
100484538079SBram Moolenaar 	    {
100584538079SBram Moolenaar 		*s++ = '=';
100684538079SBram Moolenaar 		*s++ = '=';
100784538079SBram Moolenaar 	    }
100884538079SBram Moolenaar 	    else if (vim_ispathsep(*p))
100984538079SBram Moolenaar 	    {
101084538079SBram Moolenaar 		*s++ = '=';
101184538079SBram Moolenaar #if defined(BACKSLASH_IN_FILENAME) || defined(AMIGA) || defined(VMS)
101284538079SBram Moolenaar 		if (*p == ':')
101384538079SBram Moolenaar 		    *s++ = '-';
101484538079SBram Moolenaar 		else
101584538079SBram Moolenaar #endif
101684538079SBram Moolenaar 		    *s++ = '+';
101784538079SBram Moolenaar 	    }
101884538079SBram Moolenaar 	    else
101984538079SBram Moolenaar 		*s++ = *p;
102084538079SBram Moolenaar 	}
102184538079SBram Moolenaar 	*s++ = '=';
102284538079SBram Moolenaar 	*s++ = c;
102384538079SBram Moolenaar 	STRCPY(s, ".vim");
102484538079SBram Moolenaar     }
102584538079SBram Moolenaar 
102684538079SBram Moolenaar     vim_free(sname);
102784538079SBram Moolenaar     return retval;
102884538079SBram Moolenaar }
102984538079SBram Moolenaar 
103084538079SBram Moolenaar /*
103184538079SBram Moolenaar  * ":loadview [nr]"
103284538079SBram Moolenaar  */
103384538079SBram Moolenaar     void
ex_loadview(exarg_T * eap)103484538079SBram Moolenaar ex_loadview(exarg_T *eap)
103584538079SBram Moolenaar {
103684538079SBram Moolenaar     char_u	*fname;
103784538079SBram Moolenaar 
103884538079SBram Moolenaar     fname = get_view_file(*eap->arg);
103984538079SBram Moolenaar     if (fname != NULL)
104084538079SBram Moolenaar     {
10418a7d6542SBram Moolenaar 	do_source(fname, FALSE, DOSO_NONE, NULL);
104284538079SBram Moolenaar 	vim_free(fname);
104384538079SBram Moolenaar     }
104484538079SBram Moolenaar }
104584538079SBram Moolenaar 
1046d17a57a4SBram Moolenaar # if defined(FEAT_GUI_GNOME) \
1047ac02a638SBram Moolenaar 	|| (defined(GUI_MAY_SPAWN) && defined(EXPERIMENTAL_GUI_CMD)) \
1048ac02a638SBram Moolenaar 	|| defined(PROTO)
104984538079SBram Moolenaar /*
105084538079SBram Moolenaar  * Generate a script that can be used to restore the current editing session.
105184538079SBram Moolenaar  * Save the value of v:this_session before running :mksession in order to make
105284538079SBram Moolenaar  * automagic session save fully transparent.  Return TRUE on success.
105384538079SBram Moolenaar  */
105484538079SBram Moolenaar     int
write_session_file(char_u * filename)105584538079SBram Moolenaar write_session_file(char_u *filename)
105684538079SBram Moolenaar {
105784538079SBram Moolenaar     char_u	    *escaped_filename;
105884538079SBram Moolenaar     char	    *mksession_cmdline;
105984538079SBram Moolenaar     unsigned int    save_ssop_flags;
106084538079SBram Moolenaar     int		    failed;
106184538079SBram Moolenaar 
106284538079SBram Moolenaar     // Build an ex command line to create a script that restores the current
106384538079SBram Moolenaar     // session if executed.  Escape the filename to avoid nasty surprises.
106484538079SBram Moolenaar     escaped_filename = vim_strsave_escaped(filename, escape_chars);
106584538079SBram Moolenaar     if (escaped_filename == NULL)
106684538079SBram Moolenaar 	return FALSE;
106784538079SBram Moolenaar     mksession_cmdline = alloc(10 + (int)STRLEN(escaped_filename) + 1);
106884538079SBram Moolenaar     if (mksession_cmdline == NULL)
106984538079SBram Moolenaar     {
107084538079SBram Moolenaar 	vim_free(escaped_filename);
107184538079SBram Moolenaar 	return FALSE;
107284538079SBram Moolenaar     }
107384538079SBram Moolenaar     strcpy(mksession_cmdline, "mksession ");
107484538079SBram Moolenaar     STRCAT(mksession_cmdline, escaped_filename);
107584538079SBram Moolenaar     vim_free(escaped_filename);
107684538079SBram Moolenaar 
107784538079SBram Moolenaar     // Use a reasonable hardcoded set of 'sessionoptions' flags to avoid
107884538079SBram Moolenaar     // unpredictable effects when the session is saved automatically.  Also,
107984538079SBram Moolenaar     // we definitely need SSOP_GLOBALS to be able to restore v:this_session.
108084538079SBram Moolenaar     // Don't use SSOP_BUFFERS to prevent the buffer list from becoming
108184538079SBram Moolenaar     // enormously large if the GNOME session feature is used regularly.
108284538079SBram Moolenaar     save_ssop_flags = ssop_flags;
108384538079SBram Moolenaar     ssop_flags = (SSOP_BLANK|SSOP_CURDIR|SSOP_FOLDS|SSOP_GLOBALS
108484538079SBram Moolenaar 		  |SSOP_HELP|SSOP_OPTIONS|SSOP_WINSIZE|SSOP_TABPAGES);
108584538079SBram Moolenaar 
108684538079SBram Moolenaar     do_cmdline_cmd((char_u *)"let Save_VV_this_session = v:this_session");
108784538079SBram Moolenaar     failed = (do_cmdline_cmd((char_u *)mksession_cmdline) == FAIL);
108884538079SBram Moolenaar     do_cmdline_cmd((char_u *)"let v:this_session = Save_VV_this_session");
108984538079SBram Moolenaar     do_unlet((char_u *)"Save_VV_this_session", TRUE);
109084538079SBram Moolenaar 
109184538079SBram Moolenaar     ssop_flags = save_ssop_flags;
109284538079SBram Moolenaar     vim_free(mksession_cmdline);
109384538079SBram Moolenaar 
109484538079SBram Moolenaar     // Reopen the file and append a command to restore v:this_session,
109584538079SBram Moolenaar     // as if this save never happened.	This is to avoid conflicts with
109684538079SBram Moolenaar     // the user's own sessions.  FIXME: It's probably less hackish to add
109784538079SBram Moolenaar     // a "stealth" flag to 'sessionoptions' -- gotta ask Bram.
109884538079SBram Moolenaar     if (!failed)
109984538079SBram Moolenaar     {
110084538079SBram Moolenaar 	FILE *fd;
110184538079SBram Moolenaar 
110284538079SBram Moolenaar 	fd = open_exfile(filename, TRUE, APPENDBIN);
110384538079SBram Moolenaar 
110484538079SBram Moolenaar 	failed = (fd == NULL
110584538079SBram Moolenaar 	       || put_line(fd, "let v:this_session = Save_VV_this_session")
110684538079SBram Moolenaar 									== FAIL
110784538079SBram Moolenaar 	       || put_line(fd, "unlet Save_VV_this_session") == FAIL);
110884538079SBram Moolenaar 
110984538079SBram Moolenaar 	if (fd != NULL && fclose(fd) != 0)
111084538079SBram Moolenaar 	    failed = TRUE;
111184538079SBram Moolenaar 
111284538079SBram Moolenaar 	if (failed)
111384538079SBram Moolenaar 	    mch_remove(filename);
111484538079SBram Moolenaar     }
111584538079SBram Moolenaar 
111684538079SBram Moolenaar     return !failed;
111784538079SBram Moolenaar }
111884538079SBram Moolenaar # endif
111984538079SBram Moolenaar 
112084538079SBram Moolenaar #endif // FEAT_SESSION
112184538079SBram Moolenaar 
112284538079SBram Moolenaar #if defined(FEAT_SESSION) && defined(USE_CRNL)
112384538079SBram Moolenaar # define MKSESSION_NL
112484538079SBram Moolenaar static int mksession_nl = FALSE;    // use NL only in put_eol()
112584538079SBram Moolenaar #endif
112684538079SBram Moolenaar 
112784538079SBram Moolenaar /*
112884538079SBram Moolenaar  * ":mkexrc", ":mkvimrc", ":mkview" and ":mksession".
112984538079SBram Moolenaar  */
113084538079SBram Moolenaar     void
ex_mkrc(exarg_T * eap)113184538079SBram Moolenaar ex_mkrc(exarg_T	*eap)
113284538079SBram Moolenaar {
113384538079SBram Moolenaar     FILE	*fd;
113484538079SBram Moolenaar     int		failed = FALSE;
113584538079SBram Moolenaar     char_u	*fname;
113684538079SBram Moolenaar #ifdef FEAT_BROWSE
113784538079SBram Moolenaar     char_u	*browseFile = NULL;
113884538079SBram Moolenaar #endif
113984538079SBram Moolenaar #ifdef FEAT_SESSION
114084538079SBram Moolenaar     int		view_session = FALSE;
114184538079SBram Moolenaar     int		using_vdir = FALSE;	// using 'viewdir'?
114284538079SBram Moolenaar     char_u	*viewFile = NULL;
114384538079SBram Moolenaar     unsigned	*flagp;
114484538079SBram Moolenaar #endif
114584538079SBram Moolenaar 
114684538079SBram Moolenaar     if (eap->cmdidx == CMD_mksession || eap->cmdidx == CMD_mkview)
114784538079SBram Moolenaar     {
114884538079SBram Moolenaar #ifdef FEAT_SESSION
114984538079SBram Moolenaar 	view_session = TRUE;
115084538079SBram Moolenaar #else
115184538079SBram Moolenaar 	ex_ni(eap);
115284538079SBram Moolenaar 	return;
115384538079SBram Moolenaar #endif
115484538079SBram Moolenaar     }
115584538079SBram Moolenaar 
115684538079SBram Moolenaar #ifdef FEAT_SESSION
115784538079SBram Moolenaar     // Use the short file name until ":lcd" is used.  We also don't use the
115884538079SBram Moolenaar     // short file name when 'acd' is set, that is checked later.
115984538079SBram Moolenaar     did_lcd = FALSE;
116084538079SBram Moolenaar 
116184538079SBram Moolenaar     // ":mkview" or ":mkview 9": generate file name with 'viewdir'
116284538079SBram Moolenaar     if (eap->cmdidx == CMD_mkview
116384538079SBram Moolenaar 	    && (*eap->arg == NUL
116484538079SBram Moolenaar 		|| (vim_isdigit(*eap->arg) && eap->arg[1] == NUL)))
116584538079SBram Moolenaar     {
116684538079SBram Moolenaar 	eap->forceit = TRUE;
116784538079SBram Moolenaar 	fname = get_view_file(*eap->arg);
116884538079SBram Moolenaar 	if (fname == NULL)
116984538079SBram Moolenaar 	    return;
117084538079SBram Moolenaar 	viewFile = fname;
117184538079SBram Moolenaar 	using_vdir = TRUE;
117284538079SBram Moolenaar     }
117384538079SBram Moolenaar     else
117484538079SBram Moolenaar #endif
117584538079SBram Moolenaar 	if (*eap->arg != NUL)
117684538079SBram Moolenaar 	fname = eap->arg;
117784538079SBram Moolenaar     else if (eap->cmdidx == CMD_mkvimrc)
117884538079SBram Moolenaar 	fname = (char_u *)VIMRC_FILE;
117984538079SBram Moolenaar #ifdef FEAT_SESSION
118084538079SBram Moolenaar     else if (eap->cmdidx == CMD_mksession)
118184538079SBram Moolenaar 	fname = (char_u *)SESSION_FILE;
118284538079SBram Moolenaar #endif
118384538079SBram Moolenaar     else
118484538079SBram Moolenaar 	fname = (char_u *)EXRC_FILE;
118584538079SBram Moolenaar 
118684538079SBram Moolenaar #ifdef FEAT_BROWSE
1187e1004401SBram Moolenaar     if (cmdmod.cmod_flags & CMOD_BROWSE)
118884538079SBram Moolenaar     {
118984538079SBram Moolenaar 	browseFile = do_browse(BROWSE_SAVE,
119084538079SBram Moolenaar # ifdef FEAT_SESSION
119184538079SBram Moolenaar 		eap->cmdidx == CMD_mkview ? (char_u *)_("Save View") :
119284538079SBram Moolenaar 		eap->cmdidx == CMD_mksession ? (char_u *)_("Save Session") :
119384538079SBram Moolenaar # endif
119484538079SBram Moolenaar 		(char_u *)_("Save Setup"),
119584538079SBram Moolenaar 		fname, (char_u *)"vim", NULL,
119684538079SBram Moolenaar 		(char_u *)_(BROWSE_FILTER_MACROS), NULL);
119784538079SBram Moolenaar 	if (browseFile == NULL)
119884538079SBram Moolenaar 	    goto theend;
119984538079SBram Moolenaar 	fname = browseFile;
120084538079SBram Moolenaar 	eap->forceit = TRUE;	// since dialog already asked
120184538079SBram Moolenaar     }
120284538079SBram Moolenaar #endif
120384538079SBram Moolenaar 
120484538079SBram Moolenaar #if defined(FEAT_SESSION) && defined(vim_mkdir)
120584538079SBram Moolenaar     // When using 'viewdir' may have to create the directory.
120684538079SBram Moolenaar     if (using_vdir && !mch_isdir(p_vdir))
120784538079SBram Moolenaar 	vim_mkdir_emsg(p_vdir, 0755);
120884538079SBram Moolenaar #endif
120984538079SBram Moolenaar 
121084538079SBram Moolenaar     fd = open_exfile(fname, eap->forceit, WRITEBIN);
121184538079SBram Moolenaar     if (fd != NULL)
121284538079SBram Moolenaar     {
121384538079SBram Moolenaar #ifdef FEAT_SESSION
121484538079SBram Moolenaar 	if (eap->cmdidx == CMD_mkview)
121584538079SBram Moolenaar 	    flagp = &vop_flags;
121684538079SBram Moolenaar 	else
121784538079SBram Moolenaar 	    flagp = &ssop_flags;
121884538079SBram Moolenaar #endif
121984538079SBram Moolenaar 
122084538079SBram Moolenaar #ifdef MKSESSION_NL
122184538079SBram Moolenaar 	// "unix" in 'sessionoptions': use NL line separator
122284538079SBram Moolenaar 	if (view_session && (*flagp & SSOP_UNIX))
122384538079SBram Moolenaar 	    mksession_nl = TRUE;
122484538079SBram Moolenaar #endif
122584538079SBram Moolenaar 
122684538079SBram Moolenaar 	// Write the version command for :mkvimrc
122784538079SBram Moolenaar 	if (eap->cmdidx == CMD_mkvimrc)
122884538079SBram Moolenaar 	    (void)put_line(fd, "version 6.0");
122984538079SBram Moolenaar 
123084538079SBram Moolenaar #ifdef FEAT_SESSION
123184538079SBram Moolenaar 	if (eap->cmdidx == CMD_mksession)
123284538079SBram Moolenaar 	{
123384538079SBram Moolenaar 	    if (put_line(fd, "let SessionLoad = 1") == FAIL)
123484538079SBram Moolenaar 		failed = TRUE;
123584538079SBram Moolenaar 	}
123684538079SBram Moolenaar 
123784538079SBram Moolenaar 	if (eap->cmdidx != CMD_mkview)
123884538079SBram Moolenaar #endif
123984538079SBram Moolenaar 	{
124084538079SBram Moolenaar 	    // Write setting 'compatible' first, because it has side effects.
124184538079SBram Moolenaar 	    // For that same reason only do it when needed.
124284538079SBram Moolenaar 	    if (p_cp)
124384538079SBram Moolenaar 		(void)put_line(fd, "if !&cp | set cp | endif");
124484538079SBram Moolenaar 	    else
124584538079SBram Moolenaar 		(void)put_line(fd, "if &cp | set nocp | endif");
124684538079SBram Moolenaar 	}
124784538079SBram Moolenaar 
124884538079SBram Moolenaar #ifdef FEAT_SESSION
124984538079SBram Moolenaar 	if (!view_session
125084538079SBram Moolenaar 		|| (eap->cmdidx == CMD_mksession
125184538079SBram Moolenaar 		    && (*flagp & SSOP_OPTIONS)))
125284538079SBram Moolenaar #endif
1253635bd608SBram Moolenaar 	{
1254635bd608SBram Moolenaar 	    int flags = OPT_GLOBAL;
1255635bd608SBram Moolenaar 
1256635bd608SBram Moolenaar #ifdef FEAT_SESSION
1257635bd608SBram Moolenaar 	    if (eap->cmdidx == CMD_mksession && (*flagp & SSOP_SKIP_RTP))
1258635bd608SBram Moolenaar 		flags |= OPT_SKIPRTP;
1259635bd608SBram Moolenaar #endif
126084538079SBram Moolenaar 	    failed |= (makemap(fd, NULL) == FAIL
1261635bd608SBram Moolenaar 					 || makeset(fd, flags, FALSE) == FAIL);
1262635bd608SBram Moolenaar 	}
126384538079SBram Moolenaar 
126484538079SBram Moolenaar #ifdef FEAT_SESSION
126584538079SBram Moolenaar 	if (!failed && view_session)
126684538079SBram Moolenaar 	{
126738890835SBram Moolenaar 	    if (put_line(fd, "let s:so_save = &g:so | let s:siso_save = &g:siso | setg so=0 siso=0 | setl so=-1 siso=-1") == FAIL)
126884538079SBram Moolenaar 		failed = TRUE;
126984538079SBram Moolenaar 	    if (eap->cmdidx == CMD_mksession)
127084538079SBram Moolenaar 	    {
127184538079SBram Moolenaar 		char_u *dirnow;	 // current directory
127284538079SBram Moolenaar 
127384538079SBram Moolenaar 		dirnow = alloc(MAXPATHL);
127484538079SBram Moolenaar 		if (dirnow == NULL)
127584538079SBram Moolenaar 		    failed = TRUE;
127684538079SBram Moolenaar 		else
127784538079SBram Moolenaar 		{
127884538079SBram Moolenaar 		    // Change to session file's dir.
127984538079SBram Moolenaar 		    if (mch_dirname(dirnow, MAXPATHL) == FAIL
128084538079SBram Moolenaar 					    || mch_chdir((char *)dirnow) != 0)
128184538079SBram Moolenaar 			*dirnow = NUL;
128284538079SBram Moolenaar 		    if (*dirnow != NUL && (ssop_flags & SSOP_SESDIR))
128384538079SBram Moolenaar 		    {
128484538079SBram Moolenaar 			if (vim_chdirfile(fname, NULL) == OK)
128584538079SBram Moolenaar 			    shorten_fnames(TRUE);
128684538079SBram Moolenaar 		    }
128784538079SBram Moolenaar 		    else if (*dirnow != NUL
128884538079SBram Moolenaar 			   && (ssop_flags & SSOP_CURDIR) && globaldir != NULL)
128984538079SBram Moolenaar 		    {
129084538079SBram Moolenaar 			if (mch_chdir((char *)globaldir) == 0)
129184538079SBram Moolenaar 			    shorten_fnames(TRUE);
129284538079SBram Moolenaar 		    }
129384538079SBram Moolenaar 
129484538079SBram Moolenaar 		    failed |= (makeopens(fd, dirnow) == FAIL);
129584538079SBram Moolenaar 
129684538079SBram Moolenaar 		    // restore original dir
129784538079SBram Moolenaar 		    if (*dirnow != NUL && ((ssop_flags & SSOP_SESDIR)
129884538079SBram Moolenaar 			|| ((ssop_flags & SSOP_CURDIR) && globaldir != NULL)))
129984538079SBram Moolenaar 		    {
130084538079SBram Moolenaar 			if (mch_chdir((char *)dirnow) != 0)
130184538079SBram Moolenaar 			    emsg(_(e_prev_dir));
130284538079SBram Moolenaar 			shorten_fnames(TRUE);
130384538079SBram Moolenaar 		    }
130484538079SBram Moolenaar 		    vim_free(dirnow);
130584538079SBram Moolenaar 		}
130684538079SBram Moolenaar 	    }
130784538079SBram Moolenaar 	    else
130884538079SBram Moolenaar 	    {
1309c2c82056SBram Moolenaar 		failed |= (put_view(fd, curwin, !using_vdir, flagp, -1, NULL)
1310c2c82056SBram Moolenaar 								      == FAIL);
131184538079SBram Moolenaar 	    }
131238890835SBram Moolenaar 	    if (put_line(fd, "let &g:so = s:so_save | let &g:siso = s:siso_save")
131384538079SBram Moolenaar 								      == FAIL)
131484538079SBram Moolenaar 		failed = TRUE;
131584538079SBram Moolenaar #ifdef FEAT_SEARCH_EXTRA
131684538079SBram Moolenaar 	    if (no_hlsearch && put_line(fd, "nohlsearch") == FAIL)
131784538079SBram Moolenaar 		failed = TRUE;
131884538079SBram Moolenaar #endif
131984538079SBram Moolenaar 	    if (put_line(fd, "doautoall SessionLoadPost") == FAIL)
132084538079SBram Moolenaar 		failed = TRUE;
132184538079SBram Moolenaar 	    if (eap->cmdidx == CMD_mksession)
132284538079SBram Moolenaar 	    {
132384538079SBram Moolenaar 		if (put_line(fd, "unlet SessionLoad") == FAIL)
132484538079SBram Moolenaar 		    failed = TRUE;
132584538079SBram Moolenaar 	    }
132684538079SBram Moolenaar 	}
132784538079SBram Moolenaar #endif
132884538079SBram Moolenaar 	if (put_line(fd, "\" vim: set ft=vim :") == FAIL)
132984538079SBram Moolenaar 	    failed = TRUE;
133084538079SBram Moolenaar 
133184538079SBram Moolenaar 	failed |= fclose(fd);
133284538079SBram Moolenaar 
133384538079SBram Moolenaar 	if (failed)
133484538079SBram Moolenaar 	    emsg(_(e_write));
1335f96ae0b5SBram Moolenaar #if defined(FEAT_SESSION)
133684538079SBram Moolenaar 	else if (eap->cmdidx == CMD_mksession)
133784538079SBram Moolenaar 	{
133884538079SBram Moolenaar 	    // successful session write - set this_session var
133984538079SBram Moolenaar 	    char_u	*tbuf;
134084538079SBram Moolenaar 
134184538079SBram Moolenaar 	    tbuf = alloc(MAXPATHL);
134284538079SBram Moolenaar 	    if (tbuf != NULL)
134384538079SBram Moolenaar 	    {
134484538079SBram Moolenaar 		if (vim_FullName(fname, tbuf, MAXPATHL, FALSE) == OK)
134584538079SBram Moolenaar 		    set_vim_var_string(VV_THIS_SESSION, tbuf, -1);
134684538079SBram Moolenaar 		vim_free(tbuf);
134784538079SBram Moolenaar 	    }
134884538079SBram Moolenaar 	}
134984538079SBram Moolenaar #endif
135084538079SBram Moolenaar #ifdef MKSESSION_NL
135184538079SBram Moolenaar 	mksession_nl = FALSE;
135284538079SBram Moolenaar #endif
135384538079SBram Moolenaar     }
135484538079SBram Moolenaar 
135584538079SBram Moolenaar #ifdef FEAT_BROWSE
135684538079SBram Moolenaar theend:
135784538079SBram Moolenaar     vim_free(browseFile);
135884538079SBram Moolenaar #endif
135984538079SBram Moolenaar #ifdef FEAT_SESSION
136084538079SBram Moolenaar     vim_free(viewFile);
136184538079SBram Moolenaar #endif
136284538079SBram Moolenaar }
136384538079SBram Moolenaar 
1364f96ae0b5SBram Moolenaar #if (defined(FEAT_VIMINFO) || defined(FEAT_SESSION)) || defined(PROTO)
136584538079SBram Moolenaar     var_flavour_T
var_flavour(char_u * varname)136684538079SBram Moolenaar var_flavour(char_u *varname)
136784538079SBram Moolenaar {
136884538079SBram Moolenaar     char_u *p = varname;
136984538079SBram Moolenaar 
137084538079SBram Moolenaar     if (ASCII_ISUPPER(*p))
137184538079SBram Moolenaar     {
137284538079SBram Moolenaar 	while (*(++p))
137384538079SBram Moolenaar 	    if (ASCII_ISLOWER(*p))
137484538079SBram Moolenaar 		return VAR_FLAVOUR_SESSION;
137584538079SBram Moolenaar 	return VAR_FLAVOUR_VIMINFO;
137684538079SBram Moolenaar     }
137784538079SBram Moolenaar     else
137884538079SBram Moolenaar 	return VAR_FLAVOUR_DEFAULT;
137984538079SBram Moolenaar }
138084538079SBram Moolenaar #endif
138184538079SBram Moolenaar 
138284538079SBram Moolenaar /*
138384538079SBram Moolenaar  * Write end-of-line character(s) for ":mkexrc", ":mkvimrc" and ":mksession".
138484538079SBram Moolenaar  * Return FAIL for a write error.
138584538079SBram Moolenaar  */
138684538079SBram Moolenaar     int
put_eol(FILE * fd)138784538079SBram Moolenaar put_eol(FILE *fd)
138884538079SBram Moolenaar {
138984538079SBram Moolenaar     if (
139084538079SBram Moolenaar #ifdef USE_CRNL
139184538079SBram Moolenaar 	    (
139284538079SBram Moolenaar # ifdef MKSESSION_NL
139384538079SBram Moolenaar 	     !mksession_nl &&
139484538079SBram Moolenaar # endif
139584538079SBram Moolenaar 	     (putc('\r', fd) < 0)) ||
139684538079SBram Moolenaar #endif
139784538079SBram Moolenaar 	    (putc('\n', fd) < 0))
139884538079SBram Moolenaar 	return FAIL;
139984538079SBram Moolenaar     return OK;
140084538079SBram Moolenaar }
140184538079SBram Moolenaar 
140284538079SBram Moolenaar /*
140384538079SBram Moolenaar  * Write a line to "fd".
140484538079SBram Moolenaar  * Return FAIL for a write error.
140584538079SBram Moolenaar  */
140684538079SBram Moolenaar     int
put_line(FILE * fd,char * s)140784538079SBram Moolenaar put_line(FILE *fd, char *s)
140884538079SBram Moolenaar {
140984538079SBram Moolenaar     if (fputs(s, fd) < 0 || put_eol(fd) == FAIL)
141084538079SBram Moolenaar 	return FAIL;
141184538079SBram Moolenaar     return OK;
141284538079SBram Moolenaar }
1413