summaryrefslogtreecommitdiff
path: root/data/vim/patches/8.1.1437
diff options
context:
space:
mode:
Diffstat (limited to 'data/vim/patches/8.1.1437')
-rw-r--r--data/vim/patches/8.1.14371880
1 files changed, 1880 insertions, 0 deletions
diff --git a/data/vim/patches/8.1.1437 b/data/vim/patches/8.1.1437
new file mode 100644
index 000000000..364f4efc2
--- /dev/null
+++ b/data/vim/patches/8.1.1437
@@ -0,0 +1,1880 @@
+To: vim_dev@googlegroups.com
+Subject: Patch 8.1.1437
+Fcc: outbox
+From: Bram Moolenaar <Bram@moolenaar.net>
+Mime-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+------------
+
+Patch 8.1.1437
+Problem: Code to handle callbacks is duplicated.
+Solution: Add callback_T and functions to deal with it.
+Files: src/structs.h, src/evalfunc.c, src/proto/evalfunc.pro,
+ src/change.c, src/channel.c, src/proto/channel.pro, src/buffer.c,
+ src/userfunc.c, src/proto/userfunc.pro, src/eval.c,
+ src/ex_cmds2.c, src/popupwin.c
+
+
+*** ../vim-8.1.1436/src/structs.h 2019-05-30 21:24:22.177201251 +0200
+--- src/structs.h 2019-06-01 13:00:39.892747290 +0200
+***************
+*** 1237,1242 ****
+--- 1237,1253 ----
+ typedef struct partial_S partial_T;
+ typedef struct blobvar_S blob_T;
+
++ // Struct that holds both a normal function name and a partial_T, as used for a
++ // callback argument.
++ // When used temporarily "cb_name" is not allocated. The refcounts to either
++ // the function or the partial are incremented and need to be decremented
++ // later with free_callback().
++ typedef struct {
++ char_u *cb_name;
++ partial_T *cb_partial;
++ int cb_free_name; // cb_name was allocated
++ } callback_T;
++
+ typedef struct jobvar_S job_T;
+ typedef struct readq_S readq_T;
+ typedef struct writeq_S writeq_T;
+***************
+*** 1566,1573 ****
+ char_u *jv_tty_type; // allocated
+ #endif
+ int jv_exitval;
+! char_u *jv_exit_cb; /* allocated */
+! partial_T *jv_exit_partial;
+
+ buf_T *jv_in_buf; /* buffer from "in-name" */
+
+--- 1577,1583 ----
+ char_u *jv_tty_type; // allocated
+ #endif
+ int jv_exitval;
+! callback_T jv_exit_cb;
+
+ buf_T *jv_in_buf; /* buffer from "in-name" */
+
+***************
+*** 1606,1613 ****
+
+ struct cbq_S
+ {
+! char_u *cq_callback;
+! partial_T *cq_partial;
+ int cq_seq_nr;
+ cbq_T *cq_next;
+ cbq_T *cq_prev;
+--- 1616,1622 ----
+
+ struct cbq_S
+ {
+! callback_T cq_callback;
+ int cq_seq_nr;
+ cbq_T *cq_next;
+ cbq_T *cq_prev;
+***************
+*** 1689,1696 ****
+ writeq_T ch_writeque; /* header for write queue */
+
+ cbq_T ch_cb_head; /* dummy node for per-request callbacks */
+! char_u *ch_callback; /* call when a msg is not handled */
+! partial_T *ch_partial;
+
+ bufref_T ch_bufref; /* buffer to read from or write to */
+ int ch_nomodifiable; /* TRUE when buffer can be 'nomodifiable' */
+--- 1698,1704 ----
+ writeq_T ch_writeque; /* header for write queue */
+
+ cbq_T ch_cb_head; /* dummy node for per-request callbacks */
+! callback_T ch_callback; /* call when a msg is not handled */
+
+ bufref_T ch_bufref; /* buffer to read from or write to */
+ int ch_nomodifiable; /* TRUE when buffer can be 'nomodifiable' */
+***************
+*** 1731,1740 ****
+ #ifdef MSWIN
+ int ch_named_pipe; /* using named pipe instead of pty */
+ #endif
+! char_u *ch_callback; /* call when any msg is not handled */
+! partial_T *ch_partial;
+! char_u *ch_close_cb; /* call when channel is closed */
+! partial_T *ch_close_partial;
+ int ch_drop_never;
+ int ch_keep_open; /* do not close on read error */
+ int ch_nonblock;
+--- 1739,1746 ----
+ #ifdef MSWIN
+ int ch_named_pipe; /* using named pipe instead of pty */
+ #endif
+! callback_T ch_callback; /* call when any msg is not handled */
+! callback_T ch_close_cb; /* call when channel is closed */
+ int ch_drop_never;
+ int ch_keep_open; /* do not close on read error */
+ int ch_nonblock;
+***************
+*** 1833,1848 ****
+ linenr_T jo_in_top;
+ linenr_T jo_in_bot;
+
+! char_u *jo_callback; /* not allocated! */
+! partial_T *jo_partial; /* not referenced! */
+! char_u *jo_out_cb; /* not allocated! */
+! partial_T *jo_out_partial; /* not referenced! */
+! char_u *jo_err_cb; /* not allocated! */
+! partial_T *jo_err_partial; /* not referenced! */
+! char_u *jo_close_cb; /* not allocated! */
+! partial_T *jo_close_partial; /* not referenced! */
+! char_u *jo_exit_cb; /* not allocated! */
+! partial_T *jo_exit_partial; /* not referenced! */
+ int jo_drop_never;
+ int jo_waittime;
+ int jo_timeout;
+--- 1839,1849 ----
+ linenr_T jo_in_top;
+ linenr_T jo_in_bot;
+
+! callback_T jo_callback;
+! callback_T jo_out_cb;
+! callback_T jo_err_cb;
+! callback_T jo_close_cb;
+! callback_T jo_exit_cb;
+ int jo_drop_never;
+ int jo_waittime;
+ int jo_timeout;
+***************
+*** 1886,1893 ****
+ {
+ listener_T *lr_next;
+ int lr_id;
+! char_u *lr_callback;
+! partial_T *lr_partial;
+ };
+ #endif
+
+--- 1887,1893 ----
+ {
+ listener_T *lr_next;
+ int lr_id;
+! callback_T lr_callback;
+ };
+ #endif
+
+***************
+*** 1950,1962 ****
+ #ifdef FEAT_TIMERS
+ timer_T *tr_next;
+ timer_T *tr_prev;
+! proftime_T tr_due; /* when the callback is to be invoked */
+! char tr_firing; /* when TRUE callback is being called */
+! char tr_paused; /* when TRUE callback is not invoked */
+! int tr_repeat; /* number of times to repeat, -1 forever */
+! long tr_interval; /* msec */
+! char_u *tr_callback; /* allocated */
+! partial_T *tr_partial;
+ int tr_emsg_count;
+ #endif
+ };
+--- 1950,1961 ----
+ #ifdef FEAT_TIMERS
+ timer_T *tr_next;
+ timer_T *tr_prev;
+! proftime_T tr_due; // when the callback is to be invoked
+! char tr_firing; // when TRUE callback is being called
+! char tr_paused; // when TRUE callback is not invoked
+! int tr_repeat; // number of times to repeat, -1 forever
+! long tr_interval; // msec
+! callback_T tr_callback;
+ int tr_emsg_count;
+ #endif
+ };
+***************
+*** 2509,2521 ****
+ int b_shortname; /* this file has an 8.3 file name */
+
+ #ifdef FEAT_JOB_CHANNEL
+! char_u *b_prompt_text; // set by prompt_setprompt()
+! char_u *b_prompt_callback; // set by prompt_setcallback()
+! partial_T *b_prompt_partial; // set by prompt_setcallback()
+! char_u *b_prompt_interrupt; // set by prompt_setinterrupt()
+! partial_T *b_prompt_int_partial; // set by prompt_setinterrupt()
+! int b_prompt_insert; // value for restart_edit when entering
+! // a prompt buffer window.
+ #endif
+ #ifdef FEAT_MZSCHEME
+ void *b_mzscheme_ref; /* The MzScheme reference to this buffer */
+--- 2508,2518 ----
+ int b_shortname; /* this file has an 8.3 file name */
+
+ #ifdef FEAT_JOB_CHANNEL
+! char_u *b_prompt_text; // set by prompt_setprompt()
+! callback_T b_prompt_callback; // set by prompt_setcallback()
+! callback_T b_prompt_interrupt; // set by prompt_setinterrupt()
+! int b_prompt_insert; // value for restart_edit when entering
+! // a prompt buffer window.
+ #endif
+ #ifdef FEAT_MZSCHEME
+ void *b_mzscheme_ref; /* The MzScheme reference to this buffer */
+*** ../vim-8.1.1436/src/evalfunc.c 2019-05-30 22:35:15.151191862 +0200
+--- src/evalfunc.c 2019-06-01 13:13:24.669729965 +0200
+***************
+*** 9200,9207 ****
+ f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
+ {
+ buf_T *buf;
+! char_u *callback;
+! partial_T *partial;
+
+ if (check_secure())
+ return;
+--- 9200,9206 ----
+ f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
+ {
+ buf_T *buf;
+! callback_T callback;
+
+ if (check_secure())
+ return;
+***************
+*** 9209,9225 ****
+ if (buf == NULL)
+ return;
+
+! callback = get_callback(&argvars[1], &partial);
+! if (callback == NULL)
+ return;
+
+! free_callback(buf->b_prompt_callback, buf->b_prompt_partial);
+! if (partial == NULL)
+! buf->b_prompt_callback = vim_strsave(callback);
+! else
+! /* pointer into the partial */
+! buf->b_prompt_callback = callback;
+! buf->b_prompt_partial = partial;
+ }
+
+ /*
+--- 9208,9219 ----
+ if (buf == NULL)
+ return;
+
+! callback = get_callback(&argvars[1]);
+! if (callback.cb_name == NULL)
+ return;
+
+! free_callback(&buf->b_prompt_callback);
+! set_callback(&buf->b_prompt_callback, &callback);
+ }
+
+ /*
+***************
+*** 9229,9236 ****
+ f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED)
+ {
+ buf_T *buf;
+! char_u *callback;
+! partial_T *partial;
+
+ if (check_secure())
+ return;
+--- 9223,9229 ----
+ f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED)
+ {
+ buf_T *buf;
+! callback_T callback;
+
+ if (check_secure())
+ return;
+***************
+*** 9238,9254 ****
+ if (buf == NULL)
+ return;
+
+! callback = get_callback(&argvars[1], &partial);
+! if (callback == NULL)
+ return;
+
+! free_callback(buf->b_prompt_interrupt, buf->b_prompt_int_partial);
+! if (partial == NULL)
+! buf->b_prompt_interrupt = vim_strsave(callback);
+! else
+! /* pointer into the partial */
+! buf->b_prompt_interrupt = callback;
+! buf->b_prompt_int_partial = partial;
+ }
+
+ /*
+--- 9231,9242 ----
+ if (buf == NULL)
+ return;
+
+! callback = get_callback(&argvars[1]);
+! if (callback.cb_name == NULL)
+ return;
+
+! free_callback(&buf->b_prompt_interrupt);
+! set_callback(&buf->b_prompt_interrupt, &callback);
+ }
+
+ /*
+***************
+*** 14631,14674 ****
+ /*
+ * Get a callback from "arg". It can be a Funcref or a function name.
+ * When "arg" is zero return an empty string.
+! * Return NULL for an invalid argument.
+ */
+! char_u *
+! get_callback(typval_T *arg, partial_T **pp)
+ {
+ if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
+ {
+! *pp = arg->vval.v_partial;
+! ++(*pp)->pt_refcount;
+! return partial_name(*pp);
+ }
+! *pp = NULL;
+! if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
+ {
+! func_ref(arg->vval.v_string);
+! return arg->vval.v_string;
+ }
+! if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
+! return (char_u *)"";
+! emsg(_("E921: Invalid callback argument"));
+! return NULL;
+ }
+
+ /*
+! * Unref/free "callback" and "partial" returned by get_callback().
+ */
+ void
+! free_callback(char_u *callback, partial_T *partial)
+ {
+! if (partial != NULL)
+! partial_unref(partial);
+! else if (callback != NULL)
+ {
+! func_unref(callback);
+! vim_free(callback);
+ }
+ }
+
+ #ifdef FEAT_TIMERS
+ /*
+ * "timer_info([timer])" function
+--- 14619,14724 ----
+ /*
+ * Get a callback from "arg". It can be a Funcref or a function name.
+ * When "arg" is zero return an empty string.
+! * "cb_name" is not allocated.
+! * "cb_name" is set to NULL for an invalid argument.
+ */
+! callback_T
+! get_callback(typval_T *arg)
+ {
++ callback_T res;
++
++ res.cb_free_name = FALSE;
+ if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
+ {
+! res.cb_partial = arg->vval.v_partial;
+! ++res.cb_partial->pt_refcount;
+! res.cb_name = partial_name(res.cb_partial);
+ }
+! else
+ {
+! res.cb_partial = NULL;
+! if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
+! {
+! // Note that we don't make a copy of the string.
+! res.cb_name = arg->vval.v_string;
+! func_ref(res.cb_name);
+! }
+! else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
+! {
+! res.cb_name = (char_u *)"";
+! }
+! else
+! {
+! emsg(_("E921: Invalid callback argument"));
+! res.cb_name = NULL;
+! }
+ }
+! return res;
+ }
+
+ /*
+! * Copy a callback into a typval_T.
+ */
+ void
+! put_callback(callback_T *cb, typval_T *tv)
+ {
+! if (cb->cb_partial != NULL)
+! {
+! tv->v_type = VAR_PARTIAL;
+! tv->vval.v_partial = cb->cb_partial;
+! ++tv->vval.v_partial->pt_refcount;
+! }
+! else
+ {
+! tv->v_type = VAR_FUNC;
+! tv->vval.v_string = vim_strsave(cb->cb_name);
+! func_ref(cb->cb_name);
+ }
+ }
+
++ /*
++ * Make a copy of "src" into "dest", allocating the function name if needed,
++ * without incrementing the refcount.
++ */
++ void
++ set_callback(callback_T *dest, callback_T *src)
++ {
++ if (src->cb_partial == NULL)
++ {
++ // just a function name, make a copy
++ dest->cb_name = vim_strsave(src->cb_name);
++ dest->cb_free_name = TRUE;
++ }
++ else
++ {
++ // cb_name is a pointer into cb_partial
++ dest->cb_name = src->cb_name;
++ dest->cb_free_name = FALSE;
++ }
++ dest->cb_partial = src->cb_partial;
++ }
++
++ /*
++ * Unref/free "callback" returned by get_callback() or set_callback().
++ */
++ void
++ free_callback(callback_T *callback)
++ {
++ if (callback->cb_partial != NULL)
++ {
++ partial_unref(callback->cb_partial);
++ callback->cb_partial = NULL;
++ }
++ else if (callback->cb_name != NULL)
++ func_unref(callback->cb_name);
++ if (callback->cb_free_name)
++ {
++ vim_free(callback->cb_name);
++ callback->cb_free_name = FALSE;
++ }
++ callback->cb_name = NULL;
++ }
++
+ #ifdef FEAT_TIMERS
+ /*
+ * "timer_info([timer])" function
+***************
+*** 14723,14731 ****
+ long msec = (long)tv_get_number(&argvars[0]);
+ timer_T *timer;
+ int repeat = 0;
+! char_u *callback;
+ dict_T *dict;
+- partial_T *partial;
+
+ rettv->vval.v_number = -1;
+ if (check_secure())
+--- 14773,14780 ----
+ long msec = (long)tv_get_number(&argvars[0]);
+ timer_T *timer;
+ int repeat = 0;
+! callback_T callback;
+ dict_T *dict;
+
+ rettv->vval.v_number = -1;
+ if (check_secure())
+***************
+*** 14742,14762 ****
+ repeat = dict_get_number(dict, (char_u *)"repeat");
+ }
+
+! callback = get_callback(&argvars[1], &partial);
+! if (callback == NULL)
+ return;
+
+ timer = create_timer(msec, repeat);
+ if (timer == NULL)
+! free_callback(callback, partial);
+ else
+ {
+! if (partial == NULL)
+! timer->tr_callback = vim_strsave(callback);
+! else
+! /* pointer into the partial */
+! timer->tr_callback = callback;
+! timer->tr_partial = partial;
+ rettv->vval.v_number = (varnumber_T)timer->tr_id;
+ }
+ }
+--- 14791,14806 ----
+ repeat = dict_get_number(dict, (char_u *)"repeat");
+ }
+
+! callback = get_callback(&argvars[1]);
+! if (callback.cb_name == NULL)
+ return;
+
+ timer = create_timer(msec, repeat);
+ if (timer == NULL)
+! free_callback(&callback);
+ else
+ {
+! set_callback(&timer->tr_callback, &callback);
+ rettv->vval.v_number = (varnumber_T)timer->tr_id;
+ }
+ }
+*** ../vim-8.1.1436/src/proto/evalfunc.pro 2019-05-11 21:14:02.336269566 +0200
+--- src/proto/evalfunc.pro 2019-05-31 23:04:21.602577328 +0200
+***************
+*** 11,16 ****
+ float_T vim_round(float_T f);
+ long do_searchpair(char_u *spat, char_u *mpat, char_u *epat, int dir, typval_T *skip, int flags, pos_T *match_pos, linenr_T lnum_stop, long time_limit);
+ void f_string(typval_T *argvars, typval_T *rettv);
+! char_u *get_callback(typval_T *arg, partial_T **pp);
+! void free_callback(char_u *callback, partial_T *partial);
+ /* vim: set ft=c : */
+--- 11,18 ----
+ float_T vim_round(float_T f);
+ long do_searchpair(char_u *spat, char_u *mpat, char_u *epat, int dir, typval_T *skip, int flags, pos_T *match_pos, linenr_T lnum_stop, long time_limit);
+ void f_string(typval_T *argvars, typval_T *rettv);
+! callback_T get_callback(typval_T *arg);
+! void put_callback(callback_T *cb, typval_T *tv);
+! void set_callback(callback_T *dest, callback_T *src);
+! void free_callback(callback_T *callback);
+ /* vim: set ft=c : */
+*** ../vim-8.1.1436/src/change.c 2019-05-29 22:28:25.759184826 +0200
+--- src/change.c 2019-05-31 22:55:13.929346887 +0200
+***************
+*** 270,305 ****
+ void
+ f_listener_add(typval_T *argvars, typval_T *rettv)
+ {
+! char_u *callback;
+! partial_T *partial;
+ listener_T *lnr;
+ buf_T *buf = curbuf;
+
+! callback = get_callback(&argvars[0], &partial);
+! if (callback == NULL)
+ return;
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ {
+ buf = get_buf_arg(&argvars[1]);
+ if (buf == NULL)
+ return;
+ }
+
+ lnr = ALLOC_CLEAR_ONE(listener_T);
+ if (lnr == NULL)
+ {
+! free_callback(callback, partial);
+ return;
+ }
+ lnr->lr_next = buf->b_listener;
+ buf->b_listener = lnr;
+
+! if (partial == NULL)
+! lnr->lr_callback = vim_strsave(callback);
+! else
+! lnr->lr_callback = callback; // pointer into the partial
+! lnr->lr_partial = partial;
+
+ lnr->lr_id = ++next_listener_id;
+ rettv->vval.v_number = lnr->lr_id;
+--- 270,303 ----
+ void
+ f_listener_add(typval_T *argvars, typval_T *rettv)
+ {
+! callback_T callback;
+ listener_T *lnr;
+ buf_T *buf = curbuf;
+
+! callback = get_callback(&argvars[0]);
+! if (callback.cb_name == NULL)
+ return;
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ {
+ buf = get_buf_arg(&argvars[1]);
+ if (buf == NULL)
++ {
++ free_callback(&callback);
+ return;
++ }
+ }
+
+ lnr = ALLOC_CLEAR_ONE(listener_T);
+ if (lnr == NULL)
+ {
+! free_callback(&callback);
+ return;
+ }
+ lnr->lr_next = buf->b_listener;
+ buf->b_listener = lnr;
+
+! set_callback(&lnr->lr_callback, &callback);
+
+ lnr->lr_id = ++next_listener_id;
+ rettv->vval.v_number = lnr->lr_id;
+***************
+*** 344,350 ****
+ prev->lr_next = lnr->lr_next;
+ else
+ buf->b_listener = lnr->lr_next;
+! free_callback(lnr->lr_callback, lnr->lr_partial);
+ vim_free(lnr);
+ }
+ prev = lnr;
+--- 342,348 ----
+ prev->lr_next = lnr->lr_next;
+ else
+ buf->b_listener = lnr->lr_next;
+! free_callback(&lnr->lr_callback);
+ vim_free(lnr);
+ }
+ prev = lnr;
+***************
+*** 418,425 ****
+
+ for (lnr = buf->b_listener; lnr != NULL; lnr = lnr->lr_next)
+ {
+! call_func(lnr->lr_callback, -1, &rettv,
+! 5, argv, NULL, 0L, 0L, &dummy, TRUE, lnr->lr_partial, NULL);
+ clear_tv(&rettv);
+ }
+
+--- 416,423 ----
+
+ for (lnr = buf->b_listener; lnr != NULL; lnr = lnr->lr_next)
+ {
+! call_callback(&lnr->lr_callback, -1, &rettv,
+! 5, argv, NULL, 0L, 0L, &dummy, TRUE, NULL);
+ clear_tv(&rettv);
+ }
+
+*** ../vim-8.1.1436/src/channel.c 2019-05-28 23:08:12.052648779 +0200
+--- src/channel.c 2019-06-01 12:58:20.873575186 +0200
+***************
+*** 348,354 ****
+ return FALSE;
+
+ /* If there is a close callback it may still need to be invoked. */
+! if (channel->ch_close_cb != NULL)
+ return TRUE;
+
+ /* If reading from or a buffer it's still useful. */
+--- 348,354 ----
+ return FALSE;
+
+ /* If there is a close callback it may still need to be invoked. */
+! if (channel->ch_close_cb.cb_name != NULL)
+ return TRUE;
+
+ /* If reading from or a buffer it's still useful. */
+***************
+*** 366,377 ****
+ has_err_msg = channel->ch_part[PART_ERR].ch_fd != INVALID_FD
+ || channel->ch_part[PART_ERR].ch_head.rq_next != NULL
+ || channel->ch_part[PART_ERR].ch_json_head.jq_next != NULL;
+! return (channel->ch_callback != NULL && (has_sock_msg
+ || has_out_msg || has_err_msg))
+! || ((channel->ch_part[PART_OUT].ch_callback != NULL
+ || channel->ch_part[PART_OUT].ch_bufref.br_buf != NULL)
+ && has_out_msg)
+! || ((channel->ch_part[PART_ERR].ch_callback != NULL
+ || channel->ch_part[PART_ERR].ch_bufref.br_buf != NULL)
+ && has_err_msg);
+ }
+--- 366,377 ----
+ has_err_msg = channel->ch_part[PART_ERR].ch_fd != INVALID_FD
+ || channel->ch_part[PART_ERR].ch_head.rq_next != NULL
+ || channel->ch_part[PART_ERR].ch_json_head.jq_next != NULL;
+! return (channel->ch_callback.cb_name != NULL && (has_sock_msg
+ || has_out_msg || has_err_msg))
+! || ((channel->ch_part[PART_OUT].ch_callback.cb_name != NULL
+ || channel->ch_part[PART_OUT].ch_bufref.br_buf != NULL)
+ && has_out_msg)
+! || ((channel->ch_part[PART_ERR].ch_callback.cb_name != NULL
+ || channel->ch_part[PART_ERR].ch_bufref.br_buf != NULL)
+ && has_err_msg);
+ }
+***************
+*** 1178,1206 ****
+ return buf;
+ }
+
+ static void
+! set_callback(
+! char_u **cbp,
+! partial_T **pp,
+! char_u *callback,
+! partial_T *partial)
+ {
+! free_callback(*cbp, *pp);
+! if (callback != NULL && *callback != NUL)
+ {
+! if (partial != NULL)
+! *cbp = partial_name(partial);
+! else
+! {
+! *cbp = vim_strsave(callback);
+! func_ref(*cbp);
+! }
+ }
+ else
+! *cbp = NULL;
+! *pp = partial;
+! if (partial != NULL)
+! ++partial->pt_refcount;
+ }
+
+ /*
+--- 1178,1213 ----
+ return buf;
+ }
+
++ /*
++ * Copy callback from "src" to "dest", incrementing the refcounts.
++ */
+ static void
+! copy_callback(callback_T *dest, callback_T *src)
+ {
+! dest->cb_partial = src->cb_partial;
+! if (dest->cb_partial != NULL)
+ {
+! dest->cb_name = src->cb_name;
+! dest->cb_free_name = FALSE;
+! ++dest->cb_partial->pt_refcount;
+! }
+! else
+! {
+! dest->cb_name = vim_strsave(src->cb_name);
+! dest->cb_free_name = TRUE;
+! func_ref(src->cb_name);
+ }
++ }
++
++ static void
++ free_set_callback(callback_T *cbp, callback_T *callback)
++ {
++ free_callback(cbp);
++
++ if (callback->cb_name != NULL && *callback->cb_name != NUL)
++ copy_callback(cbp, callback);
+ else
+! cbp->cb_name = NULL;
+ }
+
+ /*
+***************
+*** 1233,1251 ****
+ channel->ch_part[PART_IN].ch_block_write = 1;
+
+ if (opt->jo_set & JO_CALLBACK)
+! set_callback(&channel->ch_callback, &channel->ch_partial,
+! opt->jo_callback, opt->jo_partial);
+ if (opt->jo_set & JO_OUT_CALLBACK)
+! set_callback(&channel->ch_part[PART_OUT].ch_callback,
+! &channel->ch_part[PART_OUT].ch_partial,
+! opt->jo_out_cb, opt->jo_out_partial);
+ if (opt->jo_set & JO_ERR_CALLBACK)
+! set_callback(&channel->ch_part[PART_ERR].ch_callback,
+! &channel->ch_part[PART_ERR].ch_partial,
+! opt->jo_err_cb, opt->jo_err_partial);
+ if (opt->jo_set & JO_CLOSE_CALLBACK)
+! set_callback(&channel->ch_close_cb, &channel->ch_close_partial,
+! opt->jo_close_cb, opt->jo_close_partial);
+ channel->ch_drop_never = opt->jo_drop_never;
+
+ if ((opt->jo_set & JO_OUT_IO) && opt->jo_io[PART_OUT] == JIO_BUFFER)
+--- 1240,1254 ----
+ channel->ch_part[PART_IN].ch_block_write = 1;
+
+ if (opt->jo_set & JO_CALLBACK)
+! free_set_callback(&channel->ch_callback, &opt->jo_callback);
+ if (opt->jo_set & JO_OUT_CALLBACK)
+! free_set_callback(&channel->ch_part[PART_OUT].ch_callback,
+! &opt->jo_out_cb);
+ if (opt->jo_set & JO_ERR_CALLBACK)
+! free_set_callback(&channel->ch_part[PART_ERR].ch_callback,
+! &opt->jo_err_cb);
+ if (opt->jo_set & JO_CLOSE_CALLBACK)
+! free_set_callback(&channel->ch_close_cb, &opt->jo_close_cb);
+ channel->ch_drop_never = opt->jo_drop_never;
+
+ if ((opt->jo_set & JO_OUT_IO) && opt->jo_io[PART_OUT] == JIO_BUFFER)
+***************
+*** 1349,1356 ****
+ channel_set_req_callback(
+ channel_T *channel,
+ ch_part_T part,
+! char_u *callback,
+! partial_T *partial,
+ int id)
+ {
+ cbq_T *head = &channel->ch_part[part].ch_cb_head;
+--- 1352,1358 ----
+ channel_set_req_callback(
+ channel_T *channel,
+ ch_part_T part,
+! callback_T *callback,
+ int id)
+ {
+ cbq_T *head = &channel->ch_part[part].ch_cb_head;
+***************
+*** 1358,1374 ****
+
+ if (item != NULL)
+ {
+! item->cq_partial = partial;
+! if (partial != NULL)
+! {
+! ++partial->pt_refcount;
+! item->cq_callback = callback;
+! }
+! else
+! {
+! item->cq_callback = vim_strsave(callback);
+! func_ref(item->cq_callback);
+! }
+ item->cq_seq_nr = id;
+ item->cq_prev = head->cq_prev;
+ head->cq_prev = item;
+--- 1360,1366 ----
+
+ if (item != NULL)
+ {
+! copy_callback(&item->cq_callback, callback);
+ item->cq_seq_nr = id;
+ item->cq_prev = head->cq_prev;
+ head->cq_prev = item;
+***************
+*** 1638,1645 ****
+ * This does not redraw but sets channel_need_redraw;
+ */
+ static void
+! invoke_callback(channel_T *channel, char_u *callback, partial_T *partial,
+! typval_T *argv)
+ {
+ typval_T rettv;
+ int dummy;
+--- 1630,1636 ----
+ * This does not redraw but sets channel_need_redraw;
+ */
+ static void
+! invoke_callback(channel_T *channel, callback_T *callback, typval_T *argv)
+ {
+ typval_T rettv;
+ int dummy;
+***************
+*** 1650,1657 ****
+ argv[0].v_type = VAR_CHANNEL;
+ argv[0].vval.v_channel = channel;
+
+! call_func(callback, -1, &rettv, 2, argv, NULL,
+! 0L, 0L, &dummy, TRUE, partial, NULL);
+ clear_tv(&rettv);
+ channel_need_redraw = TRUE;
+ }
+--- 1641,1648 ----
+ argv[0].v_type = VAR_CHANNEL;
+ argv[0].vval.v_channel = channel;
+
+! call_callback(callback, -1, &rettv, 2, argv, NULL,
+! 0L, 0L, &dummy, TRUE, NULL);
+ clear_tv(&rettv);
+ channel_need_redraw = TRUE;
+ }
+***************
+*** 2414,2425 ****
+ typval_T *argv)
+ {
+ ch_log(channel, "Invoking one-time callback %s",
+! (char *)item->cq_callback);
+ /* Remove the item from the list first, if the callback
+ * invokes ch_close() the list will be cleared. */
+ remove_cb_node(cbhead, item);
+! invoke_callback(channel, item->cq_callback, item->cq_partial, argv);
+! free_callback(item->cq_callback, item->cq_partial);
+ vim_free(item);
+ }
+
+--- 2405,2416 ----
+ typval_T *argv)
+ {
+ ch_log(channel, "Invoking one-time callback %s",
+! (char *)item->cq_callback.cb_name);
+ /* Remove the item from the list first, if the callback
+ * invokes ch_close() the list will be cleared. */
+ remove_cb_node(cbhead, item);
+! invoke_callback(channel, &item->cq_callback, argv);
+! free_callback(&item->cq_callback);
+ vim_free(item);
+ }
+
+***************
+*** 2553,2560 ****
+ ch_mode_T ch_mode = ch_part->ch_mode;
+ cbq_T *cbhead = &ch_part->ch_cb_head;
+ cbq_T *cbitem;
+! char_u *callback = NULL;
+! partial_T *partial = NULL;
+ buf_T *buffer = NULL;
+ char_u *p;
+
+--- 2544,2550 ----
+ ch_mode_T ch_mode = ch_part->ch_mode;
+ cbq_T *cbhead = &ch_part->ch_cb_head;
+ cbq_T *cbitem;
+! callback_T *callback = NULL;
+ buf_T *buffer = NULL;
+ char_u *p;
+
+***************
+*** 2567,2586 ****
+ if (cbitem->cq_seq_nr == 0)
+ break;
+ if (cbitem != NULL)
+! {
+! callback = cbitem->cq_callback;
+! partial = cbitem->cq_partial;
+! }
+! else if (ch_part->ch_callback != NULL)
+! {
+! callback = ch_part->ch_callback;
+! partial = ch_part->ch_partial;
+! }
+! else
+! {
+! callback = channel->ch_callback;
+! partial = channel->ch_partial;
+! }
+
+ buffer = ch_part->ch_bufref.br_buf;
+ if (buffer != NULL && (!bufref_valid(&ch_part->ch_bufref)
+--- 2557,2567 ----
+ if (cbitem->cq_seq_nr == 0)
+ break;
+ if (cbitem != NULL)
+! callback = &cbitem->cq_callback;
+! else if (ch_part->ch_callback.cb_name != NULL)
+! callback = &ch_part->ch_callback;
+! else if (channel->ch_callback.cb_name != NULL)
+! callback = &channel->ch_callback;
+
+ buffer = ch_part->ch_bufref.br_buf;
+ if (buffer != NULL && (!bufref_valid(&ch_part->ch_bufref)
+***************
+*** 2642,2648 ****
+ {
+ /* If there is a close callback it may use ch_read() to get the
+ * messages. */
+! if (channel->ch_close_cb == NULL && !channel->ch_drop_never)
+ drop_messages(channel, part);
+ return FALSE;
+ }
+--- 2623,2629 ----
+ {
+ /* If there is a close callback it may use ch_read() to get the
+ * messages. */
+! if (channel->ch_close_cb.cb_name == NULL && !channel->ch_drop_never)
+ drop_messages(channel, part);
+ return FALSE;
+ }
+***************
+*** 2761,2768 ****
+ {
+ /* invoke the channel callback */
+ ch_log(channel, "Invoking channel callback %s",
+! (char *)callback);
+! invoke_callback(channel, callback, partial, argv);
+ }
+ }
+ }
+--- 2742,2749 ----
+ {
+ /* invoke the channel callback */
+ ch_log(channel, "Invoking channel callback %s",
+! (char *)callback->cb_name);
+! invoke_callback(channel, callback, argv);
+ }
+ }
+ }
+***************
+*** 2956,2973 ****
+ ch_part_T part;
+
+ /* Invoke callbacks and flush buffers before the close callback. */
+! if (channel->ch_close_cb != NULL)
+ ch_log(channel,
+ "Invoking callbacks and flushing buffers before closing");
+ for (part = PART_SOCK; part < PART_IN; ++part)
+ {
+! if (channel->ch_close_cb != NULL
+ || channel->ch_part[part].ch_bufref.br_buf != NULL)
+ {
+ /* Increment the refcount to avoid the channel being freed
+ * halfway. */
+ ++channel->ch_refcount;
+! if (channel->ch_close_cb == NULL)
+ ch_log(channel, "flushing %s buffers before closing",
+ part_names[part]);
+ while (may_invoke_callback(channel, part))
+--- 2937,2954 ----
+ ch_part_T part;
+
+ /* Invoke callbacks and flush buffers before the close callback. */
+! if (channel->ch_close_cb.cb_name != NULL)
+ ch_log(channel,
+ "Invoking callbacks and flushing buffers before closing");
+ for (part = PART_SOCK; part < PART_IN; ++part)
+ {
+! if (channel->ch_close_cb.cb_name != NULL
+ || channel->ch_part[part].ch_bufref.br_buf != NULL)
+ {
+ /* Increment the refcount to avoid the channel being freed
+ * halfway. */
+ ++channel->ch_refcount;
+! if (channel->ch_close_cb.cb_name == NULL)
+ ch_log(channel, "flushing %s buffers before closing",
+ part_names[part]);
+ while (may_invoke_callback(channel, part))
+***************
+*** 2976,2982 ****
+ }
+ }
+
+! if (channel->ch_close_cb != NULL)
+ {
+ typval_T argv[1];
+ typval_T rettv;
+--- 2957,2963 ----
+ }
+ }
+
+! if (channel->ch_close_cb.cb_name != NULL)
+ {
+ typval_T argv[1];
+ typval_T rettv;
+***************
+*** 2986,3004 ****
+ * halfway. */
+ ++channel->ch_refcount;
+ ch_log(channel, "Invoking close callback %s",
+! (char *)channel->ch_close_cb);
+ argv[0].v_type = VAR_CHANNEL;
+ argv[0].vval.v_channel = channel;
+! call_func(channel->ch_close_cb, -1,
+! &rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE,
+! channel->ch_close_partial, NULL);
+ clear_tv(&rettv);
+ channel_need_redraw = TRUE;
+
+ /* the callback is only called once */
+! free_callback(channel->ch_close_cb, channel->ch_close_partial);
+! channel->ch_close_cb = NULL;
+! channel->ch_close_partial = NULL;
+
+ if (channel_need_redraw)
+ {
+--- 2967,2982 ----
+ * halfway. */
+ ++channel->ch_refcount;
+ ch_log(channel, "Invoking close callback %s",
+! (char *)channel->ch_close_cb.cb_name);
+ argv[0].v_type = VAR_CHANNEL;
+ argv[0].vval.v_channel = channel;
+! call_callback(&channel->ch_close_cb, -1,
+! &rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE, NULL);
+ clear_tv(&rettv);
+ channel_need_redraw = TRUE;
+
+ /* the callback is only called once */
+! free_callback(&channel->ch_close_cb);
+
+ if (channel_need_redraw)
+ {
+***************
+*** 3061,3067 ****
+ cbq_T *node = cb_head->cq_next;
+
+ remove_cb_node(cb_head, node);
+! free_callback(node->cq_callback, node->cq_partial);
+ vim_free(node);
+ }
+
+--- 3039,3045 ----
+ cbq_T *node = cb_head->cq_next;
+
+ remove_cb_node(cb_head, node);
+! free_callback(&node->cq_callback);
+ vim_free(node);
+ }
+
+***************
+*** 3071,3079 ****
+ remove_json_node(json_head, json_head->jq_next);
+ }
+
+! free_callback(ch_part->ch_callback, ch_part->ch_partial);
+! ch_part->ch_callback = NULL;
+! ch_part->ch_partial = NULL;
+
+ while (ch_part->ch_writeque.wq_next != NULL)
+ remove_from_writeque(&ch_part->ch_writeque,
+--- 3049,3055 ----
+ remove_json_node(json_head, json_head->jq_next);
+ }
+
+! free_callback(&ch_part->ch_callback);
+
+ while (ch_part->ch_writeque.wq_next != NULL)
+ remove_from_writeque(&ch_part->ch_writeque,
+***************
+*** 3092,3103 ****
+ channel_clear_one(channel, PART_OUT);
+ channel_clear_one(channel, PART_ERR);
+ channel_clear_one(channel, PART_IN);
+! free_callback(channel->ch_callback, channel->ch_partial);
+! channel->ch_callback = NULL;
+! channel->ch_partial = NULL;
+! free_callback(channel->ch_close_cb, channel->ch_close_partial);
+! channel->ch_close_cb = NULL;
+! channel->ch_close_partial = NULL;
+ }
+
+ #if defined(EXITFREE) || defined(PROTO)
+--- 3068,3075 ----
+ channel_clear_one(channel, PART_OUT);
+ channel_clear_one(channel, PART_ERR);
+ channel_clear_one(channel, PART_IN);
+! free_callback(&channel->ch_callback);
+! free_callback(&channel->ch_close_cb);
+ }
+
+ #if defined(EXITFREE) || defined(PROTO)
+***************
+*** 3991,4009 ****
+ /* Set the callback. An empty callback means no callback and not reading
+ * the response. With "ch_evalexpr()" and "ch_evalraw()" a callback is not
+ * allowed. */
+! if (opt->jo_callback != NULL && *opt->jo_callback != NUL)
+ {
+ if (eval)
+ {
+ semsg(_("E917: Cannot use a callback with %s()"), fun);
+ return NULL;
+ }
+! channel_set_req_callback(channel, *part_read,
+! opt->jo_callback, opt->jo_partial, id);
+ }
+
+ if (channel_send(channel, part_send, text, len, fun) == OK
+! && opt->jo_callback == NULL)
+ return channel;
+ return NULL;
+ }
+--- 3963,3980 ----
+ /* Set the callback. An empty callback means no callback and not reading
+ * the response. With "ch_evalexpr()" and "ch_evalraw()" a callback is not
+ * allowed. */
+! if (opt->jo_callback.cb_name != NULL && *opt->jo_callback.cb_name != NUL)
+ {
+ if (eval)
+ {
+ semsg(_("E917: Cannot use a callback with %s()"), fun);
+ return NULL;
+ }
+! channel_set_req_callback(channel, *part_read, &opt->jo_callback, id);
+ }
+
+ if (channel_send(channel, part_send, text, len, fun) == OK
+! && opt->jo_callback.cb_name == NULL)
+ return channel;
+ return NULL;
+ }
+***************
+*** 4559,4584 ****
+ void
+ free_job_options(jobopt_T *opt)
+ {
+! if (opt->jo_partial != NULL)
+! partial_unref(opt->jo_partial);
+! else if (opt->jo_callback != NULL)
+! func_unref(opt->jo_callback);
+! if (opt->jo_out_partial != NULL)
+! partial_unref(opt->jo_out_partial);
+! else if (opt->jo_out_cb != NULL)
+! func_unref(opt->jo_out_cb);
+! if (opt->jo_err_partial != NULL)
+! partial_unref(opt->jo_err_partial);
+! else if (opt->jo_err_cb != NULL)
+! func_unref(opt->jo_err_cb);
+! if (opt->jo_close_partial != NULL)
+! partial_unref(opt->jo_close_partial);
+! else if (opt->jo_close_cb != NULL)
+! func_unref(opt->jo_close_cb);
+! if (opt->jo_exit_partial != NULL)
+! partial_unref(opt->jo_exit_partial);
+! else if (opt->jo_exit_cb != NULL)
+! func_unref(opt->jo_exit_cb);
+ if (opt->jo_env != NULL)
+ dict_unref(opt->jo_env);
+ }
+--- 4530,4555 ----
+ void
+ free_job_options(jobopt_T *opt)
+ {
+! if (opt->jo_callback.cb_partial != NULL)
+! partial_unref(opt->jo_callback.cb_partial);
+! else if (opt->jo_callback.cb_name != NULL)
+! func_unref(opt->jo_callback.cb_name);
+! if (opt->jo_out_cb.cb_partial != NULL)
+! partial_unref(opt->jo_out_cb.cb_partial);
+! else if (opt->jo_out_cb.cb_name != NULL)
+! func_unref(opt->jo_out_cb.cb_name);
+! if (opt->jo_err_cb.cb_partial != NULL)
+! partial_unref(opt->jo_err_cb.cb_partial);
+! else if (opt->jo_err_cb.cb_name != NULL)
+! func_unref(opt->jo_err_cb.cb_name);
+! if (opt->jo_close_cb.cb_partial != NULL)
+! partial_unref(opt->jo_close_cb.cb_partial);
+! else if (opt->jo_close_cb.cb_name != NULL)
+! func_unref(opt->jo_close_cb.cb_name);
+! if (opt->jo_exit_cb.cb_partial != NULL)
+! partial_unref(opt->jo_exit_cb.cb_partial);
+! else if (opt->jo_exit_cb.cb_name != NULL)
+! func_unref(opt->jo_exit_cb.cb_name);
+ if (opt->jo_env != NULL)
+ dict_unref(opt->jo_env);
+ }
+***************
+*** 4771,4778 ****
+ if (!(supported & JO_CALLBACK))
+ break;
+ opt->jo_set |= JO_CALLBACK;
+! opt->jo_callback = get_callback(item, &opt->jo_partial);
+! if (opt->jo_callback == NULL)
+ {
+ semsg(_(e_invargval), "callback");
+ return FAIL;
+--- 4742,4749 ----
+ if (!(supported & JO_CALLBACK))
+ break;
+ opt->jo_set |= JO_CALLBACK;
+! opt->jo_callback = get_callback(item);
+! if (opt->jo_callback.cb_name == NULL)
+ {
+ semsg(_(e_invargval), "callback");
+ return FAIL;
+***************
+*** 4783,4790 ****
+ if (!(supported & JO_OUT_CALLBACK))
+ break;
+ opt->jo_set |= JO_OUT_CALLBACK;
+! opt->jo_out_cb = get_callback(item, &opt->jo_out_partial);
+! if (opt->jo_out_cb == NULL)
+ {
+ semsg(_(e_invargval), "out_cb");
+ return FAIL;
+--- 4754,4761 ----
+ if (!(supported & JO_OUT_CALLBACK))
+ break;
+ opt->jo_set |= JO_OUT_CALLBACK;
+! opt->jo_out_cb = get_callback(item);
+! if (opt->jo_out_cb.cb_name == NULL)
+ {
+ semsg(_(e_invargval), "out_cb");
+ return FAIL;
+***************
+*** 4795,4802 ****
+ if (!(supported & JO_ERR_CALLBACK))
+ break;
+ opt->jo_set |= JO_ERR_CALLBACK;
+! opt->jo_err_cb = get_callback(item, &opt->jo_err_partial);
+! if (opt->jo_err_cb == NULL)
+ {
+ semsg(_(e_invargval), "err_cb");
+ return FAIL;
+--- 4766,4773 ----
+ if (!(supported & JO_ERR_CALLBACK))
+ break;
+ opt->jo_set |= JO_ERR_CALLBACK;
+! opt->jo_err_cb = get_callback(item);
+! if (opt->jo_err_cb.cb_name == NULL)
+ {
+ semsg(_(e_invargval), "err_cb");
+ return FAIL;
+***************
+*** 4807,4814 ****
+ if (!(supported & JO_CLOSE_CALLBACK))
+ break;
+ opt->jo_set |= JO_CLOSE_CALLBACK;
+! opt->jo_close_cb = get_callback(item, &opt->jo_close_partial);
+! if (opt->jo_close_cb == NULL)
+ {
+ semsg(_(e_invargval), "close_cb");
+ return FAIL;
+--- 4778,4785 ----
+ if (!(supported & JO_CLOSE_CALLBACK))
+ break;
+ opt->jo_set |= JO_CLOSE_CALLBACK;
+! opt->jo_close_cb = get_callback(item);
+! if (opt->jo_close_cb.cb_name == NULL)
+ {
+ semsg(_(e_invargval), "close_cb");
+ return FAIL;
+***************
+*** 4833,4840 ****
+ if (!(supported & JO_EXIT_CB))
+ break;
+ opt->jo_set |= JO_EXIT_CB;
+! opt->jo_exit_cb = get_callback(item, &opt->jo_exit_partial);
+! if (opt->jo_exit_cb == NULL)
+ {
+ semsg(_(e_invargval), "exit_cb");
+ return FAIL;
+--- 4804,4811 ----
+ if (!(supported & JO_EXIT_CB))
+ break;
+ opt->jo_set |= JO_EXIT_CB;
+! opt->jo_exit_cb = get_callback(item);
+! if (opt->jo_exit_cb.cb_name == NULL)
+ {
+ semsg(_(e_invargval), "exit_cb");
+ return FAIL;
+***************
+*** 5201,5207 ****
+ #ifdef MSWIN
+ vim_free(job->jv_tty_type);
+ #endif
+! free_callback(job->jv_exit_cb, job->jv_exit_partial);
+ if (job->jv_argv != NULL)
+ {
+ for (i = 0; job->jv_argv[i] != NULL; i++)
+--- 5172,5178 ----
+ #ifdef MSWIN
+ vim_free(job->jv_tty_type);
+ #endif
+! free_callback(&job->jv_exit_cb);
+ if (job->jv_argv != NULL)
+ {
+ for (i = 0; job->jv_argv[i] != NULL; i++)
+***************
+*** 5289,5295 ****
+ job_need_end_check(job_T *job)
+ {
+ return job->jv_status == JOB_STARTED
+! && (job->jv_stoponexit != NULL || job->jv_exit_cb != NULL);
+ }
+
+ /*
+--- 5260,5266 ----
+ job_need_end_check(job_T *job)
+ {
+ return job->jv_status == JOB_STARTED
+! && (job->jv_stoponexit != NULL || job->jv_exit_cb.cb_name != NULL);
+ }
+
+ /*
+***************
+*** 5465,5486 ****
+ if (job->jv_channel != NULL)
+ ch_close_part(job->jv_channel, PART_IN);
+
+! if (job->jv_exit_cb != NULL)
+ {
+ typval_T argv[3];
+ typval_T rettv;
+ int dummy;
+
+ /* Invoke the exit callback. Make sure the refcount is > 0. */
+! ch_log(job->jv_channel, "Invoking exit callback %s", job->jv_exit_cb);
+ ++job->jv_refcount;
+ 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, -1,
+! &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
+! job->jv_exit_partial, NULL);
+ clear_tv(&rettv);
+ --job->jv_refcount;
+ channel_need_redraw = TRUE;
+--- 5436,5457 ----
+ if (job->jv_channel != NULL)
+ ch_close_part(job->jv_channel, PART_IN);
+
+! if (job->jv_exit_cb.cb_name != NULL)
+ {
+ typval_T argv[3];
+ typval_T rettv;
+ int dummy;
+
+ /* Invoke the exit callback. Make sure the refcount is > 0. */
+! ch_log(job->jv_channel, "Invoking exit callback %s",
+! job->jv_exit_cb.cb_name);
+ ++job->jv_refcount;
+ 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_callback(&job->jv_exit_cb, -1,
+! &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE, NULL);
+ clear_tv(&rettv);
+ --job->jv_refcount;
+ channel_need_redraw = TRUE;
+***************
+*** 5622,5647 ****
+ }
+ if (opt->jo_set & JO_EXIT_CB)
+ {
+! free_callback(job->jv_exit_cb, job->jv_exit_partial);
+! if (opt->jo_exit_cb == NULL || *opt->jo_exit_cb == NUL)
+ {
+! job->jv_exit_cb = NULL;
+! job->jv_exit_partial = NULL;
+ }
+ else
+! {
+! job->jv_exit_partial = opt->jo_exit_partial;
+! if (job->jv_exit_partial != NULL)
+! {
+! job->jv_exit_cb = opt->jo_exit_cb;
+! ++job->jv_exit_partial->pt_refcount;
+! }
+! else
+! {
+! job->jv_exit_cb = vim_strsave(opt->jo_exit_cb);
+! func_ref(job->jv_exit_cb);
+! }
+! }
+ }
+ }
+
+--- 5593,5606 ----
+ }
+ if (opt->jo_set & JO_EXIT_CB)
+ {
+! free_callback(&job->jv_exit_cb);
+! if (opt->jo_exit_cb.cb_name == NULL || *opt->jo_exit_cb.cb_name == NUL)
+ {
+! job->jv_exit_cb.cb_name = NULL;
+! job->jv_exit_cb.cb_partial = NULL;
+ }
+ else
+! copy_callback(&job->jv_exit_cb, &opt->jo_exit_cb);
+ }
+ }
+
+***************
+*** 5959,5965 ****
+ dict_add_string(dict, "tty_out", job->jv_tty_out);
+
+ dict_add_number(dict, "exitval", job->jv_exitval);
+! dict_add_string(dict, "exit_cb", job->jv_exit_cb);
+ dict_add_string(dict, "stoponexit", job->jv_stoponexit);
+ #ifdef UNIX
+ dict_add_string(dict, "termsig", job->jv_termsig);
+--- 5918,5924 ----
+ dict_add_string(dict, "tty_out", job->jv_tty_out);
+
+ dict_add_number(dict, "exitval", job->jv_exitval);
+! dict_add_string(dict, "exit_cb", job->jv_exit_cb.cb_name);
+ dict_add_string(dict, "stoponexit", job->jv_stoponexit);
+ #ifdef UNIX
+ dict_add_string(dict, "termsig", job->jv_termsig);
+***************
+*** 6059,6065 ****
+ curwin->w_cursor.lnum = lnum + 1;
+ curwin->w_cursor.col = 0;
+
+! if (curbuf->b_prompt_callback == NULL || *curbuf->b_prompt_callback == NUL)
+ return;
+ text = ml_get(lnum);
+ prompt = prompt_text();
+--- 6018,6025 ----
+ curwin->w_cursor.lnum = lnum + 1;
+ curwin->w_cursor.col = 0;
+
+! if (curbuf->b_prompt_callback.cb_name == NULL
+! || *curbuf->b_prompt_callback.cb_name == NUL)
+ return;
+ text = ml_get(lnum);
+ prompt = prompt_text();
+***************
+*** 6069,6077 ****
+ argv[0].vval.v_string = vim_strsave(text);
+ argv[1].v_type = VAR_UNKNOWN;
+
+! call_func(curbuf->b_prompt_callback, -1,
+! &rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE,
+! curbuf->b_prompt_partial, NULL);
+ clear_tv(&argv[0]);
+ clear_tv(&rettv);
+ }
+--- 6029,6036 ----
+ argv[0].vval.v_string = vim_strsave(text);
+ argv[1].v_type = VAR_UNKNOWN;
+
+! call_callback(&curbuf->b_prompt_callback, -1,
+! &rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE, NULL);
+ clear_tv(&argv[0]);
+ clear_tv(&rettv);
+ }
+***************
+*** 6086,6100 ****
+ int dummy;
+ typval_T argv[1];
+
+! if (curbuf->b_prompt_interrupt == NULL
+! || *curbuf->b_prompt_interrupt == NUL)
+ return FALSE;
+ argv[0].v_type = VAR_UNKNOWN;
+
+ got_int = FALSE; // don't skip executing commands
+! call_func(curbuf->b_prompt_interrupt, -1,
+! &rettv, 0, argv, NULL, 0L, 0L, &dummy, TRUE,
+! curbuf->b_prompt_int_partial, NULL);
+ clear_tv(&rettv);
+ return TRUE;
+ }
+--- 6045,6058 ----
+ int dummy;
+ typval_T argv[1];
+
+! if (curbuf->b_prompt_interrupt.cb_name == NULL
+! || *curbuf->b_prompt_interrupt.cb_name == NUL)
+ return FALSE;
+ argv[0].v_type = VAR_UNKNOWN;
+
+ got_int = FALSE; // don't skip executing commands
+! call_callback(&curbuf->b_prompt_interrupt, -1,
+! &rettv, 0, argv, NULL, 0L, 0L, &dummy, TRUE, NULL);
+ clear_tv(&rettv);
+ return TRUE;
+ }
+*** ../vim-8.1.1436/src/proto/channel.pro 2019-01-12 22:47:01.264088074 +0100
+--- src/proto/channel.pro 2019-05-31 23:09:12.017119094 +0200
+***************
+*** 12,18 ****
+ void channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err);
+ void channel_set_job(channel_T *channel, job_T *job, jobopt_T *options);
+ void channel_set_options(channel_T *channel, jobopt_T *opt);
+! void channel_set_req_callback(channel_T *channel, ch_part_T part, char_u *callback, partial_T *partial, int id);
+ void channel_buffer_free(buf_T *buf);
+ void channel_write_any_lines(void);
+ void channel_write_new_lines(buf_T *buf);
+--- 12,18 ----
+ void channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err);
+ void channel_set_job(channel_T *channel, job_T *job, jobopt_T *options);
+ void channel_set_options(channel_T *channel, jobopt_T *opt);
+! void channel_set_req_callback(channel_T *channel, ch_part_T part, callback_T *callback, int id);
+ void channel_buffer_free(buf_T *buf);
+ void channel_write_any_lines(void);
+ void channel_write_new_lines(buf_T *buf);
+*** ../vim-8.1.1436/src/buffer.c 2019-05-30 22:32:10.804178558 +0200
+--- src/buffer.c 2019-05-31 22:28:27.560903172 +0200
+***************
+*** 862,868 ****
+ #endif
+ #ifdef FEAT_JOB_CHANNEL
+ vim_free(buf->b_prompt_text);
+! free_callback(buf->b_prompt_callback, buf->b_prompt_partial);
+ #endif
+
+ buf_hashtab_remove(buf);
+--- 862,868 ----
+ #endif
+ #ifdef FEAT_JOB_CHANNEL
+ vim_free(buf->b_prompt_text);
+! free_callback(&buf->b_prompt_callback);
+ #endif
+
+ buf_hashtab_remove(buf);
+*** ../vim-8.1.1436/src/userfunc.c 2019-05-28 23:08:12.080648632 +0200
+--- src/userfunc.c 2019-05-31 22:55:38.981219323 +0200
+***************
+*** 1447,1452 ****
+--- 1447,1476 ----
+ }
+
+ /*
++ * Invoke call_func() with a callback.
++ */
++ int
++ call_callback(
++ callback_T *callback,
++ int len, // length of "name" or -1 to use strlen()
++ typval_T *rettv, // return value goes here
++ int argcount, // number of "argvars"
++ typval_T *argvars, // vars for arguments, must have "argcount"
++ // PLUS ONE elements!
++ int (* argv_func)(int, typval_T *, int),
++ // function to fill in argvars
++ linenr_T firstline, // first line of range
++ linenr_T lastline, // last line of range
++ int *doesrange, // return: function handled range
++ int evaluate,
++ dict_T *selfdict) // Dictionary for "self"
++ {
++ return call_func(callback->cb_name, len, rettv, argcount, argvars,
++ argv_func, firstline, lastline, doesrange, evaluate,
++ callback->cb_partial, selfdict);
++ }
++
++ /*
+ * Call a function with its resolved parameters
+ *
+ * "argv_func", when not NULL, can be used to fill in arguments only when the
+*** ../vim-8.1.1436/src/proto/userfunc.pro 2018-12-18 21:56:25.084495836 +0100
+--- src/proto/userfunc.pro 2019-05-31 22:55:34.269243311 +0200
+***************
+*** 8,13 ****
+--- 8,14 ----
+ void restore_funccal(void);
+ void free_all_functions(void);
+ int func_call(char_u *name, typval_T *args, partial_T *partial, dict_T *selfdict, typval_T *rettv);
++ int call_callback(callback_T *callback, int len, typval_T *rettv, int argcount, typval_T *argvars, int (*argv_func)(int, typval_T *, int), linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, dict_T *selfdict);
+ int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typval_T *argvars_in, int (*argv_func)(int, typval_T *, int), linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, partial_T *partial, dict_T *selfdict_in);
+ char_u *trans_function_name(char_u **pp, int skip, int flags, funcdict_T *fdp, partial_T **partial);
+ void ex_function(exarg_T *eap);
+*** ../vim-8.1.1436/src/eval.c 2019-05-28 23:08:12.056648758 +0200
+--- src/eval.c 2019-05-31 23:15:01.475368819 +0200
+***************
+*** 5920,5929 ****
+ dtv.vval.v_channel = job->jv_channel;
+ set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
+ }
+! if (job->jv_exit_partial != NULL)
+ {
+ dtv.v_type = VAR_PARTIAL;
+! dtv.vval.v_partial = job->jv_exit_partial;
+ set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
+ }
+ }
+--- 5920,5929 ----
+ dtv.vval.v_channel = job->jv_channel;
+ set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
+ }
+! if (job->jv_exit_cb.cb_partial != NULL)
+ {
+ dtv.v_type = VAR_PARTIAL;
+! dtv.vval.v_partial = job->jv_exit_cb.cb_partial;
+ set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
+ }
+ }
+***************
+*** 5946,5974 ****
+ set_ref_in_item(jq->jq_value, copyID, ht_stack, list_stack);
+ for (cq = ch->ch_part[part].ch_cb_head.cq_next; cq != NULL;
+ cq = cq->cq_next)
+! if (cq->cq_partial != NULL)
+ {
+ dtv.v_type = VAR_PARTIAL;
+! dtv.vval.v_partial = cq->cq_partial;
+ set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
+ }
+! if (ch->ch_part[part].ch_partial != NULL)
+ {
+ dtv.v_type = VAR_PARTIAL;
+! dtv.vval.v_partial = ch->ch_part[part].ch_partial;
+ set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
+ }
+ }
+! if (ch->ch_partial != NULL)
+ {
+ dtv.v_type = VAR_PARTIAL;
+! dtv.vval.v_partial = ch->ch_partial;
+ set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
+ }
+! if (ch->ch_close_partial != NULL)
+ {
+ dtv.v_type = VAR_PARTIAL;
+! dtv.vval.v_partial = ch->ch_close_partial;
+ set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
+ }
+ }
+--- 5946,5975 ----
+ set_ref_in_item(jq->jq_value, copyID, ht_stack, list_stack);
+ for (cq = ch->ch_part[part].ch_cb_head.cq_next; cq != NULL;
+ cq = cq->cq_next)
+! if (cq->cq_callback.cb_partial != NULL)
+ {
+ dtv.v_type = VAR_PARTIAL;
+! dtv.vval.v_partial = cq->cq_callback.cb_partial;
+ set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
+ }
+! if (ch->ch_part[part].ch_callback.cb_partial != NULL)
+ {
+ dtv.v_type = VAR_PARTIAL;
+! dtv.vval.v_partial =
+! ch->ch_part[part].ch_callback.cb_partial;
+ set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
+ }
+ }
+! if (ch->ch_callback.cb_partial != NULL)
+ {
+ dtv.v_type = VAR_PARTIAL;
+! dtv.vval.v_partial = ch->ch_callback.cb_partial;
+ set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
+ }
+! if (ch->ch_close_cb.cb_partial != NULL)
+ {
+ dtv.v_type = VAR_PARTIAL;
+! dtv.vval.v_partial = ch->ch_close_cb.cb_partial;
+ set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
+ }
+ }
+*** ../vim-8.1.1436/src/ex_cmds2.c 2019-05-28 23:08:12.060648736 +0200
+--- src/ex_cmds2.c 2019-05-31 23:06:01.714074164 +0200
+***************
+*** 282,288 ****
+ static void
+ free_timer(timer_T *timer)
+ {
+! free_callback(timer->tr_callback, timer->tr_partial);
+ vim_free(timer);
+ }
+
+--- 282,288 ----
+ static void
+ free_timer(timer_T *timer)
+ {
+! free_callback(&timer->tr_callback);
+ vim_free(timer);
+ }
+
+***************
+*** 325,333 ****
+ argv[0].vval.v_number = (varnumber_T)timer->tr_id;
+ argv[1].v_type = VAR_UNKNOWN;
+
+! call_func(timer->tr_callback, -1,
+! &rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE,
+! timer->tr_partial, NULL);
+ clear_tv(&rettv);
+ }
+
+--- 325,332 ----
+ argv[0].vval.v_number = (varnumber_T)timer->tr_id;
+ argv[1].v_type = VAR_UNKNOWN;
+
+! call_callback(&timer->tr_callback, -1,
+! &rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE, NULL);
+ clear_tv(&rettv);
+ }
+
+***************
+*** 542,558 ****
+ {
+ if (dict_add(dict, di) == FAIL)
+ vim_free(di);
+- else if (timer->tr_partial != NULL)
+- {
+- di->di_tv.v_type = VAR_PARTIAL;
+- di->di_tv.vval.v_partial = timer->tr_partial;
+- ++timer->tr_partial->pt_refcount;
+- }
+ else
+! {
+! di->di_tv.v_type = VAR_FUNC;
+! di->di_tv.vval.v_string = vim_strsave(timer->tr_callback);
+! }
+ }
+ }
+
+--- 541,548 ----
+ {
+ if (dict_add(dict, di) == FAIL)
+ vim_free(di);
+ else
+! put_callback(&timer->tr_callback, &di->di_tv);
+ }
+ }
+
+***************
+*** 578,592 ****
+
+ for (timer = first_timer; timer != NULL; timer = timer->tr_next)
+ {
+! if (timer->tr_partial != NULL)
+ {
+ tv.v_type = VAR_PARTIAL;
+! tv.vval.v_partial = timer->tr_partial;
+ }
+ else
+ {
+ tv.v_type = VAR_FUNC;
+! tv.vval.v_string = timer->tr_callback;
+ }
+ abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
+ }
+--- 568,582 ----
+
+ for (timer = first_timer; timer != NULL; timer = timer->tr_next)
+ {
+! if (timer->tr_callback.cb_partial != NULL)
+ {
+ tv.v_type = VAR_PARTIAL;
+! tv.vval.v_partial = timer->tr_callback.cb_partial;
+ }
+ else
+ {
+ tv.v_type = VAR_FUNC;
+! tv.vval.v_string = timer->tr_callback.cb_name;
+ }
+ abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
+ }
+*** ../vim-8.1.1436/src/popupwin.c 2019-05-30 22:32:10.804178558 +0200
+--- src/popupwin.c 2019-05-31 23:07:27.541643206 +0200
+***************
+*** 149,158 ****
+ if (get_lambda_tv(&ptr, &tv, TRUE) == OK)
+ {
+ wp->w_popup_timer = create_timer(nr, 0);
+! wp->w_popup_timer->tr_callback =
+ vim_strsave(partial_name(tv.vval.v_partial));
+! func_ref(wp->w_popup_timer->tr_callback);
+! wp->w_popup_timer->tr_partial = tv.vval.v_partial;
+ }
+ }
+ #endif
+--- 149,158 ----
+ if (get_lambda_tv(&ptr, &tv, TRUE) == OK)
+ {
+ wp->w_popup_timer = create_timer(nr, 0);
+! wp->w_popup_timer->tr_callback.cb_name =
+ vim_strsave(partial_name(tv.vval.v_partial));
+! func_ref(wp->w_popup_timer->tr_callback.cb_name);
+! wp->w_popup_timer->tr_callback.cb_partial = tv.vval.v_partial;
+ }
+ }
+ #endif
+*** ../vim-8.1.1436/src/version.c 2019-05-31 20:42:04.694287075 +0200
+--- src/version.c 2019-06-01 13:19:22.800368900 +0200
+***************
+*** 769,770 ****
+--- 769,772 ----
+ { /* Add new patch number below this line */
++ /**/
++ 1437,
+ /**/
+
+--
+hundred-and-one symptoms of being an internet addict:
+70. ISDN lines are added to your house on a hourly basis
+
+ /// 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 ///