Patch 7.4.1380
Problem: The job exit callback is not implemented.
Solution: Add the "exit-cb" option.
Files: src/structs.h, src/eval.c, src/channel.c, src/proto/eval.pro,
src/misc2.c, src/macros.h, src/testdir/test_channel.vim
*** ../vim-7.4.1379/src/structs.h 2016-02-21 16:40:07.084383820 +0100
--- src/structs.h 2016-02-21 18:13:31.002125745 +0100
***************
*** 1265,1270 ****
--- 1265,1271 ----
#endif
jobstatus_T jv_status;
char_u *jv_stoponexit; /* allocated */
+ char_u *jv_exit_cb; /* allocated */
int jv_refcount; /* reference count */
channel_T *jv_channel; /* channel for I/O, reference counted */
***************
*** 1390,1395 ****
--- 1391,1397 ----
#define JO_PART 0x0800 /* "part" */
#define JO_ID 0x1000 /* "id" */
#define JO_STOPONEXIT 0x2000 /* "stoponexit" */
+ #define JO_EXIT_CB 0x4000 /* "exit-cb" */
#define JO_ALL 0xffffff
#define JO_MODE_ALL (JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE)
***************
*** 1418,1423 ****
--- 1420,1427 ----
int jo_id;
char_u jo_soe_buf[NUMBUFLEN];
char_u *jo_stoponexit;
+ char_u jo_ecb_buf[NUMBUFLEN];
+ char_u *jo_exit_cb;
} jobopt_T;
*** ../vim-7.4.1379/src/eval.c 2016-02-21 16:40:07.084383820 +0100
--- src/eval.c 2016-02-21 19:07:47.668211225 +0100
***************
*** 7774,7779 ****
--- 7774,7780 ----
job->jv_prev->jv_next = job->jv_next;
vim_free(job->jv_stoponexit);
+ vim_free(job->jv_exit_cb);
vim_free(job);
}
***************
*** 7781,7787 ****
job_unref(job_T *job)
{
if (job != NULL && --job->jv_refcount <= 0)
! job_free(job);
}
/*
--- 7782,7794 ----
job_unref(job_T *job)
{
if (job != NULL && --job->jv_refcount <= 0)
! {
! /* Do not free the job when it has not ended yet and there is a
! * "stoponexit" flag or an exit callback. */
! if (job->jv_status != JOB_STARTED
! || (job->jv_stoponexit == NULL && job->jv_exit_cb == NULL))
! job_free(job);
! }
}
/*
***************
*** 7819,7824 ****
--- 7826,7839 ----
else
job->jv_stoponexit = vim_strsave(opt->jo_stoponexit);
}
+ if (opt->jo_set & JO_EXIT_CB)
+ {
+ vim_free(job->jv_exit_cb);
+ if (opt->jo_exit_cb == NULL || *opt->jo_exit_cb == NUL)
+ job->jv_exit_cb = NULL;
+ else
+ job->jv_exit_cb = vim_strsave(opt->jo_exit_cb);
+ }
}
/*
***************
*** 7830,7836 ****
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
--- 7845,7851 ----
job_T *job;
for (job = first_job; job != NULL; job = job->jv_next)
! if (job->jv_status == JOB_STARTED && job->jv_stoponexit != NULL)
mch_stop_job(job, job->jv_stoponexit);
}
#endif
***************
*** 10030,10036 ****
opt->jo_out_cb = get_callback(item);
if (opt->jo_out_cb == NULL)
{
! EMSG2(_(e_invarg2), "out-db");
return FAIL;
}
}
--- 10045,10051 ----
opt->jo_out_cb = get_callback(item);
if (opt->jo_out_cb == NULL)
{
! EMSG2(_(e_invarg2), "out-cb");
return FAIL;
}
}
***************
*** 10108,10113 ****
--- 10123,10140 ----
return FAIL;
}
}
+ else if (STRCMP(hi->hi_key, "exit-cb") == 0)
+ {
+ if (!(supported & JO_EXIT_CB))
+ break;
+ opt->jo_set |= JO_EXIT_CB;
+ opt->jo_exit_cb = get_tv_string_buf_chk(item, opt->jo_ecb_buf);
+ if (opt->jo_ecb_buf == NULL)
+ {
+ EMSG2(_(e_invarg2), "exit-cb");
+ return FAIL;
+ }
+ }
else
break;
--todo;
***************
*** 14771,14777 ****
dict_list(argvars, rettv, 2);
}
! #ifdef FEAT_JOB
/*
* Get the job from the argument.
* Returns NULL if the job is invalid.
--- 14798,14804 ----
dict_list(argvars, rettv, 2);
}
! #if defined(FEAT_JOB) || defined(PROTO)
/*
* Get the job from the argument.
* Returns NULL if the job is invalid.
***************
*** 14824,14830 ****
if (job == NULL)
return;
clear_job_options(&opt);
! if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT) == FAIL)
return;
job_set_options(job, &opt);
}
--- 14851,14857 ----
if (job == NULL)
return;
clear_job_options(&opt);
! if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB) ==
FAIL)
return;
job_set_options(job, &opt);
}
***************
*** 14858,14864 ****
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);
--- 14885,14892 ----
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 + JO_EXIT_CB) == FAIL)
return;
job_set_options(job, &opt);
***************
*** 14959,14964 ****
--- 14987,15063 ----
}
/*
+ * Get the status of "job" and invoke the exit callback when needed.
+ * The returned string is not allocated.
+ */
+ static char *
+ job_status(job_T *job)
+ {
+ char *result;
+
+ 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);
+ # ifdef FEAT_CHANNEL
+ if (job->jv_status == JOB_ENDED)
+ ch_log(job->jv_channel, "Job ended");
+ # endif
+ if (job->jv_status == JOB_ENDED && job->jv_exit_cb != NULL)
+ {
+ typval_T argv[3];
+ typval_T rettv;
+ int dummy;
+
+ /* invoke the exit callback */
+ argv[0].v_type = VAR_JOB;
+ argv[0].vval.v_job = job;
+ argv[1].v_type = VAR_NUMBER;
+ argv[1].vval.v_number = job->jv_exitval;
+ call_func(job->jv_exit_cb, (int)STRLEN(job->jv_exit_cb),
+ &rettv, 2, argv, 0L, 0L, &dummy, TRUE, NULL);
+ clear_tv(&rettv);
+ }
+ if (job->jv_status == JOB_ENDED && job->jv_refcount == 0)
+ {
+ /* The job already was unreferenced, now that it ended it can be
+ * freed. Careful: caller must not use "job" after this! */
+ job_free(job);
+ }
+ }
+ return result;
+ }
+
+ /*
+ * Called once in a while: check if any jobs with an "exit-cb" have ended.
+ */
+ void
+ job_check_ended()
+ {
+ static time_t last_check = 0;
+ time_t now;
+ job_T *job;
+ job_T *next;
+
+ /* Only do this once in 10 seconds. */
+ now = time(NULL);
+ if (last_check + 10 < now)
+ {
+ last_check = now;
+ for (job = first_job; job != NULL; job = next)
+ {
+ next = job->jv_next;
+ if (job->jv_status == JOB_STARTED && job->jv_exit_cb != NULL)
+ job_status(job); /* may free "job" */
+ }
+ }
+ }
+
+ /*
* "job_status()" function
*/
static void
***************
*** 14969,14981 ****
if (job != NULL)
{
! 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);
}
--- 15068,15074 ----
if (job != NULL)
{
! result = job_status(job);
rettv->v_type = VAR_STRING;
rettv->vval.v_string = vim_strsave((char_u *)result);
}
***************
*** 22857,22863 ****
case VAR_JOB:
#ifdef FEAT_JOB
to->vval.v_job = from->vval.v_job;
! ++to->vval.v_job->jv_refcount;
break;
#endif
case VAR_CHANNEL:
--- 22950,22957 ----
case VAR_JOB:
#ifdef FEAT_JOB
to->vval.v_job = from->vval.v_job;
! if (to->vval.v_job != NULL)
! ++to->vval.v_job->jv_refcount;
break;
#endif
case VAR_CHANNEL:
*** ../vim-7.4.1379/src/channel.c 2016-02-21 17:20:51.175001604 +0100
--- src/channel.c 2016-02-21 18:08:31.777248426 +0100
***************
*** 833,838 ****
--- 833,840 ----
call_func(callback, (int)STRLEN(callback),
&rettv, 2, argv, 0L, 0L, &dummy, TRUE, NULL);
+ clear_tv(&rettv);
+
/* If an echo command was used the cursor needs to be put back where
* it belongs. */
setcursor();
*** ../vim-7.4.1379/src/proto/eval.pro 2016-02-21 16:40:07.088383778 +0100
--- src/proto/eval.pro 2016-02-21 18:40:11.457437953 +0100
***************
*** 87,92 ****
--- 87,93 ----
int call_func(char_u *funcname, int len, typval_T *rettv, int argcount,
typval_T *argvars, linenr_T firstline, linenr_T lastline, int *doesrange, int
evaluate, dict_T *selfdict);
int func_call(char_u *name, typval_T *args, dict_T *selfdict, typval_T
*rettv);
void dict_extend(dict_T *d1, dict_T *d2, char_u *action);
+ void job_check_ended(void);
void mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv);
float_T vim_round(float_T f);
long do_searchpair(char_u *spat, char_u *mpat, char_u *epat, int dir, char_u
*skip, int flags, pos_T *match_pos, linenr_T lnum_stop, long time_limit);
*** ../vim-7.4.1379/src/misc2.c 2016-02-21 17:20:51.179001562 +0100
--- src/misc2.c 2016-02-21 18:39:22.401949173 +0100
***************
*** 6256,6260 ****
--- 6256,6264 ----
/* Process the queued clientserver messages. */
server_parse_messages();
# endif
+ # ifdef FEAT_JOB
+ /* Check if any jobs have ended. */
+ job_check_ended();
+ # endif
}
#endif
*** ../vim-7.4.1379/src/macros.h 2016-01-24 20:36:18.862082391 +0100
--- src/macros.h 2016-02-21 18:40:04.989505356 +0100
***************
*** 317,322 ****
# define PLINES_NOFILL(x) plines(x)
#endif
! #if defined(FEAT_CHANNEL) || defined(FEAT_CLIENTSERVER)
# define MESSAGE_QUEUE
#endif
--- 317,322 ----
# define PLINES_NOFILL(x) plines(x)
#endif
! #if defined(FEAT_CHANNEL) || defined(FEAT_JOB) || defined(FEAT_CLIENTSERVER)
# define MESSAGE_QUEUE
#endif
*** ../vim-7.4.1379/src/testdir/test_channel.vim 2016-02-21
16:40:07.088383778 +0100
--- src/testdir/test_channel.vim 2016-02-21 19:02:15.463664885 +0100
***************
*** 468,470 ****
--- 468,495 ----
call ch_log('Test_call()')
call s:run_server('s:test_call')
endfunc
+
+ """""""""
+
+ let s:job_ret = 'not yet'
+ function MyExitCb(job, status)
+ let s:job_ret = 'done'
+ endfunc
+
+ function s:test_exit_callback(port)
+ call job_setoptions(s:job, {'exit-cb': 'MyExitCb'})
+ let s:exit_job = s:job
+ endfunc
+
+ func Test_exit_callback()
+ if has('job')
+ call s:run_server('s:test_exit_callback')
+
+ " the job may take a little while to exit
+ sleep 50m
+
+ " calling job_status() triggers the callback
+ call job_status(s:exit_job)
+ call assert_equal('done', s:job_ret)
+ endif
+ endfunc
*** ../vim-7.4.1379/src/version.c 2016-02-21 17:20:51.179001562 +0100
--- src/version.c 2016-02-21 18:10:41.599893524 +0100
***************
*** 749,750 ****
--- 749,752 ----
{ /* Add new patch number below this line */
+ /**/
+ 1380,
/**/
--
WOMAN: King of the who?
ARTHUR: The Britons.
WOMAN: Who are the Britons?
ARTHUR: Well, we all are. we're all Britons and I am your king.
The Quest for the Holy Grail (Monty Python)
/// Bram Moolenaar -- [email protected] -- 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 ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.