put_view(
    FILE	*fd,
    win_T	*wp,
    int		add_edit,	/* add ":edit" command to view */
    unsigned	*flagp,		/* vop_flags or ssop_flags */
    int		current_arg_idx) /* current argument index of the window, use
				  * -1 if unknown */
{
    win_T	*save_curwin;
    int		f;
    int		do_cursor;
    int		did_next = FALSE;

    /* Always restore cursor position for ":mksession".  For ":mkview" only
     * when 'viewoptions' contains "cursor". */
    do_cursor = (flagp == &ssop_flags || *flagp & SSOP_CURSOR);

    /*
     * Local argument list.
     */
    if (wp->w_alist == &global_alist)
    {
	if (put_line(fd, "argglobal") == FAIL)
	    return FAIL;
    }
    else
    {
	if (ses_arglist(fd, "arglocal", &wp->w_alist->al_ga,
			flagp == &vop_flags
			|| !(*flagp & SSOP_CURDIR)
			|| wp->w_localdir != NULL, flagp) == FAIL)
	    return FAIL;
    }

    /* Only when part of a session: restore the argument index.  Some
     * arguments may have been deleted, check if the index is valid. */
    if (wp->w_arg_idx != current_arg_idx && wp->w_arg_idx < WARGCOUNT(wp)
						      && flagp == &ssop_flags)
    {
	if (fprintf(fd, "%ldargu", (long)wp->w_arg_idx + 1) < 0
		|| put_eol(fd) == FAIL)
	    return FAIL;
	did_next = TRUE;
    }

    /* Edit the file.  Skip this when ":next" already did it. */
    if (add_edit && (!did_next || wp->w_arg_idx_invalid))
    {
# ifdef FEAT_TERMINAL
	if (bt_terminal(wp->w_buffer))
	{
	    if (term_write_session(fd, wp) == FAIL)
		return FAIL;
	}
	else
# endif
	/*
	 * Load the file.
	 */
	if (wp->w_buffer->b_ffname != NULL
# ifdef FEAT_QUICKFIX
		&& !bt_nofile(wp->w_buffer)
# endif
		)
	{
	    /*
	     * Editing a file in this buffer: use ":edit file".
	     * This may have side effects! (e.g., compressed or network file).
	     *
	     * Note, if a buffer for that file already exists, use :badd to
	     * edit that buffer, to not lose folding information (:edit resets
	     * folds in other buffers)
	     */
	    if (fputs("if bufexists(\"", fd) < 0
		    || ses_fname(fd, wp->w_buffer, flagp, FALSE) == FAIL
		    || fputs("\") | buffer ", fd) < 0
		    || ses_fname(fd, wp->w_buffer, flagp, FALSE) == FAIL
		    || fputs(" | else | edit ", fd) < 0
		    || ses_fname(fd, wp->w_buffer, flagp, FALSE) == FAIL
		    || fputs(" | endif", fd) < 0
		    || put_eol(fd) == FAIL)
		return FAIL;
	}
	else
	{
	    /* No file in this buffer, just make it empty. */
	    if (put_line(fd, "enew") == FAIL)
		return FAIL;
#ifdef FEAT_QUICKFIX
	    if (wp->w_buffer->b_ffname != NULL)
	    {
		/* The buffer does have a name, but it's not a file name. */
		if (fputs("file ", fd) < 0
			|| ses_fname(fd, wp->w_buffer, flagp, TRUE) == FAIL)
		    return FAIL;
	    }
#endif
	    do_cursor = FALSE;
	}
    }

    /*
     * Local mappings and abbreviations.
     */
    if ((*flagp & (SSOP_OPTIONS | SSOP_LOCALOPTIONS))
					 && makemap(fd, wp->w_buffer) == FAIL)
	return FAIL;

    /*
     * Local options.  Need to go to the window temporarily.
     * Store only local values when using ":mkview" and when ":mksession" is
     * used and 'sessionoptions' doesn't include "options".
     * Some folding options are always stored when "folds" is included,
     * otherwise the folds would not be restored correctly.
     */
    save_curwin = curwin;
    curwin = wp;
    curbuf = curwin->w_buffer;
    if (*flagp & (SSOP_OPTIONS | SSOP_LOCALOPTIONS))
	f = makeset(fd, OPT_LOCAL,
			     flagp == &vop_flags || !(*flagp & SSOP_OPTIONS));
#ifdef FEAT_FOLDING
    else if (*flagp & SSOP_FOLDS)
	f = makefoldset(fd);
#endif
    else
	f = OK;
    curwin = save_curwin;
    curbuf = curwin->w_buffer;
    if (f == FAIL)
	return FAIL;

#ifdef FEAT_FOLDING
    /*
     * Save Folds when 'buftype' is empty and for help files.
     */
    if ((*flagp & SSOP_FOLDS)
	    && wp->w_buffer->b_ffname != NULL
	    && (bt_normal(wp->w_buffer) || bt_help(wp->w_buffer)))
    {
	if (put_folds(fd, wp) == FAIL)
	    return FAIL;
    }
#endif

    /*
     * Set the cursor after creating folds, since that moves the cursor.
     */
    if (do_cursor)
    {

	/* Restore the cursor line in the file and relatively in the
	 * window.  Don't use "G", it changes the jumplist. */
	if (fprintf(fd, "let s:l = %ld - ((%ld * winheight(0) + %ld) / %ld)",
		    (long)wp->w_cursor.lnum,
		    (long)(wp->w_cursor.lnum - wp->w_topline),
		    (long)wp->w_height / 2, (long)wp->w_height) < 0
		|| put_eol(fd) == FAIL
		|| put_line(fd, "if s:l < 1 | let s:l = 1 | endif") == FAIL
		|| put_line(fd, "exe s:l") == FAIL
		|| put_line(fd, "normal! zt") == FAIL
		|| fprintf(fd, "%ld", (long)wp->w_cursor.lnum) < 0
		|| put_eol(fd) == FAIL)
	    return FAIL;
	/* Restore the cursor column and left offset when not wrapping. */
	if (wp->w_cursor.col == 0)
	{
	    if (put_line(fd, "normal! 0") == FAIL)
		return FAIL;
	}
	else
	{
	    if (!wp->w_p_wrap && wp->w_leftcol > 0 && wp->w_width > 0)
	    {
		if (fprintf(fd,
			  "let s:c = %ld - ((%ld * winwidth(0) + %ld) / %ld)",
			    (long)wp->w_virtcol + 1,
			    (long)(wp->w_virtcol - wp->w_leftcol),
			    (long)wp->w_width / 2, (long)wp->w_width) < 0
			|| put_eol(fd) == FAIL
			|| put_line(fd, "if s:c > 0") == FAIL
			|| fprintf(fd,
			    "  exe 'normal! ' . s:c . '|zs' . %ld . '|'",
			    (long)wp->w_virtcol + 1) < 0
			|| put_eol(fd) == FAIL
			|| put_line(fd, "else") == FAIL
			|| put_view_curpos(fd, wp, "  ") == FAIL
			|| put_line(fd, "endif") == FAIL)
		    return FAIL;
	    }
	    else if (put_view_curpos(fd, wp, "") == FAIL)
		return FAIL;
	}
    }

    /*
     * Local directory, if the current flag is not view options or the "curdir"
     * option is included.
     */
    if (wp->w_localdir != NULL
			    && (flagp != &vop_flags || (*flagp & SSOP_CURDIR)))
    {
	if (fputs("lcd ", fd) < 0
		|| ses_put_fname(fd, wp->w_localdir, flagp) == FAIL
		|| put_eol(fd) == FAIL)
	    return FAIL;
	did_lcd = TRUE;
    }

    return OK;
}