]> granicus.if.org Git - vim/commitdiff
patch 7.4.1485 v7.4.1485
authorBram Moolenaar <Bram@vim.org>
Thu, 3 Mar 2016 21:51:40 +0000 (22:51 +0100)
committerBram Moolenaar <Bram@vim.org>
Thu, 3 Mar 2016 21:51:40 +0000 (22:51 +0100)
Problem:    Job input from buffer is not implemented.
Solution:   Implement it.  Add "in-top" and "in-bot" options.

src/channel.c
src/eval.c
src/os_unix.c
src/os_win32.c
src/proto/channel.pro
src/structs.h
src/testdir/test_channel.vim
src/version.c

index 3709d04272140d3a9df8191e2bf8d9d84524f8bb..74cbd14d8b0881cbdfa3433dcbe06cf2cdd30471 100644 (file)
@@ -819,13 +819,32 @@ channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err)
 #endif
 
 /*
- * Sets the job the channel is associated with.
+ * Sets the job the channel is associated with and associated options.
  * This does not keep a refcount, when the job is freed ch_job is cleared.
  */
     void
-channel_set_job(channel_T *channel, job_T *job)
+channel_set_job(channel_T *channel, job_T *job, jobopt_T *options)
 {
     channel->ch_job = job;
+
+    channel_set_options(channel, options);
+
+    if (job->jv_in_buf != NULL)
+    {
+       chanpart_T *in_part = &channel->ch_part[PART_IN];
+
+       in_part->ch_buffer = job->jv_in_buf;
+       ch_logs(channel, "reading from buffer '%s'",
+                                       (char *)in_part->ch_buffer->b_ffname);
+       if (options->jo_set & JO_IN_TOP)
+           in_part->ch_buf_top = options->jo_in_top;
+       else
+           in_part->ch_buf_top = 1;
+       if (options->jo_set & JO_IN_BOT)
+           in_part->ch_buf_bot = options->jo_in_bot;
+       else
+           in_part->ch_buf_bot = in_part->ch_buffer->b_ml.ml_line_count;
+    }
 }
 
 /*
@@ -963,6 +982,47 @@ channel_set_req_callback(
     }
 }
 
+/*
+ * Write any lines to the in channel.
+ */
+    void
+channel_write_in(channel_T *channel)
+{
+    chanpart_T *in_part = &channel->ch_part[PART_IN];
+    linenr_T    lnum;
+    buf_T      *buf = in_part->ch_buffer;
+
+    if (buf == NULL)
+       return;
+    if (!buf_valid(buf) || buf->b_ml.ml_mfp == NULL)
+    {
+       /* buffer was wiped out or unloaded */
+       in_part->ch_buffer = NULL;
+       return;
+    }
+    if (in_part->ch_fd == INVALID_FD)
+       /* pipe was closed */
+       return;
+
+    for (lnum = in_part->ch_buf_top; lnum <= in_part->ch_buf_bot
+                                  && lnum <= buf->b_ml.ml_line_count; ++lnum)
+    {
+       char_u *line = ml_get_buf(buf, lnum, FALSE);
+       int     len = STRLEN(line);
+       char_u *p;
+
+       /* TODO: check if channel can be written to */
+       if ((p = alloc(len + 2)) == NULL)
+           break;
+       STRCPY(p, line);
+       p[len] = NL;
+       p[len + 1] = NUL;
+       channel_send(channel, PART_IN, p, "channel_write_in()");
+       vim_free(p);
+    }
+    in_part->ch_buf_top = lnum;
+}
+
 /*
  * Invoke the "callback" on channel "channel".
  */
index 716706855cfecfaa66895f697bb5d96cb510b72e..23154061c4f7ec48b28d7334a55d6af6c8539cc7 100644 (file)
@@ -9662,7 +9662,26 @@ f_bufloaded(typval_T *argvars, typval_T *rettv)
     rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
 }
 
-static buf_T *get_buf_tv(typval_T *tv, int curtab_only);
+    static buf_T *
+buflist_find_by_name(char_u *name, int curtab_only)
+{
+    int                save_magic;
+    char_u     *save_cpo;
+    buf_T      *buf;
+
+    /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
+    save_magic = p_magic;
+    p_magic = TRUE;
+    save_cpo = p_cpo;
+    p_cpo = (char_u *)"";
+
+    buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
+                                                   TRUE, FALSE, curtab_only));
+
+    p_magic = save_magic;
+    p_cpo = save_cpo;
+    return buf;
+}
 
 /*
  * Get buffer by number or pattern.
@@ -9671,8 +9690,6 @@ static buf_T *get_buf_tv(typval_T *tv, int curtab_only);
 get_buf_tv(typval_T *tv, int curtab_only)
 {
     char_u     *name = tv->vval.v_string;
-    int                save_magic;
-    char_u     *save_cpo;
     buf_T      *buf;
 
     if (tv->v_type == VAR_NUMBER)
@@ -9684,17 +9701,7 @@ get_buf_tv(typval_T *tv, int curtab_only)
     if (name[0] == '$' && name[1] == NUL)
        return lastbuf;
 
-    /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
-    save_magic = p_magic;
-    p_magic = TRUE;
-    save_cpo = p_cpo;
-    p_cpo = (char_u *)"";
-
-    buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
-                                                   TRUE, FALSE, curtab_only));
-
-    p_magic = save_magic;
-    p_cpo = save_cpo;
+    buf = buflist_find_by_name(name, curtab_only);
 
     /* If not found, try expanding the name, like done for bufexists(). */
     if (buf == NULL)
@@ -10110,6 +10117,30 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported)
                opt->jo_io_name[part] =
                       get_tv_string_buf_chk(item, opt->jo_io_name_buf[part]);
            }
+           else if (STRCMP(hi->hi_key, "in-top") == 0
+                   || STRCMP(hi->hi_key, "in-bot") == 0)
+           {
+               linenr_T *lp;
+
+               if (!(supported & JO_OUT_IO))
+                   break;
+               if (hi->hi_key[3] == 't')
+               {
+                   lp = &opt->jo_in_top;
+                   opt->jo_set |= JO_IN_TOP;
+               }
+               else
+               {
+                   lp = &opt->jo_in_bot;
+                   opt->jo_set |= JO_IN_BOT;
+               }
+               *lp = get_tv_number(item);
+               if (*lp < 0)
+               {
+                   EMSG2(_(e_invarg2), get_tv_string(item));
+                   return FAIL;
+               }
+           }
            else if (STRCMP(hi->hi_key, "callback") == 0)
            {
                if (!(supported & JO_CALLBACK))
@@ -15103,6 +15134,29 @@ f_job_start(typval_T *argvars UNUSED, typval_T *rettv)
            JO_MODE_ALL + JO_CB_ALL + JO_TIMEOUT_ALL
                            + JO_STOPONEXIT + JO_EXIT_CB + JO_OUT_IO) == FAIL)
        return;
+
+    if ((opt.jo_set & JO_IN_IO) && opt.jo_io[PART_IN] == JIO_BUFFER)
+    {
+       buf_T *buf;
+
+       /* check that we can find the buffer before starting the job */
+       if (!(opt.jo_set & JO_IN_NAME))
+       {
+           EMSG(_("E915: in-io buffer requires in-name to be set"));
+           return;
+       }
+       buf = buflist_find_by_name(opt.jo_io_name[PART_IN], FALSE);
+       if (buf == NULL)
+           return;
+       if (buf->b_ml.ml_mfp == NULL)
+       {
+           EMSG2(_("E918: buffer must be loaded: %s"),
+                                                    opt.jo_io_name[PART_IN]);
+           return;
+       }
+       job->jv_in_buf = buf;
+    }
+
     job_set_options(job, &opt);
 
 #ifndef USE_ARGV
@@ -15194,6 +15248,10 @@ f_job_start(typval_T *argvars UNUSED, typval_T *rettv)
     mch_start_job((char *)cmd, job, &opt);
 #endif
 
+#ifdef FEAT_CHANNEL
+    channel_write_in(job->jv_channel);
+#endif
+
 theend:
 #ifdef USE_ARGV
     vim_free(argv);
index 8e5ac6c8f071e7fa61a17fa1f5220899eabb9166..bcfffb425f0e1874b21f2456b0d0f6144d462955 100644 (file)
@@ -5141,8 +5141,7 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options)
 # ifdef FEAT_CHANNEL
     channel_set_pipes(channel, fd_in[1], fd_out[0],
                                    use_out_for_err ? INVALID_FD : fd_err[0]);
-    channel_set_job(channel, job);
-    channel_set_options(channel, options);
+    channel_set_job(channel, job, options);
 #  ifdef FEAT_GUI
     channel_gui_register(channel);
 #  endif
index 9c87346fa702eb2f7d29ca6b61931f2660996284..42e8672468492b26dec27ca0e02e20cc04b6aeba 100644 (file)
@@ -5083,9 +5083,7 @@ mch_start_job(char *cmd, job_T *job, jobopt_T *options)
     job->jv_channel = channel;
     channel_set_pipes(channel, (sock_T)ifd[1], (sock_T)ofd[0],
                               use_out_for_err ? INVALID_FD : (sock_T)efd[0]);
