Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 1 | /* vi:set ts=8 sts=4 sw=4 noet: |
| 2 | * |
| 3 | * VIM - Vi IMproved by Bram Moolenaar |
| 4 | * |
| 5 | * Do ":help uganda" in Vim to read copying and usage conditions. |
| 6 | * Do ":help credits" in Vim to see a list of people who contributed. |
| 7 | * See README.txt for an overview of the Vim source code. |
| 8 | */ |
| 9 | |
| 10 | /* |
| 11 | * session.c: session related functions |
| 12 | */ |
| 13 | |
| 14 | #include "vim.h" |
| 15 | |
| 16 | #if defined(FEAT_SESSION) || defined(PROTO) |
| 17 | |
| 18 | static int did_lcd; // whether ":lcd" was produced for a session |
| 19 | |
| 20 | /* |
| 21 | * Write a file name to the session file. |
| 22 | * Takes care of the "slash" option in 'sessionoptions' and escapes special |
| 23 | * characters. |
| 24 | * Returns FAIL if writing fails or out of memory. |
| 25 | */ |
| 26 | static int |
| 27 | ses_put_fname(FILE *fd, char_u *name, unsigned *flagp) |
| 28 | { |
| 29 | char_u *sname; |
| 30 | char_u *p; |
| 31 | int retval = OK; |
| 32 | |
| 33 | sname = home_replace_save(NULL, name); |
| 34 | if (sname == NULL) |
| 35 | return FAIL; |
| 36 | |
| 37 | if (*flagp & SSOP_SLASH) |
| 38 | { |
| 39 | // change all backslashes to forward slashes |
| 40 | for (p = sname; *p != NUL; MB_PTR_ADV(p)) |
| 41 | if (*p == '\\') |
| 42 | *p = '/'; |
| 43 | } |
| 44 | |
| 45 | // escape special characters |
Bram Moolenaar | 21c1a0c | 2021-10-17 17:20:23 +0100 | [diff] [blame] | 46 | p = vim_strsave_fnameescape(sname, VSE_NONE); |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 47 | vim_free(sname); |
| 48 | if (p == NULL) |
| 49 | return FAIL; |
| 50 | |
| 51 | // write the result |
| 52 | if (fputs((char *)p, fd) < 0) |
| 53 | retval = FAIL; |
| 54 | |
| 55 | vim_free(p); |
| 56 | return retval; |
| 57 | } |
| 58 | |
| 59 | /* |
| 60 | * Write a buffer name to the session file. |
| 61 | * Also ends the line, if "add_eol" is TRUE. |
| 62 | * Returns FAIL if writing fails. |
| 63 | */ |
| 64 | static int |
| 65 | ses_fname(FILE *fd, buf_T *buf, unsigned *flagp, int add_eol) |
| 66 | { |
| 67 | char_u *name; |
| 68 | |
| 69 | // Use the short file name if the current directory is known at the time |
| 70 | // the session file will be sourced. |
| 71 | // Don't do this for ":mkview", we don't know the current directory. |
| 72 | // Don't do this after ":lcd", we don't keep track of what the current |
| 73 | // directory is. |
| 74 | if (buf->b_sfname != NULL |
| 75 | && flagp == &ssop_flags |
| 76 | && (ssop_flags & (SSOP_CURDIR | SSOP_SESDIR)) |
| 77 | #ifdef FEAT_AUTOCHDIR |
| 78 | && !p_acd |
| 79 | #endif |
| 80 | && !did_lcd) |
| 81 | name = buf->b_sfname; |
| 82 | else |
| 83 | name = buf->b_ffname; |
| 84 | if (ses_put_fname(fd, name, flagp) == FAIL |
| 85 | || (add_eol && put_eol(fd) == FAIL)) |
| 86 | return FAIL; |
| 87 | return OK; |
| 88 | } |
| 89 | |
| 90 | /* |
| 91 | * Write an argument list to the session file. |
| 92 | * Returns FAIL if writing fails. |
| 93 | */ |
| 94 | static int |
| 95 | ses_arglist( |
| 96 | FILE *fd, |
| 97 | char *cmd, |
| 98 | garray_T *gap, |
| 99 | int fullname, // TRUE: use full path name |
| 100 | unsigned *flagp) |
| 101 | { |
| 102 | int i; |
| 103 | char_u *buf = NULL; |
| 104 | char_u *s; |
| 105 | |
| 106 | if (fputs(cmd, fd) < 0 || put_eol(fd) == FAIL) |
| 107 | return FAIL; |
| 108 | if (put_line(fd, "%argdel") == FAIL) |
| 109 | return FAIL; |
| 110 | for (i = 0; i < gap->ga_len; ++i) |
| 111 | { |
| 112 | // NULL file names are skipped (only happens when out of memory). |
| 113 | s = alist_name(&((aentry_T *)gap->ga_data)[i]); |
| 114 | if (s != NULL) |
| 115 | { |
| 116 | if (fullname) |
| 117 | { |
| 118 | buf = alloc(MAXPATHL); |
| 119 | if (buf != NULL) |
| 120 | { |
| 121 | (void)vim_FullName(s, buf, MAXPATHL, FALSE); |
| 122 | s = buf; |
| 123 | } |
| 124 | } |
| 125 | if (fputs("$argadd ", fd) < 0 |
| 126 | || ses_put_fname(fd, s, flagp) == FAIL |
| 127 | || put_eol(fd) == FAIL) |
| 128 | { |
| 129 | vim_free(buf); |
| 130 | return FAIL; |
| 131 | } |
| 132 | vim_free(buf); |
| 133 | } |
| 134 | } |
| 135 | return OK; |
| 136 | } |
| 137 | |
| 138 | /* |
| 139 | * Return non-zero if window "wp" is to be stored in the Session. |
| 140 | */ |
| 141 | static int |
| 142 | ses_do_win(win_T *wp) |
| 143 | { |
| 144 | #ifdef FEAT_TERMINAL |
| 145 | if (bt_terminal(wp->w_buffer)) |
| 146 | return !term_is_finished(wp->w_buffer) |
| 147 | && (ssop_flags & SSOP_TERMINAL) |
| 148 | && term_should_restore(wp->w_buffer); |
| 149 | #endif |
| 150 | if (wp->w_buffer->b_fname == NULL |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 151 | // When 'buftype' is "nofile" can't restore the window contents. |
Bram Moolenaar | 6d4b2f5 | 2022-08-25 15:11:15 +0100 | [diff] [blame] | 152 | || bt_nofilename(wp->w_buffer)) |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 153 | return (ssop_flags & SSOP_BLANK); |
| 154 | if (bt_help(wp->w_buffer)) |
| 155 | return (ssop_flags & SSOP_HELP); |
| 156 | return TRUE; |
| 157 | } |
| 158 | |
| 159 | /* |
| 160 | * Return TRUE if frame "fr" has a window somewhere that we want to save in |
| 161 | * the Session. |
| 162 | */ |
| 163 | static int |
| 164 | ses_do_frame(frame_T *fr) |
| 165 | { |
| 166 | frame_T *frc; |
| 167 | |
| 168 | if (fr->fr_layout == FR_LEAF) |
| 169 | return ses_do_win(fr->fr_win); |
| 170 | FOR_ALL_FRAMES(frc, fr->fr_child) |
| 171 | if (ses_do_frame(frc)) |
| 172 | return TRUE; |
| 173 | return FALSE; |
| 174 | } |
| 175 | |
| 176 | /* |
| 177 | * Skip frames that don't contain windows we want to save in the Session. |
| 178 | * Returns NULL when there none. |
| 179 | */ |
| 180 | static frame_T * |
| 181 | ses_skipframe(frame_T *fr) |
| 182 | { |
| 183 | frame_T *frc; |
| 184 | |
| 185 | FOR_ALL_FRAMES(frc, fr) |
| 186 | if (ses_do_frame(frc)) |
| 187 | break; |
| 188 | return frc; |
| 189 | } |
| 190 | |
| 191 | /* |
| 192 | * Write commands to "fd" to recursively create windows for frame "fr", |
| 193 | * horizontally and vertically split. |
| 194 | * After the commands the last window in the frame is the current window. |
| 195 | * Returns FAIL when writing the commands to "fd" fails. |
| 196 | */ |
| 197 | static int |
| 198 | ses_win_rec(FILE *fd, frame_T *fr) |
| 199 | { |
| 200 | frame_T *frc; |
| 201 | int count = 0; |
| 202 | |
Yegappan Lakshmanan | 6ec6666 | 2023-01-23 20:46:21 +0000 | [diff] [blame] | 203 | if (fr->fr_layout == FR_LEAF) |
| 204 | return OK; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 205 | |
Yegappan Lakshmanan | 6ec6666 | 2023-01-23 20:46:21 +0000 | [diff] [blame] | 206 | // Find first frame that's not skipped and then create a window for |
| 207 | // each following one (first frame is already there). |
| 208 | frc = ses_skipframe(fr->fr_child); |
| 209 | if (frc != NULL) |
| 210 | while ((frc = ses_skipframe(frc->fr_next)) != NULL) |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 211 | { |
Yegappan Lakshmanan | 6ec6666 | 2023-01-23 20:46:21 +0000 | [diff] [blame] | 212 | // Make window as big as possible so that we have lots of room |
| 213 | // to split. |
| 214 | if (put_line(fd, "wincmd _ | wincmd |") == FAIL |
| 215 | || put_line(fd, fr->fr_layout == FR_COL |
| 216 | ? "split" : "vsplit") == FAIL) |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 217 | return FAIL; |
Yegappan Lakshmanan | 6ec6666 | 2023-01-23 20:46:21 +0000 | [diff] [blame] | 218 | ++count; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 219 | } |
Yegappan Lakshmanan | 6ec6666 | 2023-01-23 20:46:21 +0000 | [diff] [blame] | 220 | |
| 221 | // Go back to the first window. |
| 222 | if (count > 0 && (fprintf(fd, fr->fr_layout == FR_COL |
| 223 | ? "%dwincmd k" : "%dwincmd h", count) < 0 |
| 224 | || put_eol(fd) == FAIL)) |
| 225 | return FAIL; |
| 226 | |
| 227 | // Recursively create frames/windows in each window of this column or |
| 228 | // row. |
| 229 | frc = ses_skipframe(fr->fr_child); |
| 230 | while (frc != NULL) |
| 231 | { |
| 232 | ses_win_rec(fd, frc); |
| 233 | frc = ses_skipframe(frc->fr_next); |
| 234 | // Go to next window. |
| 235 | if (frc != NULL && put_line(fd, "wincmd w") == FAIL) |
| 236 | return FAIL; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 237 | } |
Yegappan Lakshmanan | 6ec6666 | 2023-01-23 20:46:21 +0000 | [diff] [blame] | 238 | |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 239 | return OK; |
| 240 | } |
| 241 | |
| 242 | static int |
| 243 | ses_winsizes( |
| 244 | FILE *fd, |
| 245 | int restore_size, |
| 246 | win_T *tab_firstwin) |
| 247 | { |
| 248 | int n = 0; |
| 249 | win_T *wp; |
| 250 | |
| 251 | if (restore_size && (ssop_flags & SSOP_WINSIZE)) |
| 252 | { |
| 253 | for (wp = tab_firstwin; wp != NULL; wp = wp->w_next) |
| 254 | { |
| 255 | if (!ses_do_win(wp)) |
| 256 | continue; |
| 257 | ++n; |
| 258 | |
| 259 | // restore height when not full height |
| 260 | if (wp->w_height + wp->w_status_height < topframe->fr_height |
| 261 | && (fprintf(fd, |
| 262 | "exe '%dresize ' . ((&lines * %ld + %ld) / %ld)", |
| 263 | n, (long)wp->w_height, Rows / 2, Rows) < 0 |
| 264 | || put_eol(fd) == FAIL)) |
| 265 | return FAIL; |
| 266 | |
| 267 | // restore width when not full width |
| 268 | if (wp->w_width < Columns && (fprintf(fd, |
| 269 | "exe 'vert %dresize ' . ((&columns * %ld + %ld) / %ld)", |
| 270 | n, (long)wp->w_width, Columns / 2, Columns) < 0 |
| 271 | || put_eol(fd) == FAIL)) |
| 272 | return FAIL; |
| 273 | } |
| 274 | } |
| 275 | else |
| 276 | { |
| 277 | // Just equalise window sizes |
| 278 | if (put_line(fd, "wincmd =") == FAIL) |
| 279 | return FAIL; |
| 280 | } |
| 281 | return OK; |
| 282 | } |
| 283 | |
| 284 | static int |
| 285 | put_view_curpos(FILE *fd, win_T *wp, char *spaces) |
| 286 | { |
| 287 | int r; |
| 288 | |
| 289 | if (wp->w_curswant == MAXCOL) |
| 290 | r = fprintf(fd, "%snormal! $", spaces); |
| 291 | else |
| 292 | r = fprintf(fd, "%snormal! 0%d|", spaces, wp->w_virtcol + 1); |
| 293 | return r < 0 || put_eol(fd) == FAIL ? FALSE : OK; |
| 294 | } |
| 295 | |
| 296 | /* |
| 297 | * Write commands to "fd" to restore the view of a window. |
| 298 | * Caller must make sure 'scrolloff' is zero. |
| 299 | */ |
| 300 | static int |
| 301 | put_view( |
| 302 | FILE *fd, |
| 303 | win_T *wp, |
Bram Moolenaar | c2c8205 | 2020-09-11 22:10:22 +0200 | [diff] [blame] | 304 | int add_edit, // add ":edit" command to view |
| 305 | unsigned *flagp, // vop_flags or ssop_flags |
| 306 | int current_arg_idx, // current argument index of the window, |
| 307 | // use -1 if unknown |
| 308 | hashtab_T *terminal_bufs UNUSED) // already encountered terminal buffers, |
| 309 | // can be NULL |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 310 | { |
| 311 | win_T *save_curwin; |
| 312 | int f; |
| 313 | int do_cursor; |
| 314 | int did_next = FALSE; |
| 315 | |
| 316 | // Always restore cursor position for ":mksession". For ":mkview" only |
| 317 | // when 'viewoptions' contains "cursor". |
| 318 | do_cursor = (flagp == &ssop_flags || *flagp & SSOP_CURSOR); |
| 319 | |
| 320 | // Local argument list. |
| 321 | if (wp->w_alist == &global_alist) |
| 322 | { |
| 323 | if (put_line(fd, "argglobal") == FAIL) |
| 324 | return FAIL; |
| 325 | } |
| 326 | else |
| 327 | { |
| 328 | if (ses_arglist(fd, "arglocal", &wp->w_alist->al_ga, |
| 329 | flagp == &vop_flags |
| 330 | || !(*flagp & SSOP_CURDIR) |
| 331 | || wp->w_localdir != NULL, flagp) == FAIL) |
| 332 | return FAIL; |
| 333 | } |
| 334 | |
| 335 | // Only when part of a session: restore the argument index. Some |
| 336 | // arguments may have been deleted, check if the index is valid. |
| 337 | if (wp->w_arg_idx != current_arg_idx && wp->w_arg_idx < WARGCOUNT(wp) |
| 338 | && flagp == &ssop_flags) |
| 339 | { |
| 340 | if (fprintf(fd, "%ldargu", (long)wp->w_arg_idx + 1) < 0 |
| 341 | || put_eol(fd) == FAIL) |
| 342 | return FAIL; |
| 343 | did_next = TRUE; |
| 344 | } |
| 345 | |
| 346 | // Edit the file. Skip this when ":next" already did it. |
| 347 | if (add_edit && (!did_next || wp->w_arg_idx_invalid)) |
| 348 | { |
matveyt | 8e7d9db | 2022-01-05 14:01:30 +0000 | [diff] [blame] | 349 | if (bt_help(wp->w_buffer)) |
| 350 | { |
| 351 | char *curtag = ""; |
| 352 | |
| 353 | // A help buffer needs some options to be set. |
| 354 | // First, create a new empty buffer with "buftype=help". |
| 355 | // Then ":help" will re-use both the buffer and the window and set |
| 356 | // the options, even when "options" is not in 'sessionoptions'. |
| 357 | if (0 < wp->w_tagstackidx |
| 358 | && wp->w_tagstackidx <= wp->w_tagstacklen) |
| 359 | curtag = (char *)wp->w_tagstack[wp->w_tagstackidx - 1].tagname; |
| 360 | |
| 361 | if (put_line(fd, "enew | setl bt=help") == FAIL |
| 362 | || fprintf(fd, "help %s", curtag) < 0 |
| 363 | || put_eol(fd) == FAIL) |
| 364 | return FAIL; |
| 365 | } |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 366 | # ifdef FEAT_TERMINAL |
matveyt | 8e7d9db | 2022-01-05 14:01:30 +0000 | [diff] [blame] | 367 | else if (bt_terminal(wp->w_buffer)) |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 368 | { |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 369 | if (term_write_session(fd, wp, terminal_bufs) == FAIL) |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 370 | return FAIL; |
| 371 | } |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 372 | # endif |
| 373 | // Load the file. |
matveyt | 8e7d9db | 2022-01-05 14:01:30 +0000 | [diff] [blame] | 374 | else if (wp->w_buffer->b_ffname != NULL |
Bram Moolenaar | 6d4b2f5 | 2022-08-25 15:11:15 +0100 | [diff] [blame] | 375 | && !bt_nofilename(wp->w_buffer)) |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 376 | { |
| 377 | // Editing a file in this buffer: use ":edit file". |
| 378 | // This may have side effects! (e.g., compressed or network file). |
| 379 | // |
| 380 | // Note, if a buffer for that file already exists, use :badd to |
| 381 | // edit that buffer, to not lose folding information (:edit resets |
| 382 | // folds in other buffers) |
James Cherti | 7d42840 | 2022-03-14 20:24:51 +0000 | [diff] [blame] | 383 | if (fputs("if bufexists(fnamemodify(\"", fd) < 0 |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 384 | || ses_fname(fd, wp->w_buffer, flagp, FALSE) == FAIL |
James Cherti | 7d42840 | 2022-03-14 20:24:51 +0000 | [diff] [blame] | 385 | || fputs("\", \":p\")) | buffer ", fd) < 0 |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 386 | || ses_fname(fd, wp->w_buffer, flagp, FALSE) == FAIL |
| 387 | || fputs(" | else | edit ", fd) < 0 |
| 388 | || ses_fname(fd, wp->w_buffer, flagp, FALSE) == FAIL |
| 389 | || fputs(" | endif", fd) < 0 |
| 390 | || put_eol(fd) == FAIL) |
| 391 | return FAIL; |
| 392 | } |
| 393 | else |
| 394 | { |
| 395 | // No file in this buffer, just make it empty. |
| 396 | if (put_line(fd, "enew") == FAIL) |
| 397 | return FAIL; |
| 398 | #ifdef FEAT_QUICKFIX |
| 399 | if (wp->w_buffer->b_ffname != NULL) |
| 400 | { |
| 401 | // The buffer does have a name, but it's not a file name. |
| 402 | if (fputs("file ", fd) < 0 |
| 403 | || ses_fname(fd, wp->w_buffer, flagp, TRUE) == FAIL) |
| 404 | return FAIL; |
| 405 | } |
| 406 | #endif |
| 407 | do_cursor = FALSE; |
| 408 | } |
| 409 | } |
| 410 | |
Bram Moolenaar | 59d8e56 | 2020-11-07 18:41:10 +0100 | [diff] [blame] | 411 | if (wp->w_alt_fnum) |
| 412 | { |
| 413 | buf_T *alt = buflist_findnr(wp->w_alt_fnum); |
| 414 | |
Bram Moolenaar | 0756f75 | 2021-03-13 13:52:33 +0100 | [diff] [blame] | 415 | // Set the alternate file if the buffer is listed. |
Bram Moolenaar | 139348f | 2021-02-05 21:55:53 +0100 | [diff] [blame] | 416 | if ((flagp == &ssop_flags) |
| 417 | && alt != NULL |
Bram Moolenaar | 59d8e56 | 2020-11-07 18:41:10 +0100 | [diff] [blame] | 418 | && alt->b_fname != NULL |
| 419 | && *alt->b_fname != NUL |
Bram Moolenaar | 0756f75 | 2021-03-13 13:52:33 +0100 | [diff] [blame] | 420 | && alt->b_p_bl |
Bram Moolenaar | 59d8e56 | 2020-11-07 18:41:10 +0100 | [diff] [blame] | 421 | && (fputs("balt ", fd) < 0 |
| 422 | || ses_fname(fd, alt, flagp, TRUE) == FAIL)) |
| 423 | return FAIL; |
| 424 | } |
| 425 | |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 426 | // Local mappings and abbreviations. |
| 427 | if ((*flagp & (SSOP_OPTIONS | SSOP_LOCALOPTIONS)) |
| 428 | && makemap(fd, wp->w_buffer) == FAIL) |
| 429 | return FAIL; |
| 430 | |
| 431 | // Local options. Need to go to the window temporarily. |
| 432 | // Store only local values when using ":mkview" and when ":mksession" is |
| 433 | // used and 'sessionoptions' doesn't include "options". |
| 434 | // Some folding options are always stored when "folds" is included, |
| 435 | // otherwise the folds would not be restored correctly. |
| 436 | save_curwin = curwin; |
| 437 | curwin = wp; |
| 438 | curbuf = curwin->w_buffer; |
| 439 | if (*flagp & (SSOP_OPTIONS | SSOP_LOCALOPTIONS)) |
| 440 | f = makeset(fd, OPT_LOCAL, |
| 441 | flagp == &vop_flags || !(*flagp & SSOP_OPTIONS)); |
| 442 | #ifdef FEAT_FOLDING |
| 443 | else if (*flagp & SSOP_FOLDS) |
| 444 | f = makefoldset(fd); |
| 445 | #endif |
| 446 | else |
| 447 | f = OK; |
| 448 | curwin = save_curwin; |
| 449 | curbuf = curwin->w_buffer; |
| 450 | if (f == FAIL) |
| 451 | return FAIL; |
| 452 | |
| 453 | #ifdef FEAT_FOLDING |
| 454 | // Save Folds when 'buftype' is empty and for help files. |
| 455 | if ((*flagp & SSOP_FOLDS) |
| 456 | && wp->w_buffer->b_ffname != NULL |
| 457 | && (bt_normal(wp->w_buffer) || bt_help(wp->w_buffer))) |
| 458 | { |
| 459 | if (put_folds(fd, wp) == FAIL) |
| 460 | return FAIL; |
| 461 | } |
| 462 | #endif |
| 463 | |
| 464 | // Set the cursor after creating folds, since that moves the cursor. |
| 465 | if (do_cursor) |
| 466 | { |
| 467 | |
| 468 | // Restore the cursor line in the file and relatively in the |
| 469 | // window. Don't use "G", it changes the jumplist. |
Bram Moolenaar | b6c2e9a | 2021-04-30 21:37:51 +0200 | [diff] [blame] | 470 | if (wp->w_height <= 0) |
| 471 | { |
| 472 | if (fprintf(fd, "let s:l = %ld", (long)wp->w_cursor.lnum) < 0) |
| 473 | return FAIL; |
| 474 | } |
| 475 | else if (fprintf(fd, |
| 476 | "let s:l = %ld - ((%ld * winheight(0) + %ld) / %ld)", |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 477 | (long)wp->w_cursor.lnum, |
| 478 | (long)(wp->w_cursor.lnum - wp->w_topline), |
Bram Moolenaar | b6c2e9a | 2021-04-30 21:37:51 +0200 | [diff] [blame] | 479 | (long)wp->w_height / 2, (long)wp->w_height) < 0) |
| 480 | return FAIL; |
| 481 | |
| 482 | if (put_eol(fd) == FAIL |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 483 | || put_line(fd, "if s:l < 1 | let s:l = 1 | endif") == FAIL |
Bram Moolenaar | 3482be6 | 2020-11-27 11:00:38 +0100 | [diff] [blame] | 484 | || put_line(fd, "keepjumps exe s:l") == FAIL |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 485 | || put_line(fd, "normal! zt") == FAIL |
Bram Moolenaar | 3482be6 | 2020-11-27 11:00:38 +0100 | [diff] [blame] | 486 | || fprintf(fd, "keepjumps %ld", (long)wp->w_cursor.lnum) < 0 |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 487 | || put_eol(fd) == FAIL) |
| 488 | return FAIL; |
| 489 | // Restore the cursor column and left offset when not wrapping. |
| 490 | if (wp->w_cursor.col == 0) |
| 491 | { |
| 492 | if (put_line(fd, "normal! 0") == FAIL) |
| 493 | return FAIL; |
| 494 | } |
| 495 | else |
| 496 | { |
| 497 | if (!wp->w_p_wrap && wp->w_leftcol > 0 && wp->w_width > 0) |
| 498 | { |
| 499 | if (fprintf(fd, |
| 500 | "let s:c = %ld - ((%ld * winwidth(0) + %ld) / %ld)", |
| 501 | (long)wp->w_virtcol + 1, |
| 502 | (long)(wp->w_virtcol - wp->w_leftcol), |
| 503 | (long)wp->w_width / 2, (long)wp->w_width) < 0 |
| 504 | || put_eol(fd) == FAIL |
| 505 | || put_line(fd, "if s:c > 0") == FAIL |
| 506 | || fprintf(fd, |
| 507 | " exe 'normal! ' . s:c . '|zs' . %ld . '|'", |
| 508 | (long)wp->w_virtcol + 1) < 0 |
| 509 | || put_eol(fd) == FAIL |
| 510 | || put_line(fd, "else") == FAIL |
| 511 | || put_view_curpos(fd, wp, " ") == FAIL |
| 512 | || put_line(fd, "endif") == FAIL) |
| 513 | return FAIL; |
| 514 | } |
| 515 | else if (put_view_curpos(fd, wp, "") == FAIL) |
| 516 | return FAIL; |
| 517 | } |
| 518 | } |
| 519 | |
| 520 | // Local directory, if the current flag is not view options or the "curdir" |
| 521 | // option is included. |
| 522 | if (wp->w_localdir != NULL |
| 523 | && (flagp != &vop_flags || (*flagp & SSOP_CURDIR))) |
| 524 | { |
| 525 | if (fputs("lcd ", fd) < 0 |
| 526 | || ses_put_fname(fd, wp->w_localdir, flagp) == FAIL |
| 527 | || put_eol(fd) == FAIL) |
| 528 | return FAIL; |
| 529 | did_lcd = TRUE; |
| 530 | } |
| 531 | |
| 532 | return OK; |
| 533 | } |
| 534 | |
| 535 | #ifdef FEAT_EVAL |
| 536 | static int |
| 537 | store_session_globals(FILE *fd) |
| 538 | { |
Bram Moolenaar | da6c033 | 2019-09-01 16:01:30 +0200 | [diff] [blame] | 539 | hashtab_T *gvht = get_globvar_ht(); |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 540 | hashitem_T *hi; |
| 541 | dictitem_T *this_var; |
| 542 | int todo; |
| 543 | char_u *p, *t; |
| 544 | |
Bram Moolenaar | da6c033 | 2019-09-01 16:01:30 +0200 | [diff] [blame] | 545 | todo = (int)gvht->ht_used; |
| 546 | for (hi = gvht->ht_array; todo > 0; ++hi) |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 547 | { |
| 548 | if (!HASHITEM_EMPTY(hi)) |
| 549 | { |
| 550 | --todo; |
| 551 | this_var = HI2DI(hi); |
| 552 | if ((this_var->di_tv.v_type == VAR_NUMBER |
| 553 | || this_var->di_tv.v_type == VAR_STRING) |
| 554 | && var_flavour(this_var->di_key) == VAR_FLAVOUR_SESSION) |
| 555 | { |
| 556 | // Escape special characters with a backslash. Turn a LF and |
| 557 | // CR into \n and \r. |
| 558 | p = vim_strsave_escaped(tv_get_string(&this_var->di_tv), |
| 559 | (char_u *)"\\\"\n\r"); |
| 560 | if (p == NULL) // out of memory |
| 561 | break; |
| 562 | for (t = p; *t != NUL; ++t) |
| 563 | if (*t == '\n') |
| 564 | *t = 'n'; |
| 565 | else if (*t == '\r') |
| 566 | *t = 'r'; |
| 567 | if ((fprintf(fd, "let %s = %c%s%c", |
| 568 | this_var->di_key, |
| 569 | (this_var->di_tv.v_type == VAR_STRING) ? '"' |
| 570 | : ' ', |
| 571 | p, |
| 572 | (this_var->di_tv.v_type == VAR_STRING) ? '"' |
| 573 | : ' ') < 0) |
| 574 | || put_eol(fd) == FAIL) |
| 575 | { |
| 576 | vim_free(p); |
| 577 | return FAIL; |
| 578 | } |
| 579 | vim_free(p); |
| 580 | } |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 581 | else if (this_var->di_tv.v_type == VAR_FLOAT |
| 582 | && var_flavour(this_var->di_key) == VAR_FLAVOUR_SESSION) |
| 583 | { |
| 584 | float_T f = this_var->di_tv.vval.v_float; |
| 585 | int sign = ' '; |
| 586 | |
| 587 | if (f < 0) |
| 588 | { |
| 589 | f = -f; |
| 590 | sign = '-'; |
| 591 | } |
| 592 | if ((fprintf(fd, "let %s = %c%f", |
| 593 | this_var->di_key, sign, f) < 0) |
| 594 | || put_eol(fd) == FAIL) |
| 595 | return FAIL; |
| 596 | } |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 597 | } |
| 598 | } |
| 599 | return OK; |
| 600 | } |
| 601 | #endif |
| 602 | |
| 603 | /* |
| 604 | * Write openfile commands for the current buffers to an .exrc file. |
| 605 | * Return FAIL on error, OK otherwise. |
| 606 | */ |
| 607 | static int |
| 608 | makeopens( |
| 609 | FILE *fd, |
| 610 | char_u *dirnow) // Current directory name |
| 611 | { |
| 612 | buf_T *buf; |
| 613 | int only_save_windows = TRUE; |
| 614 | int nr; |
| 615 | int restore_size = TRUE; |
Bram Moolenaar | b4011af | 2022-05-01 00:42:24 +0100 | [diff] [blame] | 616 | int restore_height_width = FALSE; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 617 | win_T *wp; |
| 618 | char_u *sname; |
| 619 | win_T *edited_win = NULL; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 620 | int restore_stal = FALSE; |
| 621 | win_T *tab_firstwin; |
| 622 | frame_T *tab_topframe; |
| 623 | int cur_arg_idx = 0; |
| 624 | int next_arg_idx = 0; |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 625 | int ret = FAIL; |
LemonBoy | d7c9564 | 2022-04-30 16:10:27 +0100 | [diff] [blame] | 626 | tabpage_T *tp; |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 627 | #ifdef FEAT_TERMINAL |
| 628 | hashtab_T terminal_bufs; |
| 629 | |
| 630 | hash_init(&terminal_bufs); |
| 631 | #endif |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 632 | |
| 633 | if (ssop_flags & SSOP_BUFFERS) |
| 634 | only_save_windows = FALSE; // Save ALL buffers |
| 635 | |
| 636 | // Begin by setting the this_session variable, and then other |
| 637 | // sessionable variables. |
| 638 | #ifdef FEAT_EVAL |
| 639 | if (put_line(fd, "let v:this_session=expand(\"<sfile>:p\")") == FAIL) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 640 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 641 | if (ssop_flags & SSOP_GLOBALS) |
| 642 | if (store_session_globals(fd) == FAIL) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 643 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 644 | #endif |
| 645 | |
| 646 | // Close all windows and tabs but one. |
| 647 | if (put_line(fd, "silent only") == FAIL) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 648 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 649 | if ((ssop_flags & SSOP_TABPAGES) |
| 650 | && put_line(fd, "silent tabonly") == FAIL) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 651 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 652 | |
| 653 | // Now a :cd command to the session directory or the current directory |
| 654 | if (ssop_flags & SSOP_SESDIR) |
| 655 | { |
| 656 | if (put_line(fd, "exe \"cd \" . escape(expand(\"<sfile>:p:h\"), ' ')") |
| 657 | == FAIL) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 658 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 659 | } |
| 660 | else if (ssop_flags & SSOP_CURDIR) |
| 661 | { |
| 662 | sname = home_replace_save(NULL, globaldir != NULL ? globaldir : dirnow); |
| 663 | if (sname == NULL |
| 664 | || fputs("cd ", fd) < 0 |
| 665 | || ses_put_fname(fd, sname, &ssop_flags) == FAIL |
| 666 | || put_eol(fd) == FAIL) |
| 667 | { |
| 668 | vim_free(sname); |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 669 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 670 | } |
| 671 | vim_free(sname); |
| 672 | } |
| 673 | |
| 674 | // If there is an empty, unnamed buffer we will wipe it out later. |
| 675 | // Remember the buffer number. |
| 676 | if (put_line(fd, "if expand('%') == '' && !&modified && line('$') <= 1 && getline(1) == ''") == FAIL) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 677 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 678 | if (put_line(fd, " let s:wipebuf = bufnr('%')") == FAIL) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 679 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 680 | if (put_line(fd, "endif") == FAIL) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 681 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 682 | |
James Cherti | fd01280 | 2022-03-29 12:02:57 +0100 | [diff] [blame] | 683 | // save 'shortmess' if not storing options |
| 684 | if ((ssop_flags & SSOP_OPTIONS) == 0 |
| 685 | && put_line(fd, "let s:shortmess_save = &shortmess") == FAIL) |
| 686 | goto fail; |
| 687 | |
Bram Moolenaar | aaadb5b | 2022-05-18 22:07:47 +0100 | [diff] [blame] | 688 | // set 'shortmess' for the following. Add the 'A' flag if it was there |
| 689 | if (put_line(fd, "if &shortmess =~ 'A'") == FAIL |
| 690 | || put_line(fd, " set shortmess=aoOA") == FAIL |
| 691 | || put_line(fd, "else") == FAIL |
| 692 | || put_line(fd, " set shortmess=aoO") == FAIL |
| 693 | || put_line(fd, "endif") == FAIL) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 694 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 695 | |
Bram Moolenaar | aaadb5b | 2022-05-18 22:07:47 +0100 | [diff] [blame] | 696 | // Now save the current files, current buffer first. |
Evgeni Chasnovski | 26ebf1f | 2022-01-14 13:19:43 +0000 | [diff] [blame] | 697 | // Put all buffers into the buffer list. |
| 698 | // Do it very early to preserve buffer order after loading session (which |
| 699 | // can be disrupted by prior `edit` or `tabedit` calls). |
| 700 | FOR_ALL_BUFFERS(buf) |
| 701 | { |
| 702 | if (!(only_save_windows && buf->b_nwindows == 0) |
| 703 | && !(buf->b_help && !(ssop_flags & SSOP_HELP)) |
Evgeni Chasnovski | 26ebf1f | 2022-01-14 13:19:43 +0000 | [diff] [blame] | 704 | // Skip terminal buffers: finished ones are not useful, others |
| 705 | // will be resurrected and result in a new buffer. |
| 706 | && !bt_terminal(buf) |
Evgeni Chasnovski | 26ebf1f | 2022-01-14 13:19:43 +0000 | [diff] [blame] | 707 | && buf->b_fname != NULL |
| 708 | && buf->b_p_bl) |
| 709 | { |
| 710 | if (fprintf(fd, "badd +%ld ", buf->b_wininfo == NULL ? 1L |
| 711 | : buf->b_wininfo->wi_fpos.lnum) < 0 |
| 712 | || ses_fname(fd, buf, &ssop_flags, TRUE) == FAIL) |
| 713 | goto fail; |
| 714 | } |
| 715 | } |
| 716 | |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 717 | // the global argument list |
| 718 | if (ses_arglist(fd, "argglobal", &global_alist.al_ga, |
| 719 | !(ssop_flags & SSOP_CURDIR), &ssop_flags) == FAIL) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 720 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 721 | |
| 722 | if (ssop_flags & SSOP_RESIZE) |
| 723 | { |
| 724 | // Note: after the restore we still check it worked! |
| 725 | if (fprintf(fd, "set lines=%ld columns=%ld" , Rows, Columns) < 0 |
| 726 | || put_eol(fd) == FAIL) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 727 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 728 | } |
| 729 | |
| 730 | #ifdef FEAT_GUI |
| 731 | if (gui.in_use && (ssop_flags & SSOP_WINPOS)) |
| 732 | { |
| 733 | int x, y; |
| 734 | |
| 735 | if (gui_mch_get_winpos(&x, &y) == OK) |
| 736 | { |
| 737 | // Note: after the restore we still check it worked! |
| 738 | if (fprintf(fd, "winpos %d %d", x, y) < 0 || put_eol(fd) == FAIL) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 739 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 740 | } |
| 741 | } |
| 742 | #endif |
| 743 | |
| 744 | // When there are two or more tabpages and 'showtabline' is 1 the tabline |
| 745 | // will be displayed when creating the next tab. That resizes the windows |
| 746 | // in the first tab, which may cause problems. Set 'showtabline' to 2 |
| 747 | // temporarily to avoid that. |
| 748 | if (p_stal == 1 && first_tabpage->tp_next != NULL) |
| 749 | { |
| 750 | if (put_line(fd, "set stal=2") == FAIL) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 751 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 752 | restore_stal = TRUE; |
| 753 | } |
| 754 | |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 755 | if ((ssop_flags & SSOP_TABPAGES)) |
| 756 | { |
LemonBoy | d7c9564 | 2022-04-30 16:10:27 +0100 | [diff] [blame] | 757 | // "tabpages" is in 'sessionoptions': Similar to ses_win_rec() below, |
| 758 | // populate the tab pages first so later local options won't be copied |
| 759 | // to the new tabs. |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 760 | FOR_ALL_TABPAGES(tp) |
Evgeni Chasnovski | 26ebf1f | 2022-01-14 13:19:43 +0000 | [diff] [blame] | 761 | // Use `bufhidden=wipe` to remove empty "placeholder" buffers once |
| 762 | // they are not needed. This prevents creating extra buffers (see |
| 763 | // cause of patch 8.1.0829) |
| 764 | if (tp->tp_next != NULL |
| 765 | && put_line(fd, "tabnew +setlocal\\ bufhidden=wipe") == FAIL) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 766 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 767 | if (first_tabpage->tp_next != NULL && put_line(fd, "tabrewind") == FAIL) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 768 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 769 | } |
LemonBoy | d7c9564 | 2022-04-30 16:10:27 +0100 | [diff] [blame] | 770 | |
| 771 | // Assume "tabpages" is in 'sessionoptions'. If not then we only do |
| 772 | // "curtab" and bail out of the loop. |
| 773 | FOR_ALL_TABPAGES(tp) |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 774 | { |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 775 | int need_tabnext = FALSE; |
| 776 | int cnr = 1; |
| 777 | |
LemonBoy | d7c9564 | 2022-04-30 16:10:27 +0100 | [diff] [blame] | 778 | // May repeat putting Windows for each tab, when "tabpages" is in |
| 779 | // 'sessionoptions'. |
| 780 | // Don't use goto_tabpage(), it may change directory and trigger |
| 781 | // autocommands. |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 782 | if ((ssop_flags & SSOP_TABPAGES)) |
| 783 | { |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 784 | if (tp == curtab) |
| 785 | { |
| 786 | tab_firstwin = firstwin; |
| 787 | tab_topframe = topframe; |
| 788 | } |
| 789 | else |
| 790 | { |
| 791 | tab_firstwin = tp->tp_firstwin; |
| 792 | tab_topframe = tp->tp_topframe; |
| 793 | } |
LemonBoy | d7c9564 | 2022-04-30 16:10:27 +0100 | [diff] [blame] | 794 | if (tp != first_tabpage) |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 795 | need_tabnext = TRUE; |
| 796 | } |
LemonBoy | d7c9564 | 2022-04-30 16:10:27 +0100 | [diff] [blame] | 797 | else |
| 798 | { |
| 799 | tp = curtab; |
| 800 | tab_firstwin = firstwin; |
| 801 | tab_topframe = topframe; |
| 802 | } |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 803 | |
| 804 | // Before creating the window layout, try loading one file. If this |
| 805 | // is aborted we don't end up with a number of useless windows. |
| 806 | // This may have side effects! (e.g., compressed or network file). |
| 807 | for (wp = tab_firstwin; wp != NULL; wp = wp->w_next) |
| 808 | { |
| 809 | if (ses_do_win(wp) |
| 810 | && wp->w_buffer->b_ffname != NULL |
| 811 | && !bt_help(wp->w_buffer) |
Bram Moolenaar | 6d4b2f5 | 2022-08-25 15:11:15 +0100 | [diff] [blame] | 812 | && !bt_nofilename(wp->w_buffer)) |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 813 | { |
| 814 | if (need_tabnext && put_line(fd, "tabnext") == FAIL) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 815 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 816 | need_tabnext = FALSE; |
| 817 | |
| 818 | if (fputs("edit ", fd) < 0 |
| 819 | || ses_fname(fd, wp->w_buffer, &ssop_flags, TRUE) |
| 820 | == FAIL) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 821 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 822 | if (!wp->w_arg_idx_invalid) |
| 823 | edited_win = wp; |
| 824 | break; |
| 825 | } |
| 826 | } |
| 827 | |
| 828 | // If no file got edited create an empty tab page. |
| 829 | if (need_tabnext && put_line(fd, "tabnext") == FAIL) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 830 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 831 | |
Bram Moolenaar | 0995c81 | 2021-04-17 18:38:54 +0200 | [diff] [blame] | 832 | if (tab_topframe->fr_layout != FR_LEAF) |
| 833 | { |
| 834 | // Save current window layout. |
| 835 | if (put_line(fd, "let s:save_splitbelow = &splitbelow") == FAIL |
| 836 | || put_line(fd, "let s:save_splitright = &splitright") |
| 837 | == FAIL) |
| 838 | goto fail; |
| 839 | if (put_line(fd, "set splitbelow splitright") == FAIL) |
| 840 | goto fail; |
| 841 | if (ses_win_rec(fd, tab_topframe) == FAIL) |
| 842 | goto fail; |
| 843 | if (put_line(fd, "let &splitbelow = s:save_splitbelow") == FAIL |
| 844 | || put_line(fd, "let &splitright = s:save_splitright") |
| 845 | == FAIL) |
| 846 | goto fail; |
| 847 | } |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 848 | |
| 849 | // Check if window sizes can be restored (no windows omitted). |
| 850 | // Remember the window number of the current window after restoring. |
| 851 | nr = 0; |
| 852 | for (wp = tab_firstwin; wp != NULL; wp = W_NEXT(wp)) |
| 853 | { |
| 854 | if (ses_do_win(wp)) |
| 855 | ++nr; |
| 856 | else |
| 857 | restore_size = FALSE; |
| 858 | if (curwin == wp) |
| 859 | cnr = nr; |
| 860 | } |
| 861 | |
Bram Moolenaar | 0995c81 | 2021-04-17 18:38:54 +0200 | [diff] [blame] | 862 | if (tab_firstwin->w_next != NULL) |
| 863 | { |
| 864 | // Go to the first window. |
| 865 | if (put_line(fd, "wincmd t") == FAIL) |
| 866 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 867 | |
Bram Moolenaar | 0995c81 | 2021-04-17 18:38:54 +0200 | [diff] [blame] | 868 | // If more than one window, see if sizes can be restored. |
| 869 | // First set 'winheight' and 'winwidth' to 1 to avoid the windows |
| 870 | // being resized when moving between windows. |
| 871 | // Do this before restoring the view, so that the topline and the |
| 872 | // cursor can be set. This is done again below. |
| 873 | // winminheight and winminwidth need to be set to avoid an error if |
| 874 | // the user has set winheight or winwidth. |
| 875 | if (put_line(fd, "let s:save_winminheight = &winminheight") == FAIL |
| 876 | || put_line(fd, "let s:save_winminwidth = &winminwidth") |
| 877 | == FAIL) |
| 878 | goto fail; |
| 879 | if (put_line(fd, "set winminheight=0") == FAIL |
| 880 | || put_line(fd, "set winheight=1") == FAIL |
| 881 | || put_line(fd, "set winminwidth=0") == FAIL |
| 882 | || put_line(fd, "set winwidth=1") == FAIL) |
| 883 | goto fail; |
Bram Moolenaar | b4011af | 2022-05-01 00:42:24 +0100 | [diff] [blame] | 884 | restore_height_width = TRUE; |
Bram Moolenaar | 0995c81 | 2021-04-17 18:38:54 +0200 | [diff] [blame] | 885 | } |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 886 | if (nr > 1 && ses_winsizes(fd, restore_size, tab_firstwin) == FAIL) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 887 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 888 | |
| 889 | // Restore the tab-local working directory if specified |
| 890 | // Do this before the windows, so that the window-local directory can |
| 891 | // override the tab-local directory. |
LemonBoy | d7c9564 | 2022-04-30 16:10:27 +0100 | [diff] [blame] | 892 | if ((ssop_flags & SSOP_CURDIR) && tp->tp_localdir != NULL) |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 893 | { |
| 894 | if (fputs("tcd ", fd) < 0 |
LemonBoy | d7c9564 | 2022-04-30 16:10:27 +0100 | [diff] [blame] | 895 | || ses_put_fname(fd, tp->tp_localdir, &ssop_flags) == FAIL |
| 896 | || put_eol(fd) == FAIL) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 897 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 898 | did_lcd = TRUE; |
| 899 | } |
| 900 | |
| 901 | // Restore the view of the window (options, file, cursor, etc.). |
| 902 | for (wp = tab_firstwin; wp != NULL; wp = wp->w_next) |
| 903 | { |
| 904 | if (!ses_do_win(wp)) |
| 905 | continue; |
Bram Moolenaar | c2c8205 | 2020-09-11 22:10:22 +0200 | [diff] [blame] | 906 | if (put_view(fd, wp, wp != edited_win, &ssop_flags, cur_arg_idx, |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 907 | #ifdef FEAT_TERMINAL |
Bram Moolenaar | c2c8205 | 2020-09-11 22:10:22 +0200 | [diff] [blame] | 908 | &terminal_bufs |
| 909 | #else |
| 910 | NULL |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 911 | #endif |
| 912 | ) == FAIL) |
| 913 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 914 | if (nr > 1 && put_line(fd, "wincmd w") == FAIL) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 915 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 916 | next_arg_idx = wp->w_arg_idx; |
| 917 | } |
| 918 | |
| 919 | // The argument index in the first tab page is zero, need to set it in |
| 920 | // each window. For further tab pages it's the window where we do |
| 921 | // "tabedit". |
| 922 | cur_arg_idx = next_arg_idx; |
| 923 | |
| 924 | // Restore cursor to the current window if it's not the first one. |
| 925 | if (cnr > 1 && (fprintf(fd, "%dwincmd w", cnr) < 0 |
| 926 | || put_eol(fd) == FAIL)) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 927 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 928 | |
| 929 | // Restore window sizes again after jumping around in windows, because |
| 930 | // the current window has a minimum size while others may not. |
| 931 | if (nr > 1 && ses_winsizes(fd, restore_size, tab_firstwin) == FAIL) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 932 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 933 | |
| 934 | // Don't continue in another tab page when doing only the current one |
| 935 | // or when at the last tab page. |
| 936 | if (!(ssop_flags & SSOP_TABPAGES)) |
| 937 | break; |
| 938 | } |
| 939 | |
| 940 | if (ssop_flags & SSOP_TABPAGES) |
| 941 | { |
| 942 | if (fprintf(fd, "tabnext %d", tabpage_index(curtab)) < 0 |
| 943 | || put_eol(fd) == FAIL) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 944 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 945 | } |
| 946 | if (restore_stal && put_line(fd, "set stal=1") == FAIL) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 947 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 948 | |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 949 | // Wipe out an empty unnamed buffer we started in. |
| 950 | if (put_line(fd, "if exists('s:wipebuf') && len(win_findbuf(s:wipebuf)) == 0") |
| 951 | == FAIL) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 952 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 953 | if (put_line(fd, " silent exe 'bwipe ' . s:wipebuf") == FAIL) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 954 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 955 | if (put_line(fd, "endif") == FAIL) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 956 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 957 | if (put_line(fd, "unlet! s:wipebuf") == FAIL) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 958 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 959 | |
James Cherti | fd01280 | 2022-03-29 12:02:57 +0100 | [diff] [blame] | 960 | // Re-apply 'winheight' and 'winwidth'. |
| 961 | if (fprintf(fd, "set winheight=%ld winwidth=%ld", |
| 962 | p_wh, p_wiw) < 0 || put_eol(fd) == FAIL) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 963 | goto fail; |
James Cherti | fd01280 | 2022-03-29 12:02:57 +0100 | [diff] [blame] | 964 | |
| 965 | // Restore 'shortmess'. |
| 966 | if (ssop_flags & SSOP_OPTIONS) |
| 967 | { |
Bram Moolenaar | 6ed545e | 2022-05-09 20:09:23 +0100 | [diff] [blame] | 968 | if (fprintf(fd, "set shortmess=%s", p_shm) < 0 || put_eol(fd) == FAIL) |
| 969 | goto fail; |
James Cherti | fd01280 | 2022-03-29 12:02:57 +0100 | [diff] [blame] | 970 | } |
| 971 | else |
| 972 | { |
Bram Moolenaar | 6ed545e | 2022-05-09 20:09:23 +0100 | [diff] [blame] | 973 | if (put_line(fd, "let &shortmess = s:shortmess_save") == FAIL) |
| 974 | goto fail; |
James Cherti | fd01280 | 2022-03-29 12:02:57 +0100 | [diff] [blame] | 975 | } |
| 976 | |
Bram Moolenaar | b4011af | 2022-05-01 00:42:24 +0100 | [diff] [blame] | 977 | if (restore_height_width) |
Bram Moolenaar | 0995c81 | 2021-04-17 18:38:54 +0200 | [diff] [blame] | 978 | { |
| 979 | // Restore 'winminheight' and 'winminwidth'. |
| 980 | if (put_line(fd, "let &winminheight = s:save_winminheight") == FAIL |
| 981 | || put_line(fd, "let &winminwidth = s:save_winminwidth") == FAIL) |
| 982 | goto fail; |
| 983 | } |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 984 | |
| 985 | // Lastly, execute the x.vim file if it exists. |
| 986 | if (put_line(fd, "let s:sx = expand(\"<sfile>:p:r\").\"x.vim\"") == FAIL |
Bram Moolenaar | c5f33db | 2020-04-16 21:04:41 +0200 | [diff] [blame] | 987 | || put_line(fd, "if filereadable(s:sx)") == FAIL |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 988 | || put_line(fd, " exe \"source \" . fnameescape(s:sx)") == FAIL |
| 989 | || put_line(fd, "endif") == FAIL) |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 990 | goto fail; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 991 | |
Bram Moolenaar | 0e65511 | 2020-09-11 20:36:36 +0200 | [diff] [blame] | 992 | ret = OK; |
| 993 | fail: |
| 994 | #ifdef FEAT_TERMINAL |
| 995 | hash_clear_all(&terminal_bufs, 0); |
| 996 | #endif |
| 997 | return ret; |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 998 | } |
| 999 | |
| 1000 | /* |
| 1001 | * Get the name of the view file for the current buffer. |
| 1002 | */ |
| 1003 | static char_u * |
| 1004 | get_view_file(int c) |
| 1005 | { |
| 1006 | int len = 0; |
| 1007 | char_u *p, *s; |
| 1008 | char_u *retval; |
| 1009 | char_u *sname; |
| 1010 | |
| 1011 | if (curbuf->b_ffname == NULL) |
| 1012 | { |
Bram Moolenaar | e29a27f | 2021-07-20 21:07:36 +0200 | [diff] [blame] | 1013 | emsg(_(e_no_file_name)); |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 1014 | return NULL; |
| 1015 | } |
| 1016 | sname = home_replace_save(NULL, curbuf->b_ffname); |
| 1017 | if (sname == NULL) |
| 1018 | return NULL; |
| 1019 | |
| 1020 | // We want a file name without separators, because we're not going to make |
| 1021 | // a directory. |
| 1022 | // "normal" path separator -> "=+" |
| 1023 | // "=" -> "==" |
| 1024 | // ":" path separator -> "=-" |
| 1025 | for (p = sname; *p; ++p) |
| 1026 | if (*p == '=' || vim_ispathsep(*p)) |
| 1027 | ++len; |
| 1028 | retval = alloc(STRLEN(sname) + len + STRLEN(p_vdir) + 9); |
| 1029 | if (retval != NULL) |
| 1030 | { |
| 1031 | STRCPY(retval, p_vdir); |
| 1032 | add_pathsep(retval); |
| 1033 | s = retval + STRLEN(retval); |
| 1034 | for (p = sname; *p; ++p) |
| 1035 | { |
| 1036 | if (*p == '=') |
| 1037 | { |
| 1038 | *s++ = '='; |
| 1039 | *s++ = '='; |
| 1040 | } |
| 1041 | else if (vim_ispathsep(*p)) |
| 1042 | { |
| 1043 | *s++ = '='; |
| 1044 | #if defined(BACKSLASH_IN_FILENAME) || defined(AMIGA) || defined(VMS) |
| 1045 | if (*p == ':') |
| 1046 | *s++ = '-'; |
| 1047 | else |
| 1048 | #endif |
| 1049 | *s++ = '+'; |
| 1050 | } |
| 1051 | else |
| 1052 | *s++ = *p; |
| 1053 | } |
| 1054 | *s++ = '='; |
| 1055 | *s++ = c; |
| 1056 | STRCPY(s, ".vim"); |
| 1057 | } |
| 1058 | |
| 1059 | vim_free(sname); |
| 1060 | return retval; |
| 1061 | } |
| 1062 | |
| 1063 | /* |
| 1064 | * ":loadview [nr]" |
| 1065 | */ |
| 1066 | void |
| 1067 | ex_loadview(exarg_T *eap) |
| 1068 | { |
| 1069 | char_u *fname; |
| 1070 | |
| 1071 | fname = get_view_file(*eap->arg); |
Yegappan Lakshmanan | 6ec6666 | 2023-01-23 20:46:21 +0000 | [diff] [blame] | 1072 | if (fname == NULL) |
| 1073 | return; |
| 1074 | |
| 1075 | do_source(fname, FALSE, DOSO_NONE, NULL); |
| 1076 | vim_free(fname); |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 1077 | } |
| 1078 | |
Bram Moolenaar | d17a57a | 2019-09-29 20:53:55 +0200 | [diff] [blame] | 1079 | # if defined(FEAT_GUI_GNOME) \ |
Bram Moolenaar | ac02a63 | 2019-09-29 19:02:46 +0200 | [diff] [blame] | 1080 | || (defined(GUI_MAY_SPAWN) && defined(EXPERIMENTAL_GUI_CMD)) \ |
| 1081 | || defined(PROTO) |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 1082 | /* |
| 1083 | * Generate a script that can be used to restore the current editing session. |
| 1084 | * Save the value of v:this_session before running :mksession in order to make |
| 1085 | * automagic session save fully transparent. Return TRUE on success. |
| 1086 | */ |
| 1087 | int |
| 1088 | write_session_file(char_u *filename) |
| 1089 | { |
| 1090 | char_u *escaped_filename; |
| 1091 | char *mksession_cmdline; |
| 1092 | unsigned int save_ssop_flags; |
| 1093 | int failed; |
| 1094 | |
| 1095 | // Build an ex command line to create a script that restores the current |
| 1096 | // session if executed. Escape the filename to avoid nasty surprises. |
| 1097 | escaped_filename = vim_strsave_escaped(filename, escape_chars); |
| 1098 | if (escaped_filename == NULL) |
| 1099 | return FALSE; |
| 1100 | mksession_cmdline = alloc(10 + (int)STRLEN(escaped_filename) + 1); |
| 1101 | if (mksession_cmdline == NULL) |
| 1102 | { |
| 1103 | vim_free(escaped_filename); |
| 1104 | return FALSE; |
| 1105 | } |
| 1106 | strcpy(mksession_cmdline, "mksession "); |
| 1107 | STRCAT(mksession_cmdline, escaped_filename); |
| 1108 | vim_free(escaped_filename); |
| 1109 | |
| 1110 | // Use a reasonable hardcoded set of 'sessionoptions' flags to avoid |
| 1111 | // unpredictable effects when the session is saved automatically. Also, |
| 1112 | // we definitely need SSOP_GLOBALS to be able to restore v:this_session. |
| 1113 | // Don't use SSOP_BUFFERS to prevent the buffer list from becoming |
| 1114 | // enormously large if the GNOME session feature is used regularly. |
| 1115 | save_ssop_flags = ssop_flags; |
| 1116 | ssop_flags = (SSOP_BLANK|SSOP_CURDIR|SSOP_FOLDS|SSOP_GLOBALS |
| 1117 | |SSOP_HELP|SSOP_OPTIONS|SSOP_WINSIZE|SSOP_TABPAGES); |
| 1118 | |
| 1119 | do_cmdline_cmd((char_u *)"let Save_VV_this_session = v:this_session"); |
| 1120 | failed = (do_cmdline_cmd((char_u *)mksession_cmdline) == FAIL); |
| 1121 | do_cmdline_cmd((char_u *)"let v:this_session = Save_VV_this_session"); |
| 1122 | do_unlet((char_u *)"Save_VV_this_session", TRUE); |
| 1123 | |
| 1124 | ssop_flags = save_ssop_flags; |
| 1125 | vim_free(mksession_cmdline); |
| 1126 | |
| 1127 | // Reopen the file and append a command to restore v:this_session, |
| 1128 | // as if this save never happened. This is to avoid conflicts with |
| 1129 | // the user's own sessions. FIXME: It's probably less hackish to add |
| 1130 | // a "stealth" flag to 'sessionoptions' -- gotta ask Bram. |
| 1131 | if (!failed) |
| 1132 | { |
| 1133 | FILE *fd; |
| 1134 | |
| 1135 | fd = open_exfile(filename, TRUE, APPENDBIN); |
| 1136 | |
| 1137 | failed = (fd == NULL |
| 1138 | || put_line(fd, "let v:this_session = Save_VV_this_session") |
| 1139 | == FAIL |
| 1140 | || put_line(fd, "unlet Save_VV_this_session") == FAIL); |
| 1141 | |
| 1142 | if (fd != NULL && fclose(fd) != 0) |
| 1143 | failed = TRUE; |
| 1144 | |
| 1145 | if (failed) |
| 1146 | mch_remove(filename); |
| 1147 | } |
| 1148 | |
| 1149 | return !failed; |
| 1150 | } |
| 1151 | # endif |
| 1152 | |
| 1153 | #endif // FEAT_SESSION |
| 1154 | |
| 1155 | #if defined(FEAT_SESSION) && defined(USE_CRNL) |
| 1156 | # define MKSESSION_NL |
| 1157 | static int mksession_nl = FALSE; // use NL only in put_eol() |
| 1158 | #endif |
| 1159 | |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 1160 | /* |
| 1161 | * ":mkexrc", ":mkvimrc", ":mkview" and ":mksession". |
| 1162 | */ |
| 1163 | void |
| 1164 | ex_mkrc(exarg_T *eap) |
| 1165 | { |
| 1166 | FILE *fd; |
| 1167 | int failed = FALSE; |
| 1168 | char_u *fname; |
| 1169 | #ifdef FEAT_BROWSE |
| 1170 | char_u *browseFile = NULL; |
| 1171 | #endif |
| 1172 | #ifdef FEAT_SESSION |
| 1173 | int view_session = FALSE; |
| 1174 | int using_vdir = FALSE; // using 'viewdir'? |
| 1175 | char_u *viewFile = NULL; |
| 1176 | unsigned *flagp; |
| 1177 | #endif |
| 1178 | |
| 1179 | if (eap->cmdidx == CMD_mksession || eap->cmdidx == CMD_mkview) |
| 1180 | { |
| 1181 | #ifdef FEAT_SESSION |
| 1182 | view_session = TRUE; |
| 1183 | #else |
| 1184 | ex_ni(eap); |
| 1185 | return; |
| 1186 | #endif |
| 1187 | } |
| 1188 | |
| 1189 | #ifdef FEAT_SESSION |
| 1190 | // Use the short file name until ":lcd" is used. We also don't use the |
| 1191 | // short file name when 'acd' is set, that is checked later. |
| 1192 | did_lcd = FALSE; |
| 1193 | |
| 1194 | // ":mkview" or ":mkview 9": generate file name with 'viewdir' |
| 1195 | if (eap->cmdidx == CMD_mkview |
| 1196 | && (*eap->arg == NUL |
| 1197 | || (vim_isdigit(*eap->arg) && eap->arg[1] == NUL))) |
| 1198 | { |
| 1199 | eap->forceit = TRUE; |
| 1200 | fname = get_view_file(*eap->arg); |
| 1201 | if (fname == NULL) |
| 1202 | return; |
| 1203 | viewFile = fname; |
| 1204 | using_vdir = TRUE; |
| 1205 | } |
| 1206 | else |
| 1207 | #endif |
| 1208 | if (*eap->arg != NUL) |
| 1209 | fname = eap->arg; |
| 1210 | else if (eap->cmdidx == CMD_mkvimrc) |
| 1211 | fname = (char_u *)VIMRC_FILE; |
| 1212 | #ifdef FEAT_SESSION |
| 1213 | else if (eap->cmdidx == CMD_mksession) |
| 1214 | fname = (char_u *)SESSION_FILE; |
| 1215 | #endif |
| 1216 | else |
| 1217 | fname = (char_u *)EXRC_FILE; |
| 1218 | |
| 1219 | #ifdef FEAT_BROWSE |
Bram Moolenaar | e100440 | 2020-10-24 20:49:43 +0200 | [diff] [blame] | 1220 | if (cmdmod.cmod_flags & CMOD_BROWSE) |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 1221 | { |
| 1222 | browseFile = do_browse(BROWSE_SAVE, |
| 1223 | # ifdef FEAT_SESSION |
| 1224 | eap->cmdidx == CMD_mkview ? (char_u *)_("Save View") : |
| 1225 | eap->cmdidx == CMD_mksession ? (char_u *)_("Save Session") : |
| 1226 | # endif |
| 1227 | (char_u *)_("Save Setup"), |
| 1228 | fname, (char_u *)"vim", NULL, |
| 1229 | (char_u *)_(BROWSE_FILTER_MACROS), NULL); |
| 1230 | if (browseFile == NULL) |
| 1231 | goto theend; |
| 1232 | fname = browseFile; |
| 1233 | eap->forceit = TRUE; // since dialog already asked |
| 1234 | } |
| 1235 | #endif |
| 1236 | |
| 1237 | #if defined(FEAT_SESSION) && defined(vim_mkdir) |
| 1238 | // When using 'viewdir' may have to create the directory. |
| 1239 | if (using_vdir && !mch_isdir(p_vdir)) |
| 1240 | vim_mkdir_emsg(p_vdir, 0755); |
| 1241 | #endif |
| 1242 | |
| 1243 | fd = open_exfile(fname, eap->forceit, WRITEBIN); |
| 1244 | if (fd != NULL) |
| 1245 | { |
| 1246 | #ifdef FEAT_SESSION |
| 1247 | if (eap->cmdidx == CMD_mkview) |
| 1248 | flagp = &vop_flags; |
| 1249 | else |
| 1250 | flagp = &ssop_flags; |
| 1251 | #endif |
| 1252 | |
| 1253 | #ifdef MKSESSION_NL |
| 1254 | // "unix" in 'sessionoptions': use NL line separator |
| 1255 | if (view_session && (*flagp & SSOP_UNIX)) |
| 1256 | mksession_nl = TRUE; |
| 1257 | #endif |
| 1258 | |
| 1259 | // Write the version command for :mkvimrc |
| 1260 | if (eap->cmdidx == CMD_mkvimrc) |
| 1261 | (void)put_line(fd, "version 6.0"); |
| 1262 | |
| 1263 | #ifdef FEAT_SESSION |
| 1264 | if (eap->cmdidx == CMD_mksession) |
| 1265 | { |
| 1266 | if (put_line(fd, "let SessionLoad = 1") == FAIL) |
| 1267 | failed = TRUE; |
| 1268 | } |
| 1269 | |
| 1270 | if (eap->cmdidx != CMD_mkview) |
| 1271 | #endif |
| 1272 | { |
| 1273 | // Write setting 'compatible' first, because it has side effects. |
| 1274 | // For that same reason only do it when needed. |
| 1275 | if (p_cp) |
| 1276 | (void)put_line(fd, "if !&cp | set cp | endif"); |
| 1277 | else |
| 1278 | (void)put_line(fd, "if &cp | set nocp | endif"); |
| 1279 | } |
| 1280 | |
| 1281 | #ifdef FEAT_SESSION |
| 1282 | if (!view_session |
| 1283 | || (eap->cmdidx == CMD_mksession |
| 1284 | && (*flagp & SSOP_OPTIONS))) |
| 1285 | #endif |
Bram Moolenaar | 635bd60 | 2021-04-16 19:58:22 +0200 | [diff] [blame] | 1286 | { |
| 1287 | int flags = OPT_GLOBAL; |
| 1288 | |
| 1289 | #ifdef FEAT_SESSION |
| 1290 | if (eap->cmdidx == CMD_mksession && (*flagp & SSOP_SKIP_RTP)) |
| 1291 | flags |= OPT_SKIPRTP; |
| 1292 | #endif |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 1293 | failed |= (makemap(fd, NULL) == FAIL |
Bram Moolenaar | 635bd60 | 2021-04-16 19:58:22 +0200 | [diff] [blame] | 1294 | || makeset(fd, flags, FALSE) == FAIL); |
| 1295 | } |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 1296 | |
| 1297 | #ifdef FEAT_SESSION |
| 1298 | if (!failed && view_session) |
| 1299 | { |
Bram Moolenaar | 3889083 | 2020-11-01 17:40:54 +0100 | [diff] [blame] | 1300 | 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) |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 1301 | failed = TRUE; |
| 1302 | if (eap->cmdidx == CMD_mksession) |
| 1303 | { |
| 1304 | char_u *dirnow; // current directory |
| 1305 | |
| 1306 | dirnow = alloc(MAXPATHL); |
| 1307 | if (dirnow == NULL) |
| 1308 | failed = TRUE; |
| 1309 | else |
| 1310 | { |
| 1311 | // Change to session file's dir. |
| 1312 | if (mch_dirname(dirnow, MAXPATHL) == FAIL |
| 1313 | || mch_chdir((char *)dirnow) != 0) |
| 1314 | *dirnow = NUL; |
| 1315 | if (*dirnow != NUL && (ssop_flags & SSOP_SESDIR)) |
| 1316 | { |
| 1317 | if (vim_chdirfile(fname, NULL) == OK) |
| 1318 | shorten_fnames(TRUE); |
| 1319 | } |
| 1320 | else if (*dirnow != NUL |
| 1321 | && (ssop_flags & SSOP_CURDIR) && globaldir != NULL) |
| 1322 | { |
| 1323 | if (mch_chdir((char *)globaldir) == 0) |
| 1324 | shorten_fnames(TRUE); |
| 1325 | } |
| 1326 | |
| 1327 | failed |= (makeopens(fd, dirnow) == FAIL); |
| 1328 | |
| 1329 | // restore original dir |
| 1330 | if (*dirnow != NUL && ((ssop_flags & SSOP_SESDIR) |
| 1331 | || ((ssop_flags & SSOP_CURDIR) && globaldir != NULL))) |
| 1332 | { |
| 1333 | if (mch_chdir((char *)dirnow) != 0) |
Bram Moolenaar | 460ae5d | 2022-01-01 14:19:49 +0000 | [diff] [blame] | 1334 | emsg(_(e_cannot_go_back_to_previous_directory)); |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 1335 | shorten_fnames(TRUE); |
| 1336 | } |
| 1337 | vim_free(dirnow); |
| 1338 | } |
| 1339 | } |
| 1340 | else |
| 1341 | { |
Bram Moolenaar | c2c8205 | 2020-09-11 22:10:22 +0200 | [diff] [blame] | 1342 | failed |= (put_view(fd, curwin, !using_vdir, flagp, -1, NULL) |
| 1343 | == FAIL); |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 1344 | } |
Bram Moolenaar | 3889083 | 2020-11-01 17:40:54 +0100 | [diff] [blame] | 1345 | if (put_line(fd, "let &g:so = s:so_save | let &g:siso = s:siso_save") |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 1346 | == FAIL) |
| 1347 | failed = TRUE; |
Bram Moolenaar | f96ae0b | 2019-07-28 15:21:55 +0200 | [diff] [blame] | 1348 | #ifdef FEAT_SEARCH_EXTRA |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 1349 | if (no_hlsearch && put_line(fd, "nohlsearch") == FAIL) |
| 1350 | failed = TRUE; |
Bram Moolenaar | f96ae0b | 2019-07-28 15:21:55 +0200 | [diff] [blame] | 1351 | #endif |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 1352 | if (put_line(fd, "doautoall SessionLoadPost") == FAIL) |
| 1353 | failed = TRUE; |
| 1354 | if (eap->cmdidx == CMD_mksession) |
| 1355 | { |
| 1356 | if (put_line(fd, "unlet SessionLoad") == FAIL) |
| 1357 | failed = TRUE; |
| 1358 | } |
| 1359 | } |
| 1360 | #endif |
| 1361 | if (put_line(fd, "\" vim: set ft=vim :") == FAIL) |
| 1362 | failed = TRUE; |
| 1363 | |
| 1364 | failed |= fclose(fd); |
| 1365 | |
| 1366 | if (failed) |
Bram Moolenaar | 40bcec1 | 2021-12-05 22:19:27 +0000 | [diff] [blame] | 1367 | emsg(_(e_error_while_writing)); |
Bram Moolenaar | f96ae0b | 2019-07-28 15:21:55 +0200 | [diff] [blame] | 1368 | #if defined(FEAT_SESSION) |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 1369 | else if (eap->cmdidx == CMD_mksession) |
| 1370 | { |
| 1371 | // successful session write - set this_session var |
| 1372 | char_u *tbuf; |
| 1373 | |
| 1374 | tbuf = alloc(MAXPATHL); |
| 1375 | if (tbuf != NULL) |
| 1376 | { |
| 1377 | if (vim_FullName(fname, tbuf, MAXPATHL, FALSE) == OK) |
| 1378 | set_vim_var_string(VV_THIS_SESSION, tbuf, -1); |
| 1379 | vim_free(tbuf); |
| 1380 | } |
| 1381 | } |
| 1382 | #endif |
| 1383 | #ifdef MKSESSION_NL |
| 1384 | mksession_nl = FALSE; |
| 1385 | #endif |
| 1386 | } |
| 1387 | |
| 1388 | #ifdef FEAT_BROWSE |
| 1389 | theend: |
| 1390 | vim_free(browseFile); |
| 1391 | #endif |
| 1392 | #ifdef FEAT_SESSION |
| 1393 | vim_free(viewFile); |
| 1394 | #endif |
| 1395 | } |
| 1396 | |
Bram Moolenaar | f96ae0b | 2019-07-28 15:21:55 +0200 | [diff] [blame] | 1397 | #if (defined(FEAT_VIMINFO) || defined(FEAT_SESSION)) || defined(PROTO) |
Bram Moolenaar | 8453807 | 2019-07-28 14:15:42 +0200 | [diff] [blame] | 1398 | var_flavour_T |
| 1399 | var_flavour(char_u *varname) |
| 1400 | { |
| 1401 | char_u *p = varname; |
| 1402 | |
| 1403 | if (ASCII_ISUPPER(*p)) |
| 1404 | { |
| 1405 | while (*(++p)) |
| 1406 | if (ASCII_ISLOWER(*p)) |
| 1407 | return VAR_FLAVOUR_SESSION; |
| 1408 | return VAR_FLAVOUR_VIMINFO; |
| 1409 | } |
| 1410 | else |
| 1411 | return VAR_FLAVOUR_DEFAULT; |
| 1412 | } |
| 1413 | #endif |
| 1414 | |
| 1415 | /* |
| 1416 | * Write end-of-line character(s) for ":mkexrc", ":mkvimrc" and ":mksession". |
| 1417 | * Return FAIL for a write error. |
| 1418 | */ |
| 1419 | int |
| 1420 | put_eol(FILE *fd) |
| 1421 | { |
| 1422 | if ( |
| 1423 | #ifdef USE_CRNL |
| 1424 | ( |
| 1425 | # ifdef MKSESSION_NL |
| 1426 | !mksession_nl && |
| 1427 | # endif |
| 1428 | (putc('\r', fd) < 0)) || |
| 1429 | #endif |
| 1430 | (putc('\n', fd) < 0)) |
| 1431 | return FAIL; |
| 1432 | return OK; |
| 1433 | } |
| 1434 | |
| 1435 | /* |
| 1436 | * Write a line to "fd". |
| 1437 | * Return FAIL for a write error. |
| 1438 | */ |
| 1439 | int |
| 1440 | put_line(FILE *fd, char *s) |
| 1441 | { |
| 1442 | if (fputs(s, fd) < 0 || put_eol(fd) == FAIL) |
| 1443 | return FAIL; |
| 1444 | return OK; |
| 1445 | } |