To: vim_dev@googlegroups.com Subject: Patch 7.4.1378 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 7.4.1378 Problem: Can't change job settings after it started. Solution: Add job_setoptions() with the "stoponexit" flag. Files: src/eval.c, src/main.c, src/structs.h, src/proto/eval.pro, src/testdir/test_channel.vim *** ../vim-7.4.1377/src/eval.c 2016-02-20 23:30:02.884652677 +0100 --- src/eval.c 2016-02-21 16:37:12.878196474 +0100 *************** *** 451,459 **** static long dict_len(dict_T *d); static char_u *dict2string(typval_T *tv, int copyID); static int get_dict_tv(char_u **arg, typval_T *rettv, int evaluate); - #ifdef FEAT_JOB - static void job_free(job_T *job); - #endif static char_u *echo_string(typval_T *tv, char_u **tofree, char_u *numbuf, int copyID); static char_u *tv2string(typval_T *tv, char_u **tofree, char_u *numbuf, int copyID); static char_u *string_quote(char_u *str, int function); --- 451,456 ---- *************** *** 633,638 **** --- 630,636 ---- # ifdef FEAT_CHANNEL static void f_job_getchannel(typval_T *argvars, typval_T *rettv); # endif + static void f_job_setoptions(typval_T *argvars, typval_T *rettv); static void f_job_start(typval_T *argvars, typval_T *rettv); static void f_job_stop(typval_T *argvars, typval_T *rettv); static void f_job_status(typval_T *argvars, typval_T *rettv); *************** *** 7751,7757 **** } #endif ! #ifdef FEAT_JOB static void job_free(job_T *job) { --- 7749,7757 ---- } #endif ! #if defined(FEAT_JOB) || defined(PROTO) ! static job_T *first_job = NULL; ! static void job_free(job_T *job) { *************** *** 7765,7770 **** --- 7765,7779 ---- } # endif mch_clear_job(job); + + if (job->jv_next != NULL) + job->jv_next->jv_prev = job->jv_prev; + if (job->jv_prev == NULL) + first_job = job->jv_next; + else + job->jv_prev->jv_next = job->jv_next; + + vim_free(job->jv_stoponexit); vim_free(job); } *************** *** 7776,7782 **** } /* ! * Allocate a job. Sets the refcount to one. */ static job_T * job_alloc(void) --- 7785,7791 ---- } /* ! * Allocate a job. Sets the refcount to one and sets options default. */ static job_T * job_alloc(void) *************** *** 7785,7794 **** --- 7794,7838 ---- job = (job_T *)alloc_clear(sizeof(job_T)); if (job != NULL) + { job->jv_refcount = 1; + job->jv_stoponexit = vim_strsave((char_u *)"term"); + + if (first_job != NULL) + { + first_job->jv_prev = job; + job->jv_next = first_job; + } + first_job = job; + } return job; } + static void + job_set_options(job_T *job, jobopt_T *opt) + { + if (opt->jo_set & JO_STOPONEXIT) + { + vim_free(job->jv_stoponexit); + if (opt->jo_stoponexit == NULL || *opt->jo_stoponexit == NUL) + job->jv_stoponexit = NULL; + else + job->jv_stoponexit = vim_strsave(opt->jo_stoponexit); + } + } + + /* + * Called when Vim is exiting: kill all jobs that have the "stoponexit" flag. + */ + void + job_stop_on_exit() + { + job_T *job; + + for (job = first_job; job != NULL; job = job->jv_next) + if (job->jv_stoponexit != NULL && *job->jv_stoponexit != NUL) + mch_stop_job(job, job->jv_stoponexit); + } #endif static char * *************** *** 7797,7805 **** switch (nr) { case VVAL_FALSE: return "v:false"; ! case VVAL_TRUE: return "v:true"; ! case VVAL_NONE: return "v:none"; ! case VVAL_NULL: return "v:null"; } EMSG2(_(e_intern2), "get_var_special_name()"); return "42"; --- 7841,7849 ---- switch (nr) { case VVAL_FALSE: return "v:false"; ! case VVAL_TRUE: return "v:true"; ! case VVAL_NONE: return "v:none"; ! case VVAL_NULL: return "v:null"; } EMSG2(_(e_intern2), "get_var_special_name()"); return "42"; *************** *** 8260,8265 **** --- 8304,8310 ---- # ifdef FEAT_CHANNEL {"job_getchannel", 1, 1, f_job_getchannel}, # endif + {"job_setoptions", 2, 2, f_job_setoptions}, {"job_start", 1, 2, f_job_start}, {"job_status", 1, 1, f_job_status}, {"job_stop", 1, 2, f_job_stop}, *************** *** 10050,10055 **** --- 10095,10113 ---- opt->jo_set |= JO_ID; opt->jo_id = get_tv_number(item); } + else if (STRCMP(hi->hi_key, "stoponexit") == 0) + { + if (!(supported & JO_STOPONEXIT)) + break; + opt->jo_set |= JO_STOPONEXIT; + opt->jo_stoponexit = get_tv_string_buf_chk(item, + opt->jo_soe_buf); + if (opt->jo_stoponexit == NULL) + { + EMSG2(_(e_invarg2), "stoponexit"); + return FAIL; + } + } else break; --todo; *************** *** 14714,14719 **** --- 14772,14797 ---- } #ifdef FEAT_JOB + /* + * Get the job from the argument. + * Returns NULL if the job is invalid. + */ + static job_T * + get_job_arg(typval_T *tv) + { + job_T *job; + + if (tv->v_type != VAR_JOB) + { + EMSG2(_(e_invarg2), get_tv_string(tv)); + return NULL; + } + job = tv->vval.v_job; + + if (job == NULL) + EMSG(_("E916: not a valid job")); + return job; + } # ifdef FEAT_CHANNEL /* *************** *** 14722,14733 **** static void f_job_getchannel(typval_T *argvars, typval_T *rettv) { ! if (argvars[0].v_type != VAR_JOB) ! EMSG(_(e_invarg)); ! else ! { ! job_T *job = argvars[0].vval.v_job; rettv->v_type = VAR_CHANNEL; rettv->vval.v_channel = job->jv_channel; if (job->jv_channel != NULL) --- 14800,14809 ---- static void f_job_getchannel(typval_T *argvars, typval_T *rettv) { ! job_T *job = get_job_arg(&argvars[0]); + if (job != NULL) + { rettv->v_type = VAR_CHANNEL; rettv->vval.v_channel = job->jv_channel; if (job->jv_channel != NULL) *************** *** 14737,14742 **** --- 14813,14835 ---- # endif /* + * "job_setoptions()" function + */ + static void + f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED) + { + job_T *job = get_job_arg(&argvars[0]); + jobopt_T opt; + + if (job == NULL) + return; + clear_job_options(&opt); + if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT) == FAIL) + return; + job_set_options(job, &opt); + } + + /* * "job_start()" function */ static void *************** *** 14765,14772 **** clear_job_options(&opt); opt.jo_mode = MODE_NL; if (get_job_options(&argvars[1], &opt, ! JO_MODE_ALL + JO_CB_ALL + JO_TIMEOUT_ALL) == FAIL) return; #ifndef USE_ARGV ga_init2(&ga, (int)sizeof(char*), 20); --- 14858,14866 ---- clear_job_options(&opt); opt.jo_mode = MODE_NL; if (get_job_options(&argvars[1], &opt, ! JO_MODE_ALL + JO_CB_ALL + JO_TIMEOUT_ALL + JO_STOPONEXIT) == FAIL) return; + job_set_options(job, &opt); #ifndef USE_ARGV ga_init2(&ga, (int)sizeof(char*), 20); *************** *** 14870,14883 **** static void f_job_status(typval_T *argvars, typval_T *rettv) { ! char *result; ! if (argvars[0].v_type != VAR_JOB) ! EMSG(_(e_invarg)); ! else { - job_T *job = argvars[0].vval.v_job; - if (job->jv_status == JOB_ENDED) /* No need to check, dead is dead. */ result = "dead"; --- 14964,14974 ---- static void f_job_status(typval_T *argvars, typval_T *rettv) { ! job_T *job = get_job_arg(&argvars[0]); ! char *result; ! if (job != NULL) { if (job->jv_status == JOB_ENDED) /* No need to check, dead is dead. */ result = "dead"; *************** *** 14896,14904 **** static void f_job_stop(typval_T *argvars UNUSED, typval_T *rettv UNUSED) { ! if (argvars[0].v_type != VAR_JOB) ! EMSG(_(e_invarg)); ! else { char_u *arg; --- 14987,14995 ---- static void f_job_stop(typval_T *argvars UNUSED, typval_T *rettv UNUSED) { ! job_T *job = get_job_arg(&argvars[0]); ! ! if (job != NULL) { char_u *arg; *************** *** 14913,14919 **** return; } } ! if (mch_stop_job(argvars[0].vval.v_job, arg) == FAIL) rettv->vval.v_number = 0; else rettv->vval.v_number = 1; --- 15004,15010 ---- return; } } ! if (mch_stop_job(job, arg) == FAIL) rettv->vval.v_number = 0; else rettv->vval.v_number = 1; *** ../vim-7.4.1377/src/main.c 2016-02-16 15:06:54.665635275 +0100 --- src/main.c 2016-02-21 16:02:52.207743473 +0100 *************** *** 1486,1491 **** --- 1486,1494 ---- windgoto((int)Rows - 1, 0); #endif + #ifdef FEAT_JOB + job_stop_on_exit(); + #endif #ifdef FEAT_LUA lua_end(); #endif *** ../vim-7.4.1377/src/structs.h 2016-02-20 23:30:02.884652677 +0100 --- src/structs.h 2016-02-21 16:13:15.181226453 +0100 *************** *** 1253,1258 **** --- 1253,1260 ---- */ struct jobvar_S { + job_T *jv_next; + job_T *jv_prev; #ifdef UNIX pid_t jv_pid; int jv_exitval; *************** *** 1262,1267 **** --- 1264,1270 ---- HANDLE jv_job_object; #endif jobstatus_T jv_status; + char_u *jv_stoponexit; /* allocated */ int jv_refcount; /* reference count */ channel_T *jv_channel; /* channel for I/O, reference counted */ *************** *** 1386,1391 **** --- 1389,1395 ---- #define JO_ERR_TIMEOUT 0x0400 /* stderr timeouts */ #define JO_PART 0x0800 /* "part" */ #define JO_ID 0x1000 /* "id" */ + #define JO_STOPONEXIT 0x2000 /* "stoponexit" */ #define JO_ALL 0xffffff #define JO_MODE_ALL (JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE) *************** *** 1412,1417 **** --- 1416,1423 ---- int jo_err_timeout; int jo_part; int jo_id; + char_u jo_soe_buf[NUMBUFLEN]; + char_u *jo_stoponexit; } jobopt_T; *** ../vim-7.4.1377/src/proto/eval.pro 2016-02-15 20:39:42.585803341 +0100 --- src/proto/eval.pro 2016-02-21 16:02:59.547666030 +0100 *************** *** 80,85 **** --- 80,86 ---- char_u *get_dict_string(dict_T *d, char_u *key, int save); long get_dict_number(dict_T *d, char_u *key); int channel_unref(channel_T *channel); + void job_stop_on_exit(void); int string2float(char_u *text, float_T *value); char_u *get_function_name(expand_T *xp, int idx); char_u *get_expr_name(expand_T *xp, int idx); *** ../vim-7.4.1377/src/testdir/test_channel.vim 2016-02-21 13:01:49.269594550 +0100 --- src/testdir/test_channel.vim 2016-02-21 16:36:24.478702464 +0100 *************** *** 44,50 **** try if has('job') ! let s:job = job_start(cmd) elseif has('win32') exe 'silent !start cmd /c start "test_channel" ' . cmd else --- 44,51 ---- try if has('job') ! let s:job = job_start(cmd, {"stoponexit": "hup"}) ! call job_setoptions(s:job, {"stoponexit": "kill"}) elseif has('win32') exe 'silent !start cmd /c start "test_channel" ' . cmd else *** ../vim-7.4.1377/src/version.c 2016-02-21 13:01:49.273594509 +0100 --- src/version.c 2016-02-21 15:43:01.916371665 +0100 *************** *** 749,750 **** --- 749,752 ---- { /* Add new patch number below this line */ + /**/ + 1378, /**/ -- A computer programmer is a device for turning requirements into undocumented features. It runs on cola, pizza and Dilbert cartoons. Bram Moolenaar /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///