Mercurial > vim
comparison src/ex_docmd.c @ 17536:e00d12c085a5 v8.1.1766
patch 8.1.1766: code for writing session file is spread out
commit https://github.com/vim/vim/commit/845380791196aec7f991987ebf7b22de3779d106
Author: Bram Moolenaar <Bram@vim.org>
Date: Sun Jul 28 14:15:42 2019 +0200
patch 8.1.1766: code for writing session file is spread out
Problem: Code for writing session file is spread out.
Solution: Put it in one file. (Yegappan Lakshmanan, closes https://github.com/vim/vim/issues/4728)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sun, 28 Jul 2019 14:30:07 +0200 |
parents | c8152af9fa33 |
children | 554240b9574b |
comparison
equal
deleted
inserted
replaced
17535:3015901aaaa6 | 17536:e00d12c085a5 |
---|---|
255 static void ex_later(exarg_T *eap); | 255 static void ex_later(exarg_T *eap); |
256 static void ex_redir(exarg_T *eap); | 256 static void ex_redir(exarg_T *eap); |
257 static void ex_redrawstatus(exarg_T *eap); | 257 static void ex_redrawstatus(exarg_T *eap); |
258 static void ex_redrawtabline(exarg_T *eap); | 258 static void ex_redrawtabline(exarg_T *eap); |
259 static void close_redir(void); | 259 static void close_redir(void); |
260 static void ex_mkrc(exarg_T *eap); | |
261 static void ex_mark(exarg_T *eap); | 260 static void ex_mark(exarg_T *eap); |
262 static void ex_startinsert(exarg_T *eap); | 261 static void ex_startinsert(exarg_T *eap); |
263 static void ex_stopinsert(exarg_T *eap); | 262 static void ex_stopinsert(exarg_T *eap); |
264 #ifdef FEAT_FIND_ID | 263 #ifdef FEAT_FIND_ID |
265 static void ex_checkpath(exarg_T *eap); | 264 static void ex_checkpath(exarg_T *eap); |
304 # define ex_delfunction ex_ni | 303 # define ex_delfunction ex_ni |
305 # define ex_return ex_ni | 304 # define ex_return ex_ni |
306 # define ex_oldfiles ex_ni | 305 # define ex_oldfiles ex_ni |
307 #endif | 306 #endif |
308 static char_u *arg_all(void); | 307 static char_u *arg_all(void); |
309 #ifdef FEAT_SESSION | 308 #ifndef FEAT_SESSION |
310 static int makeopens(FILE *fd, char_u *dirnow); | |
311 static int put_view(FILE *fd, win_T *wp, int add_edit, unsigned *flagp, int current_arg_idx); | |
312 static void ex_loadview(exarg_T *eap); | |
313 static char_u *get_view_file(int c); | |
314 static int did_lcd; /* whether ":lcd" was produced for a session */ | |
315 #else | |
316 # define ex_loadview ex_ni | 309 # define ex_loadview ex_ni |
310 # define ex_mkrc ex_ni | |
317 #endif | 311 #endif |
318 #ifndef FEAT_EVAL | 312 #ifndef FEAT_EVAL |
319 # define ex_compiler ex_ni | 313 # define ex_compiler ex_ni |
320 #endif | 314 #endif |
321 #ifndef FEAT_VIMINFO | 315 #ifndef FEAT_VIMINFO |
8437 redir_vname = 0; | 8431 redir_vname = 0; |
8438 } | 8432 } |
8439 #endif | 8433 #endif |
8440 } | 8434 } |
8441 | 8435 |
8442 #if defined(FEAT_SESSION) && defined(USE_CRNL) | |
8443 # define MKSESSION_NL | |
8444 static int mksession_nl = FALSE; /* use NL only in put_eol() */ | |
8445 #endif | |
8446 | |
8447 /* | |
8448 * ":mkexrc", ":mkvimrc", ":mkview" and ":mksession". | |
8449 */ | |
8450 static void | |
8451 ex_mkrc( | |
8452 exarg_T *eap) | |
8453 { | |
8454 FILE *fd; | |
8455 int failed = FALSE; | |
8456 char_u *fname; | |
8457 #ifdef FEAT_BROWSE | |
8458 char_u *browseFile = NULL; | |
8459 #endif | |
8460 #ifdef FEAT_SESSION | |
8461 int view_session = FALSE; | |
8462 int using_vdir = FALSE; /* using 'viewdir'? */ | |
8463 char_u *viewFile = NULL; | |
8464 unsigned *flagp; | |
8465 #endif | |
8466 | |
8467 if (eap->cmdidx == CMD_mksession || eap->cmdidx == CMD_mkview) | |
8468 { | |
8469 #ifdef FEAT_SESSION | |
8470 view_session = TRUE; | |
8471 #else | |
8472 ex_ni(eap); | |
8473 return; | |
8474 #endif | |
8475 } | |
8476 | |
8477 #ifdef FEAT_SESSION | |
8478 /* Use the short file name until ":lcd" is used. We also don't use the | |
8479 * short file name when 'acd' is set, that is checked later. */ | |
8480 did_lcd = FALSE; | |
8481 | |
8482 /* ":mkview" or ":mkview 9": generate file name with 'viewdir' */ | |
8483 if (eap->cmdidx == CMD_mkview | |
8484 && (*eap->arg == NUL | |
8485 || (vim_isdigit(*eap->arg) && eap->arg[1] == NUL))) | |
8486 { | |
8487 eap->forceit = TRUE; | |
8488 fname = get_view_file(*eap->arg); | |
8489 if (fname == NULL) | |
8490 return; | |
8491 viewFile = fname; | |
8492 using_vdir = TRUE; | |
8493 } | |
8494 else | |
8495 #endif | |
8496 if (*eap->arg != NUL) | |
8497 fname = eap->arg; | |
8498 else if (eap->cmdidx == CMD_mkvimrc) | |
8499 fname = (char_u *)VIMRC_FILE; | |
8500 #ifdef FEAT_SESSION | |
8501 else if (eap->cmdidx == CMD_mksession) | |
8502 fname = (char_u *)SESSION_FILE; | |
8503 #endif | |
8504 else | |
8505 fname = (char_u *)EXRC_FILE; | |
8506 | |
8507 #ifdef FEAT_BROWSE | |
8508 if (cmdmod.browse) | |
8509 { | |
8510 browseFile = do_browse(BROWSE_SAVE, | |
8511 # ifdef FEAT_SESSION | |
8512 eap->cmdidx == CMD_mkview ? (char_u *)_("Save View") : | |
8513 eap->cmdidx == CMD_mksession ? (char_u *)_("Save Session") : | |
8514 # endif | |
8515 (char_u *)_("Save Setup"), | |
8516 fname, (char_u *)"vim", NULL, | |
8517 (char_u *)_(BROWSE_FILTER_MACROS), NULL); | |
8518 if (browseFile == NULL) | |
8519 goto theend; | |
8520 fname = browseFile; | |
8521 eap->forceit = TRUE; /* since dialog already asked */ | |
8522 } | |
8523 #endif | |
8524 | |
8525 #if defined(FEAT_SESSION) && defined(vim_mkdir) | |
8526 /* When using 'viewdir' may have to create the directory. */ | |
8527 if (using_vdir && !mch_isdir(p_vdir)) | |
8528 vim_mkdir_emsg(p_vdir, 0755); | |
8529 #endif | |
8530 | |
8531 fd = open_exfile(fname, eap->forceit, WRITEBIN); | |
8532 if (fd != NULL) | |
8533 { | |
8534 #ifdef FEAT_SESSION | |
8535 if (eap->cmdidx == CMD_mkview) | |
8536 flagp = &vop_flags; | |
8537 else | |
8538 flagp = &ssop_flags; | |
8539 #endif | |
8540 | |
8541 #ifdef MKSESSION_NL | |
8542 /* "unix" in 'sessionoptions': use NL line separator */ | |
8543 if (view_session && (*flagp & SSOP_UNIX)) | |
8544 mksession_nl = TRUE; | |
8545 #endif | |
8546 | |
8547 /* Write the version command for :mkvimrc */ | |
8548 if (eap->cmdidx == CMD_mkvimrc) | |
8549 (void)put_line(fd, "version 6.0"); | |
8550 | |
8551 #ifdef FEAT_SESSION | |
8552 if (eap->cmdidx == CMD_mksession) | |
8553 { | |
8554 if (put_line(fd, "let SessionLoad = 1") == FAIL) | |
8555 failed = TRUE; | |
8556 } | |
8557 | |
8558 if (eap->cmdidx != CMD_mkview) | |
8559 #endif | |
8560 { | |
8561 /* Write setting 'compatible' first, because it has side effects. | |
8562 * For that same reason only do it when needed. */ | |
8563 if (p_cp) | |
8564 (void)put_line(fd, "if !&cp | set cp | endif"); | |
8565 else | |
8566 (void)put_line(fd, "if &cp | set nocp | endif"); | |
8567 } | |
8568 | |
8569 #ifdef FEAT_SESSION | |
8570 if (!view_session | |
8571 || (eap->cmdidx == CMD_mksession | |
8572 && (*flagp & SSOP_OPTIONS))) | |
8573 #endif | |
8574 failed |= (makemap(fd, NULL) == FAIL | |
8575 || makeset(fd, OPT_GLOBAL, FALSE) == FAIL); | |
8576 | |
8577 #ifdef FEAT_SESSION | |
8578 if (!failed && view_session) | |
8579 { | |
8580 if (put_line(fd, "let s:so_save = &so | let s:siso_save = &siso | set so=0 siso=0") == FAIL) | |
8581 failed = TRUE; | |
8582 if (eap->cmdidx == CMD_mksession) | |
8583 { | |
8584 char_u *dirnow; /* current directory */ | |
8585 | |
8586 dirnow = alloc(MAXPATHL); | |
8587 if (dirnow == NULL) | |
8588 failed = TRUE; | |
8589 else | |
8590 { | |
8591 /* | |
8592 * Change to session file's dir. | |
8593 */ | |
8594 if (mch_dirname(dirnow, MAXPATHL) == FAIL | |
8595 || mch_chdir((char *)dirnow) != 0) | |
8596 *dirnow = NUL; | |
8597 if (*dirnow != NUL && (ssop_flags & SSOP_SESDIR)) | |
8598 { | |
8599 if (vim_chdirfile(fname, NULL) == OK) | |
8600 shorten_fnames(TRUE); | |
8601 } | |
8602 else if (*dirnow != NUL | |
8603 && (ssop_flags & SSOP_CURDIR) && globaldir != NULL) | |
8604 { | |
8605 if (mch_chdir((char *)globaldir) == 0) | |
8606 shorten_fnames(TRUE); | |
8607 } | |
8608 | |
8609 failed |= (makeopens(fd, dirnow) == FAIL); | |
8610 | |
8611 /* restore original dir */ | |
8612 if (*dirnow != NUL && ((ssop_flags & SSOP_SESDIR) | |
8613 || ((ssop_flags & SSOP_CURDIR) && globaldir != NULL))) | |
8614 { | |
8615 if (mch_chdir((char *)dirnow) != 0) | |
8616 emsg(_(e_prev_dir)); | |
8617 shorten_fnames(TRUE); | |
8618 } | |
8619 vim_free(dirnow); | |
8620 } | |
8621 } | |
8622 else | |
8623 { | |
8624 failed |= (put_view(fd, curwin, !using_vdir, flagp, | |
8625 -1) == FAIL); | |
8626 } | |
8627 if (put_line(fd, "let &so = s:so_save | let &siso = s:siso_save") | |
8628 == FAIL) | |
8629 failed = TRUE; | |
8630 # ifdef FEAT_SEARCH_EXTRA | |
8631 if (no_hlsearch && put_line(fd, "nohlsearch") == FAIL) | |
8632 failed = TRUE; | |
8633 # endif | |
8634 if (put_line(fd, "doautoall SessionLoadPost") == FAIL) | |
8635 failed = TRUE; | |
8636 if (eap->cmdidx == CMD_mksession) | |
8637 { | |
8638 if (put_line(fd, "unlet SessionLoad") == FAIL) | |
8639 failed = TRUE; | |
8640 } | |
8641 } | |
8642 #endif | |
8643 if (put_line(fd, "\" vim: set ft=vim :") == FAIL) | |
8644 failed = TRUE; | |
8645 | |
8646 failed |= fclose(fd); | |
8647 | |
8648 if (failed) | |
8649 emsg(_(e_write)); | |
8650 #if defined(FEAT_EVAL) && defined(FEAT_SESSION) | |
8651 else if (eap->cmdidx == CMD_mksession) | |
8652 { | |
8653 /* successful session write - set this_session var */ | |
8654 char_u *tbuf; | |
8655 | |
8656 tbuf = alloc(MAXPATHL); | |
8657 if (tbuf != NULL) | |
8658 { | |
8659 if (vim_FullName(fname, tbuf, MAXPATHL, FALSE) == OK) | |
8660 set_vim_var_string(VV_THIS_SESSION, tbuf, -1); | |
8661 vim_free(tbuf); | |
8662 } | |
8663 } | |
8664 #endif | |
8665 #ifdef MKSESSION_NL | |
8666 mksession_nl = FALSE; | |
8667 #endif | |
8668 } | |
8669 | |
8670 #ifdef FEAT_BROWSE | |
8671 theend: | |
8672 vim_free(browseFile); | |
8673 #endif | |
8674 #ifdef FEAT_SESSION | |
8675 vim_free(viewFile); | |
8676 #endif | |
8677 } | |
8678 | |
8679 #if ((defined(FEAT_SESSION) || defined(FEAT_EVAL)) && defined(vim_mkdir)) \ | 8436 #if ((defined(FEAT_SESSION) || defined(FEAT_EVAL)) && defined(vim_mkdir)) \ |
8680 || defined(PROTO) | 8437 || defined(PROTO) |
8681 int | 8438 int |
8682 vim_mkdir_emsg(char_u *name, int prot) | 8439 vim_mkdir_emsg(char_u *name, int prot) |
8683 { | 8440 { |
9715 } | 9472 } |
9716 | 9473 |
9717 return result; | 9474 return result; |
9718 } | 9475 } |
9719 | 9476 |
9720 #ifdef FEAT_SESSION | |
9721 static int ses_winsizes(FILE *fd, int restore_size, | |
9722 win_T *tab_firstwin); | |
9723 static int ses_win_rec(FILE *fd, frame_T *fr); | |
9724 static frame_T *ses_skipframe(frame_T *fr); | |
9725 static int ses_do_frame(frame_T *fr); | |
9726 static int ses_do_win(win_T *wp); | |
9727 static int ses_arglist(FILE *fd, char *cmd, garray_T *gap, int fullname, unsigned *flagp); | |
9728 static int ses_put_fname(FILE *fd, char_u *name, unsigned *flagp); | |
9729 static int ses_fname(FILE *fd, buf_T *buf, unsigned *flagp, int add_eol); | |
9730 | |
9731 /* | |
9732 * Write openfile commands for the current buffers to an .exrc file. | |
9733 * Return FAIL on error, OK otherwise. | |
9734 */ | |
9735 static int | |
9736 makeopens( | |
9737 FILE *fd, | |
9738 char_u *dirnow) /* Current directory name */ | |
9739 { | |
9740 buf_T *buf; | |
9741 int only_save_windows = TRUE; | |
9742 int nr; | |
9743 int restore_size = TRUE; | |
9744 win_T *wp; | |
9745 char_u *sname; | |
9746 win_T *edited_win = NULL; | |
9747 int tabnr; | |
9748 int restore_stal = FALSE; | |
9749 win_T *tab_firstwin; | |
9750 frame_T *tab_topframe; | |
9751 int cur_arg_idx = 0; | |
9752 int next_arg_idx = 0; | |
9753 | |
9754 if (ssop_flags & SSOP_BUFFERS) | |
9755 only_save_windows = FALSE; /* Save ALL buffers */ | |
9756 | |
9757 /* | |
9758 * Begin by setting the this_session variable, and then other | |
9759 * sessionable variables. | |
9760 */ | |
9761 #ifdef FEAT_EVAL | |
9762 if (put_line(fd, "let v:this_session=expand(\"<sfile>:p\")") == FAIL) | |
9763 return FAIL; | |
9764 if (ssop_flags & SSOP_GLOBALS) | |
9765 if (store_session_globals(fd) == FAIL) | |
9766 return FAIL; | |
9767 #endif | |
9768 | |
9769 /* | |
9770 * Close all windows and tabs but one. | |
9771 */ | |
9772 if (put_line(fd, "silent only") == FAIL) | |
9773 return FAIL; | |
9774 if ((ssop_flags & SSOP_TABPAGES) | |
9775 && put_line(fd, "silent tabonly") == FAIL) | |
9776 return FAIL; | |
9777 | |
9778 /* | |
9779 * Now a :cd command to the session directory or the current directory | |
9780 */ | |
9781 if (ssop_flags & SSOP_SESDIR) | |
9782 { | |
9783 if (put_line(fd, "exe \"cd \" . escape(expand(\"<sfile>:p:h\"), ' ')") | |
9784 == FAIL) | |
9785 return FAIL; | |
9786 } | |
9787 else if (ssop_flags & SSOP_CURDIR) | |
9788 { | |
9789 sname = home_replace_save(NULL, globaldir != NULL ? globaldir : dirnow); | |
9790 if (sname == NULL | |
9791 || fputs("cd ", fd) < 0 | |
9792 || ses_put_fname(fd, sname, &ssop_flags) == FAIL | |
9793 || put_eol(fd) == FAIL) | |
9794 { | |
9795 vim_free(sname); | |
9796 return FAIL; | |
9797 } | |
9798 vim_free(sname); | |
9799 } | |
9800 | |
9801 /* | |
9802 * If there is an empty, unnamed buffer we will wipe it out later. | |
9803 * Remember the buffer number. | |
9804 */ | |
9805 if (put_line(fd, "if expand('%') == '' && !&modified && line('$') <= 1 && getline(1) == ''") == FAIL) | |
9806 return FAIL; | |
9807 if (put_line(fd, " let s:wipebuf = bufnr('%')") == FAIL) | |
9808 return FAIL; | |
9809 if (put_line(fd, "endif") == FAIL) | |
9810 return FAIL; | |
9811 | |
9812 /* | |
9813 * Now save the current files, current buffer first. | |
9814 */ | |
9815 if (put_line(fd, "set shortmess=aoO") == FAIL) | |
9816 return FAIL; | |
9817 | |
9818 /* the global argument list */ | |
9819 if (ses_arglist(fd, "argglobal", &global_alist.al_ga, | |
9820 !(ssop_flags & SSOP_CURDIR), &ssop_flags) == FAIL) | |
9821 return FAIL; | |
9822 | |
9823 if (ssop_flags & SSOP_RESIZE) | |
9824 { | |
9825 /* Note: after the restore we still check it worked!*/ | |
9826 if (fprintf(fd, "set lines=%ld columns=%ld" , Rows, Columns) < 0 | |
9827 || put_eol(fd) == FAIL) | |
9828 return FAIL; | |
9829 } | |
9830 | |
9831 #ifdef FEAT_GUI | |
9832 if (gui.in_use && (ssop_flags & SSOP_WINPOS)) | |
9833 { | |
9834 int x, y; | |
9835 | |
9836 if (gui_mch_get_winpos(&x, &y) == OK) | |
9837 { | |
9838 /* Note: after the restore we still check it worked!*/ | |
9839 if (fprintf(fd, "winpos %d %d", x, y) < 0 || put_eol(fd) == FAIL) | |
9840 return FAIL; | |
9841 } | |
9842 } | |
9843 #endif | |
9844 | |
9845 /* | |
9846 * When there are two or more tabpages and 'showtabline' is 1 the tabline | |
9847 * will be displayed when creating the next tab. That resizes the windows | |
9848 * in the first tab, which may cause problems. Set 'showtabline' to 2 | |
9849 * temporarily to avoid that. | |
9850 */ | |
9851 if (p_stal == 1 && first_tabpage->tp_next != NULL) | |
9852 { | |
9853 if (put_line(fd, "set stal=2") == FAIL) | |
9854 return FAIL; | |
9855 restore_stal = TRUE; | |
9856 } | |
9857 | |
9858 /* | |
9859 * May repeat putting Windows for each tab, when "tabpages" is in | |
9860 * 'sessionoptions'. | |
9861 * Don't use goto_tabpage(), it may change directory and trigger | |
9862 * autocommands. | |
9863 */ | |
9864 tab_firstwin = firstwin; /* first window in tab page "tabnr" */ | |
9865 tab_topframe = topframe; | |
9866 if ((ssop_flags & SSOP_TABPAGES)) | |
9867 { | |
9868 tabpage_T *tp; | |
9869 | |
9870 // Similar to ses_win_rec() below, populate the tab pages first so | |
9871 // later local options won't be copied to the new tabs. | |
9872 FOR_ALL_TABPAGES(tp) | |
9873 if (tp->tp_next != NULL && put_line(fd, "tabnew") == FAIL) | |
9874 return FAIL; | |
9875 if (first_tabpage->tp_next != NULL && put_line(fd, "tabrewind") == FAIL) | |
9876 return FAIL; | |
9877 } | |
9878 for (tabnr = 1; ; ++tabnr) | |
9879 { | |
9880 tabpage_T *tp = NULL; | |
9881 int need_tabnext = FALSE; | |
9882 int cnr = 1; | |
9883 | |
9884 if ((ssop_flags & SSOP_TABPAGES)) | |
9885 { | |
9886 tp = find_tabpage(tabnr); | |
9887 | |
9888 if (tp == NULL) | |
9889 break; /* done all tab pages */ | |
9890 if (tp == curtab) | |
9891 { | |
9892 tab_firstwin = firstwin; | |
9893 tab_topframe = topframe; | |
9894 } | |
9895 else | |
9896 { | |
9897 tab_firstwin = tp->tp_firstwin; | |
9898 tab_topframe = tp->tp_topframe; | |
9899 } | |
9900 if (tabnr > 1) | |
9901 need_tabnext = TRUE; | |
9902 } | |
9903 | |
9904 /* | |
9905 * Before creating the window layout, try loading one file. If this | |
9906 * is aborted we don't end up with a number of useless windows. | |
9907 * This may have side effects! (e.g., compressed or network file). | |
9908 */ | |
9909 for (wp = tab_firstwin; wp != NULL; wp = wp->w_next) | |
9910 { | |
9911 if (ses_do_win(wp) | |
9912 && wp->w_buffer->b_ffname != NULL | |
9913 && !bt_help(wp->w_buffer) | |
9914 #ifdef FEAT_QUICKFIX | |
9915 && !bt_nofilename(wp->w_buffer) | |
9916 #endif | |
9917 ) | |
9918 { | |
9919 if (need_tabnext && put_line(fd, "tabnext") == FAIL) | |
9920 return FAIL; | |
9921 need_tabnext = FALSE; | |
9922 | |
9923 if (fputs("edit ", fd) < 0 | |
9924 || ses_fname(fd, wp->w_buffer, &ssop_flags, TRUE) | |
9925 == FAIL) | |
9926 return FAIL; | |
9927 if (!wp->w_arg_idx_invalid) | |
9928 edited_win = wp; | |
9929 break; | |
9930 } | |
9931 } | |
9932 | |
9933 /* If no file got edited create an empty tab page. */ | |
9934 if (need_tabnext && put_line(fd, "tabnext") == FAIL) | |
9935 return FAIL; | |
9936 | |
9937 /* | |
9938 * Save current window layout. | |
9939 */ | |
9940 if (put_line(fd, "set splitbelow splitright") == FAIL) | |
9941 return FAIL; | |
9942 if (ses_win_rec(fd, tab_topframe) == FAIL) | |
9943 return FAIL; | |
9944 if (!p_sb && put_line(fd, "set nosplitbelow") == FAIL) | |
9945 return FAIL; | |
9946 if (!p_spr && put_line(fd, "set nosplitright") == FAIL) | |
9947 return FAIL; | |
9948 | |
9949 /* | |
9950 * Check if window sizes can be restored (no windows omitted). | |
9951 * Remember the window number of the current window after restoring. | |
9952 */ | |
9953 nr = 0; | |
9954 for (wp = tab_firstwin; wp != NULL; wp = W_NEXT(wp)) | |
9955 { | |
9956 if (ses_do_win(wp)) | |
9957 ++nr; | |
9958 else | |
9959 restore_size = FALSE; | |
9960 if (curwin == wp) | |
9961 cnr = nr; | |
9962 } | |
9963 | |
9964 /* Go to the first window. */ | |
9965 if (put_line(fd, "wincmd t") == FAIL) | |
9966 return FAIL; | |
9967 | |
9968 /* | |
9969 * If more than one window, see if sizes can be restored. | |
9970 * First set 'winheight' and 'winwidth' to 1 to avoid the windows being | |
9971 * resized when moving between windows. | |
9972 * Do this before restoring the view, so that the topline and the | |
9973 * cursor can be set. This is done again below. | |
9974 * winminheight and winminwidth need to be set to avoid an error if the | |
9975 * user has set winheight or winwidth. | |
9976 */ | |
9977 if (put_line(fd, "set winminheight=0") == FAIL | |
9978 || put_line(fd, "set winheight=1") == FAIL | |
9979 || put_line(fd, "set winminwidth=0") == FAIL | |
9980 || put_line(fd, "set winwidth=1") == FAIL) | |
9981 return FAIL; | |
9982 if (nr > 1 && ses_winsizes(fd, restore_size, tab_firstwin) == FAIL) | |
9983 return FAIL; | |
9984 | |
9985 // Restore the tab-local working directory if specified | |
9986 // Do this before the windows, so that the window-local directory can | |
9987 // override the tab-local directory. | |
9988 if (tp != NULL && tp->tp_localdir != NULL && ssop_flags & SSOP_CURDIR) | |
9989 { | |
9990 if (fputs("tcd ", fd) < 0 | |
9991 || ses_put_fname(fd, tp->tp_localdir, &ssop_flags) == FAIL | |
9992 || put_eol(fd) == FAIL) | |
9993 return FAIL; | |
9994 did_lcd = TRUE; | |
9995 } | |
9996 | |
9997 /* | |
9998 * Restore the view of the window (options, file, cursor, etc.). | |
9999 */ | |
10000 for (wp = tab_firstwin; wp != NULL; wp = wp->w_next) | |
10001 { | |
10002 if (!ses_do_win(wp)) | |
10003 continue; | |
10004 if (put_view(fd, wp, wp != edited_win, &ssop_flags, | |
10005 cur_arg_idx) == FAIL) | |
10006 return FAIL; | |
10007 if (nr > 1 && put_line(fd, "wincmd w") == FAIL) | |
10008 return FAIL; | |
10009 next_arg_idx = wp->w_arg_idx; | |
10010 } | |
10011 | |
10012 /* The argument index in the first tab page is zero, need to set it in | |
10013 * each window. For further tab pages it's the window where we do | |
10014 * "tabedit". */ | |
10015 cur_arg_idx = next_arg_idx; | |
10016 | |
10017 /* | |
10018 * Restore cursor to the current window if it's not the first one. | |
10019 */ | |
10020 if (cnr > 1 && (fprintf(fd, "%dwincmd w", cnr) < 0 | |
10021 || put_eol(fd) == FAIL)) | |
10022 return FAIL; | |
10023 | |
10024 /* | |
10025 * Restore window sizes again after jumping around in windows, because | |
10026 * the current window has a minimum size while others may not. | |
10027 */ | |
10028 if (nr > 1 && ses_winsizes(fd, restore_size, tab_firstwin) == FAIL) | |
10029 return FAIL; | |
10030 | |
10031 /* Don't continue in another tab page when doing only the current one | |
10032 * or when at the last tab page. */ | |
10033 if (!(ssop_flags & SSOP_TABPAGES)) | |
10034 break; | |
10035 } | |
10036 | |
10037 if (ssop_flags & SSOP_TABPAGES) | |
10038 { | |
10039 if (fprintf(fd, "tabnext %d", tabpage_index(curtab)) < 0 | |
10040 || put_eol(fd) == FAIL) | |
10041 return FAIL; | |
10042 } | |
10043 if (restore_stal && put_line(fd, "set stal=1") == FAIL) | |
10044 return FAIL; | |
10045 | |
10046 // Now put the remaining buffers into the buffer list. | |
10047 // This is near the end, so that when 'hidden' is set we don't create extra | |
10048 // buffers. If the buffer was already created with another command the | |
10049 // ":badd" will have no effect. | |
10050 FOR_ALL_BUFFERS(buf) | |
10051 { | |
10052 if (!(only_save_windows && buf->b_nwindows == 0) | |
10053 && !(buf->b_help && !(ssop_flags & SSOP_HELP)) | |
10054 #ifdef FEAT_TERMINAL | |
10055 // Skip terminal buffers: finished ones are not useful, others | |
10056 // will be resurrected and result in a new buffer. | |
10057 && !bt_terminal(buf) | |
10058 #endif | |
10059 && buf->b_fname != NULL | |
10060 && buf->b_p_bl) | |
10061 { | |
10062 if (fprintf(fd, "badd +%ld ", buf->b_wininfo == NULL ? 1L | |
10063 : buf->b_wininfo->wi_fpos.lnum) < 0 | |
10064 || ses_fname(fd, buf, &ssop_flags, TRUE) == FAIL) | |
10065 return FAIL; | |
10066 } | |
10067 } | |
10068 | |
10069 /* | |
10070 * Wipe out an empty unnamed buffer we started in. | |
10071 */ | |
10072 if (put_line(fd, "if exists('s:wipebuf') && len(win_findbuf(s:wipebuf)) == 0") | |
10073 == FAIL) | |
10074 return FAIL; | |
10075 if (put_line(fd, " silent exe 'bwipe ' . s:wipebuf") == FAIL) | |
10076 return FAIL; | |
10077 if (put_line(fd, "endif") == FAIL) | |
10078 return FAIL; | |
10079 if (put_line(fd, "unlet! s:wipebuf") == FAIL) | |
10080 return FAIL; | |
10081 | |
10082 /* Re-apply 'winheight', 'winwidth' and 'shortmess'. */ | |
10083 if (fprintf(fd, "set winheight=%ld winwidth=%ld shortmess=%s", | |
10084 p_wh, p_wiw, p_shm) < 0 || put_eol(fd) == FAIL) | |
10085 return FAIL; | |
10086 /* Re-apply 'winminheight' and 'winminwidth'. */ | |
10087 if (fprintf(fd, "set winminheight=%ld winminwidth=%ld", | |
10088 p_wmh, p_wmw) < 0 || put_eol(fd) == FAIL) | |
10089 return FAIL; | |
10090 | |
10091 /* | |
10092 * Lastly, execute the x.vim file if it exists. | |
10093 */ | |
10094 if (put_line(fd, "let s:sx = expand(\"<sfile>:p:r\").\"x.vim\"") == FAIL | |
10095 || put_line(fd, "if file_readable(s:sx)") == FAIL | |
10096 || put_line(fd, " exe \"source \" . fnameescape(s:sx)") == FAIL | |
10097 || put_line(fd, "endif") == FAIL) | |
10098 return FAIL; | |
10099 | |
10100 return OK; | |
10101 } | |
10102 | |
10103 static int | |
10104 ses_winsizes( | |
10105 FILE *fd, | |
10106 int restore_size, | |
10107 win_T *tab_firstwin) | |
10108 { | |
10109 int n = 0; | |
10110 win_T *wp; | |
10111 | |
10112 if (restore_size && (ssop_flags & SSOP_WINSIZE)) | |
10113 { | |
10114 for (wp = tab_firstwin; wp != NULL; wp = wp->w_next) | |
10115 { | |
10116 if (!ses_do_win(wp)) | |
10117 continue; | |
10118 ++n; | |
10119 | |
10120 /* restore height when not full height */ | |
10121 if (wp->w_height + wp->w_status_height < topframe->fr_height | |
10122 && (fprintf(fd, | |
10123 "exe '%dresize ' . ((&lines * %ld + %ld) / %ld)", | |
10124 n, (long)wp->w_height, Rows / 2, Rows) < 0 | |
10125 || put_eol(fd) == FAIL)) | |
10126 return FAIL; | |
10127 | |
10128 /* restore width when not full width */ | |
10129 if (wp->w_width < Columns && (fprintf(fd, | |
10130 "exe 'vert %dresize ' . ((&columns * %ld + %ld) / %ld)", | |
10131 n, (long)wp->w_width, Columns / 2, Columns) < 0 | |
10132 || put_eol(fd) == FAIL)) | |
10133 return FAIL; | |
10134 } | |
10135 } | |
10136 else | |
10137 { | |
10138 /* Just equalise window sizes */ | |
10139 if (put_line(fd, "wincmd =") == FAIL) | |
10140 return FAIL; | |
10141 } | |
10142 return OK; | |
10143 } | |
10144 | |
10145 /* | |
10146 * Write commands to "fd" to recursively create windows for frame "fr", | |
10147 * horizontally and vertically split. | |
10148 * After the commands the last window in the frame is the current window. | |
10149 * Returns FAIL when writing the commands to "fd" fails. | |
10150 */ | |
10151 static int | |
10152 ses_win_rec(FILE *fd, frame_T *fr) | |
10153 { | |
10154 frame_T *frc; | |
10155 int count = 0; | |
10156 | |
10157 if (fr->fr_layout != FR_LEAF) | |
10158 { | |
10159 /* Find first frame that's not skipped and then create a window for | |
10160 * each following one (first frame is already there). */ | |
10161 frc = ses_skipframe(fr->fr_child); | |
10162 if (frc != NULL) | |
10163 while ((frc = ses_skipframe(frc->fr_next)) != NULL) | |
10164 { | |
10165 /* Make window as big as possible so that we have lots of room | |
10166 * to split. */ | |
10167 if (put_line(fd, "wincmd _ | wincmd |") == FAIL | |
10168 || put_line(fd, fr->fr_layout == FR_COL | |
10169 ? "split" : "vsplit") == FAIL) | |
10170 return FAIL; | |
10171 ++count; | |
10172 } | |
10173 | |
10174 /* Go back to the first window. */ | |
10175 if (count > 0 && (fprintf(fd, fr->fr_layout == FR_COL | |
10176 ? "%dwincmd k" : "%dwincmd h", count) < 0 | |
10177 || put_eol(fd) == FAIL)) | |
10178 return FAIL; | |
10179 | |
10180 /* Recursively create frames/windows in each window of this column or | |
10181 * row. */ | |
10182 frc = ses_skipframe(fr->fr_child); | |
10183 while (frc != NULL) | |
10184 { | |
10185 ses_win_rec(fd, frc); | |
10186 frc = ses_skipframe(frc->fr_next); | |
10187 /* Go to next window. */ | |
10188 if (frc != NULL && put_line(fd, "wincmd w") == FAIL) | |
10189 return FAIL; | |
10190 } | |
10191 } | |
10192 return OK; | |
10193 } | |
10194 | |
10195 /* | |
10196 * Skip frames that don't contain windows we want to save in the Session. | |
10197 * Returns NULL when there none. | |
10198 */ | |
10199 static frame_T * | |
10200 ses_skipframe(frame_T *fr) | |
10201 { | |
10202 frame_T *frc; | |
10203 | |
10204 FOR_ALL_FRAMES(frc, fr) | |
10205 if (ses_do_frame(frc)) | |
10206 break; | |
10207 return frc; | |
10208 } | |
10209 | |
10210 /* | |
10211 * Return TRUE if frame "fr" has a window somewhere that we want to save in | |
10212 * the Session. | |
10213 */ | |
10214 static int | |
10215 ses_do_frame(frame_T *fr) | |
10216 { | |
10217 frame_T *frc; | |
10218 | |
10219 if (fr->fr_layout == FR_LEAF) | |
10220 return ses_do_win(fr->fr_win); | |
10221 FOR_ALL_FRAMES(frc, fr->fr_child) | |
10222 if (ses_do_frame(frc)) | |
10223 return TRUE; | |
10224 return FALSE; | |
10225 } | |
10226 | |
10227 /* | |
10228 * Return non-zero if window "wp" is to be stored in the Session. | |
10229 */ | |
10230 static int | |
10231 ses_do_win(win_T *wp) | |
10232 { | |
10233 #ifdef FEAT_TERMINAL | |
10234 if (bt_terminal(wp->w_buffer)) | |
10235 return !term_is_finished(wp->w_buffer) | |
10236 && (ssop_flags & SSOP_TERMINAL) | |
10237 && term_should_restore(wp->w_buffer); | |
10238 #endif | |
10239 if (wp->w_buffer->b_fname == NULL | |
10240 #ifdef FEAT_QUICKFIX | |
10241 /* When 'buftype' is "nofile" can't restore the window contents. */ | |
10242 || bt_nofilename(wp->w_buffer) | |
10243 #endif | |
10244 ) | |
10245 return (ssop_flags & SSOP_BLANK); | |
10246 if (bt_help(wp->w_buffer)) | |
10247 return (ssop_flags & SSOP_HELP); | |
10248 return TRUE; | |
10249 } | |
10250 | |
10251 static int | |
10252 put_view_curpos(FILE *fd, win_T *wp, char *spaces) | |
10253 { | |
10254 int r; | |
10255 | |
10256 if (wp->w_curswant == MAXCOL) | |
10257 r = fprintf(fd, "%snormal! $", spaces); | |
10258 else | |
10259 r = fprintf(fd, "%snormal! 0%d|", spaces, wp->w_virtcol + 1); | |
10260 return r < 0 || put_eol(fd) == FAIL ? FALSE : OK; | |
10261 } | |
10262 | |
10263 /* | |
10264 * Write commands to "fd" to restore the view of a window. | |
10265 * Caller must make sure 'scrolloff' is zero. | |
10266 */ | |
10267 static int | |
10268 put_view( | |
10269 FILE *fd, | |
10270 win_T *wp, | |
10271 int add_edit, /* add ":edit" command to view */ | |
10272 unsigned *flagp, /* vop_flags or ssop_flags */ | |
10273 int current_arg_idx) /* current argument index of the window, use | |
10274 * -1 if unknown */ | |
10275 { | |
10276 win_T *save_curwin; | |
10277 int f; | |
10278 int do_cursor; | |
10279 int did_next = FALSE; | |
10280 | |
10281 /* Always restore cursor position for ":mksession". For ":mkview" only | |
10282 * when 'viewoptions' contains "cursor". */ | |
10283 do_cursor = (flagp == &ssop_flags || *flagp & SSOP_CURSOR); | |
10284 | |
10285 /* | |
10286 * Local argument list. | |
10287 */ | |
10288 if (wp->w_alist == &global_alist) | |
10289 { | |
10290 if (put_line(fd, "argglobal") == FAIL) | |
10291 return FAIL; | |
10292 } | |
10293 else | |
10294 { | |
10295 if (ses_arglist(fd, "arglocal", &wp->w_alist->al_ga, | |
10296 flagp == &vop_flags | |
10297 || !(*flagp & SSOP_CURDIR) | |
10298 || wp->w_localdir != NULL, flagp) == FAIL) | |
10299 return FAIL; | |
10300 } | |
10301 | |
10302 /* Only when part of a session: restore the argument index. Some | |
10303 * arguments may have been deleted, check if the index is valid. */ | |
10304 if (wp->w_arg_idx != current_arg_idx && wp->w_arg_idx < WARGCOUNT(wp) | |
10305 && flagp == &ssop_flags) | |
10306 { | |
10307 if (fprintf(fd, "%ldargu", (long)wp->w_arg_idx + 1) < 0 | |
10308 || put_eol(fd) == FAIL) | |
10309 return FAIL; | |
10310 did_next = TRUE; | |
10311 } | |
10312 | |
10313 /* Edit the file. Skip this when ":next" already did it. */ | |
10314 if (add_edit && (!did_next || wp->w_arg_idx_invalid)) | |
10315 { | |
10316 # ifdef FEAT_TERMINAL | |
10317 if (bt_terminal(wp->w_buffer)) | |
10318 { | |
10319 if (term_write_session(fd, wp) == FAIL) | |
10320 return FAIL; | |
10321 } | |
10322 else | |
10323 # endif | |
10324 /* | |
10325 * Load the file. | |
10326 */ | |
10327 if (wp->w_buffer->b_ffname != NULL | |
10328 # ifdef FEAT_QUICKFIX | |
10329 && !bt_nofilename(wp->w_buffer) | |
10330 # endif | |
10331 ) | |
10332 { | |
10333 /* | |
10334 * Editing a file in this buffer: use ":edit file". | |
10335 * This may have side effects! (e.g., compressed or network file). | |
10336 * | |
10337 * Note, if a buffer for that file already exists, use :badd to | |
10338 * edit that buffer, to not lose folding information (:edit resets | |
10339 * folds in other buffers) | |
10340 */ | |
10341 if (fputs("if bufexists(\"", fd) < 0 | |
10342 || ses_fname(fd, wp->w_buffer, flagp, FALSE) == FAIL | |
10343 || fputs("\") | buffer ", fd) < 0 | |
10344 || ses_fname(fd, wp->w_buffer, flagp, FALSE) == FAIL | |
10345 || fputs(" | else | edit ", fd) < 0 | |
10346 || ses_fname(fd, wp->w_buffer, flagp, FALSE) == FAIL | |
10347 || fputs(" | endif", fd) < 0 | |
10348 || put_eol(fd) == FAIL) | |
10349 return FAIL; | |
10350 } | |
10351 else | |
10352 { | |
10353 /* No file in this buffer, just make it empty. */ | |
10354 if (put_line(fd, "enew") == FAIL) | |
10355 return FAIL; | |
10356 #ifdef FEAT_QUICKFIX | |
10357 if (wp->w_buffer->b_ffname != NULL) | |
10358 { | |
10359 /* The buffer does have a name, but it's not a file name. */ | |
10360 if (fputs("file ", fd) < 0 | |
10361 || ses_fname(fd, wp->w_buffer, flagp, TRUE) == FAIL) | |
10362 return FAIL; | |
10363 } | |
10364 #endif | |
10365 do_cursor = FALSE; | |
10366 } | |
10367 } | |
10368 | |
10369 /* | |
10370 * Local mappings and abbreviations. | |
10371 */ | |
10372 if ((*flagp & (SSOP_OPTIONS | SSOP_LOCALOPTIONS)) | |
10373 && makemap(fd, wp->w_buffer) == FAIL) | |
10374 return FAIL; | |
10375 | |
10376 /* | |
10377 * Local options. Need to go to the window temporarily. | |
10378 * Store only local values when using ":mkview" and when ":mksession" is | |
10379 * used and 'sessionoptions' doesn't include "options". | |
10380 * Some folding options are always stored when "folds" is included, | |
10381 * otherwise the folds would not be restored correctly. | |
10382 */ | |
10383 save_curwin = curwin; | |
10384 curwin = wp; | |
10385 curbuf = curwin->w_buffer; | |
10386 if (*flagp & (SSOP_OPTIONS | SSOP_LOCALOPTIONS)) | |
10387 f = makeset(fd, OPT_LOCAL, | |
10388 flagp == &vop_flags || !(*flagp & SSOP_OPTIONS)); | |
10389 #ifdef FEAT_FOLDING | |
10390 else if (*flagp & SSOP_FOLDS) | |
10391 f = makefoldset(fd); | |
10392 #endif | |
10393 else | |
10394 f = OK; | |
10395 curwin = save_curwin; | |
10396 curbuf = curwin->w_buffer; | |
10397 if (f == FAIL) | |
10398 return FAIL; | |
10399 | |
10400 #ifdef FEAT_FOLDING | |
10401 /* | |
10402 * Save Folds when 'buftype' is empty and for help files. | |
10403 */ | |
10404 if ((*flagp & SSOP_FOLDS) | |
10405 && wp->w_buffer->b_ffname != NULL | |
10406 && (bt_normal(wp->w_buffer) || bt_help(wp->w_buffer))) | |
10407 { | |
10408 if (put_folds(fd, wp) == FAIL) | |
10409 return FAIL; | |
10410 } | |
10411 #endif | |
10412 | |
10413 /* | |
10414 * Set the cursor after creating folds, since that moves the cursor. | |
10415 */ | |
10416 if (do_cursor) | |
10417 { | |
10418 | |
10419 /* Restore the cursor line in the file and relatively in the | |
10420 * window. Don't use "G", it changes the jumplist. */ | |
10421 if (fprintf(fd, "let s:l = %ld - ((%ld * winheight(0) + %ld) / %ld)", | |
10422 (long)wp->w_cursor.lnum, | |
10423 (long)(wp->w_cursor.lnum - wp->w_topline), | |
10424 (long)wp->w_height / 2, (long)wp->w_height) < 0 | |
10425 || put_eol(fd) == FAIL | |
10426 || put_line(fd, "if s:l < 1 | let s:l = 1 | endif") == FAIL | |
10427 || put_line(fd, "exe s:l") == FAIL | |
10428 || put_line(fd, "normal! zt") == FAIL | |
10429 || fprintf(fd, "%ld", (long)wp->w_cursor.lnum) < 0 | |
10430 || put_eol(fd) == FAIL) | |
10431 return FAIL; | |
10432 /* Restore the cursor column and left offset when not wrapping. */ | |
10433 if (wp->w_cursor.col == 0) | |
10434 { | |
10435 if (put_line(fd, "normal! 0") == FAIL) | |
10436 return FAIL; | |
10437 } | |
10438 else | |
10439 { | |
10440 if (!wp->w_p_wrap && wp->w_leftcol > 0 && wp->w_width > 0) | |
10441 { | |
10442 if (fprintf(fd, | |
10443 "let s:c = %ld - ((%ld * winwidth(0) + %ld) / %ld)", | |
10444 (long)wp->w_virtcol + 1, | |
10445 (long)(wp->w_virtcol - wp->w_leftcol), | |
10446 (long)wp->w_width / 2, (long)wp->w_width) < 0 | |
10447 || put_eol(fd) == FAIL | |
10448 || put_line(fd, "if s:c > 0") == FAIL | |
10449 || fprintf(fd, | |
10450 " exe 'normal! ' . s:c . '|zs' . %ld . '|'", | |
10451 (long)wp->w_virtcol + 1) < 0 | |
10452 || put_eol(fd) == FAIL | |
10453 || put_line(fd, "else") == FAIL | |
10454 || put_view_curpos(fd, wp, " ") == FAIL | |
10455 || put_line(fd, "endif") == FAIL) | |
10456 return FAIL; | |
10457 } | |
10458 else if (put_view_curpos(fd, wp, "") == FAIL) | |
10459 return FAIL; | |
10460 } | |
10461 } | |
10462 | |
10463 /* | |
10464 * Local directory, if the current flag is not view options or the "curdir" | |
10465 * option is included. | |
10466 */ | |
10467 if (wp->w_localdir != NULL | |
10468 && (flagp != &vop_flags || (*flagp & SSOP_CURDIR))) | |
10469 { | |
10470 if (fputs("lcd ", fd) < 0 | |
10471 || ses_put_fname(fd, wp->w_localdir, flagp) == FAIL | |
10472 || put_eol(fd) == FAIL) | |
10473 return FAIL; | |
10474 did_lcd = TRUE; | |
10475 } | |
10476 | |
10477 return OK; | |
10478 } | |
10479 | |
10480 /* | |
10481 * Write an argument list to the session file. | |
10482 * Returns FAIL if writing fails. | |
10483 */ | |
10484 static int | |
10485 ses_arglist( | |
10486 FILE *fd, | |
10487 char *cmd, | |
10488 garray_T *gap, | |
10489 int fullname, /* TRUE: use full path name */ | |
10490 unsigned *flagp) | |
10491 { | |
10492 int i; | |
10493 char_u *buf = NULL; | |
10494 char_u *s; | |
10495 | |
10496 if (fputs(cmd, fd) < 0 || put_eol(fd) == FAIL) | |
10497 return FAIL; | |
10498 if (put_line(fd, "%argdel") == FAIL) | |
10499 return FAIL; | |
10500 for (i = 0; i < gap->ga_len; ++i) | |
10501 { | |
10502 /* NULL file names are skipped (only happens when out of memory). */ | |
10503 s = alist_name(&((aentry_T *)gap->ga_data)[i]); | |
10504 if (s != NULL) | |
10505 { | |
10506 if (fullname) | |
10507 { | |
10508 buf = alloc(MAXPATHL); | |
10509 if (buf != NULL) | |
10510 { | |
10511 (void)vim_FullName(s, buf, MAXPATHL, FALSE); | |
10512 s = buf; | |
10513 } | |
10514 } | |
10515 if (fputs("$argadd ", fd) < 0 | |
10516 || ses_put_fname(fd, s, flagp) == FAIL | |
10517 || put_eol(fd) == FAIL) | |
10518 { | |
10519 vim_free(buf); | |
10520 return FAIL; | |
10521 } | |
10522 vim_free(buf); | |
10523 } | |
10524 } | |
10525 return OK; | |
10526 } | |
10527 | |
10528 /* | |
10529 * Write a buffer name to the session file. | |
10530 * Also ends the line, if "add_eol" is TRUE. | |
10531 * Returns FAIL if writing fails. | |
10532 */ | |
10533 static int | |
10534 ses_fname(FILE *fd, buf_T *buf, unsigned *flagp, int add_eol) | |
10535 { | |
10536 char_u *name; | |
10537 | |
10538 /* Use the short file name if the current directory is known at the time | |
10539 * the session file will be sourced. | |
10540 * Don't do this for ":mkview", we don't know the current directory. | |
10541 * Don't do this after ":lcd", we don't keep track of what the current | |
10542 * directory is. */ | |
10543 if (buf->b_sfname != NULL | |
10544 && flagp == &ssop_flags | |
10545 && (ssop_flags & (SSOP_CURDIR | SSOP_SESDIR)) | |
10546 #ifdef FEAT_AUTOCHDIR | |
10547 && !p_acd | |
10548 #endif | |
10549 && !did_lcd) | |
10550 name = buf->b_sfname; | |
10551 else | |
10552 name = buf->b_ffname; | |
10553 if (ses_put_fname(fd, name, flagp) == FAIL | |
10554 || (add_eol && put_eol(fd) == FAIL)) | |
10555 return FAIL; | |
10556 return OK; | |
10557 } | |
10558 | |
10559 /* | |
10560 * Write a file name to the session file. | |
10561 * Takes care of the "slash" option in 'sessionoptions' and escapes special | |
10562 * characters. | |
10563 * Returns FAIL if writing fails or out of memory. | |
10564 */ | |
10565 static int | |
10566 ses_put_fname(FILE *fd, char_u *name, unsigned *flagp) | |
10567 { | |
10568 char_u *sname; | |
10569 char_u *p; | |
10570 int retval = OK; | |
10571 | |
10572 sname = home_replace_save(NULL, name); | |
10573 if (sname == NULL) | |
10574 return FAIL; | |
10575 | |
10576 if (*flagp & SSOP_SLASH) | |
10577 { | |
10578 /* change all backslashes to forward slashes */ | |
10579 for (p = sname; *p != NUL; MB_PTR_ADV(p)) | |
10580 if (*p == '\\') | |
10581 *p = '/'; | |
10582 } | |
10583 | |
10584 /* escape special characters */ | |
10585 p = vim_strsave_fnameescape(sname, FALSE); | |
10586 vim_free(sname); | |
10587 if (p == NULL) | |
10588 return FAIL; | |
10589 | |
10590 /* write the result */ | |
10591 if (fputs((char *)p, fd) < 0) | |
10592 retval = FAIL; | |
10593 | |
10594 vim_free(p); | |
10595 return retval; | |
10596 } | |
10597 | |
10598 /* | |
10599 * ":loadview [nr]" | |
10600 */ | |
10601 static void | |
10602 ex_loadview(exarg_T *eap) | |
10603 { | |
10604 char_u *fname; | |
10605 | |
10606 fname = get_view_file(*eap->arg); | |
10607 if (fname != NULL) | |
10608 { | |
10609 do_source(fname, FALSE, DOSO_NONE); | |
10610 vim_free(fname); | |
10611 } | |
10612 } | |
10613 | |
10614 /* | |
10615 * Get the name of the view file for the current buffer. | |
10616 */ | |
10617 static char_u * | |
10618 get_view_file(int c) | |
10619 { | |
10620 int len = 0; | |
10621 char_u *p, *s; | |
10622 char_u *retval; | |
10623 char_u *sname; | |
10624 | |
10625 if (curbuf->b_ffname == NULL) | |
10626 { | |
10627 emsg(_(e_noname)); | |
10628 return NULL; | |
10629 } | |
10630 sname = home_replace_save(NULL, curbuf->b_ffname); | |
10631 if (sname == NULL) | |
10632 return NULL; | |
10633 | |
10634 /* | |
10635 * We want a file name without separators, because we're not going to make | |
10636 * a directory. | |
10637 * "normal" path separator -> "=+" | |
10638 * "=" -> "==" | |
10639 * ":" path separator -> "=-" | |
10640 */ | |
10641 for (p = sname; *p; ++p) | |
10642 if (*p == '=' || vim_ispathsep(*p)) | |
10643 ++len; | |
10644 retval = alloc(STRLEN(sname) + len + STRLEN(p_vdir) + 9); | |
10645 if (retval != NULL) | |
10646 { | |
10647 STRCPY(retval, p_vdir); | |
10648 add_pathsep(retval); | |
10649 s = retval + STRLEN(retval); | |
10650 for (p = sname; *p; ++p) | |
10651 { | |
10652 if (*p == '=') | |
10653 { | |
10654 *s++ = '='; | |
10655 *s++ = '='; | |
10656 } | |
10657 else if (vim_ispathsep(*p)) | |
10658 { | |
10659 *s++ = '='; | |
10660 #if defined(BACKSLASH_IN_FILENAME) || defined(AMIGA) || defined(VMS) | |
10661 if (*p == ':') | |
10662 *s++ = '-'; | |
10663 else | |
10664 #endif | |
10665 *s++ = '+'; | |
10666 } | |
10667 else | |
10668 *s++ = *p; | |
10669 } | |
10670 *s++ = '='; | |
10671 *s++ = c; | |
10672 STRCPY(s, ".vim"); | |
10673 } | |
10674 | |
10675 vim_free(sname); | |
10676 return retval; | |
10677 } | |
10678 | |
10679 #endif /* FEAT_SESSION */ | |
10680 | |
10681 /* | |
10682 * Write end-of-line character(s) for ":mkexrc", ":mkvimrc" and ":mksession". | |
10683 * Return FAIL for a write error. | |
10684 */ | |
10685 int | |
10686 put_eol(FILE *fd) | |
10687 { | |
10688 if ( | |
10689 #ifdef USE_CRNL | |
10690 ( | |
10691 # ifdef MKSESSION_NL | |
10692 !mksession_nl && | |
10693 # endif | |
10694 (putc('\r', fd) < 0)) || | |
10695 #endif | |
10696 (putc('\n', fd) < 0)) | |
10697 return FAIL; | |
10698 return OK; | |
10699 } | |
10700 | |
10701 /* | |
10702 * Write a line to "fd". | |
10703 * Return FAIL for a write error. | |
10704 */ | |
10705 int | |
10706 put_line(FILE *fd, char *s) | |
10707 { | |
10708 if (fputs(s, fd) < 0 || put_eol(fd) == FAIL) | |
10709 return FAIL; | |
10710 return OK; | |
10711 } | |
10712 | |
10713 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO) | 9477 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO) |
10714 /* | 9478 /* |
10715 * Make a dialog message in "buff[DIALOG_MSG_SIZE]". | 9479 * Make a dialog message in "buff[DIALOG_MSG_SIZE]". |
10716 * "format" must contain "%s". | 9480 * "format" must contain "%s". |
10717 */ | 9481 */ |