diff options
author | Bram Moolenaar <Bram@vim.org> | 2016-02-07 14:27:38 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2016-02-07 14:27:38 +0100 |
commit | 835dc636a5350f610b62f110227d2363b5b2880a (patch) | |
tree | d14dbbe08553b530c8fd593844a34c244a05677d /src/eval.c | |
parent | c5f98ee987ae0c369867cf6cc581c766d3c0226d (diff) | |
download | vim-git-835dc636a5350f610b62f110227d2363b5b2880a.tar.gz |
patch 7.4.1274v7.4.1274
Problem: Cannot run a job.
Solution: Add job_start(), job_status() and job_stop(). Currently only works
for Unix.
Diffstat (limited to 'src/eval.c')
-rw-r--r-- | src/eval.c | 313 |
1 files changed, 289 insertions, 24 deletions
diff --git a/src/eval.c b/src/eval.c index a50fdbf27..833c41c04 100644 --- a/src/eval.c +++ b/src/eval.c @@ -451,6 +451,9 @@ static dict_T *dict_copy(dict_T *orig, int deep, int copyID); 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); @@ -619,6 +622,11 @@ static void f_invert(typval_T *argvars, typval_T *rettv); static void f_isdirectory(typval_T *argvars, typval_T *rettv); static void f_islocked(typval_T *argvars, typval_T *rettv); static void f_items(typval_T *argvars, typval_T *rettv); +#ifdef FEAT_JOB +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); +#endif static void f_join(typval_T *argvars, typval_T *rettv); static void f_jsondecode(typval_T *argvars, typval_T *rettv); static void f_jsonencode(typval_T *argvars, typval_T *rettv); @@ -3062,10 +3070,11 @@ tv_op(typval_T *tv1, typval_T *tv2, char_u *op) { switch (tv1->v_type) { + case VAR_UNKNOWN: case VAR_DICT: case VAR_FUNC: case VAR_SPECIAL: - case VAR_UNKNOWN: + case VAR_JOB: break; case VAR_LIST: @@ -3844,6 +3853,7 @@ item_lock(typval_T *tv, int deep, int lock) case VAR_FUNC: case VAR_FLOAT: case VAR_SPECIAL: + case VAR_JOB: break; case VAR_LIST: @@ -5339,6 +5349,7 @@ eval_index( return FAIL; #endif case VAR_SPECIAL: + case VAR_JOB: if (verbose) EMSG(_("E909: Cannot index a special variable")); return FAIL; @@ -5446,10 +5457,11 @@ eval_index( switch (rettv->v_type) { - case VAR_SPECIAL: + case VAR_UNKNOWN: case VAR_FUNC: case VAR_FLOAT: - case VAR_UNKNOWN: + case VAR_SPECIAL: + case VAR_JOB: break; /* not evaluating, skipping over subscript */ case VAR_NUMBER: @@ -6167,9 +6179,6 @@ tv_equal( switch (tv1->v_type) { - case VAR_UNKNOWN: - break; - case VAR_LIST: ++recursive_cnt; r = list_equal(tv1->vval.v_list, tv2->vval.v_list, ic, TRUE); @@ -6190,11 +6199,6 @@ tv_equal( case VAR_NUMBER: return tv1->vval.v_number == tv2->vval.v_number; -#ifdef FEAT_FLOAT - case VAR_FLOAT: - return tv1->vval.v_float == tv2->vval.v_float; -#endif - case VAR_STRING: s1 = get_tv_string_buf(tv1, buf1); s2 = get_tv_string_buf(tv2, buf2); @@ -6202,6 +6206,17 @@ tv_equal( case VAR_SPECIAL: return tv1->vval.v_number == tv2->vval.v_number; + + case VAR_FLOAT: +#ifdef FEAT_FLOAT + return tv1->vval.v_float == tv2->vval.v_float; +#endif + case VAR_JOB: +#ifdef FEAT_JOB + return tv1->vval.v_job == tv2->vval.v_job; +#endif + case VAR_UNKNOWN: + break; } /* VAR_UNKNOWN can be the result of a invalid expression, let's say it @@ -6924,7 +6939,7 @@ garbage_collect(void) } /* - * Free lists and dictionaries that are no longer referenced. + * Free lists, dictionaries and jobs that are no longer referenced. */ static int free_unref_items(int copyID) @@ -6969,6 +6984,7 @@ free_unref_items(int copyID) } ll = ll_next; } + return did_free; } @@ -7694,6 +7710,40 @@ failret: return OK; } +#ifdef FEAT_JOB + static void +job_free(job_T *job) +{ + /* TODO: free any handles */ + + vim_free(job); +} + + static void +job_unref(job_T *job) +{ + if (job != NULL && --job->jv_refcount <= 0) + job_free(job); +} + +/* + * Allocate a job. Sets the refcount to one. + */ + static job_T * +job_alloc(void) +{ + job_T *job; + + job = (job_T *)alloc_clear(sizeof(job_T)); + if (job != NULL) + { + job->jv_refcount = 1; + } + return job; +} + +#endif + static char * get_var_special_name(int nr) { @@ -7789,12 +7839,13 @@ echo_string( case VAR_STRING: case VAR_NUMBER: case VAR_UNKNOWN: + case VAR_JOB: *tofree = NULL; r = get_tv_string_buf(tv, numbuf); break; -#ifdef FEAT_FLOAT case VAR_FLOAT: +#ifdef FEAT_FLOAT *tofree = NULL; vim_snprintf((char *)numbuf, NUMBUFLEN, "%g", tv->vval.v_float); r = numbuf; @@ -7844,6 +7895,7 @@ tv2string( case VAR_LIST: case VAR_DICT: case VAR_SPECIAL: + case VAR_JOB: case VAR_UNKNOWN: break; } @@ -8148,6 +8200,11 @@ static struct fst {"isdirectory", 1, 1, f_isdirectory}, {"islocked", 1, 1, f_islocked}, {"items", 1, 1, f_items}, +#ifdef FEAT_CHANNEL + {"job_start", 1, 2, f_job_start}, + {"job_status", 1, 1, f_job_status}, + {"job_stop", 1, 1, f_job_stop}, +#endif {"join", 1, 2, f_join}, {"jsondecode", 1, 1, f_jsondecode}, {"jsonencode", 1, 1, f_jsonencode}, @@ -10535,8 +10592,8 @@ f_empty(typval_T *argvars, typval_T *rettv) case VAR_NUMBER: n = argvars[0].vval.v_number == 0; break; -#ifdef FEAT_FLOAT case VAR_FLOAT: +#ifdef FEAT_FLOAT n = argvars[0].vval.v_float == 0.0; break; #endif @@ -10552,6 +10609,11 @@ f_empty(typval_T *argvars, typval_T *rettv) n = argvars[0].vval.v_number != VVAL_TRUE; break; + case VAR_JOB: +#ifdef FEAT_JOB + n = argvars[0].vval.v_job->jv_status != JOB_STARTED; + break; +#endif case VAR_UNKNOWN: EMSG2(_(e_intern2), "f_empty(UNKNOWN)"); n = TRUE; @@ -13060,6 +13122,9 @@ f_has(typval_T *argvars, typval_T *rettv) #ifdef FEAT_INS_EXPAND "insert_expand", #endif +#ifdef FEAT_JOB + "job", +#endif #ifdef FEAT_JUMPLIST "jumplist", #endif @@ -14188,6 +14253,161 @@ f_items(typval_T *argvars, typval_T *rettv) dict_list(argvars, rettv, 2); } +#ifdef FEAT_JOB +/* + * "job_start()" function + */ + static void +f_job_start(typval_T *argvars UNUSED, typval_T *rettv) +{ + job_T *job; + char_u *cmd = NULL; +#if defined(UNIX) +# define USE_ARGV + char **argv = NULL; + int argc = 0; +#else + garray_T ga; +#endif + + rettv->v_type = VAR_JOB; + job = job_alloc(); + rettv->vval.v_job = job; + if (job == NULL) + return; + + rettv->vval.v_job->jv_status = JOB_FAILED; +#ifndef USE_ARGV + ga_init2(&ga, 200); +#endif + + if (argvars[0].v_type == VAR_STRING) + { + /* Command is a string. */ + cmd = argvars[0].vval.v_string; +#ifdef USE_ARGV + if (mch_parse_cmd(cmd, FALSE, &argv, &argc) == FAIL) + return; + argv[argc] = NULL; +#endif + } + else if (argvars[0].v_type != VAR_LIST + || argvars[0].vval.v_list == NULL + || argvars[0].vval.v_list->lv_len < 1) + { + EMSG(_(e_invarg)); + return; + } + else + { + list_T *l = argvars[0].vval.v_list; + listitem_T *li; + char_u *s; + +#ifdef USE_ARGV + /* Pass argv[] to mch_call_shell(). */ + argv = (char **)alloc(sizeof(char *) * (l->lv_len + 1)); + if (argv == NULL) + return; +#endif + for (li = l->lv_first; li != NULL; li = li->li_next) + { + s = get_tv_string_chk(&li->li_tv); + if (s == NULL) + goto theend; +#ifdef USE_ARGV + argv[argc++] = (char *)s; +#else + if (li != l->lv_first) + { + s = vim_strsave_shellescape(s, FALSE, TRUE); + if (s == NULL) + goto theend; + } + ga_concat(&ga, s); + vim_free(s); + if (li->li_next != NULL) + ga_append(&ga, ' '); +#endif + } +#ifdef USE_ARGV + argv[argc] = NULL; +#else + cmd = ga.ga_data; +#endif + } +#ifdef USE_ARGV + mch_start_job(argv, job); +#else + mch_start_job(cmd, job); +#endif + +theend: +#ifdef USE_ARGV + if (argv != NULL) + vim_free(argv); +#else + vim_free(ga.ga_data); +#endif +} + +/* + * "job_status()" function + */ + static void +f_job_status(typval_T *argvars UNUSED, typval_T *rettv UNUSED) +{ + 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"; + else if (job->jv_status == JOB_FAILED) + result = "fail"; + else + result = mch_job_status(job); + rettv->v_type = VAR_STRING; + rettv->vval.v_string = vim_strsave((char_u *)result); + } +} + +/* + * "job_stop()" function + */ + 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; + + if (argvars[1].v_type == VAR_UNKNOWN) + arg = (char_u *)""; + else + { + arg = get_tv_string_chk(&argvars[1]); + if (arg == NULL) + { + EMSG(_(e_invarg)); + return; + } + } + if (mch_stop_job(argvars[0].vval.v_job, arg) == FAIL) + rettv->vval.v_number = 0; + else + rettv->vval.v_number = 1; + } +} +#endif + /* * "join()" function */ @@ -14295,6 +14515,7 @@ f_len(typval_T *argvars, typval_T *rettv) case VAR_SPECIAL: case VAR_FLOAT: case VAR_FUNC: + case VAR_JOB: EMSG(_("E701: Invalid type for len()")); break; } @@ -19658,6 +19879,9 @@ f_type(typval_T *argvars, typval_T *rettv) else n = 7; break; +#ifdef FEAT_JOB + case VAR_JOB: n = 8; break; +#endif case VAR_UNKNOWN: EMSG2(_(e_intern2), "f_type(UNKNOWN)"); n = -1; @@ -21024,10 +21248,13 @@ free_tv(typval_T *varp) case VAR_DICT: dict_unref(varp->vval.v_dict); break; + case VAR_JOB: +#ifdef FEAT_JOB + job_unref(varp->vval.v_job); + break; +#endif case VAR_NUMBER: -#ifdef FEAT_FLOAT case VAR_FLOAT: -#endif case VAR_UNKNOWN: case VAR_SPECIAL: break; @@ -21065,11 +21292,17 @@ clear_tv(typval_T *varp) case VAR_SPECIAL: varp->vval.v_number = 0; break; -#ifdef FEAT_FLOAT case VAR_FLOAT: +#ifdef FEAT_FLOAT varp->vval.v_float = 0.0; break; #endif + case VAR_JOB: +#ifdef FEAT_JOB + job_unref(varp->vval.v_job); + varp->vval.v_job = NULL; +#endif + break; case VAR_UNKNOWN: break; } @@ -21112,8 +21345,8 @@ get_tv_number_chk(typval_T *varp, int *denote) { case VAR_NUMBER: return (long)(varp->vval.v_number); -#ifdef FEAT_FLOAT case VAR_FLOAT: +#ifdef FEAT_FLOAT EMSG(_("E805: Using a Float as a Number")); break; #endif @@ -21134,6 +21367,11 @@ get_tv_number_chk(typval_T *varp, int *denote) case VAR_SPECIAL: return varp->vval.v_number == VVAL_TRUE ? 1 : 0; break; + case VAR_JOB: +#ifdef FEAT_JOB + EMSG(_("E910: Using a Job as a Number")); + break; +#endif case VAR_UNKNOWN: EMSG2(_(e_intern2), "get_tv_number(UNKNOWN)"); break; @@ -21153,10 +21391,8 @@ get_tv_float(typval_T *varp) { case VAR_NUMBER: return (float_T)(varp->vval.v_number); -#ifdef FEAT_FLOAT case VAR_FLOAT: return varp->vval.v_float; -#endif case VAR_FUNC: EMSG(_("E891: Using a Funcref as a Float")); break; @@ -21172,6 +21408,11 @@ get_tv_float(typval_T *varp) case VAR_SPECIAL: EMSG(_("E907: Using a special value as a Float")); break; + case VAR_JOB: +# ifdef FEAT_JOB + EMSG(_("E911: Using a Job as a Float")); + break; +# endif case VAR_UNKNOWN: EMSG2(_(e_intern2), "get_tv_float(UNKNOWN)"); break; @@ -21272,8 +21513,8 @@ get_tv_string_buf_chk(typval_T *varp, char_u *buf) case VAR_DICT: EMSG(_("E731: using Dictionary as a String")); break; -#ifdef FEAT_FLOAT case VAR_FLOAT: +#ifdef FEAT_FLOAT EMSG(_(e_float_as_string)); break; #endif @@ -21284,6 +21525,24 @@ get_tv_string_buf_chk(typval_T *varp, char_u *buf) case VAR_SPECIAL: STRCPY(buf, get_var_special_name(varp->vval.v_number)); return buf; + case VAR_JOB: +#ifdef FEAT_JOB + { + job_T *job = varp->vval.v_job; + char *status = job->jv_status == JOB_FAILED ? "fail" + : job->jv_status == JOB_ENDED ? "dead" + : "run"; +# ifdef UNIX + vim_snprintf((char *)buf, NUMBUFLEN, + "process %ld %s", (long)job->jv_pid, status); +# else + /* TODO */ + vim_snprintf((char *)buf, NUMBUFLEN, "process ? %s", status); +# endif + return buf; + } +#endif + break; case VAR_UNKNOWN: EMSG(_("E908: using an invalid value as a String")); break; @@ -21903,11 +22162,17 @@ copy_tv(typval_T *from, typval_T *to) case VAR_SPECIAL: to->vval.v_number = from->vval.v_number; break; -#ifdef FEAT_FLOAT case VAR_FLOAT: +#ifdef FEAT_FLOAT to->vval.v_float = from->vval.v_float; break; #endif + case VAR_JOB: +#ifdef FEAT_FLOAT + to->vval.v_job = from->vval.v_job; + ++to->vval.v_job->jv_refcount; + break; +#endif case VAR_STRING: case VAR_FUNC: if (from->vval.v_string == NULL) @@ -21970,12 +22235,11 @@ item_copy( switch (from->v_type) { case VAR_NUMBER: -#ifdef FEAT_FLOAT case VAR_FLOAT: -#endif case VAR_STRING: case VAR_FUNC: case VAR_SPECIAL: + case VAR_JOB: copy_tv(from, to); break; case VAR_LIST: @@ -24649,6 +24913,7 @@ write_viminfo_varlist(FILE *fp) case VAR_UNKNOWN: case VAR_FUNC: + case VAR_JOB: continue; } fprintf(fp, "!%s\t%s\t", this_var->di_key, s); |