Patch 7.4.1559
Problem:    Passing cookie to a callback is clumsy.
Solution:   Change function() to take arguments and return a partial.
Files:      src/structs.h, src/channel.c, src/eval.c, src/if_python.c,
            src/if_python3.c, src/if_py_both.h, src/json.c,
            src/proto/eval.pro, src/testdir/test_partial.vim,
            src/testdir/test_alot.vim, runtime/doc/eval.txt


*** ../vim-7.4.1558/src/structs.h       2016-03-13 18:06:59.520803811 +0100
--- src/structs.h       2016-03-14 22:45:33.611073843 +0100
***************
*** 1110,1115 ****
--- 1110,1116 ----
  
  typedef struct listvar_S list_T;
  typedef struct dictvar_S dict_T;
+ typedef struct partial_S partial_T;
  
  typedef struct jobvar_S job_T;
  typedef struct readq_S readq_T;
***************
*** 1123,1128 ****
--- 1124,1130 ----
      VAR_NUMBER,        /* "v_number" is used */
      VAR_STRING,        /* "v_string" is used */
      VAR_FUNC,  /* "v_string" is function name */
+     VAR_PARTIAL, /* "v_partial" is used */
      VAR_LIST,  /* "v_list" is used */
      VAR_DICT,  /* "v_dict" is used */
      VAR_FLOAT,         /* "v_float" is used */
***************
*** 1147,1152 ****
--- 1149,1155 ----
        char_u          *v_string;      /* string value (can be NULL!) */
        list_T          *v_list;        /* list value (can be NULL!) */
        dict_T          *v_dict;        /* dict value (can be NULL!) */
+       partial_T       *v_partial;     /* closure: function with args */
  #ifdef FEAT_JOB_CHANNEL
        job_T           *v_job;         /* job value (can be NULL!) */
        channel_T       *v_channel;     /* channel value (can be NULL!) */
***************
*** 1239,1244 ****
--- 1242,1256 ----
      dict_T    *dv_used_prev;  /* previous dict in used dicts list */
  };
  
+ struct partial_S
+ {
+     int               pt_refcount;    /* reference count */
+     char_u    *pt_name;       /* function name */
+     int               pt_argc;        /* number of arguments */
+     typval_T  *pt_argv;       /* arguments in allocated array */
+     dict_T    *pt_dict;       /* dict for "self" */
+ };
+ 
  typedef enum
  {
      JOB_FAILED,
***************
*** 1264,1269 ****
--- 1276,1282 ----
      char_u    *jv_stoponexit; /* allocated */
      int               jv_exitval;
      char_u    *jv_exit_cb;    /* allocated */
+     partial_T *jv_exit_partial;
  
      buf_T     *jv_in_buf;     /* buffer from "in-name" */
  
***************
*** 1291,1296 ****
--- 1304,1310 ----
  struct cbq_S
  {
      char_u    *cq_callback;
+     partial_T *cq_partial;
      int               cq_seq_nr;
      cbq_T     *cq_next;
      cbq_T     *cq_prev;
***************
*** 1346,1351 ****
--- 1360,1366 ----
  
      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;
  
      buf_T     *ch_buffer;     /* buffer to read from or write to */
      linenr_T  ch_buf_top;     /* next line to send */
***************
*** 1371,1377 ****
--- 1386,1394 ----
                                 * closed */
  
      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;
  
      job_T     *ch_job;        /* Job that uses this channel; this does not
                                 * count as a reference to avoid a circular
***************
*** 1447,1455 ****
--- 1464,1478 ----
      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_waittime;
      int               jo_timeout;
      int               jo_out_timeout;
***************
*** 1459,1465 ****
      char_u    jo_soe_buf[NUMBUFLEN];
      char_u    *jo_stoponexit;
      char_u    jo_ecb_buf[NUMBUFLEN];
-     char_u    *jo_exit_cb;
  } jobopt_T;
  
  
--- 1482,1487 ----
*** ../vim-7.4.1558/src/channel.c       2016-03-12 15:58:30.020231560 +0100
--- src/channel.c       2016-03-14 22:50:20.228063983 +0100
***************
*** 1025,1032 ****
      void
  channel_set_options(channel_T *channel, jobopt_T *opt)
  {
!     int    part;
!     char_u **cbp;
  
      if (opt->jo_set & JO_MODE)
        for (part = PART_SOCK; part <= PART_IN; ++part)
--- 1025,1033 ----
      void
  channel_set_options(channel_T *channel, jobopt_T *opt)
  {
!     int               part;
!     char_u    **cbp;
!     partial_T **pp;
  
      if (opt->jo_set & JO_MODE)
        for (part = PART_SOCK; part <= PART_IN; ++part)
***************
*** 1049,1086 ****
--- 1050,1107 ----
      if (opt->jo_set & JO_CALLBACK)
      {
        cbp = &channel->ch_callback;
+       pp = &channel->ch_partial;
        vim_free(*cbp);
+       partial_unref(*pp);
        if (opt->jo_callback != NULL && *opt->jo_callback != NUL)
            *cbp = vim_strsave(opt->jo_callback);
        else
            *cbp = NULL;
+       *pp = opt->jo_partial;
+       if (*pp != NULL)
+           ++(*pp)->pt_refcount;
      }
      if (opt->jo_set & JO_OUT_CALLBACK)
      {
        cbp = &channel->ch_part[PART_OUT].ch_callback;
+       pp = &channel->ch_part[PART_OUT].ch_partial;
        vim_free(*cbp);
+       partial_unref(*pp);
        if (opt->jo_out_cb != NULL && *opt->jo_out_cb != NUL)
            *cbp = vim_strsave(opt->jo_out_cb);
        else
            *cbp = NULL;
+       *pp = opt->jo_out_partial;
+       if (*pp != NULL)
+           ++(*pp)->pt_refcount;
      }
      if (opt->jo_set & JO_ERR_CALLBACK)
      {
        cbp = &channel->ch_part[PART_ERR].ch_callback;
+       pp = &channel->ch_part[PART_ERR].ch_partial;
        vim_free(*cbp);
+       partial_unref(*pp);
        if (opt->jo_err_cb != NULL && *opt->jo_err_cb != NUL)
            *cbp = vim_strsave(opt->jo_err_cb);
        else
            *cbp = NULL;
+       *pp = opt->jo_err_partial;
+       if (*pp != NULL)
+           ++(*pp)->pt_refcount;
      }
      if (opt->jo_set & JO_CLOSE_CALLBACK)
      {
        cbp = &channel->ch_close_cb;
+       pp = &channel->ch_close_partial;
        vim_free(*cbp);
+       partial_unref(*pp);
        if (opt->jo_close_cb != NULL && *opt->jo_close_cb != NUL)
            *cbp = vim_strsave(opt->jo_close_cb);
        else
            *cbp = NULL;
+       *pp = opt->jo_err_partial;
+       if (*pp != NULL)
+           ++(*pp)->pt_refcount;
      }
  
      if ((opt->jo_set & JO_OUT_IO) && opt->jo_io[PART_OUT] == JIO_BUFFER)
***************
*** 1124,1133 ****
   */
      void
  channel_set_req_callback(
!       channel_T *channel,
!       int part,
!       char_u *callback,
!       int id)
  {
      cbq_T *head = &channel->ch_part[part].ch_cb_head;
      cbq_T *item = (cbq_T *)alloc((int)sizeof(cbq_T));
--- 1145,1155 ----
   */
      void
  channel_set_req_callback(
!       channel_T   *channel,
!       int         part,
!       char_u      *callback,
!       partial_T   *partial,
!       int         id)
  {
      cbq_T *head = &channel->ch_part[part].ch_cb_head;
      cbq_T *item = (cbq_T *)alloc((int)sizeof(cbq_T));
***************
*** 1135,1140 ****
--- 1157,1165 ----
      if (item != NULL)
      {
        item->cq_callback = vim_strsave(callback);
+       item->cq_partial = partial;
+       if (partial != NULL)
+           ++partial->pt_refcount;
        item->cq_seq_nr = id;
        item->cq_prev = head->cq_prev;
        head->cq_prev = item;
***************
*** 1247,1253 ****
   * Invoke the "callback" on channel "channel".
   */
      static void
! invoke_callback(channel_T *channel, char_u *callback, typval_T *argv)
  {
      typval_T  rettv;
      int               dummy;
--- 1272,1279 ----
   * Invoke the "callback" on channel "channel".
   */
      static void
! invoke_callback(channel_T *channel, char_u *callback, partial_T *partial,
!                                                              typval_T *argv)
  {
      typval_T  rettv;
      int               dummy;
***************
*** 1256,1262 ****
      argv[0].vval.v_channel = channel;
  
      call_func(callback, (int)STRLEN(callback),
!                            &rettv, 2, argv, 0L, 0L, &dummy, TRUE, NULL);
      clear_tv(&rettv);
  
      /* If an echo command was used the cursor needs to be put back where
--- 1282,1288 ----
      argv[0].vval.v_channel = channel;
  
      call_func(callback, (int)STRLEN(callback),
!                       &rettv, 2, argv, 0L, 0L, &dummy, TRUE, partial, NULL);
      clear_tv(&rettv);
  
      /* If an echo command was used the cursor needs to be put back where
***************
*** 1629,1635 ****
            ++emsg_skip;
            if (!is_call)
                tv = eval_expr(arg, NULL);
!           else if (func_call(arg, &argv[2], NULL, &res_tv) == OK)
                tv = &res_tv;
            else
                tv = NULL;
--- 1655,1661 ----
            ++emsg_skip;
            if (!is_call)
                tv = eval_expr(arg, NULL);
!           else if (func_call(arg, &argv[2], NULL, NULL, &res_tv) == OK)
                tv = &res_tv;
            else
                tv = NULL;
***************
*** 1685,1692 ****
      /* 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);
      vim_free(item->cq_callback);
      vim_free(item);
  }
  
--- 1711,1719 ----
      /* 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);
      vim_free(item->cq_callback);
+     partial_unref(item->cq_partial);
      vim_free(item);
  }
  
***************
*** 1775,1780 ****
--- 1802,1808 ----
      cbq_T     *cbhead = &channel->ch_part[part].ch_cb_head;
      cbq_T     *cbitem;
      char_u    *callback = NULL;
+     partial_T *partial = NULL;
      buf_T     *buffer = NULL;
  
      if (channel->ch_nb_close_cb != NULL)
***************
*** 1786,1796 ****
--- 1814,1833 ----
        if (cbitem->cq_seq_nr == 0)
            break;
      if (cbitem != NULL)
+     {
        callback = cbitem->cq_callback;
+       partial = cbitem->cq_partial;
+     }
      else if (channel->ch_part[part].ch_callback != NULL)
+     {
        callback = channel->ch_part[part].ch_callback;
+       partial = channel->ch_part[part].ch_partial;
+     }
      else
+     {
        callback = channel->ch_callback;
+       partial = channel->ch_partial;
+     }
  
      buffer = channel->ch_part[part].ch_buffer;
      if (buffer != NULL && !buf_valid(buffer))
***************
*** 1936,1942 ****
                /* invoke the channel callback */
                ch_logs(channel, "Invoking channel callback %s",
                                                            (char *)callback);
!               invoke_callback(channel, callback, argv);
            }
        }
      }
--- 1973,1979 ----
                /* invoke the channel callback */
                ch_logs(channel, "Invoking channel callback %s",
                                                            (char *)callback);
!               invoke_callback(channel, callback, partial, argv);
            }
        }
      }
***************
*** 2024,2036 ****
          argv[0].vval.v_channel = channel;
          ++channel->ch_refcount;
          call_func(channel->ch_close_cb, (int)STRLEN(channel->ch_close_cb),
!                                &rettv, 1, argv, 0L, 0L, &dummy, TRUE, NULL);
          clear_tv(&rettv);
          --channel->ch_refcount;
  
          /* the callback is only called once */
          vim_free(channel->ch_close_cb);
          channel->ch_close_cb = NULL;
      }
  
      channel->ch_nb_close_cb = NULL;
