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 -- [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].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/201906011128.x51BSqGL002828%40masaka.moolenaar.net.
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui