# HG changeset patch # User Christian Brabandt # Date 1456008304 -3600 # Node ID 973686665238573fc92ac3a0a0240cfcd77d96d7 # Parent 9a197f537595a47248dc43eeb7e9fac2c0caa249 commit https://github.com/vim/vim/commit/b6b5252bcde68b296858bc090cb424493635dfec Author: Bram Moolenaar Date: Sat Feb 20 23:30:07 2016 +0100 patch 7.4.1376 Problem: ch_setoptions() cannot set all options. Solution: Support more options. diff --git a/src/channel.c b/src/channel.c --- a/src/channel.c +++ b/src/channel.c @@ -737,27 +737,58 @@ channel_set_job(channel_T *channel, job_ } /* - * Set various properties from an "options" argument. + * Set various properties from an "opt" argument. */ void -channel_set_options(channel_T *channel, jobopt_T *options) +channel_set_options(channel_T *channel, jobopt_T *opt) { - int part; + int part; + char_u **cbp; - if (options->jo_set & JO_MODE) + if (opt->jo_set & JO_MODE) for (part = PART_SOCK; part <= PART_IN; ++part) - channel->ch_part[part].ch_mode = options->jo_mode; - if (options->jo_set & JO_TIMEOUT) + channel->ch_part[part].ch_mode = opt->jo_mode; + if (opt->jo_set & JO_IN_MODE) + channel->ch_part[PART_IN].ch_mode = opt->jo_in_mode; + if (opt->jo_set & JO_OUT_MODE) + channel->ch_part[PART_OUT].ch_mode = opt->jo_out_mode; + if (opt->jo_set & JO_ERR_MODE) + channel->ch_part[PART_ERR].ch_mode = opt->jo_err_mode; + + if (opt->jo_set & JO_TIMEOUT) for (part = PART_SOCK; part <= PART_IN; ++part) - channel->ch_part[part].ch_timeout = options->jo_timeout; + channel->ch_part[part].ch_timeout = opt->jo_timeout; + if (opt->jo_set & JO_OUT_TIMEOUT) + channel->ch_part[PART_OUT].ch_timeout = opt->jo_out_timeout; + if (opt->jo_set & JO_ERR_TIMEOUT) + channel->ch_part[PART_ERR].ch_timeout = opt->jo_err_timeout; - if (options->jo_set & JO_CALLBACK) + if (opt->jo_set & JO_CALLBACK) { - vim_free(channel->ch_callback); - if (options->jo_callback != NULL && *options->jo_callback != NUL) - channel->ch_callback = vim_strsave(options->jo_callback); + cbp = &channel->ch_callback; + vim_free(*cbp); + if (opt->jo_callback != NULL && *opt->jo_callback != NUL) + *cbp = vim_strsave(opt->jo_callback); else - channel->ch_callback = NULL; + *cbp = NULL; + } + if (opt->jo_set & JO_OUT_CALLBACK) + { + cbp = &channel->ch_part[PART_OUT].ch_callback; + vim_free(*cbp); + if (opt->jo_out_cb != NULL && *opt->jo_out_cb != NUL) + *cbp = vim_strsave(opt->jo_out_cb); + else + *cbp = NULL; + } + if (opt->jo_set & JO_ERR_CALLBACK) + { + cbp = &channel->ch_part[PART_ERR].ch_callback; + vim_free(*cbp); + if (opt->jo_err_cb != NULL && *opt->jo_err_cb != NUL) + *cbp = vim_strsave(opt->jo_err_cb); + else + *cbp = NULL; } } diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -9873,6 +9873,34 @@ get_callback(typval_T *arg) return NULL; } + static int +handle_mode(typval_T *item, jobopt_T *opt, ch_mode_T *modep, int jo) +{ + char_u *val = get_tv_string(item); + + opt->jo_set |= jo; + if (STRCMP(val, "nl") == 0) + *modep = MODE_NL; + else if (STRCMP(val, "raw") == 0) + *modep = MODE_RAW; + else if (STRCMP(val, "js") == 0) + *modep = MODE_JS; + else if (STRCMP(val, "json") == 0) + *modep = MODE_JSON; + else + { + EMSG2(_(e_invarg2), val); + return FAIL; + } + return OK; +} + + static void +clear_job_options(jobopt_T *opt) +{ + vim_memset(opt, 0, sizeof(jobopt_T)); +} + /* * Get the option entries from the dict in "tv", parse them and put the result * in "opt". @@ -9910,21 +9938,32 @@ get_job_options(typval_T *tv, jobopt_T * { if (!(supported & JO_MODE)) break; - opt->jo_set |= JO_MODE; - val = get_tv_string(item); - if (STRCMP(val, "nl") == 0) - opt->jo_mode = MODE_NL; - else if (STRCMP(val, "raw") == 0) - opt->jo_mode = MODE_RAW; - else if (STRCMP(val, "js") == 0) - opt->jo_mode = MODE_JS; - else if (STRCMP(val, "json") == 0) - opt->jo_mode = MODE_JSON; - else - { - EMSG2(_(e_invarg2), val); + if (handle_mode(item, opt, &opt->jo_mode, JO_MODE) == FAIL) + return FAIL; + } + else if (STRCMP(hi->hi_key, "in-mode") == 0) + { + if (!(supported & JO_IN_MODE)) + break; + if (handle_mode(item, opt, &opt->jo_in_mode, JO_IN_MODE) + == FAIL) return FAIL; - } + } + else if (STRCMP(hi->hi_key, "out-mode") == 0) + { + if (!(supported & JO_OUT_MODE)) + break; + if (handle_mode(item, opt, &opt->jo_out_mode, JO_OUT_MODE) + == FAIL) + return FAIL; + } + else if (STRCMP(hi->hi_key, "err-mode") == 0) + { + if (!(supported & JO_ERR_MODE)) + break; + if (handle_mode(item, opt, &opt->jo_err_mode, JO_ERR_MODE) + == FAIL) + return FAIL; } else if (STRCMP(hi->hi_key, "callback") == 0) { @@ -9938,6 +9977,30 @@ get_job_options(typval_T *tv, jobopt_T * return FAIL; } } + else if (STRCMP(hi->hi_key, "out-cb") == 0) + { + if (!(supported & JO_OUT_CALLBACK)) + break; + opt->jo_set |= JO_OUT_CALLBACK; + opt->jo_out_cb = get_callback(item); + if (opt->jo_out_cb == NULL) + { + EMSG2(_(e_invarg2), "out-db"); + return FAIL; + } + } + else if (STRCMP(hi->hi_key, "err-cb") == 0) + { + if (!(supported & JO_ERR_CALLBACK)) + break; + opt->jo_set |= JO_ERR_CALLBACK; + opt->jo_err_cb = get_callback(item); + if (opt->jo_err_cb == NULL) + { + EMSG2(_(e_invarg2), "err-cb"); + return FAIL; + } + } else if (STRCMP(hi->hi_key, "waittime") == 0) { if (!(supported & JO_WAITTIME)) @@ -9952,6 +10015,20 @@ get_job_options(typval_T *tv, jobopt_T * opt->jo_set |= JO_TIMEOUT; opt->jo_timeout = get_tv_number(item); } + else if (STRCMP(hi->hi_key, "out-timeout") == 0) + { + if (!(supported & JO_OUT_TIMEOUT)) + break; + opt->jo_set |= JO_OUT_TIMEOUT; + opt->jo_out_timeout = get_tv_number(item); + } + else if (STRCMP(hi->hi_key, "err-timeout") == 0) + { + if (!(supported & JO_ERR_TIMEOUT)) + break; + opt->jo_set |= JO_ERR_TIMEOUT; + opt->jo_err_timeout = get_tv_number(item); + } else if (STRCMP(hi->hi_key, "part") == 0) { if (!(supported & JO_PART)) @@ -10107,12 +10184,11 @@ f_ch_open(typval_T *argvars, typval_T *r } /* parse options */ + clear_job_options(&opt); opt.jo_mode = MODE_JSON; - opt.jo_callback = NULL; - opt.jo_waittime = 0; opt.jo_timeout = 2000; if (get_job_options(&argvars[1], &opt, - JO_MODE + JO_CALLBACK + JO_WAITTIME + JO_TIMEOUT) == FAIL) + JO_MODE_ALL + JO_CB_ALL + JO_WAITTIME + JO_TIMEOUT_ALL) == FAIL) return; if (opt.jo_timeout < 0) { @@ -10147,7 +10223,7 @@ common_channel_read(typval_T *argvars, t rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; - opt.jo_set = 0; + clear_job_options(&opt); if (get_job_options(&argvars[1], &opt, JO_TIMEOUT + JO_PART + JO_ID) == FAIL) return; @@ -10219,7 +10295,7 @@ send_common(typval_T *argvars, char_u *t part_send = channel_part_send(channel); *part_read = channel_part_read(channel); - opt.jo_callback = NULL; + clear_job_options(&opt); if (get_job_options(&argvars[2], &opt, JO_CALLBACK) == FAIL) return NULL; @@ -10329,7 +10405,9 @@ f_ch_setoptions(typval_T *argvars, typva channel = get_channel_arg(&argvars[0]); if (channel == NULL) return; - if (get_job_options(&argvars[1], &opt, JO_CALLBACK + JO_TIMEOUT) == FAIL) + clear_job_options(&opt); + if (get_job_options(&argvars[1], &opt, + JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL) == FAIL) return; channel_set_options(channel, &opt); } @@ -14684,9 +14762,10 @@ f_job_start(typval_T *argvars UNUSED, ty rettv->vval.v_job->jv_status = JOB_FAILED; /* Default mode is NL. */ + clear_job_options(&opt); opt.jo_mode = MODE_NL; - opt.jo_callback = NULL; - if (get_job_options(&argvars[1], &opt, JO_MODE + JO_CALLBACK) == FAIL) + if (get_job_options(&argvars[1], &opt, + JO_MODE_ALL + JO_CB_ALL + JO_TIMEOUT_ALL) == FAIL) return; #ifndef USE_ARGV diff --git a/src/structs.h b/src/structs.h --- a/src/structs.h +++ b/src/structs.h @@ -1373,14 +1373,25 @@ struct channel_S { int ch_refcount; /* reference count */ }; -#define JO_MODE 1 /* all modes */ -#define JO_CALLBACK 2 /* channel callback */ -#define JO_WAITTIME 4 /* only for ch_open() */ -#define JO_TIMEOUT 8 /* all timeouts */ -#define JO_PART 16 /* "part" */ -#define JO_ID 32 /* "id" */ +#define JO_MODE 0x0001 /* channel mode */ +#define JO_IN_MODE 0x0002 /* stdin mode */ +#define JO_OUT_MODE 0x0004 /* stdout mode */ +#define JO_ERR_MODE 0x0008 /* stderr mode */ +#define JO_CALLBACK 0x0010 /* channel callback */ +#define JO_OUT_CALLBACK 0x0020 /* stdout callback */ +#define JO_ERR_CALLBACK 0x0040 /* stderr callback */ +#define JO_WAITTIME 0x0080 /* only for ch_open() */ +#define JO_TIMEOUT 0x0100 /* all timeouts */ +#define JO_OUT_TIMEOUT 0x0200 /* stdout timeouts */ +#define JO_ERR_TIMEOUT 0x0400 /* stderr timeouts */ +#define JO_PART 0x0800 /* "part" */ +#define JO_ID 0x1000 /* "id" */ #define JO_ALL 0xffffff +#define JO_MODE_ALL (JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE) +#define JO_CB_ALL (JO_CALLBACK + JO_OUT_CALLBACK + JO_ERR_CALLBACK) +#define JO_TIMEOUT_ALL (JO_TIMEOUT + JO_OUT_TIMEOUT + JO_ERR_TIMEOUT) + /* * Options for job and channel commands. */ @@ -1389,9 +1400,16 @@ typedef struct int jo_set; /* JO_ bits for values that were set */ ch_mode_T jo_mode; + ch_mode_T jo_in_mode; + ch_mode_T jo_out_mode; + ch_mode_T jo_err_mode; char_u *jo_callback; /* not allocated! */ + char_u *jo_out_cb; /* not allocated! */ + char_u *jo_err_cb; /* not allocated! */ int jo_waittime; int jo_timeout; + int jo_out_timeout; + int jo_err_timeout; int jo_part; int jo_id; } jobopt_T; diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim --- a/src/testdir/test_channel.vim +++ b/src/testdir/test_channel.vim @@ -147,8 +147,8 @@ func s:communicate(port) " check setting options (without testing the effect) call ch_setoptions(handle, {'callback': 's:NotUsed'}) call ch_setoptions(handle, {'timeout': 1111}) + call ch_setoptions(handle, {'mode': 'json'}) call assert_fails("call ch_setoptions(handle, {'waittime': 111})", "E475") - call assert_fails("call ch_setoptions(handle, {'mode': 'json'})", "E475") call ch_setoptions(handle, {'callback': ''}) " Send an eval request that works. diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -748,6 +748,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1376, +/**/ 1375, /**/ 1374,