Skip to content

Commit 4d8bac8

Browse files
committed
patch 8.0.1592: terminal windows in a session are not properly restored
Problem: Terminal windows in a session are not properly restored. Solution: Add "terminal" in 'sessionoptions'. When possible restore the command running in a terminal.
1 parent 20586cb commit 4d8bac8

File tree

12 files changed

+274
-20
lines changed

12 files changed

+274
-20
lines changed

src/channel.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4777,6 +4777,13 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
47774777
opt->jo_set |= JO2_HIDDEN;
47784778
opt->jo_hidden = get_tv_number(item);
47794779
}
4780+
else if (STRCMP(hi->hi_key, "norestore") == 0)
4781+
{
4782+
if (!(supported2 & JO2_NORESTORE))
4783+
break;
4784+
opt->jo_set |= JO2_NORESTORE;
4785+
opt->jo_term_norestore = get_tv_number(item);
4786+
}
47804787
#endif
47814788
else if (STRCMP(hi->hi_key, "env") == 0)
47824789
{
@@ -5470,6 +5477,7 @@ job_start(typval_T *argvars, jobopt_T *opt_arg)
54705477
goto theend;
54715478
}
54725479
#ifdef USE_ARGV
5480+
/* This will modify "cmd". */
54735481
if (mch_parse_cmd(cmd, FALSE, &argv, &argc) == FAIL)
54745482
goto theend;
54755483
argv[argc] = NULL;

src/evalfunc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -867,6 +867,7 @@ static struct fst
867867
{"term_list", 0, 0, f_term_list},
868868
{"term_scrape", 2, 2, f_term_scrape},
869869
{"term_sendkeys", 2, 2, f_term_sendkeys},
870+
{"term_setrestore", 2, 2, f_term_setrestore},
870871
{"term_start", 1, 2, f_term_start},
871872
{"term_wait", 1, 2, f_term_wait},
872873
#endif

