aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/ex_docmd.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/ex_docmd.c')
-rw-r--r--src/nvim/ex_docmd.c1002
1 files changed, 2 insertions, 1000 deletions
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index d87dd29f88..12bee3ab86 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -1,9 +1,7 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
-/*
- * ex_docmd.c: functions for executing an Ex command line.
- */
+// ex_docmd.c: functions for executing an Ex command line.
#include <assert.h>
#include <string.h>
@@ -40,6 +38,7 @@
#include "nvim/menu.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
+#include "nvim/ex_session.h"
#include "nvim/keymap.h"
#include "nvim/file_search.h"
#include "nvim/garray.h"
@@ -79,9 +78,6 @@
static int quitmore = 0;
static bool ex_pressedreturn = false;
-/// Whether ":lcd" or ":tcd" was produced for a session.
-static int did_lcd;
-
typedef struct ucmd {
char_u *uc_name; // The command name
uint32_t uc_argt; // The argument type
@@ -8085,162 +8081,6 @@ static void close_redir(void)
}
}
-#define PUTLINE_FAIL(s) \
- do { if (FAIL == put_line(fd, (s))) { return FAIL; } } while (0)
-
-/// ":mkexrc", ":mkvimrc", ":mkview", ":mksession".
-///
-/// Legacy 'sessionoptions' flags SSOP_UNIX, SSOP_SLASH are always enabled.
-/// - SSOP_UNIX: line-endings are always LF
-/// - SSOP_SLASH: filenames are always written with "/" slash
-static void ex_mkrc(exarg_T *eap)
-{
- FILE *fd;
- int failed = false;
- int view_session = false; // :mkview, :mksession
- int using_vdir = false; // using 'viewdir'?
- char *viewFile = NULL;
- unsigned *flagp;
-
- if (eap->cmdidx == CMD_mksession || eap->cmdidx == CMD_mkview) {
- view_session = TRUE;
- }
-
- /* Use the short file name until ":lcd" is used. We also don't use the
- * short file name when 'acd' is set, that is checked later. */
- did_lcd = FALSE;
-
- char *fname;
- // ":mkview" or ":mkview 9": generate file name with 'viewdir'
- if (eap->cmdidx == CMD_mkview
- && (*eap->arg == NUL
- || (ascii_isdigit(*eap->arg) && eap->arg[1] == NUL))) {
- eap->forceit = true;
- fname = get_view_file(*eap->arg);
- if (fname == NULL) {
- return;
- }
- viewFile = fname;
- using_vdir = true;
- } else if (*eap->arg != NUL) {
- fname = (char *) eap->arg;
- } else if (eap->cmdidx == CMD_mkvimrc) {
- fname = VIMRC_FILE;
- } else if (eap->cmdidx == CMD_mksession) {
- fname = SESSION_FILE;
- } else {
- fname = EXRC_FILE;
- }
-
- /* When using 'viewdir' may have to create the directory. */
- if (using_vdir && !os_isdir(p_vdir)) {
- vim_mkdir_emsg((const char *)p_vdir, 0755);
- }
-
- fd = open_exfile((char_u *) fname, eap->forceit, WRITEBIN);
- if (fd != NULL) {
- if (eap->cmdidx == CMD_mkview)
- flagp = &vop_flags;
- else
- flagp = &ssop_flags;
-
- // Write the version command for :mkvimrc
- if (eap->cmdidx == CMD_mkvimrc) {
- (void)put_line(fd, "version 6.0");
- }
-
- if (eap->cmdidx == CMD_mksession) {
- if (put_line(fd, "let SessionLoad = 1") == FAIL)
- failed = TRUE;
- }
-
- if (!view_session || (eap->cmdidx == CMD_mksession
- && (*flagp & SSOP_OPTIONS))) {
- failed |= (makemap(fd, NULL) == FAIL
- || makeset(fd, OPT_GLOBAL, false) == FAIL);
- }
-
- if (!failed && view_session) {
- if (put_line(fd,
- "let s:so_save = &so | let s:siso_save = &siso | set so=0 siso=0")
- == FAIL)
- failed = TRUE;
- if (eap->cmdidx == CMD_mksession) {
- char_u *dirnow; /* current directory */
-
- dirnow = xmalloc(MAXPATHL);
- /*
- * Change to session file's dir.
- */
- if (os_dirname(dirnow, MAXPATHL) == FAIL
- || os_chdir((char *)dirnow) != 0)
- *dirnow = NUL;
- if (*dirnow != NUL && (ssop_flags & SSOP_SESDIR)) {
- if (vim_chdirfile((char_u *) fname) == OK) {
- shorten_fnames(true);
- }
- } else if (*dirnow != NUL
- && (ssop_flags & SSOP_CURDIR) && globaldir != NULL) {
- if (os_chdir((char *)globaldir) == 0)
- shorten_fnames(TRUE);
- }
-
- failed |= (makeopens(fd, dirnow) == FAIL);
-
- /* restore original dir */
- if (*dirnow != NUL && ((ssop_flags & SSOP_SESDIR)
- || ((ssop_flags & SSOP_CURDIR) && globaldir !=
- NULL))) {
- if (os_chdir((char *)dirnow) != 0)
- EMSG(_(e_prev_dir));
- shorten_fnames(TRUE);
- /* restore original dir */
- if (*dirnow != NUL && ((ssop_flags & SSOP_SESDIR)
- || ((ssop_flags & SSOP_CURDIR) && globaldir !=
- NULL))) {
- if (os_chdir((char *)dirnow) != 0)
- EMSG(_(e_prev_dir));
- shorten_fnames(TRUE);
- }
- }
- xfree(dirnow);
- } else {
- failed |= (put_view(fd, curwin, !using_vdir, flagp,
- -1) == FAIL);
- }
- if (fprintf(fd,
- "%s",
- "let &so = s:so_save | let &siso = s:siso_save\n"
- "doautoall SessionLoadPost\n")
- < 0) {
- failed = true;
- }
- if (eap->cmdidx == CMD_mksession) {
- if (fprintf(fd, "unlet SessionLoad\n") < 0) {
- failed = true;
- }
- }
- }
- if (put_line(fd, "\" vim: set ft=vim :") == FAIL)
- failed = TRUE;
-
- failed |= fclose(fd);
-
- if (failed) {
- EMSG(_(e_write));
- } else if (eap->cmdidx == CMD_mksession) {
- // successful session write - set v:this_session
- char *const tbuf = xmalloc(MAXPATHL);
- if (vim_FullName(fname, tbuf, MAXPATHL, false) == OK) {
- set_vim_var_string(VV_THIS_SESSION, tbuf, -1);
- }
- xfree(tbuf);
- }
- }
-
- xfree(viewFile);
-}
-
/// Try creating a directory, give error message on failure
///
/// @param[in] name Directory to create.
@@ -9113,844 +8953,6 @@ char_u *expand_sfile(char_u *arg)
return result;
}
-
-/// Writes commands for restoring the current buffers, for :mksession.
-///
-/// Legacy 'sessionoptions' flags SSOP_UNIX, SSOP_SLASH are always enabled.
-///
-/// @param dirnow Current directory name
-/// @param fd File descriptor to write to
-///
-/// @return FAIL on error, OK otherwise.
-static int makeopens(FILE *fd, char_u *dirnow)
-{
- int only_save_windows = TRUE;
- int nr;
- int restore_size = true;
- win_T *wp;
- char_u *sname;
- win_T *edited_win = NULL;
- int tabnr;
- win_T *tab_firstwin;
- frame_T *tab_topframe;
- int cur_arg_idx = 0;
- int next_arg_idx = 0;
-
- if (ssop_flags & SSOP_BUFFERS)
- only_save_windows = FALSE; /* Save ALL buffers */
-
- // Begin by setting v:this_session, and then other sessionable variables.
- PUTLINE_FAIL("let v:this_session=expand(\"<sfile>:p\")");
- if (ssop_flags & SSOP_GLOBALS) {
- if (store_session_globals(fd) == FAIL) {
- return FAIL;
- }
- }
-
- // Close all windows but one.
- PUTLINE_FAIL("silent only");
-
- //
- // Now a :cd command to the session directory or the current directory
- //
- if (ssop_flags & SSOP_SESDIR) {
- PUTLINE_FAIL("exe \"cd \" . escape(expand(\"<sfile>:p:h\"), ' ')");
- } else if (ssop_flags & SSOP_CURDIR) {
- sname = home_replace_save(NULL, globaldir != NULL ? globaldir : dirnow);
- char *fname_esc = ses_escape_fname((char *)sname, &ssop_flags);
- if (fprintf(fd, "cd %s\n", fname_esc) < 0) {
- xfree(fname_esc);
- xfree(sname);
- return FAIL;
- }
- xfree(fname_esc);
- xfree(sname);
- }
-
- if (fprintf(fd,
- "%s",
- // If there is an empty, unnamed buffer we will wipe it out later.
- // Remember the buffer number.
- "if expand('%') == '' && !&modified && line('$') <= 1"
- " && getline(1) == ''\n"
- " let s:wipebuf = bufnr('%')\n"
- "endif\n"
- // Now save the current files, current buffer first.
- "set shortmess=aoO\n") < 0) {
- return FAIL;
- }
-
- // Now put the other buffers into the buffer list.
- FOR_ALL_BUFFERS(buf) {
- if (!(only_save_windows && buf->b_nwindows == 0)
- && !(buf->b_help && !(ssop_flags & SSOP_HELP))
- && buf->b_fname != NULL
- && buf->b_p_bl) {
- if (fprintf(fd, "badd +%" PRId64 " ",
- buf->b_wininfo == NULL
- ? (int64_t)1L
- : (int64_t)buf->b_wininfo->wi_fpos.lnum) < 0
- || ses_fname(fd, buf, &ssop_flags, true) == FAIL) {
- return FAIL;
- }
- }
- }
-
- /* the global argument list */
- if (ses_arglist(fd, "argglobal", &global_alist.al_ga,
- !(ssop_flags & SSOP_CURDIR), &ssop_flags) == FAIL) {
- return FAIL;
- }
-
- if (ssop_flags & SSOP_RESIZE) {
- // Note: after the restore we still check it worked!
- if (fprintf(fd, "set lines=%" PRId64 " columns=%" PRId64 "\n",
- (int64_t)Rows, (int64_t)Columns) < 0) {
- return FAIL;
- }
- }
-
- int restore_stal = FALSE;
- // When there are two or more tabpages and 'showtabline' is 1 the tabline
- // will be displayed when creating the next tab. That resizes the windows
- // in the first tab, which may cause problems. Set 'showtabline' to 2
- // temporarily to avoid that.
- if (p_stal == 1 && first_tabpage->tp_next != NULL) {
- PUTLINE_FAIL("set stal=2");
- restore_stal = true;
- }
-
- //
- // For each tab:
- // - Put windows for each tab, when "tabpages" is in 'sessionoptions'.
- // - Don't use goto_tabpage(), it may change CWD and trigger autocommands.
- //
- tab_firstwin = firstwin; // First window in tab page "tabnr".
- tab_topframe = topframe;
- for (tabnr = 1;; tabnr++) {
- tabpage_T *tp = find_tabpage(tabnr);
- if (tp == NULL) {
- break; // done all tab pages
- }
-
- int need_tabnew = false;
- int cnr = 1;
-
- if ((ssop_flags & SSOP_TABPAGES)) {
- if (tp == curtab) {
- tab_firstwin = firstwin;
- tab_topframe = topframe;
- } else {
- tab_firstwin = tp->tp_firstwin;
- tab_topframe = tp->tp_topframe;
- }
- if (tabnr > 1)
- need_tabnew = TRUE;
- }
-
- //
- // Before creating the window layout, try loading one file. If this
- // is aborted we don't end up with a number of useless windows.
- // This may have side effects! (e.g., compressed or network file).
- //
- for (wp = tab_firstwin; wp != NULL; wp = wp->w_next) {
- if (ses_do_win(wp)
- && wp->w_buffer->b_ffname != NULL
- && !bt_help(wp->w_buffer)
- && !bt_nofile(wp->w_buffer)
- ) {
- if (fputs(need_tabnew ? "tabedit " : "edit ", fd) < 0
- || ses_fname(fd, wp->w_buffer, &ssop_flags, true) == FAIL) {
- return FAIL;
- }
- need_tabnew = false;
- if (!wp->w_arg_idx_invalid) {
- edited_win = wp;
- }
- break;
- }
- }
-
- // If no file got edited create an empty tab page.
- if (need_tabnew && put_line(fd, "tabnew") == FAIL) {
- return FAIL;
- }
-
- //
- // Save current window layout.
- //
- PUTLINE_FAIL("set splitbelow splitright");
- if (ses_win_rec(fd, tab_topframe) == FAIL) {
- return FAIL;
- }
- if (!p_sb && put_line(fd, "set nosplitbelow") == FAIL) {
- return FAIL;
- }
- if (!p_spr && put_line(fd, "set nosplitright") == FAIL) {
- return FAIL;
- }
-
- //
- // Check if window sizes can be restored (no windows omitted).
- // Remember the window number of the current window after restoring.
- //
- nr = 0;
- for (wp = tab_firstwin; wp != NULL; wp = wp->w_next) {
- if (ses_do_win(wp))
- ++nr;
- else
- restore_size = FALSE;
- if (curwin == wp)
- cnr = nr;
- }
-
- // Go to the first window.
- PUTLINE_FAIL("wincmd t");
-
- // If more than one window, see if sizes can be restored.
- // First set 'winheight' and 'winwidth' to 1 to avoid the windows being
- // resized when moving between windows.
- // Do this before restoring the view, so that the topline and the
- // cursor can be set. This is done again below.
- // winminheight and winminwidth need to be set to avoid an error if the
- // user has set winheight or winwidth.
- if (fprintf(fd,
- "set winminheight=0\n"
- "set winheight=1\n"
- "set winminwidth=0\n"
- "set winwidth=1\n") < 0) {
- return FAIL;
- }
- if (nr > 1 && ses_winsizes(fd, restore_size, tab_firstwin) == FAIL) {
- return FAIL;
- }
-
- //
- // Restore the view of the window (options, file, cursor, etc.).
- //
- for (wp = tab_firstwin; wp != NULL; wp = wp->w_next) {
- if (!ses_do_win(wp)) {
- continue;
- }
- if (put_view(fd, wp, wp != edited_win, &ssop_flags, cur_arg_idx)
- == FAIL) {
- return FAIL;
- }
- if (nr > 1 && put_line(fd, "wincmd w") == FAIL) {
- return FAIL;
- }
- next_arg_idx = wp->w_arg_idx;
- }
-
- // The argument index in the first tab page is zero, need to set it in
- // each window. For further tab pages it's the window where we do
- // "tabedit".
- cur_arg_idx = next_arg_idx;
-
- //
- // Restore cursor to the current window if it's not the first one.
- //
- if (cnr > 1 && (fprintf(fd, "%dwincmd w\n", cnr) < 0)) {
- return FAIL;
- }
-
- //
- // Restore window sizes again after jumping around in windows, because
- // the current window has a minimum size while others may not.
- //
- if (nr > 1 && ses_winsizes(fd, restore_size, tab_firstwin) == FAIL) {
- return FAIL;
- }
-
- // Take care of tab-local working directories if applicable
- if (tp->tp_localdir) {
- if (fputs("if exists(':tcd') == 2 | tcd ", fd) < 0
- || ses_put_fname(fd, tp->tp_localdir, &ssop_flags) == FAIL
- || fputs(" | endif\n", fd) < 0) {
- return FAIL;
- }
- did_lcd = true;
- }
-
- // Don't continue in another tab page when doing only the current one
- // or when at the last tab page.
- if (!(ssop_flags & SSOP_TABPAGES)) {
- break;
- }
- }
-
- if (ssop_flags & SSOP_TABPAGES) {
- if (fprintf(fd, "tabnext %d\n", tabpage_index(curtab)) < 0) {
- return FAIL;
- }
- }
- if (restore_stal && put_line(fd, "set stal=1") == FAIL) {
- return FAIL;
- }
-
- //
- // Wipe out an empty unnamed buffer we started in.
- //
- if (fprintf(fd, "%s",
- "if exists('s:wipebuf') "
- "&& getbufvar(s:wipebuf, '&buftype') isnot# 'terminal'\n"
- " silent exe 'bwipe ' . s:wipebuf\n"
- "endif\n"
- "unlet! s:wipebuf\n") < 0) {
- return FAIL;
- }
-
- // Re-apply options.
- if (fprintf(fd,
- "set winheight=%" PRId64 " winwidth=%" PRId64
- " winminheight=%" PRId64 " winminwidth=%" PRId64
- " shortmess=%s\n",
- (int64_t)p_wh,
- (int64_t)p_wiw,
- (int64_t)p_wmh,
- (int64_t)p_wmw,
- p_shm) < 0) {
- return FAIL;
- }
-
- //
- // Lastly, execute the x.vim file if it exists.
- //
- if (fprintf(fd, "%s",
- "let s:sx = expand(\"<sfile>:p:r\").\"x.vim\"\n"
- "if file_readable(s:sx)\n"
- " exe \"source \" . fnameescape(s:sx)\n"
- "endif\n") < 0) {
- return FAIL;
- }
-
- return OK;
-}
-
-static int ses_winsizes(FILE *fd, int restore_size, win_T *tab_firstwin)
-{
- int n = 0;
- win_T *wp;
-
- if (restore_size && (ssop_flags & SSOP_WINSIZE)) {
- for (wp = tab_firstwin; wp != NULL; wp = wp->w_next) {
- if (!ses_do_win(wp)) {
- continue;
- }
- n++;
-
- // restore height when not full height
- if (wp->w_height + wp->w_status_height < topframe->fr_height
- && (fprintf(fd,
- "exe '%dresize ' . ((&lines * %" PRId64
- " + %" PRId64 ") / %" PRId64 ")\n",
- n, (int64_t)wp->w_height,
- (int64_t)Rows / 2, (int64_t)Rows) < 0)) {
- return FAIL;
- }
-
- // restore width when not full width
- if (wp->w_width < Columns
- && (fprintf(fd,
- "exe 'vert %dresize ' . ((&columns * %" PRId64
- " + %" PRId64 ") / %" PRId64 ")\n",
- n, (int64_t)wp->w_width, (int64_t)Columns / 2,
- (int64_t)Columns) < 0)) {
- return FAIL;
- }
- }
- } else {
- // Just equalize window sizes.
- PUTLINE_FAIL("wincmd =");
- }
- return OK;
-}
-
-// Write commands to "fd" to recursively create windows for frame "fr",
-// horizontally and vertically split.
-// After the commands the last window in the frame is the current window.
-// Returns FAIL when writing the commands to "fd" fails.
-static int ses_win_rec(FILE *fd, frame_T *fr)
-{
- frame_T *frc;
- int count = 0;
-
- if (fr->fr_layout != FR_LEAF) {
- // Find first frame that's not skipped and then create a window for
- // each following one (first frame is already there).
- frc = ses_skipframe(fr->fr_child);
- if (frc != NULL)
- while ((frc = ses_skipframe(frc->fr_next)) != NULL) {
- // Make window as big as possible so that we have lots of room
- // to split.
- if (fprintf(fd, "%s%s",
- "wincmd _ | wincmd |\n",
- (fr->fr_layout == FR_COL ? "split\n" : "vsplit\n")) < 0) {
- return FAIL;
- }
- count++;
- }
-
- // Go back to the first window.
- if (count > 0 && (fprintf(fd, fr->fr_layout == FR_COL
- ? "%dwincmd k\n" : "%dwincmd h\n", count) < 0)) {
- return FAIL;
- }
-
- // Recursively create frames/windows in each window of this column or row.
- frc = ses_skipframe(fr->fr_child);
- while (frc != NULL) {
- ses_win_rec(fd, frc);
- frc = ses_skipframe(frc->fr_next);
- // Go to next window.
- if (frc != NULL && put_line(fd, "wincmd w") == FAIL) {
- return FAIL;
- }
- }
- }
- return OK;
-}
-
-// Skip frames that don't contain windows we want to save in the Session.
-// Returns NULL when there none.
-static frame_T *ses_skipframe(frame_T *fr)
-{
- frame_T *frc;
-
- FOR_ALL_FRAMES(frc, fr) {
- if (ses_do_frame(frc)) {
- break;
- }
- }
- return frc;
-}
-
-// Return true if frame "fr" has a window somewhere that we want to save in
-// the Session.
-static bool ses_do_frame(const frame_T *fr)
- FUNC_ATTR_NONNULL_ARG(1)
-{
- const frame_T *frc;
-
- if (fr->fr_layout == FR_LEAF) {
- return ses_do_win(fr->fr_win);
- }
- FOR_ALL_FRAMES(frc, fr->fr_child) {
- if (ses_do_frame(frc)) {
- return true;
- }
- }
- return false;
-}
-
-/// Return non-zero if window "wp" is to be stored in the Session.
-static int ses_do_win(win_T *wp)
-{
- if (wp->w_buffer->b_fname == NULL
- // When 'buftype' is "nofile" can't restore the window contents.
- || (!wp->w_buffer->terminal && bt_nofile(wp->w_buffer))) {
- return ssop_flags & SSOP_BLANK;
- }
- if (bt_help(wp->w_buffer)) {
- return ssop_flags & SSOP_HELP;
- }
- return true;
-}
-
-static int put_view_curpos(FILE *fd, const win_T *wp, char *spaces)
-{
- int r;
-
- if (wp->w_curswant == MAXCOL) {
- r = fprintf(fd, "%snormal! $\n", spaces);
- } else {
- r = fprintf(fd, "%snormal! 0%d|\n", spaces, wp->w_virtcol + 1);
- }
- return r >= 0;
-}
-
-/*
- * Write commands to "fd" to restore the view of a window.
- * Caller must make sure 'scrolloff' is zero.
- */
-static int
-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) {
- PUTLINE_FAIL("argglobal");
- } 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, "%" PRId64 "argu\n", (int64_t)wp->w_arg_idx + 1) < 0) {
- 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)) {
- char *fname_esc =
- ses_escape_fname(ses_get_fname(wp->w_buffer, flagp), flagp);
- //
- // Load the file.
- //
- if (wp->w_buffer->b_ffname != NULL
- && (!bt_nofile(wp->w_buffer) || wp->w_buffer->terminal)
- ) {
- // 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 (fprintf(fd,
- "if bufexists(\"%s\") | buffer %s | else | edit %s | endif\n"
- // Fixup :terminal buffer name. #7836
- "if &buftype ==# 'terminal'\n"
- " silent file %s\n"
- "endif\n",
- fname_esc,
- fname_esc,
- fname_esc,
- fname_esc) < 0) {
- xfree(fname_esc);
- return FAIL;
- }
- } else {
- // No file in this buffer, just make it empty.
- PUTLINE_FAIL("enew");
- if (wp->w_buffer->b_ffname != NULL) {
- // The buffer does have a name, but it's not a file name.
- if (fprintf(fd, "file %s\n", fname_esc) < 0) {
- xfree(fname_esc);
- return FAIL;
- }
- }
- do_cursor = false;
- }
- xfree(fname_esc);
- }
-
- /*
- * 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 "nvim/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));
- else if (*flagp & SSOP_FOLDS)
- f = makefoldset(fd);
- else
- f = OK;
- curwin = save_curwin;
- curbuf = curwin->w_buffer;
- if (f == FAIL) {
- return FAIL;
- }
-
- //
- // 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;
- }
-
- //
- // 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 = %" PRId64 " - ((%" PRId64
- " * winheight(0) + %" PRId64 ") / %" PRId64 ")\n"
- "if s:l < 1 | let s:l = 1 | endif\n"
- "exe s:l\n"
- "normal! zt\n"
- "%" PRId64 "\n",
- (int64_t)wp->w_cursor.lnum,
- (int64_t)(wp->w_cursor.lnum - wp->w_topline),
- (int64_t)(wp->w_height_inner / 2),
- (int64_t)wp->w_height_inner,
- (int64_t)wp->w_cursor.lnum) < 0) {
- return FAIL;
- }
- // Restore the cursor column and left offset when not wrapping.
- if (wp->w_cursor.col == 0) {
- PUTLINE_FAIL("normal! 0");
- } else {
- if (!wp->w_p_wrap && wp->w_leftcol > 0 && wp->w_width > 0) {
- if (fprintf(fd,
- "let s:c = %" PRId64 " - ((%" PRId64
- " * winwidth(0) + %" PRId64 ") / %" PRId64 ")\n"
- "if s:c > 0\n"
- " exe 'normal! ' . s:c . '|zs' . %" PRId64 " . '|'\n"
- "else\n",
- (int64_t)wp->w_virtcol + 1,
- (int64_t)(wp->w_virtcol - wp->w_leftcol),
- (int64_t)(wp->w_width / 2),
- (int64_t)wp->w_width,
- (int64_t)wp->w_virtcol + 1) < 0
- || 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
- || fprintf(fd, "\n") < 0) {
- return FAIL;
- }
- did_lcd = true;
- }
-
- return OK;
-}
-
-/// Writes an :argument list to the session file.
-///
-/// @param fd
-/// @param cmd
-/// @param gap
-/// @param fullname true: use full path name
-/// @param flagp
-///
-/// @returns FAIL if writing fails.
-static int ses_arglist(FILE *fd, char *cmd, garray_T *gap, int fullname,
- unsigned *flagp)
-{
- char_u *buf = NULL;
- char_u *s;
-
- if (fprintf(fd, "%s\n%s\n", cmd, "%argdel") < 0) {
- return FAIL;
- }
- for (int i = 0; i < gap->ga_len; i++) {
- // NULL file names are skipped (only happens when out of memory).
- s = alist_name(&((aentry_T *)gap->ga_data)[i]);
- if (s != NULL) {
- if (fullname) {
- buf = xmalloc(MAXPATHL);
- (void)vim_FullName((char *)s, (char *)buf, MAXPATHL, FALSE);
- s = buf;
- }
- char *fname_esc = ses_escape_fname((char *)s, flagp);
- if (fprintf(fd, "$argadd %s\n", fname_esc) < 0) {
- xfree(fname_esc);
- xfree(buf);
- return FAIL;
- }
- xfree(fname_esc);
- xfree(buf);
- }
- }
- return OK;
-}
-
-/// Gets the buffer name for `buf`.
-static char *ses_get_fname(buf_T *buf, unsigned *flagp)
-{
- // Use the short file name if the current directory is known at the time
- // the session file will be sourced.
- // Don't do this for ":mkview", we don't know the current directory.
- // Don't do this after ":lcd", we don't keep track of what the current
- // directory is.
- if (buf->b_sfname != NULL
- && flagp == &ssop_flags
- && (ssop_flags & (SSOP_CURDIR | SSOP_SESDIR))
- && !p_acd
- && !did_lcd) {
- return (char *)buf->b_sfname;
- }
- return (char *)buf->b_ffname;
-}
-
-/// Write a buffer name to the session file.
-/// Also ends the line, if "add_eol" is true.
-/// Returns FAIL if writing fails.
-static int ses_fname(FILE *fd, buf_T *buf, unsigned *flagp, bool add_eol)
-{
- char *name = ses_get_fname(buf, flagp);
- if (ses_put_fname(fd, (char_u *)name, flagp) == FAIL
- || (add_eol && fprintf(fd, "\n") < 0)) {
- return FAIL;
- }
- return OK;
-}
-
-// Escapes a filename for session writing.
-// Takes care of "slash" flag in 'sessionoptions' and escapes special
-// characters.
-//
-// Returns allocated string or NULL.
-static char *ses_escape_fname(char *name, unsigned *flagp)
-{
- char *p;
- char *sname = (char *)home_replace_save(NULL, (char_u *)name);
-
- // Always SSOP_SLASH: change all backslashes to forward slashes.
- for (p = sname; *p != NUL; MB_PTR_ADV(p)) {
- if (*p == '\\') {
- *p = '/';
- }
- }
-
- // Escape special characters.
- p = vim_strsave_fnameescape(sname, false);
- xfree(sname);
- return p;
-}
-
-// Write a file name to the session file.
-// Takes care of the "slash" option in 'sessionoptions' and escapes special
-// characters.
-// Returns FAIL if writing fails.
-static int ses_put_fname(FILE *fd, char_u *name, unsigned *flagp)
-{
- char *p = ses_escape_fname((char *)name, flagp);
- bool retval = fputs(p, fd) < 0 ? FAIL : OK;
- xfree(p);
- return retval;
-}
-
-/*
- * ":loadview [nr]"
- */
-static void ex_loadview(exarg_T *eap)
-{
- char *fname = get_view_file(*eap->arg);
- if (fname != NULL) {
- if (do_source((char_u *)fname, FALSE, DOSO_NONE) == FAIL) {
- EMSG2(_(e_notopen), fname);
- }
- xfree(fname);
- }
-}
-
-/// Get the name of the view file for the current buffer.
-static char *get_view_file(int c)
-{
- if (curbuf->b_ffname == NULL) {
- EMSG(_(e_noname));
- return NULL;
- }
- char *sname = (char *)home_replace_save(NULL, curbuf->b_ffname);
-
- // We want a file name without separators, because we're not going to make
- // a directory.
- // "normal" path separator -> "=+"
- // "=" -> "=="
- // ":" path separator -> "=-"
- size_t len = 0;
- for (char *p = sname; *p; p++) {
- if (*p == '=' || vim_ispathsep(*p)) {
- ++len;
- }
- }
- char *retval = xmalloc(strlen(sname) + len + STRLEN(p_vdir) + 9);
- STRCPY(retval, p_vdir);
- add_pathsep(retval);
- char *s = retval + strlen(retval);
- for (char *p = sname; *p; p++) {
- if (*p == '=') {
- *s++ = '=';
- *s++ = '=';
- } else if (vim_ispathsep(*p)) {
- *s++ = '=';
-#if defined(BACKSLASH_IN_FILENAME)
- if (*p == ':')
- *s++ = '-';
- else
-#endif
- *s++ = '+';
- } else
- *s++ = *p;
- }
- *s++ = '=';
- *s++ = c;
- strcpy(s, ".vim");
-
- xfree(sname);
- return retval;
-}
-
-
-// TODO(justinmk): remove this, not needed after 5ba3cecb68cd.
-int put_eol(FILE *fd)
-{
- if (putc('\n', fd) < 0) {
- return FAIL;
- }
- return OK;
-}
-
-// TODO(justinmk): remove this, not needed after 5ba3cecb68cd.
-int put_line(FILE *fd, char *s)
-{
- if (fprintf(fd, "%s\n", s) < 0) {
- return FAIL;
- }
- return OK;
-}
-
/*
* ":rshada" and ":wshada".
*/