@@ -451,9 +451,6 @@ static dict_T *dict_copy(dict_T *orig, int deep, int copyID);
451451static long dict_len(dict_T *d);
452452static char_u *dict2string(typval_T *tv, int copyID);
453453static int get_dict_tv(char_u **arg, typval_T *rettv, int evaluate);
454- #ifdef FEAT_JOB
455- static void job_free(job_T *job);
456- #endif
457454static char_u *echo_string(typval_T *tv, char_u **tofree, char_u *numbuf, int copyID);
458455static char_u *tv2string(typval_T *tv, char_u **tofree, char_u *numbuf, int copyID);
459456static char_u *string_quote(char_u *str, int function);
@@ -633,6 +630,7 @@ static void f_items(typval_T *argvars, typval_T *rettv);
633630# ifdef FEAT_CHANNEL
634631static void f_job_getchannel(typval_T *argvars, typval_T *rettv);
635632# endif
633+ static void f_job_setoptions(typval_T *argvars, typval_T *rettv);
636634static void f_job_start(typval_T *argvars, typval_T *rettv);
637635static void f_job_stop(typval_T *argvars, typval_T *rettv);
638636static void f_job_status(typval_T *argvars, typval_T *rettv);
@@ -7751,7 +7749,9 @@ channel_unref(channel_T *channel)
77517749}
77527750#endif
77537751
7754- #ifdef FEAT_JOB
7752+ #if defined(FEAT_JOB) || defined(PROTO)
7753+ static job_T *first_job = NULL;
7754+
77557755 static void
77567756job_free(job_T *job)
77577757{
@@ -7765,6 +7765,15 @@ job_free(job_T *job)
77657765 }
77667766# endif
77677767 mch_clear_job(job);
7768+
7769+ if (job->jv_next != NULL)
7770+ job->jv_next->jv_prev = job->jv_prev;
7771+ if (job->jv_prev == NULL)
7772+ first_job = job->jv_next;
7773+ else
7774+ job->jv_prev->jv_next = job->jv_next;
7775+
7776+ vim_free(job->jv_stoponexit);
77687777 vim_free(job);
77697778}
77707779
@@ -7776,7 +7785,7 @@ job_unref(job_T *job)
77767785}
77777786
77787787/*
7779- * Allocate a job. Sets the refcount to one.
7788+ * Allocate a job. Sets the refcount to one and sets options default .
77807789 */
77817790 static job_T *
77827791job_alloc(void)
@@ -7785,10 +7794,45 @@ job_alloc(void)
77857794
77867795 job = (job_T *)alloc_clear(sizeof(job_T));
77877796 if (job != NULL)
7797+ {
77887798 job->jv_refcount = 1;
7799+ job->jv_stoponexit = vim_strsave((char_u *)"term");
7800+
7801+ if (first_job != NULL)
7802+ {
7803+ first_job->jv_prev = job;
7804+ job->jv_next = first_job;
7805+ }
7806+ first_job = job;
7807+ }
77897808 return job;
77907809}
77917810
7811+ static void
7812+ job_set_options(job_T *job, jobopt_T *opt)
7813+ {
7814+ if (opt->jo_set & JO_STOPONEXIT)
7815+ {
7816+ vim_free(job->jv_stoponexit);
7817+ if (opt->jo_stoponexit == NULL || *opt->jo_stoponexit == NUL)
7818+ job->jv_stoponexit = NULL;
7819+ else
7820+ job->jv_stoponexit = vim_strsave(opt->jo_stoponexit);
7821+ }
7822+ }
7823+
7824+ /*
7825+ * Called when Vim is exiting: kill all jobs that have the "stoponexit" flag.
7826+ */
7827+ void
7828+ job_stop_on_exit()
7829+ {
7830+ job_T *job;
7831+
7832+ for (job = first_job; job != NULL; job = job->jv_next)
7833+ if (job->jv_stoponexit != NULL && *job->jv_stoponexit != NUL)
7834+ mch_stop_job(job, job->jv_stoponexit);
7835+ }
77927836#endif
77937837
77947838 static char *
@@ -7797,9 +7841,9 @@ get_var_special_name(int nr)
77977841 switch (nr)
77987842 {
77997843 case VVAL_FALSE: return "v:false";
7800- case VVAL_TRUE: return "v:true";
7801- case VVAL_NONE: return "v:none";
7802- case VVAL_NULL: return "v:null";
7844+ case VVAL_TRUE: return "v:true";
7845+ case VVAL_NONE: return "v:none";
7846+ case VVAL_NULL: return "v:null";
78037847 }
78047848 EMSG2(_(e_intern2), "get_var_special_name()");
78057849 return "42";
@@ -8260,6 +8304,7 @@ static struct fst
82608304# ifdef FEAT_CHANNEL
82618305 {"job_getchannel", 1, 1, f_job_getchannel},
82628306# endif
8307+ {"job_setoptions", 2, 2, f_job_setoptions},
82638308 {"job_start", 1, 2, f_job_start},
82648309 {"job_status", 1, 1, f_job_status},
82658310 {"job_stop", 1, 2, f_job_stop},
@@ -10050,6 +10095,19 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported)
1005010095 opt->jo_set |= JO_ID;
1005110096 opt->jo_id = get_tv_number(item);
1005210097 }
10098+ else if (STRCMP(hi->hi_key, "stoponexit") == 0)
10099+ {
10100+ if (!(supported & JO_STOPONEXIT))
10101+ break;
10102+ opt->jo_set |= JO_STOPONEXIT;
10103+ opt->jo_stoponexit = get_tv_string_buf_chk(item,
10104+ opt->jo_soe_buf);
10105+ if (opt->jo_stoponexit == NULL)
10106+ {
10107+ EMSG2(_(e_invarg2), "stoponexit");
10108+ return FAIL;
10109+ }
10110+ }
1005310111 else
1005410112 break;
1005510113 --todo;
@@ -14714,6 +14772,26 @@ f_items(typval_T *argvars, typval_T *rettv)
1471414772}
1471514773
1471614774#ifdef FEAT_JOB
14775+ /*
14776+ * Get the job from the argument.
14777+ * Returns NULL if the job is invalid.
14778+ */
14779+ static job_T *
14780+ get_job_arg(typval_T *tv)
14781+ {
14782+ job_T *job;
14783+
14784+ if (tv->v_type != VAR_JOB)
14785+ {
14786+ EMSG2(_(e_invarg2), get_tv_string(tv));
14787+ return NULL;
14788+ }
14789+ job = tv->vval.v_job;
14790+
14791+ if (job == NULL)
14792+ EMSG(_("E916: not a valid job"));
14793+ return job;
14794+ }
1471714795
1471814796# ifdef FEAT_CHANNEL
1471914797/*
@@ -14722,12 +14800,10 @@ f_items(typval_T *argvars, typval_T *rettv)
1472214800 static void
1472314801f_job_getchannel(typval_T *argvars, typval_T *rettv)
1472414802{
14725- if (argvars[0].v_type != VAR_JOB)
14726- EMSG(_(e_invarg));
14727- else
14728- {
14729- job_T *job = argvars[0].vval.v_job;
14803+ job_T *job = get_job_arg(&argvars[0]);
1473014804
14805+ if (job != NULL)
14806+ {
1473114807 rettv->v_type = VAR_CHANNEL;
1473214808 rettv->vval.v_channel = job->jv_channel;
1473314809 if (job->jv_channel != NULL)
@@ -14736,6 +14812,23 @@ f_job_getchannel(typval_T *argvars, typval_T *rettv)
1473614812}
1473714813# endif
1473814814
14815+ /*
14816+ * "job_setoptions()" function
14817+ */
14818+ static void
14819+ f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
14820+ {
14821+ job_T *job = get_job_arg(&argvars[0]);
14822+ jobopt_T opt;
14823+
14824+ if (job == NULL)
14825+ return;
14826+ clear_job_options(&opt);
14827+ if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT) == FAIL)
14828+ return;
14829+ job_set_options(job, &opt);
14830+ }
14831+
1473914832/*
1474014833 * "job_start()" function
1474114834 */
@@ -14765,8 +14858,9 @@ f_job_start(typval_T *argvars UNUSED, typval_T *rettv)
1476514858 clear_job_options(&opt);
1476614859 opt.jo_mode = MODE_NL;
1476714860 if (get_job_options(&argvars[1], &opt,
14768- JO_MODE_ALL + JO_CB_ALL + JO_TIMEOUT_ALL) == FAIL)
14861+ JO_MODE_ALL + JO_CB_ALL + JO_TIMEOUT_ALL + JO_STOPONEXIT ) == FAIL)
1476914862 return;
14863+ job_set_options(job, &opt);
1477014864
1477114865#ifndef USE_ARGV
1477214866 ga_init2(&ga, (int)sizeof(char*), 20);
@@ -14870,14 +14964,11 @@ f_job_start(typval_T *argvars UNUSED, typval_T *rettv)
1487014964 static void
1487114965f_job_status(typval_T *argvars, typval_T *rettv)
1487214966{
14873- char *result;
14967+ job_T *job = get_job_arg(&argvars[0]);
14968+ char *result;
1487414969
14875- if (argvars[0].v_type != VAR_JOB)
14876- EMSG(_(e_invarg));
14877- else
14970+ if (job != NULL)
1487814971 {
14879- job_T *job = argvars[0].vval.v_job;
14880-
1488114972 if (job->jv_status == JOB_ENDED)
1488214973 /* No need to check, dead is dead. */
1488314974 result = "dead";
@@ -14896,9 +14987,9 @@ f_job_status(typval_T *argvars, typval_T *rettv)
1489614987 static void
1489714988f_job_stop(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1489814989{
14899- if ( argvars[0].v_type != VAR_JOB)
14900- EMSG(_(e_invarg));
14901- else
14990+ job_T *job = get_job_arg(& argvars[0]);
14991+
14992+ if (job != NULL)
1490214993 {
1490314994 char_u *arg;
1490414995
@@ -14913,7 +15004,7 @@ f_job_stop(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1491315004 return;
1491415005 }
1491515006 }
14916- if (mch_stop_job(argvars[0].vval.v_job , arg) == FAIL)
15007+ if (mch_stop_job(job , arg) == FAIL)
1491715008 rettv->vval.v_number = 0;
1491815009 else
1491915010 rettv->vval.v_number = 1;
0 commit comments