src/ex_docmd.c

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11095,6 +11095,11 @@ makeopens(
1109511095
{
1109611096
if (!(only_save_windows && buf->b_nwindows == 0)
1109711097
&& !(buf->b_help && !(ssop_flags & SSOP_HELP))
11098+
#ifdef FEAT_TERMINAL
11099+
/* skip terminal buffers: finished ones are not useful, others
11100+
* will be resurrected and result in a new buffer */
11101+
&& !bt_terminal(buf)
11102+
#endif
1109811103
&& buf->b_fname != NULL
1109911104
&& buf->b_p_bl)
1110011105
{
@@ -11305,7 +11310,8 @@ makeopens(
1130511310
/*
1130611311
* Wipe out an empty unnamed buffer we started in.
1130711312
*/
11308-
if (put_line(fd, "if exists('s:wipebuf')") == FAIL)
11313+
if (put_line(fd, "if exists('s:wipebuf') && s:wipebuf != bufnr('%')")
11314+
== FAIL)
1130911315
return FAIL;
1131011316
if (put_line(fd, " silent exe 'bwipe ' . s:wipebuf") == FAIL)
1131111317
return FAIL;
@@ -11465,6 +11471,12 @@ ses_do_frame(frame_T *fr)
1146511471
static int
1146611472
ses_do_win(win_T *wp)
1146711473
{
11474+
#ifdef FEAT_TERMINAL
11475+
if (bt_terminal(wp->w_buffer))
11476+
return !term_is_finished(wp->w_buffer)
11477+
&& (ssop_flags & SSOP_TERMINAL)
11478+
&& term_should_restore(wp->w_buffer);
11479+
#endif
1146811480
if (wp->w_buffer->b_fname == NULL
1146911481
#ifdef FEAT_QUICKFIX
1147011482
/* When 'buftype' is "nofile" can't restore the window contents. */
@@ -11530,13 +11542,21 @@ put_view(
1153011542
/* Edit the file. Skip this when ":next" already did it. */
1153111543
if (add_edit && (!did_next || wp->w_arg_idx_invalid))
1153211544
{
11545+
# ifdef FEAT_TERMINAL
11546+
if (bt_terminal(wp->w_buffer))
11547+
{
11548+
if (term_write_session(fd, wp) == FAIL)
11549+
return FAIL;
11550+
}
11551+
else
11552+
# endif
1153311553
/*
1153411554
* Load the file.
1153511555
*/
1153611556
if (wp->w_buffer->b_ffname != NULL
11537-
#ifdef FEAT_QUICKFIX
11557+
# ifdef FEAT_QUICKFIX
1153811558
&& !bt_nofile(wp->w_buffer)
11539-
#endif
11559+
# endif
1154011560
)
1154111561
{
1154211562
/*
@@ -11554,8 +11574,7 @@ put_view(
1155411574
|| fputs(" | else | edit ", fd) < 0
1155511575
|| ses_fname(fd, wp->w_buffer, flagp, FALSE) == FAIL
1155611576
|| fputs(" | endif", fd) < 0
11557-
||
11558-
put_eol(fd) == FAIL)
11577+
|| put_eol(fd) == FAIL)
1155911578
return FAIL;
1156011579
}
1156111580
else

src/option.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2403,7 +2403,7 @@ static struct vimoption options[] =
24032403
{"sessionoptions", "ssop", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
24042404
#ifdef FEAT_SESSION
24052405
(char_u *)&p_ssop, PV_NONE,
2406-
{(char_u *)"blank,buffers,curdir,folds,help,options,tabpages,winsize",
2406+
{(char_u *)"blank,buffers,curdir,folds,help,options,tabpages,winsize,terminal",
24072407
(char_u *)0L}
24082408
#else
24092409
(char_u *)NULL, PV_NONE,

src/option.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,7 @@ EXTERN unsigned ssop_flags;
751751
/* Also used for 'viewoptions'! */
752752
static char *(p_ssop_values[]) = {"buffers", "winpos", "resize", "winsize",
753753
"localoptions", "options", "help", "blank", "globals", "slash", "unix",
754-
"sesdir", "curdir", "folds", "cursor", "tabpages", NULL};
754+
"sesdir", "curdir", "folds", "cursor", "tabpages", "terminal", NULL};
755755
# endif
756756
# define SSOP_BUFFERS 0x001
757757
# define SSOP_WINPOS 0x002
@@ -769,6 +769,7 @@ static char *(p_ssop_values[]) = {"buffers", "winpos", "resize", "winsize",
769769
# define SSOP_FOLDS 0x2000
770770
# define SSOP_CURSOR 0x4000
771771
# define SSOP_TABPAGES 0x8000
772+
# define SSOP_TERMINAL 0x10000
772773
#endif
773774
EXTERN char_u *p_sh; /* 'shell' */
774775
EXTERN char_u *p_shcf; /* 'shellcmdflag' */

src/proto/terminal.pro

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
/* terminal.c */
22
void ex_terminal(exarg_T *eap);
3+
int term_write_session(FILE *fd, win_T *wp);
4+
int term_should_restore(buf_T *buf);
5+
void f_term_setrestore(typval_T *argvars, typval_T *rettv);
36
void free_terminal(buf_T *buf);
47
void write_to_term(buf_T *buffer, char_u *msg, channel_T *channel);
58
int term_job_running(term_T *term);

src/structs.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1706,7 +1706,8 @@ struct channel_S {
17061706
#define JO2_HIDDEN 0x0400 /* "hidden" */
17071707
#define JO2_TERM_OPENCMD 0x0800 /* "term_opencmd" */
17081708
#define JO2_EOF_CHARS 0x1000 /* "eof_chars" */
1709-
#define JO2_ALL 0x1FFF
1709+
#define JO2_NORESTORE 0x2000 /* "norestore" */
1710+
#define JO2_ALL 0x2FFF
17101711

17111712
#define JO_MODE_ALL (JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE)
17121713
#define JO_CB_ALL \
@@ -1769,6 +1770,7 @@ typedef struct
17691770
int jo_vertical;
17701771
int jo_curwin;
17711772
int jo_hidden;
1773+
int jo_term_norestore;
17721774
char_u *jo_term_name;
17731775
char_u *jo_term_opencmd;
17741776
int jo_term_finish;

src/terminal.c

Lines changed: 119 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,10 @@
3838
* in tl_scrollback are no longer used.
3939
*
4040
* TODO:
41-
* - What to store in a session file? Shell at the prompt would be OK to
42-
* restore, but others may not. Open the window and let the user start the
43-
* command? Also see #2650.
44-
* - Adding WinBar to terminal window doesn't display, text isn't shifted down.
41+
* - Add a flag to kill the job when Vim is exiting. Useful when it's showing
42+
* a logfile. Or send keys there to make it quit: "exit\r" for a shell.
4543
* - When using 'termguicolors' still use the 16 ANSI colors as-is. Helps for
44+
* - Adding WinBar to terminal window doesn't display, text isn't shifted down.
4645
* a job that uses 16 colors while Vim is using > 256.
4746
* - in GUI vertical split causes problems. Cursor is flickering. (Hirohito
4847
* Higashi, 2017 Sep 19)
@@ -135,6 +134,9 @@ struct terminal_S {
135134
void *tl_winpty_config;
136135
void *tl_winpty;
137136
#endif
137+
#if defined(FEAT_SESSION)
138+
char_u *tl_command;
139+
#endif
138140

139141
/* last known vterm size */
140142
int tl_rows;
@@ -487,6 +489,52 @@ term_start(typval_T *argvar, jobopt_T *opt, int without_job, int forceit)
487489
if (without_job)
488490
return curbuf;
489491

492+
#if defined(FEAT_SESSION)
493+
/* Remember the command for the session file. */
494+
if (opt->jo_term_norestore)
495+
{
496+
term->tl_command = vim_strsave((char_u *)"NONE");
497+
}
498+
else if (argvar->v_type == VAR_STRING)
499+
{
500+
char_u *cmd = argvar->vval.v_string;
501+
502+
if (cmd != NULL && STRCMP(cmd, p_sh) != 0)
503+
term->tl_command = vim_strsave(cmd);
504+
}
505+
else if (argvar->v_type == VAR_LIST
506+
&& argvar->vval.v_list != NULL
507+
&& argvar->vval.v_list->lv_len > 0)
508+
{
509+
garray_T ga;
510+
listitem_T *item;
511+
512+
ga_init2(&ga, 1, 100);
513+
for (item = argvar->vval.v_list->lv_first;
514+
item != NULL; item = item->li_next)
515+
{
516+
char_u *s = get_tv_string_chk(&item->li_tv);
517+
char_u *p;
518+
519+
if (s == NULL)
520+
break;
521+
p = vim_strsave_fnameescape(s, FALSE);
522+
if (p == NULL)
523+
break;
524+
ga_concat(&ga, p);
525+
vim_free(p);
526+
ga_append(&ga, ' ');
527+
}
528+
if (item == NULL)
529+
{
530+
ga_append(&ga, NUL);
531+
term->tl_command = ga.ga_data;
532+
}
533+
else
534+
ga_clear(&ga);
535+
}
536+
#endif
537+
490538
/* System dependent: setup the vterm and maybe start the job in it. */
491539
if (argvar->v_type == VAR_STRING
492540
&& argvar->vval.v_string != NULL
@@ -561,6 +609,8 @@ ex_terminal(exarg_T *eap)
561609
opt.jo_curwin = 1;
562610
else if ((int)(p - cmd) == 6 && STRNICMP(cmd, "hidden", 6) == 0)
563611
opt.jo_hidden = 1;
612+
else if ((int)(p - cmd) == 9 && STRNICMP(cmd, "norestore", 9) == 0)
613+
opt.jo_term_norestore = 1;
564614
else if ((int)(p - cmd) == 4 && STRNICMP(cmd, "rows", 4) == 0
565615
&& ep != NULL && isdigit(ep[1]))
566616
{
@@ -620,6 +670,42 @@ ex_terminal(exarg_T *eap)
620670
vim_free(opt.jo_eof_chars);
621671
}
622672

673+
#if defined(FEAT_SESSION) || defined(PROTO)
674+
/*
675+
* Write a :terminal command to the session file to restore the terminal in
676+
* window "wp".
677+
* Return FAIL if writing fails.
678+
*/
679+
int
680+
term_write_session(FILE *fd, win_T *wp)
681+
{
682+
term_T *term = wp->w_buffer->b_term;
683+
684+
/* Create the terminal and run the command. This is not without
685+
* risk, but let's assume the user only creates a session when this
686+
* will be OK. */
687+
if (fprintf(fd, "terminal ++curwin ++cols=%d ++rows=%d ",
688+
term->tl_cols, term->tl_rows) < 0)
689+
return FAIL;
690+
if (term->tl_command != NULL && fputs((char *)term->tl_command, fd) < 0)
691+
return FAIL;
692+
693+
return put_eol(fd);
694+
}
695+
696+
/*
697+
* Return TRUE if "buf" has a terminal that should be restored.
698+
*/
699+
int
700+
term_should_restore(buf_T *buf)
701+
{
702+
term_T *term = buf->b_term;
703+
704+
return term != NULL && (term->tl_command == NULL
705+
|| STRCMP(term->tl_command, "NONE") != 0);
706+
}
707+
#endif
708+
623709
/*
624710
* Free the scrollback buffer for "term".
625711
*/
@@ -669,6 +755,9 @@ free_terminal(buf_T *buf)
669755

670756
term_free_vterm(term);
671757
vim_free(term->tl_title);
758+
#ifdef FEAT_SESSION
759+
vim_free(term->tl_command);
760+
#endif
672761
vim_free(term->tl_status_text);
673762
vim_free(term->tl_opencmd);
674763
vim_free(term->tl_eof_chars);
@@ -4047,6 +4136,29 @@ f_term_sendkeys(typval_T *argvars, typval_T *rettv)
40474136
}
40484137
}
40494138

4139+
/*
4140+
* "term_setrestore(buf, command)" function
4141+
*/
4142+
void
4143+
f_term_setrestore(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4144+
{
4145+
#if defined(FEAT_SESSION)
4146+
buf_T *buf = term_get_buf(argvars);
4147+
term_T *term;
4148+
char_u *cmd;
4149+
4150+
if (buf == NULL)
4151+
return;
4152+
term = buf->b_term;
4153+
vim_free(term->tl_command);
4154+
cmd = get_tv_string_chk(&argvars[1]);
4155+
if (cmd != NULL)
4156+
term->tl_command = vim_strsave(cmd);
4157+
else
4158+
term->tl_command = NULL;
4159+
#endif
4160+
}
4161+
40504162
/*
40514163
* "term_start(command, options)" function
40524164
*/
@@ -4064,7 +4176,8 @@ f_term_start(typval_T *argvars, typval_T *rettv)
40644176
+ JO_EXIT_CB + JO_CLOSE_CALLBACK + JO_OUT_IO,
40654177
JO2_TERM_NAME + JO2_TERM_FINISH + JO2_HIDDEN + JO2_TERM_OPENCMD
40664178
+ JO2_TERM_COLS + JO2_TERM_ROWS + JO2_VERTICAL + JO2_CURWIN
4067-
+ JO2_CWD + JO2_ENV + JO2_EOF_CHARS) == FAIL)
4179+
+ JO2_CWD + JO2_ENV + JO2_EOF_CHARS
4180+
+ JO2_NORESTORE) == FAIL)
40684181
return;
40694182

40704183
if (opt.jo_vertical)
@@ -4566,6 +4679,7 @@ term_and_job_init(
45664679
{
45674680
create_vterm(term, term->tl_rows, term->tl_cols);
45684681

4682+
/* This will change a string in "argvar". */
45694683
term->tl_job = job_start(argvar, opt);
45704684
if (term->tl_job != NULL)
45714685
++term->tl_job->jv_refcount;

src/testdir/shared.vim

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,3 +270,10 @@ func! Screenline(lnum)
270270
let line = join(chars, '')
271271
return matchstr(line, '^.\{-}\ze\s*$')
272272
endfunc
273+
274+
" Stops the shell running in terminal "buf".
275+
func Stop_shell_in_terminal(buf)
276+
call term_sendkeys(a:buf, "exit\r")
277+
let job = term_getjob(a:buf)
278+
call WaitFor({-> job_status(job) == "dead"})
279+
endfunc

0 commit comments

Comments
 (0)