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