--- 2061,2076 ----
          argv[0].vval.v_channel = channel;
          ++channel->ch_refcount;
          call_func(channel->ch_close_cb, (int)STRLEN(channel->ch_close_cb),
!                          &rettv, 1, argv, 0L, 0L, &dummy, TRUE,
!                          channel->ch_close_partial, NULL);
          clear_tv(&rettv);
          --channel->ch_refcount;
  
          /* the callback is only called once */
          vim_free(channel->ch_close_cb);
          channel->ch_close_cb = NULL;
+         partial_unref(channel->ch_close_partial);
+         channel->ch_close_partial = NULL;
      }
  
      channel->ch_nb_close_cb = NULL;
***************
*** 2068,2073 ****
--- 2108,2114 ----
  
        remove_cb_node(cb_head, node);
        vim_free(node->cq_callback);
+       partial_unref(node->cq_partial);
        vim_free(node);
      }
  
***************
*** 2079,2084 ****
--- 2120,2127 ----
  
      vim_free(channel->ch_part[part].ch_callback);
      channel->ch_part[part].ch_callback = NULL;
+     partial_unref(channel->ch_part[part].ch_partial);
+     channel->ch_part[part].ch_partial = NULL;
  }
  
  /*
***************
*** 2093,2100 ****
--- 2136,2147 ----
      channel_clear_one(channel, PART_ERR);
      vim_free(channel->ch_callback);
      channel->ch_callback = NULL;
+     partial_unref(channel->ch_partial);
+     channel->ch_partial = NULL;
      vim_free(channel->ch_close_cb);
      channel->ch_close_cb = NULL;
+     partial_unref(channel->ch_close_partial);
+     channel->ch_close_partial = NULL;
  }
  
  #if defined(EXITFREE) || defined(PROTO)
***************
*** 2592,2598 ****
            EMSG2(_("E917: Cannot use a callback with %s()"), fun);
            return NULL;
        }
!       channel_set_req_callback(channel, part_send, opt->jo_callback, id);
      }
  
      if (channel_send(channel, part_send, text, fun) == OK
--- 2639,2646 ----
            EMSG2(_("E917: Cannot use a callback with %s()"), fun);
            return NULL;
        }
!       channel_set_req_callback(channel, part_send,
!                                      opt->jo_callback, opt->jo_partial, id);
      }
  
      if (channel_send(channel, part_send, text, fun) == OK
***************
*** 2982,2994 ****
   * Return NULL for an invalid argument.
   */
      static char_u *
! get_callback(typval_T *arg)
  {
      if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
        return arg->vval.v_string;
      if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
        return (char_u *)"";
!     EMSG(_("E999: Invalid callback argument"));
      return NULL;
  }
  
--- 3030,3048 ----
   * Return NULL for an invalid argument.
   */
      static 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;
+       return (*pp)->pt_name;
+     }
+     *pp = NULL;
      if (arg->v_type == VAR_FUNC || arg->v_type == VAR_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;
  }
  
***************
*** 3201,3207 ****
                if (!(supported & JO_CALLBACK))
                    break;
                opt->jo_set |= JO_CALLBACK;
