changeset 8793:dda254280bab v7.4.1685

commit https://github.com/vim/vim/commit/7fed5c18f8577b75404b80d8b9a9907b1bbd27e4 Author: Bram Moolenaar <Bram@vim.org> Date: Tue Mar 29 23:10:31 2016 +0200 patch 7.4.1685 Problem: There is no easy way to get all the information about a match. Solution: Add matchstrpos(). (Ozaki Kiichi)
author Christian Brabandt <cb@256bit.org>
date Tue, 29 Mar 2016 23:15:06 +0200
parents a100e1e907dc
children c861b4fd579f
files runtime/doc/eval.txt runtime/doc/usr_41.txt src/eval.c src/testdir/test_alot.vim src/testdir/test_matchstrpos.vim src/version.c
diffstat 6 files changed, 89 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -2020,6 +2020,8 @@ matchlist( {expr}, {pat}[, {start}[, {co
 				List	match and submatches of {pat} in {expr}
 matchstr( {expr}, {pat}[, {start}[, {count}]])
 				String	{count}'th match of {pat} in {expr}
+matchstrpos( {expr}, {pat}[, {start}[, {count}]])
+				List	{count}'th match of {pat} in {expr}
 max( {list})			Number	maximum value of items in {list}
 min( {list})			Number	minimum value of items in {list}
 mkdir( {name} [, {path} [, {prot}]])
@@ -5206,6 +5208,24 @@ matchstr({expr}, {pat}[, {start}[, {coun
 		When {expr} is a |List| then the matching item is returned.
 		The type isn't changed, it's not necessarily a String.
 
+matchstrpos({expr}, {pat}[, {start}[, {count}]])		*matchstrpos()*
+		Same as |matchstr()|, but return the matched string, the start
+		position and the end position of the match.  Example: >
+			:echo matchstrpos("testing", "ing")
+<		results in ["ing", 4, 7].
+		When there is no match ["", -1, -1] is returned.
+		The {start}, if given, has the same meaning as for |match()|. >
+			:echo matchstrpos("testing", "ing", 2)
+<		results in ["ing", 4, 7]. >
+			:echo matchstrpos("testing", "ing", 5)
+<		result is ["", -1, -1].
+		When {expr} is a |List| then the matching item, the index
+		of first item where {pat} matches, the start position and the
+		end position of the match are returned. >
+			:echo matchstrpos([1, '__x'], '\a')
+<		result is ["x", 1, 2, 3].
+		The type isn't changed, it's not necessarily a String.
+
 							*max()*
 max({list})	Return the maximum value of all items in {list}.
 		If {list} is not a list or one of the items in {list} cannot
--- a/runtime/doc/usr_41.txt
+++ b/runtime/doc/usr_41.txt
@@ -592,6 +592,7 @@ String manipulation:					*string-functio
 	match()			position where a pattern matches in a string
 	matchend()		position where a pattern match ends in a string
 	matchstr()		match of a pattern in a string
+	matchstrpos()		match and postions of a pattern in a string
 	matchlist()		like matchstr() and also return submatches
 	stridx()		first index of a short string in a long string
 	strridx()		last index of a short string in a long string
--- a/src/eval.c
+++ b/src/eval.c
@@ -673,6 +673,7 @@ static void f_matchdelete(typval_T *argv
 static void f_matchend(typval_T *argvars, typval_T *rettv);
 static void f_matchlist(typval_T *argvars, typval_T *rettv);
 static void f_matchstr(typval_T *argvars, typval_T *rettv);
+static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
 static void f_max(typval_T *argvars, typval_T *rettv);
 static void f_min(typval_T *argvars, typval_T *rettv);
 #ifdef vim_mkdir
@@ -8383,6 +8384,7 @@ static struct fst
     {"matchend",	2, 4, f_matchend},
     {"matchlist",	2, 4, f_matchlist},
     {"matchstr",	2, 4, f_matchstr},
+    {"matchstrpos",	2, 4, f_matchstrpos},
     {"max",		1, 1, f_max},
     {"min",		1, 1, f_min},
 #ifdef vim_mkdir
@@ -15302,11 +15304,26 @@ find_some_match(typval_T *argvars, typva
     p_cpo = (char_u *)"";
 
     rettv->vval.v_number = -1;
-    if (type == 3)
-    {
-	/* return empty list when there are no matches */
+    if (type == 3 || type == 4)
+    {
+	/* type 3: return empty list when there are no matches.
+	 * type 4: return ["", -1, -1, -1] */
 	if (rettv_list_alloc(rettv) == FAIL)
 	    goto theend;
+	if (type == 4
+		&& (list_append_string(rettv->vval.v_list,
+					    (char_u *)"", 0) == FAIL
+		    || list_append_number(rettv->vval.v_list,
+					    (varnumber_T)-1) == FAIL
+		    || list_append_number(rettv->vval.v_list,
+					    (varnumber_T)-1) == FAIL
+		    || list_append_number(rettv->vval.v_list,
+					    (varnumber_T)-1) == FAIL))
+	{
+		list_free(rettv->vval.v_list, TRUE);
+		rettv->vval.v_list = NULL;
+		goto theend;
+	}
     }
     else if (type == 2)
     {
@@ -15383,7 +15400,7 @@ find_some_match(typval_T *argvars, typva
 		    break;
 		}
 		vim_free(tofree);
-		str = echo_string(&li->li_tv, &tofree, strbuf, 0);
+		expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
 		if (str == NULL)
 		    break;
 	    }
@@ -15420,7 +15437,23 @@ find_some_match(typval_T *argvars, typva
 
 	if (match)
 	{
-	    if (type == 3)
+	    if (type == 4)
+	    {
+		listitem_T *li1 = rettv->vval.v_list->lv_first;
+		listitem_T *li2 = li1->li_next;
+		listitem_T *li3 = li2->li_next;
+		listitem_T *li4 = li3->li_next;
+
+		li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
+				(int)(regmatch.endp[0] - regmatch.startp[0]));
+		li3->li_tv.vval.v_number =
+				      (varnumber_T)(regmatch.startp[0] - expr);
+		li4->li_tv.vval.v_number =
+					(varnumber_T)(regmatch.endp[0] - expr);
+		if (l != NULL)
+		    li2->li_tv.vval.v_number = (varnumber_T)idx;
+	    }
+	    else if (type == 3)
 	    {
 		int i;
 
@@ -15465,6 +15498,11 @@ find_some_match(typval_T *argvars, typva
 	vim_regfree(regmatch.regprog);
     }
 
+    if (type == 4 && l == NULL)
+	/* matchstrpos() without a list: drop the second item. */
+	listitem_remove(rettv->vval.v_list,
+				       rettv->vval.v_list->lv_first->li_next);
+
 theend:
     vim_free(tofree);
     p_cpo = save_cpo;
@@ -15665,6 +15703,15 @@ f_matchstr(typval_T *argvars, typval_T *
     find_some_match(argvars, rettv, 2);
 }
 
+/*
+ * "matchstrpos()" function
+ */
+    static void
+f_matchstrpos(typval_T *argvars, typval_T *rettv)
+{
+    find_some_match(argvars, rettv, 4);
+}
+
 static void max_min(typval_T *argvars, typval_T *rettv, int domax);
 
     static void
--- a/src/testdir/test_alot.vim
+++ b/src/testdir/test_alot.vim
@@ -15,6 +15,7 @@ source test_glob2regpat.vim
 source test_help_tagjump.vim
 source test_join.vim
 source test_lispwords.vim
+source test_matchstrpos.vim
 source test_menu.vim
 source test_partial.vim
 source test_reltime.vim
new file mode 100644
--- /dev/null
+++ b/src/testdir/test_matchstrpos.vim
@@ -0,0 +1,13 @@
+" Test matchstrpos
+
+func Test_matchstrpos()
+  call assert_equal(['ing', 4, 7], matchstrpos('testing', 'ing'))
+
+  call assert_equal(['ing', 4, 7], matchstrpos('testing', 'ing', 2))
+
+  call assert_equal(['', -1, -1], matchstrpos('testing', 'ing', 5))
+
+  call assert_equal(['ing', 1, 4, 7], matchstrpos(['vim', 'testing', 'execute'], 'ing'))
+
+  call assert_equal(['', -1, -1, -1], matchstrpos(['vim', 'testing', 'execute'], 'img'))
+endfunc
--- a/src/version.c
+++ b/src/version.c
@@ -749,6 +749,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1685,
+/**/
     1684,
 /**/
     1683,