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