!               opt->jo_callback = get_callback(item);
                if (opt->jo_callback == NULL)
                {
                    EMSG2(_(e_invarg2), "callback");
--- 3255,3261 ----
                if (!(supported & JO_CALLBACK))
                    break;
                opt->jo_set |= JO_CALLBACK;
!               opt->jo_callback = get_callback(item, &opt->jo_partial);
                if (opt->jo_callback == NULL)
                {
                    EMSG2(_(e_invarg2), "callback");
***************
*** 3213,3219 ****
                if (!(supported & JO_OUT_CALLBACK))
                    break;
                opt->jo_set |= JO_OUT_CALLBACK;
!               opt->jo_out_cb = get_callback(item);
                if (opt->jo_out_cb == NULL)
                {
                    EMSG2(_(e_invarg2), "out-cb");
--- 3267,3273 ----
                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)
                {
                    EMSG2(_(e_invarg2), "out-cb");
***************
*** 3225,3231 ****
                if (!(supported & JO_ERR_CALLBACK))
                    break;
                opt->jo_set |= JO_ERR_CALLBACK;
!               opt->jo_err_cb = get_callback(item);
                if (opt->jo_err_cb == NULL)
                {
                    EMSG2(_(e_invarg2), "err-cb");
--- 3279,3285 ----
                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)
                {
                    EMSG2(_(e_invarg2), "err-cb");
***************
*** 3237,3243 ****
                if (!(supported & JO_CLOSE_CALLBACK))
                    break;
                opt->jo_set |= JO_CLOSE_CALLBACK;
!               opt->jo_close_cb = get_callback(item);
                if (opt->jo_close_cb == NULL)
                {
                    EMSG2(_(e_invarg2), "close-cb");
--- 3291,3297 ----
                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)
                {
                    EMSG2(_(e_invarg2), "close-cb");
***************
*** 3311,3317 ****
                if (!(supported & JO_EXIT_CB))
                    break;
                opt->jo_set |= JO_EXIT_CB;
!               opt->jo_exit_cb = get_tv_string_buf_chk(item, opt->jo_ecb_buf);
                if (opt->jo_exit_cb == NULL)
                {
                    EMSG2(_(e_invarg2), "exit-cb");
--- 3365,3378 ----
                if (!(supported & JO_EXIT_CB))
                    break;
                opt->jo_set |= JO_EXIT_CB;
!               if (item->v_type == VAR_PARTIAL && item->vval.v_partial != NULL)
!               {
!                   opt->jo_exit_partial = item->vval.v_partial;
!                   opt->jo_exit_cb = item->vval.v_partial->pt_name;
!               }
!               else
!                   opt->jo_exit_cb = get_tv_string_buf_chk(
!                                                      item, opt->jo_ecb_buf);
                if (opt->jo_exit_cb == NULL)
                {
                    EMSG2(_(e_invarg2), "exit-cb");
***************
*** 3390,3395 ****
--- 3451,3457 ----
  
      vim_free(job->jv_stoponexit);
      vim_free(job->jv_exit_cb);
+     partial_unref(job->jv_exit_partial);
      vim_free(job);
  }
  
***************
*** 3454,3463 ****
--- 3516,3534 ----
      if (opt->jo_set & JO_EXIT_CB)
      {
        vim_free(job->jv_exit_cb);
+       partial_unref(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_cb = vim_strsave(opt->jo_exit_cb);
+           job->jv_exit_partial = opt->jo_exit_partial;
+           if (job->jv_exit_partial != NULL)
+               ++job->jv_exit_partial->pt_refcount;
+       }
      }
  }
  
***************
*** 3721,3727 ****
            argv[1].v_type = VAR_NUMBER;
            argv[1].vval.v_number = job->jv_exitval;
            call_func(job->jv_exit_cb, (int)STRLEN(job->jv_exit_cb),
!                                &rettv, 2, argv, 0L, 0L, &dummy, TRUE, NULL);
            clear_tv(&rettv);
            --job->jv_refcount;
        }
--- 3792,3799 ----
            argv[1].v_type = VAR_NUMBER;
            argv[1].vval.v_number = job->jv_exitval;
            call_func(job->jv_exit_cb, (int)STRLEN(job->jv_exit_cb),
!                          &rettv, 2, argv, 0L, 0L, &dummy, TRUE,
!                          job->jv_exit_partial, NULL);
            clear_tv(&rettv);
            --job->jv_refcount;
        }
*** ../vim-7.4.1558/src/eval.c  2016-03-13 19:04:45.381224860 +0100
--- src/eval.c  2016-03-14 22:44:48.439548238 +0100
***************
*** 452,459 ****
  static char_u *string_quote(char_u *str, int function);
  static int get_env_tv(char_u **arg, typval_T *rettv, int evaluate);
  static int find_internal_func(char_u *name);
! static char_u *deref_func_name(char_u *name, int *lenp, int no_autoload);
! static int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, 
linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, dict_T 
*selfdict);
  static void emsg_funcname(char *ermsg, char_u *name);
  static int non_zero_arg(typval_T *argvars);
  
--- 452,459 ----
  static char_u *string_quote(char_u *str, int function);
  static int get_env_tv(char_u **arg, typval_T *rettv, int evaluate);
  static int find_internal_func(char_u *name);
! static char_u *deref_func_name(char_u *name, int *lenp, partial_T **partial, 
int no_autoload);
! static int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, 
linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, partial_T 
*partial, dict_T *selfdict);
  static void emsg_funcname(char *ermsg, char_u *name);
  static int non_zero_arg(typval_T *argvars);
  
***************
*** 1675,1681 ****
      rettv->v_type = VAR_UNKNOWN;              /* clear_tv() uses this */
      ret = call_func(func, (int)STRLEN(func), rettv, argc, argvars,
                    curwin->w_cursor.lnum, curwin->w_cursor.lnum,
!                   &doesrange, TRUE, NULL);
      if (safe)
      {
        --sandbox;
--- 1675,1681 ----
      rettv->v_type = VAR_UNKNOWN;              /* clear_tv() uses this */
      ret = call_func(func, (int)STRLEN(func), rettv, argc, argvars,
                    curwin->w_cursor.lnum, curwin->w_cursor.lnum,
!                   &doesrange, TRUE, NULL, NULL);
      if (safe)
      {
        --sandbox;
***************
*** 3091,3096 ****
--- 3091,3097 ----
            case VAR_UNKNOWN:
            case VAR_DICT:
            case VAR_FUNC:
+           case VAR_PARTIAL:
            case VAR_SPECIAL:
            case VAR_JOB:
            case VAR_CHANNEL:
***************
*** 3456,3461 ****
--- 3457,3463 ----
      int               doesrange;
      int               failed = FALSE;
      funcdict_T        fudi;
+     partial_T *partial;
  
      if (eap->skip)
      {
***************
*** 3486,3492 ****
  
      /* If it is the name of a variable of type VAR_FUNC use its contents. */
      len = (int)STRLEN(tofree);
!     name = deref_func_name(tofree, &len, FALSE);
  
      /* Skip white space to allow ":call func ()".  Not good, but required for
       * backward compatibility. */
--- 3488,3494 ----
  
      /* If it is the name of a variable of type VAR_FUNC use its contents. */
      len = (int)STRLEN(tofree);
!     name = deref_func_name(tofree, &len, &partial, FALSE);
  
      /* Skip white space to allow ":call func ()".  Not good, but required for
       * backward compatibility. */
***************
*** 3525,3531 ****
        arg = startarg;
        if (get_func_tv(name, (int)STRLEN(name), &rettv, &arg,
                    eap->line1, eap->line2, &doesrange,
!                                           !eap->skip, fudi.fd_dict) == FAIL)
        {
            failed = TRUE;
            break;
--- 3527,3533 ----
        arg = startarg;
        if (get_func_tv(name, (int)STRLEN(name), &rettv, &arg,
                    eap->line1, eap->line2, &doesrange,
!                                  !eap->skip, partial, fudi.fd_dict) == FAIL)
        {
            failed = TRUE;
            break;
***************
*** 3870,3875 ****
--- 3872,3878 ----
        case VAR_NUMBER:
        case VAR_STRING:
        case VAR_FUNC:
+       case VAR_PARTIAL:
        case VAR_FLOAT:
        case VAR_SPECIAL:
        case VAR_JOB:
***************
*** 4542,4548 ****
                }
            }
  
!           else if (rettv->v_type == VAR_FUNC || var2.v_type == VAR_FUNC)
            {
                if (rettv->v_type != var2.v_type
                        || (type != TYPE_EQUAL && type != TYPE_NEQUAL))
--- 4545,4552 ----
                }
            }
  
!           else if (rettv->v_type == VAR_FUNC || var2.v_type == VAR_FUNC
!               || rettv->v_type == VAR_PARTIAL || var2.v_type == VAR_PARTIAL)
            {
                if (rettv->v_type != var2.v_type
                        || (type != TYPE_EQUAL && type != TYPE_NEQUAL))
***************
*** 4555,4560 ****
--- 4559,4570 ----
                    clear_tv(&var2);
                    return FAIL;
                }
+               else if (rettv->v_type == VAR_PARTIAL)
+               {
+                   /* Partials are only equal when identical. */
+                   n1 = rettv->vval.v_partial != NULL
+                             && rettv->vval.v_partial == var2.vval.v_partial;
+               }
                else
                {
                    /* Compare two Funcrefs for being equal or unequal. */
***************
*** 4564,4572 ****
                    else
                        n1 = STRCMP(rettv->vval.v_string,
                                                     var2.vval.v_string) == 0;
-                   if (type == TYPE_NEQUAL)
-                       n1 = !n1;
                }
            }
  
  #ifdef FEAT_FLOAT
--- 4574,4582 ----
                    else
                        n1 = STRCMP(rettv->vval.v_string,
                                                     var2.vval.v_string) == 0;
                }
+               if (type == TYPE_NEQUAL)
+                   n1 = !n1;
            }
  
  #ifdef FEAT_FLOAT
