# HG changeset patch # User Christian Brabandt # Date 1500327003 -7200 # Node ID ce434212d68228f43670608f583e5a87f540cb00 # Parent d0213284cfb4d02d7adf78ec61b2e17eabeb86f6 patch 8.0.0728: the terminal structure is never freed commit https://github.com/vim/vim/commit/96ca27a0ee8ae738cab9fb386984c75c6821e31a Author: Bram Moolenaar Date: Mon Jul 17 23:20:24 2017 +0200 patch 8.0.0728: the terminal structure is never freed Problem: The terminal structure is never freed. Solution: Free the structure and unreference what it contains. diff --git a/src/buffer.c b/src/buffer.c --- a/src/buffer.c +++ b/src/buffer.c @@ -859,6 +859,9 @@ free_buffer(buf_T *buf) #ifdef FEAT_JOB_CHANNEL channel_buffer_free(buf); #endif +#ifdef FEAT_TERMINAL + free_terminal(buf->b_term); +#endif buf_hashtab_remove(buf); @@ -1771,7 +1774,7 @@ enter_buffer(buf_T *buf) #endif #ifdef FEAT_SYN_HL - curwin->w_s = &(buf->b_s); + curwin->w_s = &(curbuf->b_s); #endif /* Cursor on first line by default. */ diff --git a/src/channel.c b/src/channel.c --- a/src/channel.c +++ b/src/channel.c @@ -4893,7 +4893,9 @@ job_check_ended(void) } /* - * "job_start()" function + * Create a job and return it. Implements job_start(). + * The returned job has a refcount of one. + * Returns NULL when out of memory. */ job_T * job_start(typval_T *argvars, jobopt_T *opt_arg) @@ -5149,12 +5151,19 @@ job_info(job_T *job, dict_T *dict) dict_add_nr_str(dict, "stoponexit", 0L, job->jv_stoponexit); } +/* + * Send a signal to "job". Implements job_stop(). + * When "type" is not NULL use this for the type. + * Otherwise use argvars[1] for the type. + */ int -job_stop(job_T *job, typval_T *argvars) +job_stop(job_T *job, typval_T *argvars, char *type) { char_u *arg; - if (argvars[1].v_type == VAR_UNKNOWN) + if (type != NULL) + arg = (char_u *)type; + else if (argvars[1].v_type == VAR_UNKNOWN) arg = (char_u *)""; else { diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -6772,7 +6772,7 @@ f_job_stop(typval_T *argvars, typval_T * job_T *job = get_job_arg(&argvars[0]); if (job != NULL) - rettv->vval.v_number = job_stop(job, argvars); + rettv->vval.v_number = job_stop(job, argvars, NULL); } #endif diff --git a/src/proto/channel.pro b/src/proto/channel.pro --- a/src/proto/channel.pro +++ b/src/proto/channel.pro @@ -67,5 +67,5 @@ void job_check_ended(void); job_T *job_start(typval_T *argvars, jobopt_T *opt_arg); char *job_status(job_T *job); void job_info(job_T *job, dict_T *dict); -int job_stop(job_T *job, typval_T *argvars); +int job_stop(job_T *job, typval_T *argvars, char *type); /* vim: set ft=c : */ diff --git a/src/proto/terminal.pro b/src/proto/terminal.pro --- a/src/proto/terminal.pro +++ b/src/proto/terminal.pro @@ -1,5 +1,6 @@ /* terminal.c */ void ex_terminal(exarg_T *eap); +void free_terminal(term_T *term); void write_to_term(buf_T *buffer, char_u *msg, channel_T *channel); void term_update_window(win_T *wp); void terminal_loop(void); diff --git a/src/terminal.c b/src/terminal.c --- a/src/terminal.c +++ b/src/terminal.c @@ -25,11 +25,10 @@ * * TODO: * - pressing Enter sends two CR and/or NL characters to "bash -i"? - * - free b_term when closing terminal. - * - remove term from first_term list when closing terminal. + * Passing Enter as NL seems to work. * - set buffer options to be scratch, hidden, nomodifiable, etc. * - set buffer name to command, add (1) to avoid duplicates. - * - if buffer is wiped, cleanup terminal, may stop job. + * - If [command] is not given the 'shell' option is used. * - if the job ends, write "-- JOB ENDED --" in the terminal * - when closing window and job ended, delete the terminal * - when closing window and job has not ended, make terminal hidden? @@ -43,13 +42,14 @@ * - support minimal size when 'termsize' is "rows*cols". * - support minimal size when 'termsize' is empty. * - implement ":buf {term-buf-name}" - * - implement term_getsize() - * - implement term_setsize() - * - implement term_sendkeys() send keystrokes to a terminal - * - implement term_wait() wait for screen to be updated - * - implement term_scrape() inspect terminal screen - * - implement term_open() open terminal window - * - implement term_getjob() + * - implement term_list() list of buffers with a terminal + * - implement term_getsize(buf) + * - implement term_setsize(buf) + * - implement term_sendkeys(buf, keys) send keystrokes to a terminal + * - implement term_wait(buf) wait for screen to be updated + * - implement term_scrape(buf, row) inspect terminal screen + * - implement term_open(command, options) open terminal window + * - implement term_getjob(buf) * - implement 'termkey' */ @@ -165,7 +165,6 @@ ex_terminal(exarg_T *eap) vterm_screen_reset(screen, 1 /* hard */); /* By default NL means CR-NL. */ - /* TODO: this causes two prompts when using ":term bash -i". */ vterm_input_write(vterm, "\x1b[20h", 5); argvars[0].v_type = VAR_STRING; @@ -185,11 +184,47 @@ ex_terminal(exarg_T *eap) term->tl_job = job_start(argvars, &opt); - /* TODO: setup channel to job */ + if (term->tl_job == NULL) + /* Wiping out the buffer will also close the window. */ + do_buffer(DOBUF_WIPE, DOBUF_CURRENT, FORWARD, 0, TRUE); + /* Setup pty, see mch_call_shell(). */ } /* + * Free a terminal and everything it refers to. + * Kills the job if there is one. + * Called when wiping out a buffer. + */ + void +free_terminal(term_T *term) +{ + term_T *tp; + + if (term == NULL) + return; + if (first_term == term) + first_term = term->tl_next; + else + for (tp = first_term; tp->tl_next != NULL; tp = tp->tl_next) + if (tp->tl_next == term) + { + tp->tl_next = term->tl_next; + break; + } + + if (term->tl_job != NULL) + { + if (term->tl_job->jv_status != JOB_ENDED) + job_stop(term->tl_job, NULL, "kill"); + job_unref(term->tl_job); + } + + vterm_free(term->tl_vterm); + vim_free(term); +} + +/* * Invoked when "msg" output from a job was received. Write it to the terminal * of "buffer". */ @@ -340,7 +375,12 @@ terminal_loop(void) stuffcharReadbuff(Ctrl_W); return; + /* TODO: which of these two should be used? */ +#if 0 case CAR: key = VTERM_KEY_ENTER; break; +#else + case CAR: c = NL; break; +#endif case ESC: key = VTERM_KEY_ESCAPE; break; case K_BS: key = VTERM_KEY_BACKSPACE; break; case K_DEL: key = VTERM_KEY_DEL; break; diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -770,6 +770,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 728, +/**/ 727, /**/ 726,