]> granicus.if.org Git - vim/commitdiff
patch 7.4.2072 v7.4.2072
authorBram Moolenaar <Bram@vim.org>
Tue, 19 Jul 2016 17:10:51 +0000 (19:10 +0200)
committerBram Moolenaar <Bram@vim.org>
Tue, 19 Jul 2016 17:10:51 +0000 (19:10 +0200)
Problem:    substitute() does not support a Funcref argument.
Solution:   Support a Funcref like it supports  a string starting with "\=".

src/eval.c
src/evalfunc.c
src/proto/eval.pro
src/proto/regexp.pro
src/regexp.c
src/testdir/test_expr.vim
src/version.c

index ee24d7557fc1b9fc13c96e9a283213500633a5e4..2ba90f94d6ca7e9aa6b771a550ad80450ac49fcb 100644 (file)
@@ -9769,7 +9769,7 @@ repeat:
                        if (sub != NULL && str != NULL)
                        {
                            *usedlen = (int)(p + 1 - src);
-                           s = do_string_sub(str, pat, sub, flags);
+                           s = do_string_sub(str, pat, sub, NULL, flags);
                            if (s != NULL)
                            {
                                *fnamep = s;
@@ -9813,6 +9813,7 @@ repeat:
 
 /*
  * Perform a substitution on "str" with pattern "pat" and substitute "sub".
+ * When "sub" is NULL "expr" is used, must be a VAR_FUNC or VAR_PARTIAL.
  * "flags" can be "g" to do a global substitute.
  * Returns an allocated string, NULL for error.
  */
@@ -9821,6 +9822,7 @@ do_string_sub(
     char_u     *str,
     char_u     *pat,
     char_u     *sub,
+    typval_T   *expr,
     char_u     *flags)
 {
     int                sublen;
@@ -9873,7 +9875,7 @@ do_string_sub(
             * - The substituted text.
             * - The text after the match.
             */
-           sublen = vim_regsub(&regmatch, sub, tail, FALSE, TRUE, FALSE);
+           sublen = vim_regsub(&regmatch, sub, expr, tail, FALSE, TRUE, FALSE);
            if (ga_grow(&ga, (int)((end - tail) + sublen -
                            (regmatch.endp[0] - regmatch.startp[0]))) == FAIL)
            {
@@ -9885,7 +9887,7 @@ do_string_sub(
            i = (int)(regmatch.startp[0] - tail);
            mch_memmove((char_u *)ga.ga_data + ga.ga_len, tail, (size_t)i);
            /* add the substituted text */
-           (void)vim_regsub(&regmatch, sub, (char_u *)ga.ga_data
+           (void)vim_regsub(&regmatch, sub, expr, (char_u *)ga.ga_data
                                          + ga.ga_len + i, TRUE, TRUE, FALSE);
            ga.ga_len += i + sublen - 1;
            tail = regmatch.endp[0];
@@ -9906,7 +9908,7 @@ do_string_sub(
     if (p_cpo == empty_option)
        p_cpo = save_cpo;
     else
-       /* Darn, evaluating {sub} expression changed the value. */
+       /* Darn, evaluating {sub} expression or {expr} changed the value. */
        free_string_option(save_cpo);
 
     return ret;
index 00b1577449b7e9095259abb6d5843b023be33d6c..54b5a53bb9b740e91cdfc040cf25063c54652d01 100644 (file)
@@ -11061,14 +11061,21 @@ f_substitute(typval_T *argvars, typval_T *rettv)
 
     char_u     *str = get_tv_string_chk(&argvars[0]);
     char_u     *pat = get_tv_string_buf_chk(&argvars[1], patbuf);
-    char_u     *sub = get_tv_string_buf_chk(&argvars[2], subbuf);
+    char_u     *sub = NULL;
+    typval_T   *expr = NULL;
     char_u     *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf);
 
+    if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
+       expr = &argvars[2];
+    else
+       sub = get_tv_string_buf_chk(&argvars[2], subbuf);
+
     rettv->v_type = VAR_STRING;
-    if (str == NULL || pat == NULL || sub == NULL || flg == NULL)
+    if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
+                                                               || flg == NULL)
        rettv->vval.v_string = NULL;
     else
-       rettv->vval.v_string = do_string_sub(str, pat, sub, flg);
+       rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
 }
 
 /*
index c6d202d582753c503ae8d56e7ab62fd37880b9f5..e9ec97df4fe2621701399777756e488ca1a2ad7b 100644 (file)
@@ -126,6 +126,6 @@ void assert_exception(typval_T *argvars);
 void assert_fails(typval_T *argvars);
 void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv, char_u *exp_str, typval_T *exp_tv, typval_T *got_tv, assert_type_T atype);
 int modify_fname(char_u *src, int *usedlen, char_u **fnamep, char_u **bufp, int *fnamelen);
-char_u *do_string_sub(char_u *str, char_u *pat, char_u *sub, char_u *flags);
+char_u *do_string_sub(char_u *str, char_u *pat, char_u *sub, typval_T *expr, char_u *flags);
 void filter_map(typval_T *argvars, typval_T *rettv, int map);
 /* vim: set ft=c : */
index 5cdabb26a76b4cf4ad6999d82c405a7a7f2b6ce8..dfe5c91d52c7387fca90b0ac51305c6fdd784412 100644 (file)
@@ -7,7 +7,7 @@ void free_regexp_stuff(void);
 reg_extmatch_T *ref_extmatch(reg_extmatch_T *em);
 void unref_extmatch(reg_extmatch_T *em);
 char_u *regtilde(char_u *source, int magic);
-int vim_regsub(regmatch_T *rmp, char_u *source, char_u *dest, int copy, int magic, int backslash);
+int vim_regsub(regmatch_T *rmp, char_u *source, typval_T *expr, char_u *dest, int copy, int magic, int backslash);
 int vim_regsub_multi(regmmatch_T *rmp, linenr_T lnum, char_u *source, char_u *dest, int copy, int magic, int backslash);
 char_u *reg_submatch(int no);
 list_T *reg_submatch_list(int no);
index 5f1fc1c150a5d48a18e65d451667726e431667dd..1a7775894a4f30ac43cb4d4e8f89146478a7691d 100644 (file)
@@ -7169,7 +7169,7 @@ static fptr_T do_Upper(int *, int);
 static fptr_T do_lower(int *, int);
 static fptr_T do_Lower(int *, int);
 
-static int vim_regsub_both(char_u *source, char_u *dest, int copy, int magic, int backslash);
+static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest, int copy, int magic, int backslash);
 
     static fptr_T
 do_upper(int *d, int c)
@@ -7312,6 +7312,7 @@ static int                submatch_line_lbr;
 vim_regsub(
     regmatch_T *rmp,
     char_u     *source,
+    typval_T   *expr,
     char_u     *dest,
     int                copy,
     int                magic,
@@ -7322,7 +7323,7 @@ vim_regsub(
     reg_maxline = 0;
     reg_buf = curbuf;
     reg_line_lbr = TRUE;
-    return vim_regsub_both(source, dest, copy, magic, backslash);
+    return vim_regsub_both(source, expr, dest, copy, magic, backslash);
 }
 #endif
 
@@ -7342,12 +7343,13 @@ vim_regsub_multi(
     reg_firstlnum = lnum;
     reg_maxline = curbuf->b_ml.ml_line_count - lnum;
     reg_line_lbr = FALSE;
-    return vim_regsub_both(source, dest, copy, magic, backslash);
+    return vim_regsub_both(source, NULL, dest, copy, magic, backslash);
 }
 
     static int
 vim_regsub_both(
     char_u     *source,
+    typval_T   *expr,
     char_u     *dest,
     int                copy,
     int                magic,
@@ -7364,11 +7366,11 @@ vim_regsub_both(
     linenr_T   clnum = 0;      /* init for GCC */
     int                len = 0;        /* init for GCC */
 #ifdef FEAT_EVAL
-    static char_u *eval_result = NULL;
+    static char_u   *eval_result = NULL;
 #endif
 
     /* Be paranoid... */
-    if (source == NULL || dest == NULL)
+    if ((source == NULL && expr == NULL) || dest == NULL)
     {
        EMSG(_(e_null));
        return 0;
@@ -7381,11 +7383,11 @@ vim_regsub_both(
     /*
      * When the substitute part starts with "\=" evaluate it as an expression.
      */
-    if (source[0] == '\\' && source[1] == '='
+    if (expr != NULL || (source[0] == '\\' && source[1] == '='
 #ifdef FEAT_EVAL
            && !can_f_submatch      /* can't do this recursively */
 #endif
-           )
+           ))
     {
 #ifdef FEAT_EVAL
        /* To make sure that the length doesn't change between checking the
@@ -7406,6 +7408,7 @@ vim_regsub_both(
        {
            win_T       *save_reg_win;
            int         save_ireg_ic;
+           int         prev_can_f_submatch = can_f_submatch;
 
            vim_free(eval_result);
 
@@ -7422,7 +7425,40 @@ vim_regsub_both(
            save_ireg_ic = ireg_ic;
            can_f_submatch = TRUE;
 
-           eval_result = eval_to_string(source + 2, NULL, TRUE);
+           if (expr != NULL)
+           {
+               typval_T        argv[1];
+               int             dummy;
+               char_u          buf[NUMBUFLEN];
+               typval_T        rettv;
+
+               rettv.v_type = VAR_STRING;
+               rettv.vval.v_string = NULL;
+               if (prev_can_f_submatch)
+               {
+                   /* can't do this recursively */
+               }
+               else if (expr->v_type == VAR_FUNC)
+               {
+                   s = expr->vval.v_string;
+                   call_func(s, (int)STRLEN(s), &rettv, 0, argv,
+                                            0L, 0L, &dummy, TRUE, NULL, NULL);
+               }
+               else if (expr->v_type == VAR_PARTIAL)
+               {
+                   partial_T   *partial = expr->vval.v_partial;
+
+                   s = partial->pt_name;
+                   call_func(s, (int)STRLEN(s), &rettv, 0, argv,
+                                         0L, 0L, &dummy, TRUE, partial, NULL);
+               }
+               eval_result = get_tv_string_buf_chk(&rettv, buf);
+               if (eval_result != NULL)
+                   eval_result = vim_strsave(eval_result);
+           }
+           else
+               eval_result = eval_to_string(source + 2, NULL, TRUE);
+
            if (eval_result != NULL)
            {
                int had_backslash = FALSE;
index 86c86c58d5a853fa31f2ecd399a7b5c8fbd50ccd..235dd8d65a1c667f3b1303647fe7c68d29ed38f7 100644 (file)
@@ -135,3 +135,21 @@ function Test_printf_64bit()
     call assert_equal("123456789012345", printf('%d', 123456789012345))
   endif
 endfunc
+
+func Test_substitute_expr()
+  let g:val = 'XXX'
+  call assert_equal('XXX', substitute('yyy', 'y*', '\=g:val', ''))
+  call assert_equal('XXX', substitute('yyy', 'y*', {-> g:val}, ''))
+  call assert_equal("-\u1b \uf2-", substitute("-%1b %f2-", '%\(\x\x\)',
+                          \ '\=nr2char("0x" . submatch(1))', 'g'))
+  call assert_equal("-\u1b \uf2-", substitute("-%1b %f2-", '%\(\x\x\)',
+                          \ {-> nr2char("0x" . submatch(1))}, 'g'))
+
+  call assert_equal('231', substitute('123', '\(.\)\(.\)\(.\)',
+       \ {-> submatch(2) . submatch(3) . submatch(1)}, ''))
+
+  func Recurse()
+    return substitute('yyy', 'y*', {-> g:val}, '')
+  endfunc
+  call assert_equal('--', substitute('xxx', 'x*', {-> '-' . Recurse() . '-'}, ''))
+endfunc
index 5cb78977de4e6e49da52b5312996a12d0ac69a97..a7b65c8f061ce3c04195f8227845020e0f00a23a 100644 (file)
@@ -758,6 +758,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2072,
 /**/
     2071,
 /**/