summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/eval.txt16
-rw-r--r--src/eval.c31
-rw-r--r--src/proto/regexp.pro1
-rw-r--r--src/regexp.c79
-rw-r--r--src/testdir/test79.inbin2713 -> 3123 bytes
-rw-r--r--src/testdir/test79.okbin421 -> 556 bytes
-rw-r--r--src/testdir/test80.in2
-rw-r--r--src/testdir/test80.ok3
-rw-r--r--src/version.c2
9 files changed, 128 insertions, 6 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 007c7f746..cdf8d72bb 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -1990,7 +1990,8 @@ strridx( {haystack}, {needle} [, {start}])
Number last index of {needle} in {haystack}
strtrans( {expr}) String translate string to make it printable
strwidth( {expr}) Number display cell length of the String {expr}
-submatch( {nr}) String specific match in ":s" or substitute()
+submatch( {nr}[, {list}]) String or List
+ specific match in ":s" or substitute()
substitute( {expr}, {pat}, {sub}, {flags})
String all {pat} in {expr} replaced with {sub}
synID( {lnum}, {col}, {trans}) Number syntax ID at {lnum} and {col}
@@ -5797,12 +5798,23 @@ strwidth({expr}) *strwidth()*
Ambiguous, this function's return value depends on 'ambiwidth'.
Also see |strlen()|, |strdisplaywidth()| and |strchars()|.
-submatch({nr}) *submatch()*
+submatch({nr}[, {list}]) *submatch()*
Only for an expression in a |:substitute| command or
substitute() function.
Returns the {nr}'th submatch of the matched text. When {nr}
is 0 the whole matched text is returned.
+ Note that a NL in the string can stand for a line break of a
+ multi-line match or a NUL character in the text.
Also see |sub-replace-expression|.
+
+ If {list} is present and non-zero then submatch() returns
+ a list of strings, similar to |getline()| with two arguments.
+ NL characters in the text represent NUL characters in the
+ text.
+ Only returns more than one item for |:substitute|, inside
+ |substitute()| this list will always contain one or zero
+ items, since there are no real line breaks.
+
Example: >
:s/\d\+/\=submatch(0) + 1/
< This finds the first number in the line and adds one to it.
diff --git a/src/eval.c b/src/eval.c
index 05f91b303..7b682572c 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -8129,7 +8129,7 @@ static struct fst
{"strridx", 2, 3, f_strridx},
{"strtrans", 1, 1, f_strtrans},
{"strwidth", 1, 1, f_strwidth},
- {"submatch", 1, 1, f_submatch},
+ {"submatch", 1, 2, f_submatch},
{"substitute", 4, 4, f_substitute},
{"synID", 3, 3, f_synID},
{"synIDattr", 2, 3, f_synIDattr},
@@ -17890,9 +17890,32 @@ f_submatch(argvars, rettv)
typval_T *argvars;
typval_T *rettv;
{
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string =
- reg_submatch((int)get_tv_number_chk(&argvars[0], NULL));
+ int error = FALSE;
+ char_u **match;
+ char_u **s;
+ listitem_T *li;
+ int no;
+ int retList = 0;
+
+ no = (int)get_tv_number_chk(&argvars[0], &error);
+ if (error)
+ return;
+ error = FALSE;
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ retList = get_tv_number_chk(&argvars[1], &error);
+ if (error)
+ return;
+
+ if (retList == 0)
+ {
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = reg_submatch(no);
+ }
+ else
+ {
+ rettv->v_type = VAR_LIST;
+ rettv->vval.v_list = reg_submatch_list(no);
+ }
}
/*
diff --git a/src/proto/regexp.pro b/src/proto/regexp.pro
index 38c9c33c4..a42c5944a 100644
--- a/src/proto/regexp.pro
+++ b/src/proto/regexp.pro
@@ -10,6 +10,7 @@ char_u *regtilde __ARGS((char_u *source, int magic));
int vim_regsub __ARGS((regmatch_T *rmp, char_u *source, char_u *dest, int copy, int magic, int backslash));
int vim_regsub_multi __ARGS((regmmatch_T *rmp, linenr_T lnum, char_u *source, char_u *dest, int copy, int magic, int backslash));
char_u *reg_submatch __ARGS((int no));
+list_T *reg_submatch_list __ARGS((int no));
regprog_T *vim_regcomp __ARGS((char_u *expr_arg, int re_flags));
void vim_regfree __ARGS((regprog_T *prog));
int vim_regexec __ARGS((regmatch_T *rmp, char_u *line, colnr_T col));
diff --git a/src/regexp.c b/src/regexp.c
index 32a51884b..0a590f66d 100644
--- a/src/regexp.c
+++ b/src/regexp.c
@@ -7897,6 +7897,85 @@ reg_submatch(no)
return retval;
}
+
+/*
+ * Used for the submatch() function with the optional non-zero argument: get
+ * the list of strings from the n'th submatch in allocated memory with NULs
+ * represented in NLs.
+ * Returns a list of allocated strings. Returns NULL when not in a ":s"
+ * command, for a non-existing submatch and for any error.
+ */
+ list_T *
+reg_submatch_list(no)
+ int no;
+{
+ char_u *s;
+ linenr_T slnum;
+ linenr_T elnum;
+ colnr_T scol;
+ colnr_T ecol;
+ int i;
+ list_T *list;
+ int error = FALSE;
+
+ if (!can_f_submatch || no < 0)
+ return NULL;
+
+ if (submatch_match == NULL)
+ {
+ slnum = submatch_mmatch->startpos[no].lnum;
+ elnum = submatch_mmatch->endpos[no].lnum;
+ if (slnum < 0 || elnum < 0)
+ return NULL;
+
+ scol = submatch_mmatch->startpos[no].col;
+ ecol = submatch_mmatch->endpos[no].col;
+
+ list = list_alloc();
+ if (list == NULL)
+ return NULL;
+
+ s = reg_getline_submatch(slnum) + scol;
+ if (slnum == elnum)
+ {
+ if (list_append_string(list, s, ecol - scol) == FAIL)
+ error = TRUE;
+ }
+ else
+ {
+ if (list_append_string(list, s, -1) == FAIL)
+ error = TRUE;
+ for (i = 1; i < elnum - slnum; i++)
+ {
+ s = reg_getline_submatch(slnum + i);
+ if (list_append_string(list, s, -1) == FAIL)
+ error = TRUE;
+ }
+ s = reg_getline_submatch(elnum);
+ if (list_append_string(list, s, ecol) == FAIL)
+ error = TRUE;
+ }
+ }
+ else
+ {
+ s = submatch_match->startp[no];
+ if (s == NULL || submatch_match->endp[no] == NULL)
+ return NULL;
+ list = list_alloc();
+ if (list == NULL)
+ return NULL;
+ if (list_append_string(list, s,
+ (int)(submatch_match->endp[no] - s)) == FAIL)
+ error = TRUE;
+ }
+
+ if (error)
+ {
+ list_free(list, TRUE);
+ return NULL;
+ }
+ return list;
+}
#endif
static regengine_T bt_regengine =
diff --git a/src/testdir/test79.in b/src/testdir/test79.in
index f15ecc0f8..56955c231 100644
--- a/src/testdir/test79.in
+++ b/src/testdir/test79.in
Binary files differ
diff --git a/src/testdir/test79.ok b/src/testdir/test79.ok
index bb30d1405..0f6ea4545 100644
--- a/src/testdir/test79.ok
+++ b/src/testdir/test79.ok
Binary files differ
diff --git a/src/testdir/test80.in b/src/testdir/test80.in
index c62fdc02b..406fb6dac 100644
--- a/src/testdir/test80.in
+++ b/src/testdir/test80.in
@@ -117,6 +117,7 @@ STARTTEST
:set cpo&
:$put =\"\n\nTEST_5:\"
:$put =substitute('A123456789', 'A\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)', '\=submatch(0) . submatch(9) . submatch(8) . submatch(7) . submatch(6) . submatch(5) . submatch(4) . submatch(3) . submatch(2) . submatch(1)', '')
+:$put =substitute('A123456789', 'A\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)', '\=string([submatch(0, 1), submatch(9, 1), submatch(8, 1), submatch(7, 1), submatch(6, 1), submatch(5, 1), submatch(4, 1), submatch(3, 1), submatch(2, 1), submatch(1, 1)])', '')
/^TEST_6
ENDTEST
@@ -142,6 +143,7 @@ STARTTEST
:$put =\"\n\nTEST_7:\"
:$put =substitute('A A', 'A.', '\=submatch(0)', '')
:$put =substitute(\"B\nB\", 'B.', '\=submatch(0)', '')
+:$put =substitute(\"B\nB\", 'B.', '\=string(submatch(0, 1))', '')
:$put =substitute('-bb', '\zeb', 'a', 'g')
:$put =substitute('-bb', '\ze', 'c', 'g')
/^TEST_8
diff --git a/src/testdir/test80.ok b/src/testdir/test80.ok
index 2b79d377a..b42f604a0 100644
--- a/src/testdir/test80.ok
+++ b/src/testdir/test80.ok
@@ -90,6 +90,7 @@ l
TEST_5:
A123456789987654321
+[['A123456789'], ['9'], ['8'], ['7'], ['6'], ['5'], ['4'], ['3'], ['2'], ['1']]
TEST_6:
@@ -103,6 +104,8 @@ TEST_7:
A A
B
B
+['B
+']B
-abab
c-cbcbc
diff --git a/src/version.c b/src/version.c
index 472a7fad0..fbfb5e66a 100644
--- a/src/version.c
+++ b/src/version.c
@@ -735,6 +735,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 241,
+/**/
240,
/**/
239,