diff src/channel.c @ 13778:5f6c61a71c02 v8.0.1761

patch 8.0.1761: job in terminal window with no output channel is killed commit https://github.com/vim/vim/commit/4e9d443a25b451e3f2de62e9eeea439aa4c3f039 Author: Bram Moolenaar <Bram@vim.org> Date: Tue Apr 24 20:54:07 2018 +0200 patch 8.0.1761: job in terminal window with no output channel is killed Problem: Job in terminal window with no output channel is killed. Solution: Keep the job running when the input is a tty. (Ozaki Kiichi, closes #2734)
author Christian Brabandt <cb@256bit.org>
date Tue, 24 Apr 2018 21:00:07 +0200
parents 3ab6198c1f9a
children c01864ecf233
line wrap: on
line diff
--- a/src/channel.c
+++ b/src/channel.c
@@ -345,6 +345,15 @@ channel_still_useful(channel_T *channel)
 }
 
 /*
+ * Return TRUE if "channel" is closeable (i.e. all readable fds are closed).
+ */
+    static int
+channel_can_close(channel_T *channel)
+{
+    return channel->ch_to_be_closed == 0;
+}
+
+/*
  * Close a channel and free all its resources.
  */
     static void
@@ -892,7 +901,7 @@ channel_open(
     channel->ch_nb_close_cb = nb_close_cb;
     channel->ch_hostname = (char *)vim_strsave((char_u *)hostname);
     channel->ch_port = port_in;
-    channel->ch_to_be_closed |= (1 << PART_SOCK);
+    channel->ch_to_be_closed |= (1U << PART_SOCK);
 
 #ifdef FEAT_GUI
     channel_gui_register_one(channel, PART_SOCK);
@@ -988,7 +997,8 @@ ch_close_part(channel_T *channel, ch_par
 	}
 	*fd = INVALID_FD;
 
-	channel->ch_to_be_closed &= ~(1 << part);
+	/* channel is closed, may want to end the job if it was the last */
+	channel->ch_to_be_closed &= ~(1U << part);
     }
 }
 
@@ -999,6 +1009,12 @@ channel_set_pipes(channel_T *channel, so
     {
 	ch_close_part(channel, PART_IN);
 	channel->CH_IN_FD = in;
+# if defined(UNIX)
+	/* Do not end the job when all output channels are closed, wait until
+	 * the job ended. */
+	if (isatty(in))
+	    channel->ch_to_be_closed |= (1U << PART_IN);
+# endif
     }
     if (out != INVALID_FD)
     {
@@ -1007,7 +1023,7 @@ channel_set_pipes(channel_T *channel, so
 # endif
 	ch_close_part(channel, PART_OUT);
 	channel->CH_OUT_FD = out;
-	channel->ch_to_be_closed |= (1 << PART_OUT);
+	channel->ch_to_be_closed |= (1U << PART_OUT);
 # if defined(FEAT_GUI)
 	channel_gui_register_one(channel, PART_OUT);
 # endif
@@ -1019,7 +1035,7 @@ channel_set_pipes(channel_T *channel, so
 # endif
 	ch_close_part(channel, PART_ERR);
 	channel->CH_ERR_FD = err;
-	channel->ch_to_be_closed |= (1 << PART_ERR);
+	channel->ch_to_be_closed |= (1U << PART_ERR);
 # if defined(FEAT_GUI)
 	channel_gui_register_one(channel, PART_ERR);
 # endif
@@ -4200,9 +4216,9 @@ channel_parse_messages(void)
     }
     while (channel != NULL)
     {
-	if (channel->ch_to_be_closed == 0)
+	if (channel_can_close(channel))
 	{
-	    channel->ch_to_be_closed = (1 << PART_COUNT);
+	    channel->ch_to_be_closed = (1U << PART_COUNT);
 	    channel_close_now(channel);
 	    /* channel may have been freed, start over */
 	    channel = first_channel;
@@ -5080,6 +5096,15 @@ job_channel_still_useful(job_T *job)
 }
 
 /*
+ * Return TRUE if the channel of "job" is closeable.
+ */
+    static int
+job_channel_can_close(job_T *job)
+{
+    return job->jv_channel != NULL && channel_can_close(job->jv_channel);
+}
+
+/*
  * Return TRUE if the job should not be freed yet.  Do not free the job when
  * it has not ended yet and there is a "stoponexit" flag, an exit callback
  * or when the associated channel will do something with the job output.
@@ -5209,6 +5234,10 @@ job_cleanup(job_T *job)
     /* Ready to cleanup the job. */
     job->jv_status = JOB_FINISHED;
 
+    /* When only channel-in is kept open, close explicitly. */
+    if (job->jv_channel != NULL)
+	ch_close_part(job->jv_channel, PART_IN);
+
     if (job->jv_exit_cb != NULL)
     {
 	typval_T	argv[3];
@@ -5413,8 +5442,9 @@ has_pending_job(void)
     for (job = first_job; job != NULL; job = job->jv_next)
 	/* Only should check if the channel has been closed, if the channel is
 	 * open the job won't exit. */
-	if (job->jv_status == JOB_STARTED && job->jv_exit_cb != NULL
-					    && !job_channel_still_useful(job))
+	if ((job->jv_status == JOB_STARTED && !job_channel_still_useful(job))
+		    || (job->jv_status == JOB_FINISHED
+					      && job_channel_can_close(job)))
 	    return TRUE;
     return FALSE;
 }