To: vim_dev@googlegroups.com Subject: Patch 7.4.2072 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 7.4.2072 Problem: substitute() does not support a Funcref argument. Solution: Support a Funcref like it supports a string starting with "\=". Files: src/evalfunc.c, src/regexp.c, src/eval.c, src/proto/eval.pro, src/proto/regexp.pro, src/testdir/test_expr.vim *** ../vim-7.4.2071/src/evalfunc.c 2016-07-19 17:25:19.082023340 +0200 --- src/evalfunc.c 2016-07-19 17:39:59.700759367 +0200 *************** *** 11061,11074 **** 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 *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf); rettv->v_type = VAR_STRING; ! if (str == NULL || pat == NULL || sub == NULL || flg == NULL) rettv->vval.v_string = NULL; else ! rettv->vval.v_string = do_string_sub(str, pat, sub, flg); } /* --- 11061,11081 ---- char_u *str = get_tv_string_chk(&argvars[0]); char_u *pat = get_tv_string_buf_chk(&argvars[1], patbuf); ! 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 && expr == NULL) ! || flg == NULL) rettv->vval.v_string = NULL; else ! rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg); } /* *** ../vim-7.4.2071/src/regexp.c 2016-04-26 21:39:08.227018806 +0200 --- src/regexp.c 2016-07-19 18:01:30.251218469 +0200 *************** *** 7169,7175 **** 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 fptr_T do_upper(int *d, int c) --- 7169,7175 ---- static fptr_T do_lower(int *, int); static fptr_T do_Lower(int *, int); ! 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,7317 **** --- 7312,7318 ---- vim_regsub( regmatch_T *rmp, char_u *source, + typval_T *expr, char_u *dest, int copy, int magic, *************** *** 7322,7328 **** reg_maxline = 0; reg_buf = curbuf; reg_line_lbr = TRUE; ! return vim_regsub_both(source, dest, copy, magic, backslash); } #endif --- 7323,7329 ---- reg_maxline = 0; reg_buf = curbuf; reg_line_lbr = TRUE; ! return vim_regsub_both(source, expr, dest, copy, magic, backslash); } #endif *************** *** 7342,7353 **** 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); } static int vim_regsub_both( char_u *source, char_u *dest, int copy, int magic, --- 7343,7355 ---- reg_firstlnum = lnum; reg_maxline = curbuf->b_ml.ml_line_count - lnum; reg_line_lbr = FALSE; ! 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,7374 **** linenr_T clnum = 0; /* init for GCC */ int len = 0; /* init for GCC */ #ifdef FEAT_EVAL ! static char_u *eval_result = NULL; #endif /* Be paranoid... */ ! if (source == NULL || dest == NULL) { EMSG(_(e_null)); return 0; --- 7366,7376 ---- linenr_T clnum = 0; /* init for GCC */ int len = 0; /* init for GCC */ #ifdef FEAT_EVAL ! static char_u *eval_result = NULL; #endif /* Be paranoid... */ ! if ((source == NULL && expr == NULL) || dest == NULL) { EMSG(_(e_null)); return 0; *************** *** 7381,7391 **** /* * When the substitute part starts with "\=" evaluate it as an expression. */ ! if (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 --- 7383,7393 ---- /* * When the substitute part starts with "\=" evaluate it as an expression. */ ! 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,7411 **** --- 7408,7414 ---- { win_T *save_reg_win; int save_ireg_ic; + int prev_can_f_submatch = can_f_submatch; vim_free(eval_result); *************** *** 7422,7428 **** save_ireg_ic = ireg_ic; can_f_submatch = TRUE; ! eval_result = eval_to_string(source + 2, NULL, TRUE); if (eval_result != NULL) { int had_backslash = FALSE; --- 7425,7464 ---- save_ireg_ic = ireg_ic; can_f_submatch = 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; *** ../vim-7.4.2071/src/eval.c 2016-07-19 17:25:19.078023383 +0200 --- src/eval.c 2016-07-19 17:42:57.118896673 +0200 *************** *** 9769,9775 **** if (sub != NULL && str != NULL) { *usedlen = (int)(p + 1 - src); ! s = do_string_sub(str, pat, sub, flags); if (s != NULL) { *fnamep = s; --- 9769,9775 ---- if (sub != NULL && str != NULL) { *usedlen = (int)(p + 1 - src); ! s = do_string_sub(str, pat, sub, NULL, flags); if (s != NULL) { *fnamep = s; *************** *** 9813,9818 **** --- 9813,9819 ---- /* * 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,9826 **** --- 9822,9828 ---- char_u *str, char_u *pat, char_u *sub, + typval_T *expr, char_u *flags) { int sublen; *************** *** 9873,9879 **** * - The substituted text. * - The text after the match. */ ! sublen = vim_regsub(®match, sub, tail, FALSE, TRUE, FALSE); if (ga_grow(&ga, (int)((end - tail) + sublen - (regmatch.endp[0] - regmatch.startp[0]))) == FAIL) { --- 9875,9881 ---- * - The substituted text. * - The text after the match. */ ! sublen = vim_regsub(®match, sub, expr, tail, FALSE, TRUE, FALSE); if (ga_grow(&ga, (int)((end - tail) + sublen - (regmatch.endp[0] - regmatch.startp[0]))) == FAIL) { *************** *** 9885,9891 **** 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(®match, sub, (char_u *)ga.ga_data + ga.ga_len + i, TRUE, TRUE, FALSE); ga.ga_len += i + sublen - 1; tail = regmatch.endp[0]; --- 9887,9893 ---- 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(®match, 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,9912 **** if (p_cpo == empty_option) p_cpo = save_cpo; else ! /* Darn, evaluating {sub} expression changed the value. */ free_string_option(save_cpo); return ret; --- 9908,9914 ---- if (p_cpo == empty_option) p_cpo = save_cpo; else ! /* Darn, evaluating {sub} expression or {expr} changed the value. */ free_string_option(save_cpo); return ret; *** ../vim-7.4.2071/src/proto/eval.pro 2016-07-17 22:13:26.817095253 +0200 --- src/proto/eval.pro 2016-07-19 17:45:37.957209022 +0200 *************** *** 126,131 **** 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); void filter_map(typval_T *argvars, typval_T *rettv, int map); /* vim: set ft=c : */ --- 126,131 ---- 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, typval_T *expr, char_u *flags); void filter_map(typval_T *argvars, typval_T *rettv, int map); /* vim: set ft=c : */ *** ../vim-7.4.2071/src/proto/regexp.pro 2016-01-19 13:21:55.845334290 +0100 --- src/proto/regexp.pro 2016-07-19 18:01:53.570973761 +0200 *************** *** 7,13 **** 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_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); --- 7,13 ---- 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, 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); *** ../vim-7.4.2071/src/testdir/test_expr.vim 2016-07-12 21:11:28.711223556 +0200 --- src/testdir/test_expr.vim 2016-07-19 19:00:18.070614811 +0200 *************** *** 135,137 **** --- 135,155 ---- 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 *** ../vim-7.4.2071/src/version.c 2016-07-19 17:25:19.082023340 +0200 --- src/version.c 2016-07-19 18:11:40.232821362 +0200 *************** *** 760,761 **** --- 760,763 ---- { /* Add new patch number below this line */ + /**/ + 2072, /**/ -- A mathematician is a device for turning coffee into theorems. Paul Erdos A computer programmer is a device for turning coffee into bugs. Bram Moolenaar /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///