-    channel_set_job(channel, job);
-    channel_set_options(channel, options);
-
+    channel_set_job(channel, job, options);
 #   ifdef FEAT_GUI
      channel_gui_register(channel);
 #   endif
index 5fd7f1405e47e5860978956eda64b04ce846464c..7e9d3a82e63bdc18bfbcae97c06f6536de7a14ca 100644 (file)
@@ -10,9 +10,10 @@ void channel_gui_register(channel_T *channel);
 void channel_gui_register_all(void);
 channel_T *channel_open(char *hostname, int port_in, int waittime, void (*nb_close_cb)(void));
 void channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err);
-void channel_set_job(channel_T *channel, job_T *job);
+void channel_set_job(channel_T *channel, job_T *job, jobopt_T *options);
 void channel_set_options(channel_T *channel, jobopt_T *opt);
 void channel_set_req_callback(channel_T *channel, int part, char_u *callback, int id);
+void channel_write_in(channel_T *channel);
 char_u *channel_get(channel_T *channel, int part);
 int channel_collapse(channel_T *channel, int part);
 int channel_can_write_to(channel_T *channel);
index 2989dcd9e36e8705061c6094f1258f3994ec1e93..42ca96c283f4c963c51192004fc3f8b3b034732d 100644 (file)
@@ -1267,6 +1267,8 @@ struct jobvar_S
     int                jv_exitval;
     char_u     *jv_exit_cb;    /* allocated */
 
+    buf_T      *jv_in_buf;     /* buffer from "in-name" */
+
     int                jv_refcount;    /* reference count */
     channel_T  *jv_channel;    /* channel for I/O, reference counted */
 };
@@ -1347,7 +1349,10 @@ typedef struct {
 
     cbq_T      ch_cb_head;     /* dummy node for per-request callbacks */
     char_u     *ch_callback;   /* call when a msg is not handled */
+
     buf_T      *ch_buffer;     /* buffer to read from or write to */
+    linenr_T   ch_buf_top;     /* next line to send */
+    linenr_T   ch_buf_bot;     /* last line to send */
 } chanpart_T;
 
 struct channel_S {
@@ -1402,6 +1407,8 @@ struct channel_S {
 #define JO_OUT_NAME        0x80000     /* "out-name" */
 #define JO_ERR_NAME        0x100000    /* "err-name" (JO_OUT_NAME << 1) */
 #define JO_IN_NAME         0x200000    /* "in-name" (JO_OUT_NAME << 2) */
+#define JO_IN_TOP          0x400000    /* "in-top" */
+#define JO_IN_BOT          0x800000    /* "in-bot" */
 #define JO_ALL             0xffffff
 
 #define JO_MODE_ALL    (JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE)
@@ -1433,6 +1440,9 @@ typedef struct
     char_u     jo_io_name_buf[4][NUMBUFLEN];
     char_u     *jo_io_name[4]; /* not allocated! */
 
+    linenr_T   jo_in_top;
+    linenr_T   jo_in_bot;
+
     char_u     *jo_callback;   /* not allocated! */
     char_u     *jo_out_cb;     /* not allocated! */
     char_u     *jo_err_cb;     /* not allocated! */
index c8779344d1f0af22efc130d36518f11492f217b2..faa89f3e84bcdd1ebe952a9267dfbf5b342e69a7 100644 (file)
@@ -479,6 +479,31 @@ func Test_pipe_to_buffer()
   endtry
 endfunc
 
+func Test_pipe_from_buffer()
+  if !has('job')
+    return
+  endif
+call ch_logfile('channellog', 'w')
+  call ch_log('Test_pipe_from_buffer()')
+
+  sp pipe-input
+  call setline(1, ['echo one', 'echo two', 'echo three'])
+
+  let job = job_start(s:python . " test_channel_pipe.py",
+       \ {'in-io': 'buffer', 'in-name': 'pipe-input'})
+  call assert_equal("run", job_status(job))
+  try
+    let handle = job_getchannel(job)
+    call assert_equal('one', ch_read(handle))
+    call assert_equal('two', ch_read(handle))
+    call assert_equal('three', ch_read(handle))
+    bwipe!
+  finally
+    call job_stop(job)
+  endtry
+call ch_logfile('')
+endfunc
+
 func Test_pipe_to_nameless_buffer()
   if !has('job')
     return
index 512d8561af06086c0f9a92648a21b2db45e72a64..f64660f8ab0ad774d5310ee8a7cd5cf3a84e2e6a 100644 (file)
@@ -743,6 +743,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1485,
 /**/
     1484,
 /**/