***************
*** 5230,5243 ****
        {
            if (**arg == '(')           /* recursive! */
            {
                /* If "s" is the name of a variable of type VAR_FUNC
                 * use its contents. */
!               s = deref_func_name(s, &len, !evaluate);
  
                /* Invoke the function. */
                ret = get_func_tv(s, len, rettv, arg,
                          curwin->w_cursor.lnum, curwin->w_cursor.lnum,
!                         &len, evaluate, NULL);
  
                /* If evaluate is FALSE rettv->v_type was not set in
                 * get_func_tv, but it's needed in handle_subscript() to parse
--- 5240,5255 ----
        {
            if (**arg == '(')           /* recursive! */
            {
+               partial_T *partial;
+ 
                /* If "s" is the name of a variable of type VAR_FUNC
                 * use its contents. */
!               s = deref_func_name(s, &len, &partial, !evaluate);
  
                /* Invoke the function. */
                ret = get_func_tv(s, len, rettv, arg,
                          curwin->w_cursor.lnum, curwin->w_cursor.lnum,
!                         &len, evaluate, partial, NULL);
  
                /* If evaluate is FALSE rettv->v_type was not set in
                 * get_func_tv, but it's needed in handle_subscript() to parse
***************
*** 5359,5364 ****
--- 5371,5377 ----
      switch (rettv->v_type)
      {
        case VAR_FUNC:
+       case VAR_PARTIAL:
            if (verbose)
                EMSG(_("E695: Cannot index a Funcref"));
            return FAIL;
***************
*** 5480,5485 ****
--- 5493,5499 ----
        {
            case VAR_UNKNOWN:
            case VAR_FUNC:
+           case VAR_PARTIAL:
            case VAR_FLOAT:
            case VAR_SPECIAL:
            case VAR_JOB:
***************
*** 6218,6223 ****
--- 6232,6241 ----
                    && tv2->vval.v_string != NULL
                    && STRCMP(tv1->vval.v_string, tv2->vval.v_string) == 0);
  
+       case VAR_PARTIAL:
+           return tv1->vval.v_partial != NULL
+                   && tv1->vval.v_partial == tv2->vval.v_partial;
+ 
        case VAR_NUMBER:
            return tv1->vval.v_number == tv2->vval.v_number;
  
***************
*** 7793,7798 ****
--- 7811,7822 ----
            r = tv->vval.v_string;
            break;
  
+       case VAR_PARTIAL:
+           *tofree = NULL;
+           /* TODO: arguments */
+           r = tv->vval.v_partial == NULL ? NULL : tv->vval.v_partial->pt_name;
+           break;
+ 
        case VAR_LIST:
            if (tv->vval.v_list == NULL)
            {
***************
*** 7878,7883 ****
--- 7902,7911 ----
        case VAR_FUNC:
            *tofree = string_quote(tv->vval.v_string, TRUE);
            return *tofree;
+       case VAR_PARTIAL:
+           *tofree = string_quote(tv->vval.v_partial == NULL ? NULL
+                                        : tv->vval.v_partial->pt_name, TRUE);
+           return *tofree;
        case VAR_STRING:
            *tofree = string_quote(tv->vval.v_string, FALSE);
            return *tofree;
***************
*** 8146,8152 ****
      {"foldtext",      0, 0, f_foldtext},
      {"foldtextresult",        1, 1, f_foldtextresult},
      {"foreground",    0, 0, f_foreground},
!     {"function",      1, 1, f_function},
      {"garbagecollect",        0, 1, f_garbagecollect},
      {"get",           2, 3, f_get},
      {"getbufline",    2, 3, f_getbufline},
--- 8174,8180 ----
      {"foldtext",      0, 0, f_foldtext},
      {"foldtextresult",        1, 1, f_foldtextresult},
      {"foreground",    0, 0, f_foreground},
!     {"function",      1, 3, f_function},
      {"garbagecollect",        0, 1, f_garbagecollect},
      {"get",           2, 3, f_get},
      {"getbufline",    2, 3, f_getbufline},
***************
*** 8524,8536 ****
  /*
   * Check if "name" is a variable of type VAR_FUNC.  If so, return the function
   * name it contains, otherwise return "name".
   */
      static char_u *
! deref_func_name(char_u *name, int *lenp, int no_autoload)
  {
      dictitem_T        *v;
      int               cc;
  
      cc = name[*lenp];
      name[*lenp] = NUL;
      v = find_var(name, NULL, no_autoload);
--- 8552,8567 ----
  /*
   * Check if "name" is a variable of type VAR_FUNC.  If so, return the function
   * name it contains, otherwise return "name".
+  * If "name" is of type VAR_PARTIAL also return "partial"
   */
      static char_u *
! deref_func_name(char_u *name, int *lenp, partial_T **partial, int no_autoload)
  {
      dictitem_T        *v;
      int               cc;
  
+     *partial = NULL;
+ 
      cc = name[*lenp];
      name[*lenp] = NUL;
      v = find_var(name, NULL, no_autoload);
***************
*** 8546,8551 ****
--- 8577,8594 ----
        return v->di_tv.vval.v_string;
      }
  
+     if (v != NULL && v->di_tv.v_type == VAR_PARTIAL)
+     {
+       *partial = v->di_tv.vval.v_partial;
+       if (*partial == NULL)
+       {
+           *lenp = 0;
+           return (char_u *)"";        /* just in case */
+       }
+       *lenp = (int)STRLEN((*partial)->pt_name);
+       return (*partial)->pt_name;
+     }
+ 
      return name;
  }
  
***************
*** 8563,8568 ****
--- 8606,8612 ----
      linenr_T  lastline,       /* last line of range */
      int               *doesrange,     /* return: function handled range */
      int               evaluate,
+     partial_T *partial,       /* for extra arguments */
      dict_T    *selfdict)      /* Dictionary for "self" */
  {
      char_u    *argp;
***************
*** 8574,8580 ****
       * Get the arguments.
       */
      argp = *arg;
!     while (argcount < MAX_FUNC_ARGS)
      {
        argp = skipwhite(argp + 1);         /* skip the '(' or ',' */
        if (*argp == ')' || *argp == ',' || *argp == NUL)
--- 8618,8624 ----
       * Get the arguments.
       */
      argp = *arg;
!     while (argcount < MAX_FUNC_ARGS - (partial == NULL ? 0 : 
partial->pt_argc))
      {
        argp = skipwhite(argp + 1);         /* skip the '(' or ',' */
        if (*argp == ')' || *argp == ',' || *argp == NUL)
***************
*** 8595,8601 ****
  
      if (ret == OK)
        ret = call_func(name, len, rettv, argcount, argvars,
!                         firstline, lastline, doesrange, evaluate, selfdict);
      else if (!aborting())
      {
        if (argcount == MAX_FUNC_ARGS)
--- 8639,8645 ----
  
      if (ret == OK)
        ret = call_func(name, len, rettv, argcount, argvars,
!                firstline, lastline, doesrange, evaluate, partial, selfdict);
      else if (!aborting())
      {
        if (argcount == MAX_FUNC_ARGS)
***************
*** 8622,8635 ****
      char_u    *funcname,      /* name of the function */
      int               len,            /* length of "name" */
      typval_T  *rettv,         /* return value goes here */
!     int               argcount,       /* number of "argvars" */
!     typval_T  *argvars,       /* vars for arguments, must have "argcount"
                                   PLUS ONE elements! */
      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" */
  {
      int               ret = FAIL;
  #define ERROR_UNKNOWN 0
--- 8666,8680 ----
      char_u    *funcname,      /* name of the function */
      int               len,            /* length of "name" */
      typval_T  *rettv,         /* return value goes here */
!     int               argcount_in,    /* number of "argvars" */
!     typval_T  *argvars_in,    /* vars for arguments, must have "argcount"
                                   PLUS ONE elements! */
      linenr_T  firstline,      /* first line of range */
      linenr_T  lastline,       /* last line of range */
      int               *doesrange,     /* return: function handled range */
      int               evaluate,
!     partial_T *partial,       /* optional, can be NULL */
!     dict_T    *selfdict_in)   /* Dictionary for "self" */
  {
      int               ret = FAIL;
  #define ERROR_UNKNOWN 0
***************
*** 8639,8644 ****
--- 8684,8690 ----
  #define ERROR_DICT    4
  #define ERROR_NONE    5
  #define ERROR_OTHER   6
+ #define ERROR_BOTH    7
      int               error = ERROR_NONE;
      int               i;
      int               llen;
***************
*** 8647,8652 ****
--- 8693,8703 ----
      char_u    fname_buf[FLEN_FIXED + 1];
      char_u    *fname;
      char_u    *name;
+     int               argcount = argcount_in;
+     typval_T  *argvars = argvars_in;
+     dict_T    *selfdict = selfdict_in;
+     typval_T  argv[MAX_FUNC_ARGS + 1]; /* used when "partial" is not NULL */
+     int               argv_clear = 0;
  
      /* Make a copy of the name, if it comes from a funcref variable it could
       * be changed or deleted in the called function. */
***************
*** 8698,8703 ****
--- 8749,8775 ----
  
      *doesrange = FALSE;
  
+     if (partial != NULL)
+     {
+       if (partial->pt_dict != NULL)
+       {
+           if (selfdict_in != NULL)
+               error = ERROR_BOTH;
+           selfdict = partial->pt_dict;
+       }
+       if (error == ERROR_NONE && partial->pt_argc > 0)
+       {
+           int     i;
+ 
+           for (argv_clear = 0; argv_clear < partial->pt_argc; ++argv_clear)
+               copy_tv(&partial->pt_argv[argv_clear], &argv[argv_clear]);
+           for (i = 0; i < argcount_in; ++i)
+               argv[i + argv_clear] = argvars_in[i];
+           argvars = argv;
+           argcount = partial->pt_argc + argcount_in;
+       }
+     }
+ 
  
      /* execute the function if no errors detected and executing */
      if (evaluate && error == ERROR_NONE)
***************
*** 8841,8849 ****
--- 8913,8927 ----
                    emsg_funcname(N_("E725: Calling dict function without 
Dictionary: %s"),
                                                                        name);
                    break;
+           case ERROR_BOTH:
+                   emsg_funcname(N_("E924: can't have both a \"self\" dict and 
a partial: %s"),
+                                                                       name);
+                   break;
        }
      }
  
+     while (argv_clear > 0)
+       clear_tv(&argv[--argv_clear]);
      if (fname != name && fname != fname_buf)
        vim_free(fname);
      vim_free(name);
***************
*** 9737,9742 ****
--- 9815,9821 ----
  func_call(
      char_u    *name,
      typval_T  *args,
+     partial_T *partial,
      dict_T    *selfdict,
      typval_T  *rettv)
  {
***************
*** 9749,9755 ****
      for (item = args->vval.v_list->lv_first; item != NULL;
                                                         item = item->li_next)
      {
!       if (argc == MAX_FUNC_ARGS)
        {
            EMSG(_("E699: Too many arguments"));
            break;
--- 9828,9834 ----
      for (item = args->vval.v_list->lv_first; item != NULL;
                                                         item = item->li_next)
      {
!       if (argc == MAX_FUNC_ARGS - (partial == NULL ? 0 : partial->pt_argc))
        {
            EMSG(_("E699: Too many arguments"));
            break;
***************
*** 9763,9769 ****
      if (item == NULL)
        r = call_func(name, (int)STRLEN(name), rettv, argc, argv,
                                 curwin->w_cursor.lnum, curwin->w_cursor.lnum,
!                                                     &dummy, TRUE, selfdict);
  
      /* Free the arguments. */
      while (argc > 0)
--- 9842,9848 ----
      if (item == NULL)
        r = call_func(name, (int)STRLEN(name), rettv, argc, argv,
                                 curwin->w_cursor.lnum, curwin->w_cursor.lnum,
!                                            &dummy, TRUE, partial, selfdict);
  
      /* Free the arguments. */
      while (argc > 0)
***************
*** 9773,9784 ****
  }
  
  /*
!  * "call(func, arglist)" function
   */
      static void
  f_call(typval_T *argvars, typval_T *rettv)
  {
      char_u    *func;
      dict_T    *selfdict = NULL;
  
      if (argvars[1].v_type != VAR_LIST)
--- 9852,9864 ----
  }
  
  /*
!  * "call(func, arglist [, dict])" function
   */
      static void
  f_call(typval_T *argvars, typval_T *rettv)
  {
      char_u    *func;
+     partial_T   *partial = NULL;
      dict_T    *selfdict = NULL;
  
      if (argvars[1].v_type != VAR_LIST)
***************
*** 9791,9796 ****
--- 9871,9881 ----
  
      if (argvars[0].v_type == VAR_FUNC)
        func = argvars[0].vval.v_string;
+     else if (argvars[0].v_type == VAR_PARTIAL)
+     {
+       partial = argvars[0].vval.v_partial;
+       func = partial->pt_name;
+     }
      else
        func = get_tv_string(&argvars[0]);
      if (*func == NUL)
***************
*** 9806,9812 ****
        selfdict = argvars[2].vval.v_dict;
      }
  
!     (void)func_call(func, &argvars[1], selfdict, rettv);
  }
  
  #ifdef FEAT_FLOAT
--- 9891,9897 ----
        selfdict = argvars[2].vval.v_dict;
      }
  
!     (void)func_call(func, &argvars[1], partial, selfdict, rettv);
  }
  
  #ifdef FEAT_FLOAT
***************
*** 10627,10632 ****
--- 10712,10720 ----
            n = argvars[0].vval.v_string == NULL
                                          || *argvars[0].vval.v_string == NUL;
            break;
+       case VAR_PARTIAL:
+           n = FALSE;
+           break;
        case VAR_NUMBER:
            n = argvars[0].vval.v_number == 0;
            break;
***************
*** 11688,11693 ****
--- 11776,11782 ----
  f_function(typval_T *argvars, typval_T *rettv)
  {
      char_u    *s;
+     char_u    *name;
  
      s = get_tv_string(&argvars[0]);
      if (s == NULL || *s == NUL || VIM_ISDIGIT(*s))
***************
*** 11707,11726 ****
             * would also work, but some plugins depend on the name being
             * printable text. */
            sprintf(sid_buf, "<SNR>%ld_", (long)current_SID);
!           rettv->vval.v_string =
!                           alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
!           if (rettv->vval.v_string != NULL)
            {
!               STRCPY(rettv->vval.v_string, sid_buf);
!               STRCAT(rettv->vval.v_string, s + off);
            }
        }
        else
!           rettv->vval.v_string = vim_strsave(s);
!       rettv->v_type = VAR_FUNC;
      }
  }
  
  /*
   * "garbagecollect()" function
   */
--- 11796,11915 ----
             * would also work, but some plugins depend on the name being
             * printable text. */
            sprintf(sid_buf, "<SNR>%ld_", (long)current_SID);
!           name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
!           if (name != NULL)
!           {
!               STRCPY(name, sid_buf);
!               STRCAT(name, s + off);
!           }
!       }
!       else
!           name = vim_strsave(s);
! 
!       if (argvars[1].v_type != VAR_UNKNOWN)
!       {
!           partial_T   *pt;
!           int         dict_idx = 0;
!           int         arg_idx = 0;
! 
!           if (argvars[2].v_type != VAR_UNKNOWN)
!           {
!               /* function(name, [args], dict) */
!               arg_idx = 1;
!               dict_idx = 2;
!           }
!           else if (argvars[1].v_type == VAR_DICT)
!               /* function(name, dict) */
!               dict_idx = 1;
!           else
!               /* function(name, [args]) */
!               arg_idx = 1;
!           if (dict_idx > 0 && (argvars[dict_idx].v_type != VAR_DICT
!                                    || argvars[dict_idx].vval.v_dict == NULL))
!           {
!               EMSG(_("E922: expected a dict"));
!               vim_free(name);
!               return;
!           }
!           if (arg_idx > 0 && (argvars[arg_idx].v_type != VAR_LIST
!                                    || argvars[arg_idx].vval.v_list == NULL))
            {
!               EMSG(_("E923: Second argument of function() must be a list or a 
dict"));
!               vim_free(name);
!               return;
            }
+ 
+           pt = (partial_T *)alloc_clear(sizeof(partial_T));
+           if (pt != NULL)
+           {
+               if (arg_idx > 0)
+               {
+                   list_T      *list = argvars[arg_idx].vval.v_list;
+                   listitem_T  *li;
+                   int         i = 0;
+ 
+                   pt->pt_argv = (typval_T *)alloc(
+                                            sizeof(typval_T) * list->lv_len);
+                   if (pt->pt_argv == NULL)
+                   {
+                       vim_free(pt);
+                       vim_free(name);
+                       return;
+                   }
+                   else
+                   {
+                       pt->pt_argc = list->lv_len;
+                       for (li = list->lv_first; li != NULL; li = li->li_next)
+                           copy_tv(&li->li_tv, &pt->pt_argv[i++]);
+                   }
+               }
+ 
+               if (dict_idx > 0)
+               {
+                   pt->pt_dict = argvars[dict_idx].vval.v_dict;
+                   ++pt->pt_dict->dv_refcount;
+               }
+ 
+               pt->pt_refcount = 1;
+               pt->pt_name = name;
+               func_ref(pt->pt_name);
+           }
+           rettv->v_type = VAR_PARTIAL;
+           rettv->vval.v_partial = pt;
        }
        else
!       {
!           rettv->v_type = VAR_FUNC;
!           rettv->vval.v_string = name;
!           func_ref(name);
!       }
      }
  }
  
+     static void
+ partial_free(partial_T *pt)
+ {
+     int i;
+ 
+     for (i = 0; i < pt->pt_argc; ++i)
+       clear_tv(&pt->pt_argv[i]);
+     vim_free(pt->pt_argv);
+     func_unref(pt->pt_name);
+     vim_free(pt->pt_name);
+     vim_free(pt);
+ }
+ 
+ /*
+  * Unreference a closure: decrement the reference count and free it when it
+  * becomes zero.
+  */
+     void
+ partial_unref(partial_T *pt)
+ {
+     if (pt != NULL && --pt->pt_refcount <= 0)
+       partial_free(pt);
+ }
+ 
  /*
   * "garbagecollect()" function
   */
***************
*** 14598,14603 ****
--- 14787,14793 ----
        case VAR_SPECIAL:
        case VAR_FLOAT:
        case VAR_FUNC:
+       case VAR_PARTIAL:
        case VAR_JOB:
        case VAR_CHANNEL:
            EMSG(_("E701: Invalid type for len()"));
***************
*** 18169,18174 ****
--- 18359,18365 ----
      int               item_compare_float;
  #endif
      char_u    *item_compare_func;
+     partial_T *item_compare_partial;
      dict_T    *item_compare_selfdict;
      int               item_compare_func_err;
      int               item_compare_keep_zero;
***************
*** 18278,18283 ****
--- 18469,18476 ----
      typval_T  rettv;
      typval_T  argv[3];
      int               dummy;
+     char_u    *func_name;
+     partial_T *partial = sortinfo->item_compare_partial;
  
      /* shortcut after failure in previous call; compare all items equal */
      if (sortinfo->item_compare_func_err)
***************
*** 18286,18301 ****
      si1 = (sortItem_T *)s1;
      si2 = (sortItem_T *)s2;
  
      /* Copy the values.  This is needed to be able to set v_lock to VAR_FIXED
       * in the copy without changing the original list items. */
      copy_tv(&si1->item->li_tv, &argv[0]);
      copy_tv(&si2->item->li_tv, &argv[1]);
  
      rettv.v_type = VAR_UNKNOWN;               /* clear_tv() uses this */
!     res = call_func(sortinfo->item_compare_func,
!                                (int)STRLEN(sortinfo->item_compare_func),
                                 &rettv, 2, argv, 0L, 0L, &dummy, TRUE,
!                                sortinfo->item_compare_selfdict);
      clear_tv(&argv[0]);
      clear_tv(&argv[1]);
  
--- 18479,18498 ----
      si1 = (sortItem_T *)s1;
      si2 = (sortItem_T *)s2;
  
+     if (partial == NULL)
+       func_name = sortinfo->item_compare_func;
+     else
+       func_name = partial->pt_name;
+ 
      /* Copy the values.  This is needed to be able to set v_lock to VAR_FIXED
       * in the copy without changing the original list items. */
      copy_tv(&si1->item->li_tv, &argv[0]);
      copy_tv(&si2->item->li_tv, &argv[1]);
  
      rettv.v_type = VAR_UNKNOWN;               /* clear_tv() uses this */
!     res = call_func(func_name, (int)STRLEN(func_name),
                                 &rettv, 2, argv, 0L, 0L, &dummy, TRUE,
!                                partial, sortinfo->item_compare_selfdict);
      clear_tv(&argv[0]);
      clear_tv(&argv[1]);
  
***************
*** 18358,18369 ****
--- 18555,18569 ----
        info.item_compare_float = FALSE;
  #endif
        info.item_compare_func = NULL;
+       info.item_compare_partial = NULL;
        info.item_compare_selfdict = NULL;
        if (argvars[1].v_type != VAR_UNKNOWN)
        {
            /* optional second argument: {func} */
            if (argvars[1].v_type == VAR_FUNC)
                info.item_compare_func = argvars[1].vval.v_string;
+           else if (argvars[1].v_type == VAR_PARTIAL)
+               info.item_compare_partial = argvars[1].vval.v_partial;
            else
            {
                int         error = FALSE;
***************
*** 18443,18449 ****
            info.item_compare_func_err = FALSE;
            info.item_compare_keep_zero = FALSE;
            /* test the compare function */
!           if (info.item_compare_func != NULL
                    && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
                                                         == ITEM_COMPARE_FAIL)
                EMSG(_("E702: Sort compare function failed"));
--- 18643,18650 ----
            info.item_compare_func_err = FALSE;
            info.item_compare_keep_zero = FALSE;
            /* test the compare function */
!           if ((info.item_compare_func != NULL
!                                        || info.item_compare_partial != NULL)
                    && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
                                                         == ITEM_COMPARE_FAIL)
                EMSG(_("E702: Sort compare function failed"));
***************
*** 18452,18457 ****
--- 18653,18659 ----
                /* Sort the array with item pointers. */
                qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
                    info.item_compare_func == NULL
+                                         && info.item_compare_partial == NULL
                                               ? item_compare : item_compare2);
  
                if (!info.item_compare_func_err)
***************
*** 18471,18477 ****
            /* f_uniq(): ptrs will be a stack of items to remove */
            info.item_compare_func_err = FALSE;
            info.item_compare_keep_zero = TRUE;
!           item_compare_func_ptr = info.item_compare_func
                                               ? item_compare2 : item_compare;
  
            for (li = l->lv_first; li != NULL && li->li_next != NULL;
--- 18673,18680 ----
            /* f_uniq(): ptrs will be a stack of items to remove */
            info.item_compare_func_err = FALSE;
            info.item_compare_keep_zero = TRUE;
!           item_compare_func_ptr = info.item_compare_func != NULL
!                                         || info.item_compare_partial != NULL
                                               ? item_compare2 : item_compare;
  
            for (li = l->lv_first; li != NULL && li->li_next != NULL;
***************
*** 20045,20050 ****
--- 20248,20254 ----
             break;
        case VAR_JOB:     n = 8; break;
        case VAR_CHANNEL: n = 9; break;
+       case VAR_PARTIAL: n = 10; break;
        case VAR_UNKNOWN:
             EMSG2(_(e_intern2), "f_type(UNKNOWN)");
             n = -1;
***************
*** 21295,21305 ****
      char_u    *s;
      int               len;
      typval_T  functv;
  
      while (ret == OK
            && (**arg == '['
                || (**arg == '.' && rettv->v_type == VAR_DICT)
!               || (**arg == '(' && (!evaluate || rettv->v_type == VAR_FUNC)))
            && !vim_iswhite(*(*arg - 1)))
      {
        if (**arg == '(')
--- 21499,21511 ----
      char_u    *s;
      int               len;
      typval_T  functv;
+     partial_T *pt = NULL;
  
      while (ret == OK
            && (**arg == '['
                || (**arg == '.' && rettv->v_type == VAR_DICT)
!               || (**arg == '(' && (!evaluate || rettv->v_type == VAR_FUNC
!                                           || rettv->v_type == VAR_PARTIAL)))
            && !vim_iswhite(*(*arg - 1)))
      {
        if (**arg == '(')
***************
*** 21311,21323 ****
                rettv->v_type = VAR_UNKNOWN;
  
                /* Invoke the function.  Recursive! */
!               s = functv.vval.v_string;
            }
            else
                s = (char_u *)"";
            ret = get_func_tv(s, (int)STRLEN(s), rettv, arg,
                        curwin->w_cursor.lnum, curwin->w_cursor.lnum,
!                       &len, evaluate, selfdict);
  
            /* Clear the funcref afterwards, so that deleting it while
             * evaluating the arguments is possible (see test55). */
--- 21517,21535 ----
                rettv->v_type = VAR_UNKNOWN;
  
                /* Invoke the function.  Recursive! */
!               if (rettv->v_type == VAR_PARTIAL)
!               {
!                   pt = functv.vval.v_partial;
!                   s = pt->pt_name;
!               }
!               else
!                   s = functv.vval.v_string;
            }
            else
                s = (char_u *)"";
            ret = get_func_tv(s, (int)STRLEN(s), rettv, arg,
                        curwin->w_cursor.lnum, curwin->w_cursor.lnum,
!                       &len, evaluate, pt, selfdict);
  
            /* Clear the funcref afterwards, so that deleting it while
             * evaluating the arguments is possible (see test55). */
***************
*** 21405,21410 ****
--- 21617,21625 ----
            case VAR_STRING:
                vim_free(varp->vval.v_string);
                break;
+           case VAR_PARTIAL:
+               partial_unref(varp->vval.v_partial);
+               break;
            case VAR_LIST:
                list_unref(varp->vval.v_list);
                break;
***************
*** 21448,21453 ****
--- 21663,21672 ----
                vim_free(varp->vval.v_string);
                varp->vval.v_string = NULL;
                break;
+           case VAR_PARTIAL:
+               partial_unref(varp->vval.v_partial);
+               varp->vval.v_partial = NULL;
+               break;
            case VAR_LIST:
                list_unref(varp->vval.v_list);
                varp->vval.v_list = NULL;
***************
*** 21524,21529 ****
--- 21743,21749 ----
            break;
  #endif
        case VAR_FUNC:
+       case VAR_PARTIAL:
            EMSG(_("E703: Using a Funcref as a Number"));
            break;
        case VAR_STRING:
***************
*** 21572,21577 ****
--- 21792,21798 ----
        case VAR_FLOAT:
            return varp->vval.v_float;
        case VAR_FUNC:
+       case VAR_PARTIAL:
            EMSG(_("E891: Using a Funcref as a Float"));
            break;
        case VAR_STRING:
***************
*** 21688,21693 ****
--- 21909,21915 ----
            sprintf((char *)buf, "%ld", (long)varp->vval.v_number);
            return buf;
        case VAR_FUNC:
+       case VAR_PARTIAL:
            EMSG(_("E729: using Funcref as a String"));
            break;
        case VAR_LIST:
***************
*** 22087,22093 ****
      msg_advance(22);
      if (type == VAR_NUMBER)
        msg_putchar('#');
!     else if (type == VAR_FUNC)
        msg_putchar('*');
      else if (type == VAR_LIST)
      {
--- 22309,22315 ----
      msg_advance(22);
      if (type == VAR_NUMBER)
        msg_putchar('#');
!     else if (type == VAR_FUNC || type == VAR_PARTIAL)
        msg_putchar('*');
      else if (type == VAR_LIST)
      {
***************
*** 22106,22112 ****
  
      msg_outtrans(string);
  
!     if (type == VAR_FUNC)
        msg_puts((char_u *)"()");
      if (*first)
      {
--- 22328,22334 ----
  
      msg_outtrans(string);
  
!     if (type == VAR_FUNC || type == VAR_PARTIAL)
        msg_puts((char_u *)"()");
      if (*first)
      {
***************
*** 22138,22144 ****
      }
      v = find_var_in_ht(ht, 0, varname, TRUE);
  
!     if (tv->v_type == VAR_FUNC && var_check_func_name(name, v == NULL))
        return;
  
      if (v != NULL)
--- 22360,22367 ----
      }
      v = find_var_in_ht(ht, 0, varname, TRUE);
  
!     if ((tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL)
!                                     && var_check_func_name(name, v == NULL))
        return;
  
      if (v != NULL)
***************
*** 22383,22388 ****
--- 22606,22620 ----
                    func_ref(to->vval.v_string);
            }
            break;
+       case VAR_PARTIAL:
+           if (from->vval.v_partial == NULL)
+               to->vval.v_partial = NULL;
+           else
+           {
+               to->vval.v_partial = from->vval.v_partial;
+               ++to->vval.v_partial->pt_refcount;
+           }
+           break;
        case VAR_LIST:
            if (from->vval.v_list == NULL)
                to->vval.v_list = NULL;
***************
*** 22437,22442 ****
--- 22669,22675 ----
        case VAR_FLOAT:
        case VAR_STRING:
        case VAR_FUNC:
+       case VAR_PARTIAL:
        case VAR_SPECIAL:
        case VAR_JOB:
        case VAR_CHANNEL:
***************
*** 23415,23420 ****
--- 23648,23654 ----
      char_u    sid_buf[20];
      int               len;
      lval_T    lv;
+     partial_T *partial;
  
      if (fdp != NULL)
        vim_memset(fdp, 0, sizeof(funcdict_T));
***************
*** 23499,23512 ****
      if (lv.ll_exp_name != NULL)
      {
        len = (int)STRLEN(lv.ll_exp_name);
!       name = deref_func_name(lv.ll_exp_name, &len, flags & TFN_NO_AUTOLOAD);
        if (name == lv.ll_exp_name)
            name = NULL;
      }
      else
      {
        len = (int)(end - *pp);
!       name = deref_func_name(*pp, &len, flags & TFN_NO_AUTOLOAD);
        if (name == *pp)
            name = NULL;
      }
--- 23733,23747 ----
      if (lv.ll_exp_name != NULL)
      {
        len = (int)STRLEN(lv.ll_exp_name);
!       name = deref_func_name(lv.ll_exp_name, &len, &partial,
!                                                    flags & TFN_NO_AUTOLOAD);
        if (name == lv.ll_exp_name)
            name = NULL;
      }
      else
      {
        len = (int)(end - *pp);
!       name = deref_func_name(*pp, &len, &partial, flags & TFN_NO_AUTOLOAD);
        if (name == *pp)
            name = NULL;
      }
***************
*** 25111,25116 ****
--- 25346,25352 ----
  
                    case VAR_UNKNOWN:
                    case VAR_FUNC:
+                   case VAR_PARTIAL:
                    case VAR_JOB:
                    case VAR_CHANNEL:
                                     continue;
*** ../vim-7.4.1558/src/if_python.c     2016-02-16 15:06:54.661635316 +0100
--- src/if_python.c     2016-03-13 21:58:43.707962531 +0100
***************
*** 1561,1566 ****
--- 1561,1567 ----
        case VAR_DICT: ++rettv->vval.v_dict->dv_refcount; break;
        case VAR_LIST: ++rettv->vval.v_list->lv_refcount; break;
        case VAR_FUNC: func_ref(rettv->vval.v_string);    break;
+       case VAR_PARTIAL: ++rettv->vval.v_partial->pt_refcount; break;
        case VAR_UNKNOWN:
            rettv->v_type = VAR_NUMBER;
            rettv->vval.v_number = 0;
*** ../vim-7.4.1558/src/if_python3.c    2016-02-16 15:06:54.661635316 +0100
--- src/if_python3.c    2016-03-13 21:59:10.571680867 +0100
***************
*** 1654,1659 ****
--- 1654,1660 ----
        case VAR_DICT: ++rettv->vval.v_dict->dv_refcount; break;
        case VAR_LIST: ++rettv->vval.v_list->lv_refcount; break;
        case VAR_FUNC: func_ref(rettv->vval.v_string);    break;
+       case VAR_PARTIAL: ++rettv->vval.v_partial->pt_refcount; break;
        case VAR_UNKNOWN:
            rettv->v_type = VAR_NUMBER;
            rettv->vval.v_number = 0;
*** ../vim-7.4.1558/src/if_py_both.h    2016-03-12 22:11:34.243300238 +0100
--- src/if_py_both.h    2016-03-14 21:13:05.965595807 +0100
***************
*** 2944,2950 ****
      Python_Lock_Vim();
  
      VimTryStart();
!     error = func_call(name, &args, selfdict, &rettv);
  
      Python_Release_Vim();
      Py_END_ALLOW_THREADS
--- 2944,2950 ----
      Python_Lock_Vim();
  
      VimTryStart();
!     error = func_call(name, &args, NULL, selfdict, &rettv);
  
      Python_Release_Vim();
      Py_END_ALLOW_THREADS
*** ../vim-7.4.1558/src/json.c  2016-03-05 23:22:57.781396509 +0100
--- src/json.c  2016-03-13 21:59:47.967288790 +0100
***************
*** 212,217 ****
--- 212,218 ----
            break;
  
        case VAR_FUNC:
+       case VAR_PARTIAL:
        case VAR_JOB:
        case VAR_CHANNEL:
            /* no JSON equivalent TODO: better error */
*** ../vim-7.4.1558/src/proto/eval.pro  2016-03-13 18:06:59.528803729 +0100
--- src/proto/eval.pro  2016-03-14 22:44:54.475484846 +0100
***************
*** 83,92 ****
  int string2float(char_u *text, float_T *value);
  char_u *get_function_name(expand_T *xp, int idx);
  char_u *get_expr_name(expand_T *xp, int idx);
! int call_func(char_u *funcname, int len, typval_T *rettv, int argcount, 
typval_T *argvars, linenr_T firstline, linenr_T lastline, int *doesrange, int 
evaluate, dict_T *selfdict);
  buf_T *buflist_find_by_name(char_u *name, int curtab_only);
! int func_call(char_u *name, typval_T *args, dict_T *selfdict, typval_T 
*rettv);
  void dict_extend(dict_T *d1, dict_T *d2, char_u *action);
  void mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv);
  float_T vim_round(float_T f);
  long do_searchpair(char_u *spat, char_u *mpat, char_u *epat, int dir, char_u 
*skip, int flags, pos_T *match_pos, linenr_T lnum_stop, long time_limit);
--- 83,93 ----
  int string2float(char_u *text, float_T *value);
  char_u *get_function_name(expand_T *xp, int idx);
  char_u *get_expr_name(expand_T *xp, int idx);
! int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, 
typval_T *argvars_in, linenr_T firstline, linenr_T lastline, int *doesrange, 
int evaluate, partial_T *partial, dict_T *selfdict_in);
  buf_T *buflist_find_by_name(char_u *name, int curtab_only);
! int func_call(char_u *name, typval_T *args, partial_T *partial, dict_T 
*selfdict, typval_T *rettv);
  void dict_extend(dict_T *d1, dict_T *d2, char_u *action);
+ void partial_unref(partial_T *pt);
  void mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv);
  float_T vim_round(float_T f);
  long do_searchpair(char_u *spat, char_u *mpat, char_u *epat, int dir, char_u 
*skip, int flags, pos_T *match_pos, linenr_T lnum_stop, long time_limit);
*** ../vim-7.4.1558/src/testdir/test_partial.vim        2016-03-14 
23:01:21.345113210 +0100
--- src/testdir/test_partial.vim        2016-03-14 22:59:27.918305643 +0100
***************
*** 0 ****
--- 1,43 ----
+ " Test binding arguments to a Funcref.
+ 
+ func MyFunc(arg1, arg2, arg3)
+   return a:arg1 . '/' . a:arg2 . '/' . a:arg3
+ endfunc
+ 
+ func MySort(up, one, two)
+   if a:one == a:two
+     return 0
+   endif
+   if a:up
+     return a:one > a:two
+   endif
+   return a:one < a:two
+ endfunc
+ 
+ func Test_partial_args()
+   let Cb = function('MyFunc', ["foo", "bar"])
+   call assert_equal("foo/bar/xxx", Cb("xxx"))
+   call assert_equal("foo/bar/yyy", call(Cb, ["yyy"]))
+ 
+   let Sort = function('MySort', [1])
+   call assert_equal([1, 2, 3], sort([3, 1, 2], Sort))
+   let Sort = function('MySort', [0])
+   call assert_equal([3, 2, 1], sort([3, 1, 2], Sort))
+ endfunc
+ 
+ func MyDictFunc(arg1, arg2) dict
+   return self.name . '/' . a:arg1 . '/' . a:arg2
+ endfunc
+ 
+ func Test_partial_dict()
+   let dict = {'name': 'hello'}
+   let Cb = function('MyDictFunc', ["foo", "bar"], dict)
+   call assert_equal("hello/foo/bar", Cb())
+   call assert_fails('Cb("xxx")', 'E492:')
+   let Cb = function('MyDictFunc', ["foo"], dict)
+   call assert_equal("hello/foo/xxx", Cb("xxx"))
+   call assert_fails('Cb()', 'E492:')
+   let Cb = function('MyDictFunc', dict)
+   call assert_equal("hello/xxx/yyy", Cb("xxx", "yyy"))
+   call assert_fails('Cb()', 'E492:')
+ endfunc
*** ../vim-7.4.1558/src/testdir/test_alot.vim   2016-03-12 19:22:43.781293285 
+0100
--- src/testdir/test_alot.vim   2016-03-13 22:05:31.331689410 +0100
***************
*** 12,17 ****
--- 12,18 ----
  source test_join.vim
  source test_lispwords.vim
  source test_menu.vim
+ source test_partial.vim
  source test_reltime.vim
  source test_searchpos.vim
  source test_set.vim
*** ../vim-7.4.1558/runtime/doc/eval.txt        2016-03-13 19:04:45.381224860 
+0100
--- runtime/doc/eval.txt        2016-03-14 23:03:33.367725396 +0100
***************
*** 1876,1885 ****
  foldclosed( {lnum})           Number  first line of fold at {lnum} if closed
  foldclosedend( {lnum})                Number  last line of fold at {lnum} if 
closed
  foldlevel( {lnum})            Number  fold level at {lnum}
! foldtext( )                   String  line displayed for closed fold
  foldtextresult( {lnum})               String  text for closed fold at {lnum}
! foreground( )                 Number  bring the Vim window to the foreground
! function( {name})             Funcref reference to function {name}
  garbagecollect( [{atexit}])   none    free memory, breaking cyclic references
  get( {list}, {idx} [, {def}]) any     get item {idx} from {list} or {def}
  get( {dict}, {key} [, {def}]) any     get item {key} from {dict} or {def}
--- 1892,1902 ----
  foldclosed( {lnum})           Number  first line of fold at {lnum} if closed
  foldclosedend( {lnum})                Number  last line of fold at {lnum} if 
closed
  foldlevel( {lnum})            Number  fold level at {lnum}
! foldtext()                    String  line displayed for closed fold
  foldtextresult( {lnum})               String  text for closed fold at {lnum}
! foreground()                  Number  bring the Vim window to the foreground
! function({name} [, {arglist}] [, {dict}])
!                               Funcref reference to function {name}
  garbagecollect( [{atexit}])   none    free memory, breaking cyclic references
  get( {list}, {idx} [, {def}]) any     get item {idx} from {list} or {def}
  get( {dict}, {key} [, {def}]) any     get item {key} from {dict} or {def}
***************
*** 3521,3530 ****
                Win32 console version}
  
  
! function({name})                                      *function()* *E700*
                Return a |Funcref| variable that refers to function {name}.
                {name} can be a user defined function or an internal function.
  
  
  garbagecollect([{atexit}])                            *garbagecollect()*
                Cleanup unused |Lists| and |Dictionaries| that have circular
--- 3569,3614 ----
                Win32 console version}
  
  
!                                       *function()* *E700* *E922* *E923*
! function({name} [, {arglist}] [, {dict}])
                Return a |Funcref| variable that refers to function {name}.
                {name} can be a user defined function or an internal function.
  
+               When {arglist} or {dict} is present this creates a partial.
+               That mans the argument list and/or the dictionary is stored in
+               the Funcref and will be used when the Funcref is called.
+               
+               The arguments are passed to the function in front of other
+               arguments.  Example: >
+                       func Callback(arg1, arg2, name)
+                       ...
+                       let Func = function('Callback', ['one', 'two'])
+                       ...
+                       call Func('name')
+ <             Invokes the function as with: >
+                       call Callback('one', 'two', 'name')
+ 
+ <             The Dictionary is only useful when calling a "dict" function.
+               In that case the {dict} is passed in as "self". Example: >
+                       function Callback() dict
+                          echo "called for " . self.name
+                       endfunction
+                       ...
+                       let context = {"name": "example"}
+                       let Func = function('Callback', context)
+                       ...
+                       call Func()     " will echo: called for example
+ 
+ <             The argument list and the Dictionary can be combined: >
+                       function Callback(arg1, count) dict
+                       ...
+                       let context = {"name": "example"}
+                       let Func = function('Callback', ['one'], context)
+                       ...
+                       call Func(500)
+ <             Invokes the function as with: >
+                       call context.Callback('one', 500)
+ 
  
  garbagecollect([{atexit}])                            *garbagecollect()*
                Cleanup unused |Lists| and |Dictionaries| that have circular
*** ../vim-7.4.1558/src/version.c       2016-03-13 19:04:45.385224819 +0100
--- src/version.c       2016-03-14 23:00:45.813486736 +0100
***************
*** 745,746 ****
--- 745,748 ----
  {   /* Add new patch number below this line */
+ /**/
+     1559,
  /**/

-- 
The users that I support would double-click on a landmine to find out
what happens.                           -- A system administrator

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui