summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2017-07-17 23:20:24 +0200
committerBram Moolenaar <Bram@vim.org>2017-07-17 23:20:24 +0200
commit96ca27a0ee8ae738cab9fb386984c75c6821e31a (patch)
treed4c986e7262a996a095f6b4b71601dfc361c57a5
parent60d0e97497f1104b31f711072ef174af533b61fa (diff)
downloadvim-git-96ca27a0ee8ae738cab9fb386984c75c6821e31a.tar.gz
patch 8.0.0728: the terminal structure is never freedv8.0.0728
Problem: The terminal structure is never freed. Solution: Free the structure and unreference what it contains.
-rw-r--r--src/buffer.c5
-rw-r--r--src/channel.c15
-rw-r--r--src/evalfunc.c2
-rw-r--r--src/proto/channel.pro2
-rw-r--r--src/proto/terminal.pro1
-rw-r--r--src/terminal.c64
-rw-r--r--src/version.c2
7 files changed, 73 insertions, 18 deletions
diff --git a/src/buffer.c b/src/buffer.c
index e8e1a6de0..dbd4d3ae9 100644
--- 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
index 939b51392..db3468353 100644
--- 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
index 428d7a4c5..33307e527 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -6772,7 +6772,7 @@ f_job_stop(typval_T *argvars, typval_T *rettv)
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
index 6c845ca94..e576584c4 100644
--- 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
index e89b0a26a..58eb77fb5 100644
--- 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
index 63bc6abb1..9d1f35ff1 100644
--- 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
index 77ff8c773..41b0690ef 100644
--- 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,