diff options
author | Bram Moolenaar <Bram@vim.org> | 2016-03-03 22:51:40 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2016-03-03 22:51:40 +0100 |
commit | 014069a7ac51557e531eb3c8b94e36f2193f6c21 (patch) | |
tree | 82f6fa36a91227356a4e120f6f6c24101369abc5 | |
parent | c25558bff4ed10d2642e6f5c016701641c494916 (diff) | |
download | vim-git-014069a7ac51557e531eb3c8b94e36f2193f6c21.tar.gz |
patch 7.4.1485v7.4.1485
Problem: Job input from buffer is not implemented.
Solution: Implement it. Add "in-top" and "in-bot" options.
-rw-r--r-- | src/channel.c | 64 | ||||
-rw-r--r-- | src/eval.c | 86 | ||||
-rw-r--r-- | src/os_unix.c | 3 | ||||
-rw-r--r-- | src/os_win32.c | 4 | ||||
-rw-r--r-- | src/proto/channel.pro | 3 | ||||
-rw-r--r-- | src/structs.h | 10 | ||||
-rw-r--r-- | src/testdir/test_channel.vim | 25 | ||||
-rw-r--r-- | src/version.c | 2 |
8 files changed, 175 insertions, 22 deletions
diff --git a/src/channel.c b/src/channel.c index 3709d0427..74cbd14d8 100644 --- a/src/channel.c +++ b/src/channel.c @@ -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; + } } /* @@ -964,6 +983,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". */ static void diff --git a/src/eval.c b/src/eval.c index 716706855..23154061c 100644 --- a/src/eval.c +++ b/src/eval.c @@ -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); diff --git a/src/os_unix.c b/src/os_unix.c index 8e5ac6c8f..bcfffb425 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -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 diff --git a/src/os_win32.c b/src/os_win32.c index 9c87346fa..42e867246 100644 --- a/src/os_win32.c +++ b/src/os_win32.c @@ -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 diff --git a/src/proto/channel.pro b/src/proto/channel.pro index 5fd7f1405..7e9d3a82e 100644 --- a/src/proto/channel.pro +++ b/src/proto/channel.pro @@ -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); diff --git a/src/structs.h b/src/structs.h index 2989dcd9e..42ca96c28 100644 --- a/src/structs.h +++ b/src/structs.h @@ -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! */ diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim index c8779344d..faa89f3e8 100644 --- a/src/testdir/test_channel.vim +++ b/src/testdir/test_channel.vim @@ -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 diff --git a/src/version.c b/src/version.c index 512d8561a..f64660f8a 100644 --- a/src/version.c +++ b/src/version.c @@ -744,6 +744,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1485, +/**/ 1484, /**/ 1483, |