Here is latest patch (with the failing test).

2014-06-02 18:08 GMT+04:00 Alexey Radkov <alexey.rad...@gmail.com>:

>
>
>
> 2014-06-02 0:01 GMT+04:00 Bram Moolenaar <b...@moolenaar.net>:
>
>
>> Alexey Radkov wrote:
>>
>> > A new version: next_search_hl_pos() moved into next_search_hl().
>> > A number of fixes added.
>> > Docs were added too, here is an excerpt:
>> >
>> > matchaddpos({group}, {pos}[, {priority}[, {id}]])        *matchaddpos()*
>> >         Same as |matchadd()|, but requires a list of positions {pos}
>> >         instead of a pattern. This command is faster than |matchadd()|
>> >         because it does not require to handle regular expressions and
>> >         sets buffer line boundaries to redraw screen. It is supposed
>> >         to be used when fast match additions and deletions are
>> >         required, for example to highlight matching parentheses.
>> >
>> >         The list {pos} accepts sublists: positions like [23, 24] or
>> >         plain numbers like 34. In the first case the 24th character in
>> >         line 23 will be highlighted; in the second case the whole line
>> >         34 will be highlighted. Maximum number of positions is 8.
>> >
>> >         Example: >
>> >             :highlight MyGroup ctermbg=green guibg=green
>> >             :let m = matchaddpos("MyGroup", [[23, 24], 34])
>> > <        Deletion of the pattern: >
>> >             :call matchdelete(m)
>>
>> I would suggest a third argument: the number of columns to highlight.
>> So it's [lnum, col, length].  When length is missing highlight one
>> screen cell, when col is missing highlight the whole line. I think
>> that's flexible enough.
>>
>
> Implemented
>
>
>> > Still no tests, will add them soon.
>>
>> OK, I will wait for that.
>>
>
> About tests. Here is what i added into test63.in:
>
> :" --- Check that "matchaddpos()" positions match correctly
> :let @r .= "*** Test 11: "
> :call append(0, 'test()')
> :call matchaddpos("MyGroup1", [[1, 5], [1, 6]], 10, 3)
> :let v1 = screenattr(1, 1)
> :let v2 = screenattr(1, 5)
> :let v3 = screenattr(1, 6)
> :let @r .= v1."\n"
> :let @r .= v2."\n"
> :let @r .= v3."\n"
> :if v1 != v2 && v2 == v3
> :  let @r .= "OK\n"
> :else
> :  let @r .= "FAILED\n"
> :endif
> :call clearmatches()
> :unlet v1
> :unlet v2
> :unlet v3
>
> Run
>
> VIMRUNTIME=../../runtime; export VIMRUNTIME;  ../vim -u unix.vim -U NONE
> --noplugin -s dotest.in test63.in. Result:
>
> Results of test63:
> *** Test 1: OK
> *** Test 2: OK
> *** Test 3: OK
> *** Test 4: OK
> *** Test 5: OK
> *** Test 6: OK
> *** Test 7: OK
> *** Test 8: OK
> *** Test 9: OK
> *** Test 10: OK
> *** Test 11: 0
> 0
> 0
> FAILED
>
> I remember that when vim is running in scripting mode as well as when its
> stdin is not a terminal it won't actually apply color attributes and
> screenattr() will always get 0. If it's true then screenattr() is not
> suitable here... (Though i see that it is used in test101.in). Anyway
> this test work when i ran it from vim manually.
>
>
>>
>> --
>> hundred-and-one symptoms of being an internet addict:
>> 251. You've never seen your closest friends who usually live WAY too far
>> away.
>>
>>  /// Bram Moolenaar -- b...@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
>>  ///
>>
>
>

-- 
-- 
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 vim_dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
diff -r bed71c37618c runtime/doc/eval.txt
--- a/runtime/doc/eval.txt	Thu May 29 14:36:29 2014 +0200
+++ b/runtime/doc/eval.txt	Mon Jun 02 18:58:10 2014 +0400
@@ -1887,6 +1887,8 @@
 				Number	position where {pat} matches in {expr}
 matchadd( {group}, {pattern}[, {priority}[, {id}]])
 				Number	highlight {pattern} with {group}
+matchaddpos( {group}, {list}[, {priority}[, {id}]])
+				Number	highlight {list} of positions with {group}
 matcharg( {nr})			List	arguments of |:match|
 matchdelete( {id})		Number	delete match identified by {id}
 matchend( {expr}, {pat}[, {start}[, {count}]])
@@ -4348,6 +4350,32 @@
 		available from |getmatches()|.	All matches can be deleted in
 		one operation by |clearmatches()|.
 
+matchaddpos({group}, {pos}[, {priority}[, {id}]])		*matchaddpos()*
+		Same as |matchadd()|, but requires a list of positions {pos}
+		instead of a pattern. This command is faster than |matchadd()|
+		because it does not require to handle regular expressions and
+		sets buffer line boundaries to redraw screen. It is supposed
+		to be used when fast match additions and deletions are
+		required, for example to highlight matching parentheses.
+
+		The list {pos} accepts sublists: positions like [23, 24] or
+		plain numbers like 34. In the first case the 24th character in
+		line 23 will be highlighted; in the second case the whole line
+		34 will be highlighted. Maximum number of positions is 8. If
+		position sublist contains 3rd number then it is considered to
+		be the length of the match: by default the length is equal to
+		1.
+
+		Example: >
+			:highlight MyGroup ctermbg=green guibg=green
+			:let m = matchaddpos("MyGroup", [[23, 24], 34])
+<		Deletion of the pattern: >
+			:call matchdelete(m)
+
+<		Matches added by |matchaddpos()| are not returned by
+		|getmatches()| nor can they be set via |setmatches()|,
+		however they can still be deleted by |clearmatches()|.
+
 matcharg({nr})							*matcharg()*
 		Selects the {nr} match item, as set with a |:match|,
 		|:2match| or |:3match| command.
diff -r bed71c37618c runtime/doc/pattern.txt
--- a/runtime/doc/pattern.txt	Thu May 29 14:36:29 2014 +0200
+++ b/runtime/doc/pattern.txt	Mon Jun 02 18:58:10 2014 +0400
@@ -1332,7 +1332,7 @@
 		patterns defined by both |matchadd()| and |:match|.
 
 		Highlighting matches using |:match| are limited to three
-		matches (aside from |:match|, |:2match| and |:3match|are
+		matches (aside from |:match|, |:2match| and |:3match| are
 		available). |matchadd()| does not have this limitation and in
 		addition makes it possible to prioritize matches.
 
diff -r bed71c37618c runtime/doc/usr_41.txt
--- a/runtime/doc/usr_41.txt	Thu May 29 14:36:29 2014 +0200
+++ b/runtime/doc/usr_41.txt	Mon Jun 02 18:58:10 2014 +0400
@@ -826,6 +826,7 @@
 	synconcealed()		get info about concealing
 	diff_hlID()		get highlight ID for diff mode at a position
 	matchadd()		define a pattern to highlight (a "match")
+	matchaddpos()		define a list of positions to highlight
 	matcharg()		get info about |:match| arguments
 	matchdelete()		delete a match defined by |matchadd()| or a
 				|:match| command
diff -r bed71c37618c runtime/plugin/matchparen.vim
--- a/runtime/plugin/matchparen.vim	Thu May 29 14:36:29 2014 +0200
+++ b/runtime/plugin/matchparen.vim	Mon Jun 02 18:58:10 2014 +0400
@@ -39,7 +39,7 @@
 function! s:Highlight_Matching_Pair()
   " Remove any previous match.
   if exists('w:paren_hl_on') && w:paren_hl_on
-    3match none
+    silent! call matchdelete(3)
     let w:paren_hl_on = 0
   endif
 
@@ -152,14 +152,13 @@
 
   " If a match is found setup match highlighting.
   if m_lnum > 0 && m_lnum >= stoplinetop && m_lnum <= stoplinebottom 
-    exe '3match MatchParen /\(\%' . c_lnum . 'l\%' . (c_col - before) .
-	  \ 'c\)\|\(\%' . m_lnum . 'l\%' . m_col . 'c\)/'
+    call matchaddpos('MatchParen', [[c_lnum, c_col - before], [m_lnum, m_col]], 10, 3)
     let w:paren_hl_on = 1
   endif
 endfunction
 
 " Define commands that will disable and enable the plugin.
-command! NoMatchParen windo 3match none | unlet! g:loaded_matchparen |
+command! NoMatchParen windo silent! call matchdelete(3) | unlet! g:loaded_matchparen |
 	  \ au! matchparen
 command! DoMatchParen runtime plugin/matchparen.vim | windo doau CursorMoved
 
diff -r bed71c37618c src/eval.c
--- a/src/eval.c	Thu May 29 14:36:29 2014 +0200
+++ b/src/eval.c	Mon Jun 02 18:58:10 2014 +0400
@@ -619,6 +619,7 @@
 static void f_mapcheck __ARGS((typval_T *argvars, typval_T *rettv));
 static void f_match __ARGS((typval_T *argvars, typval_T *rettv));
 static void f_matchadd __ARGS((typval_T *argvars, typval_T *rettv));
+static void f_matchaddpos __ARGS((typval_T *argvars, typval_T *rettv));
 static void f_matcharg __ARGS((typval_T *argvars, typval_T *rettv));
 static void f_matchdelete __ARGS((typval_T *argvars, typval_T *rettv));
 static void f_matchend __ARGS((typval_T *argvars, typval_T *rettv));
@@ -8039,6 +8040,7 @@
     {"mapcheck",	1, 3, f_mapcheck},
     {"match",		2, 4, f_match},
     {"matchadd",	2, 4, f_matchadd},
+    {"matchaddpos",	2, 4, f_matchaddpos},
     {"matcharg",	1, 1, f_matcharg},
     {"matchdelete",	1, 1, f_matchdelete},
     {"matchend",	2, 4, f_matchend},
@@ -11757,6 +11759,11 @@
     {
 	while (cur != NULL)
 	{
+	    if (cur->match.regprog == 0)
+	    {
+		cur = cur->next;
+		continue;
+	    }
 	    dict = dict_alloc();
 	    if (dict == NULL)
 		return;
@@ -14298,7 +14305,58 @@
 	return;
     }
 
-    rettv->vval.v_number = match_add(curwin, grp, pat, prio, id);
+    rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL);
+#endif
+}
+
+/*
+ * "matchaddpos()" function
+ */
+    static void
+f_matchaddpos(argvars, rettv)
+    typval_T	*argvars UNUSED;
+    typval_T	*rettv UNUSED;
+{
+#ifdef FEAT_SEARCH_EXTRA
+    char_u	buf[NUMBUFLEN];
+    char_u	*grp = get_tv_string_buf_chk(&argvars[0], buf);	/* group */
+    char_u	*pat = NULL;	/* pattern */
+    int		prio = 10;	/* default priority */
+    int		id = -1;
+    int		error = FALSE;
+    list_T	*l;
+    listitem_T	*li;
+
+    rettv->vval.v_number = -1;
+
+    if (grp == NULL)
+	return;
+
+    if (argvars[1].v_type != VAR_LIST)
+    {
+	EMSG2(_(e_listarg), "matchaddpos()");
+	return;
+    }
+    l = argvars[1].vval.v_list;
+    if (l == NULL)
+	return;
+
+    if (argvars[2].v_type != VAR_UNKNOWN)
+    {
+	prio = get_tv_number_chk(&argvars[2], &error);
+	if (argvars[3].v_type != VAR_UNKNOWN)
+	    id = get_tv_number_chk(&argvars[3], &error);
+    }
+    if (error == TRUE)
+	return;
+    /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
+    if (id >= 1 && id <= 2)
+    {
+	EMSGN("E798: ID is reserved for \":match\": %ld", id);
+	return;
+    }
+
+    rettv->vval.v_number = match_add(curwin, grp, NULL, prio, id, l);
 #endif
 }
 
@@ -16801,7 +16859,7 @@
 	    match_add(curwin, get_dict_string(d, (char_u *)"group", FALSE),
 		    get_dict_string(d, (char_u *)"pattern", FALSE),
 		    (int)get_dict_number(d, (char_u *)"priority"),
-		    (int)get_dict_number(d, (char_u *)"id"));
+		    (int)get_dict_number(d, (char_u *)"id"), NULL);
 	    li = li->li_next;
 	}
 	rettv->vval.v_number = 0;
diff -r bed71c37618c src/ex_docmd.c
--- a/src/ex_docmd.c	Thu May 29 14:36:29 2014 +0200
+++ b/src/ex_docmd.c	Mon Jun 02 18:58:10 2014 +0400
@@ -11489,7 +11489,7 @@
 
 	    c = *end;
 	    *end = NUL;
-	    match_add(curwin, g, p + 1, 10, id);
+	    match_add(curwin, g, p + 1, 10, id, NULL);
 	    vim_free(g);
 	    *end = c;
 	}
diff -r bed71c37618c src/proto/window.pro
--- a/src/proto/window.pro	Thu May 29 14:36:29 2014 +0200
+++ b/src/proto/window.pro	Mon Jun 02 18:58:10 2014 +0400
@@ -75,7 +75,7 @@
 void switch_buffer __ARGS((buf_T **save_curbuf, buf_T *buf));
 void restore_buffer __ARGS((buf_T *save_curbuf));
 int win_hasvertsplit __ARGS((void));
-int match_add __ARGS((win_T *wp, char_u *grp, char_u *pat, int prio, int id));
+int match_add __ARGS((win_T *wp, char_u *grp, char_u *pat, int prio, int id, list_T *pos));
 int match_delete __ARGS((win_T *wp, int id, int perr));
 void clear_matches __ARGS((win_T *wp));
 matchitem_T *get_match __ARGS((win_T *wp, int id));
diff -r bed71c37618c src/screen.c
--- a/src/screen.c	Thu May 29 14:36:29 2014 +0200
+++ b/src/screen.c	Mon Jun 02 18:58:10 2014 +0400
@@ -144,7 +144,8 @@
 static void end_search_hl __ARGS((void));
 static void init_search_hl __ARGS((win_T *wp));
 static void prepare_search_hl __ARGS((win_T *wp, linenr_T lnum));
-static void next_search_hl __ARGS((win_T *win, match_T *shl, linenr_T lnum, colnr_T mincol));
+static void next_search_hl __ARGS((win_T *win, match_T *shl, linenr_T lnum, colnr_T mincol, matchitem_T *cur));
+static int next_search_hl_pos __ARGS((match_T *shl, linenr_T lnum, posmatch_T *pos, colnr_T mincol));
 #endif
 static void screen_start_highlight __ARGS((int attr));
 static void screen_char __ARGS((unsigned off, int row, int col));
@@ -2929,6 +2930,8 @@
     match_T	*shl;			/* points to search_hl or a match */
     int		shl_flag;		/* flag to indicate whether search_hl
 					   has been processed or not */
+    int		pos_inprogress;		/* marks that position match search is
+					   in progress */
     int		prevcol_hl_flag;	/* flag to indicate whether prevcol
 					   equals startcol of search_hl or one
 					   of the matches */
@@ -3439,44 +3442,43 @@
 	shl->startcol = MAXCOL;
 	shl->endcol = MAXCOL;
 	shl->attr_cur = 0;
-	if (shl->rm.regprog != NULL)
-	{
-	    v = (long)(ptr - line);
-	    next_search_hl(wp, shl, lnum, (colnr_T)v);
-
-	    /* Need to get the line again, a multi-line regexp may have made it
-	     * invalid. */
-	    line = ml_get_buf(wp->w_buffer, lnum, FALSE);
-	    ptr = line + v;
-
-	    if (shl->lnum != 0 && shl->lnum <= lnum)
-	    {
-		if (shl->lnum == lnum)
-		    shl->startcol = shl->rm.startpos[0].col;
+	v = (long)(ptr - line);
+	if (cur != NULL)
+	    cur->pos.cur = 0;
+	next_search_hl(wp, shl, lnum, (colnr_T)v, cur);
+
+	/* Need to get the line again, a multi-line regexp may have made it
+	    * invalid. */
+	line = ml_get_buf(wp->w_buffer, lnum, FALSE);
+	ptr = line + v;
+
+	if (shl->lnum != 0 && shl->lnum <= lnum)
+	{
+	    if (shl->lnum == lnum)
+		shl->startcol = shl->rm.startpos[0].col;
+	    else
+		shl->startcol = 0;
+	    if (lnum == shl->lnum + shl->rm.endpos[0].lnum
+						- shl->rm.startpos[0].lnum)
+		shl->endcol = shl->rm.endpos[0].col;
+	    else
+		shl->endcol = MAXCOL;
+	    /* Highlight one character for an empty match. */
+	    if (shl->startcol == shl->endcol)
+	    {
+#ifdef FEAT_MBYTE
+		if (has_mbyte && line[shl->endcol] != NUL)
+		    shl->endcol += (*mb_ptr2len)(line + shl->endcol);
 		else
-		    shl->startcol = 0;
-		if (lnum == shl->lnum + shl->rm.endpos[0].lnum
-						  - shl->rm.startpos[0].lnum)
-		    shl->endcol = shl->rm.endpos[0].col;
-		else
-		    shl->endcol = MAXCOL;
-		/* Highlight one character for an empty match. */
-		if (shl->startcol == shl->endcol)
-		{
-#ifdef FEAT_MBYTE
-		    if (has_mbyte && line[shl->endcol] != NUL)
-			shl->endcol += (*mb_ptr2len)(line + shl->endcol);
-		    else
-#endif
-			++shl->endcol;
-		}
-		if ((long)shl->startcol < v)  /* match at leftcol */
-		{
-		    shl->attr_cur = shl->attr;
-		    search_attr = shl->attr;
-		}
-		area_highlighting = TRUE;
-	    }
+#endif
+		    ++shl->endcol;
+	    }
+	    if ((long)shl->startcol < v)  /* match at leftcol */
+	    {
+		shl->attr_cur = shl->attr;
+		search_attr = shl->attr;
+	    }
+	    area_highlighting = TRUE;
 	}
 	if (shl != &search_hl && cur != NULL)
 	    cur = cur->next;
@@ -3488,7 +3490,7 @@
      * when Visual mode is active, because it's not clear what is selected
      * then. */
     if (wp->w_p_cul && lnum == wp->w_cursor.lnum
-					 && !(wp == curwin  && VIsual_active))
+					 && !(wp == curwin && VIsual_active))
     {
 	line_attr = hl_attr(HLF_CUL);
 	area_highlighting = TRUE;
@@ -3792,7 +3794,11 @@
 		    }
 		    else
 			shl = &cur->hl;
-		    while (shl->rm.regprog != NULL)
+		    if (cur != NULL)
+			cur->pos.cur = 0;
+		    pos_inprogress = TRUE;
+		    while (shl->rm.regprog != NULL ||
+			   (cur != NULL && pos_inprogress))
 		    {
 			if (shl->startcol != MAXCOL
 				&& v >= (long)shl->startcol
@@ -3803,8 +3809,9 @@
 			else if (v == (long)shl->endcol)
 			{
 			    shl->attr_cur = 0;
-
-			    next_search_hl(wp, shl, lnum, (colnr_T)v);
+			    next_search_hl(wp, shl, lnum, (colnr_T)v, cur);
+			    pos_inprogress = cur == NULL || cur->pos.cur == 0 ?
+				    FALSE : TRUE;
 
 			    /* Need to get the line again, a multi-line regexp
 			     * may have made it invalid. */
@@ -7277,6 +7284,8 @@
     match_T	*shl;		/* points to search_hl or a match */
     int		shl_flag;	/* flag to indicate whether search_hl
 				   has been processed or not */
+    int		pos_inprogress;	/* marks that position match search is
+				   in progress */
     int		n;
 
     /*
@@ -7311,10 +7320,16 @@
 		shl->first_lnum = wp->w_topline;
 # endif
 	    }
+	    if (cur != NULL)
+		cur->pos.cur = 0;
+	    pos_inprogress = TRUE;
 	    n = 0;
-	    while (shl->first_lnum < lnum && shl->rm.regprog != NULL)
-	    {
-		next_search_hl(wp, shl, shl->first_lnum, (colnr_T)n);
+	    while (shl->first_lnum < lnum && (shl->rm.regprog != NULL ||
+					      (cur != NULL && pos_inprogress)))
+	    {
+		next_search_hl(wp, shl, shl->first_lnum, (colnr_T)n, cur);
+		pos_inprogress = cur == NULL || cur->pos.cur == 0 ?
+			FALSE : TRUE;
 		if (shl->lnum != 0)
 		{
 		    shl->first_lnum = shl->lnum
@@ -7343,11 +7358,12 @@
  * Careful: Any pointers for buffer lines will become invalid.
  */
     static void
-next_search_hl(win, shl, lnum, mincol)
-    win_T	*win;
-    match_T	*shl;		/* points to search_hl or a match */
-    linenr_T	lnum;
-    colnr_T	mincol;		/* minimal column for a match */
+next_search_hl(win, shl, lnum, mincol, cur)
+    win_T	    *win;
+    match_T	    *shl;	/* points to search_hl or a match */
+    linenr_T	    lnum;
+    colnr_T	    mincol;	/* minimal column for a match */
+    matchitem_T	    *cur;	/* to retrieve match postions if any */
 {
     linenr_T	l;
     colnr_T	matchcol;
@@ -7415,26 +7431,35 @@
 	    matchcol = shl->rm.endpos[0].col;
 
 	shl->lnum = lnum;
-	nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum, matchcol,
+	if (shl->rm.regprog != NULL)
+	{
+	    nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum,
+		    matchcol,
 #ifdef FEAT_RELTIME
-		&(shl->tm)
+		    &(shl->tm)
 #else
-		NULL
-#endif
-		);
-	if (called_emsg || got_int)
-	{
-	    /* Error while handling regexp: stop using this regexp. */
-	    if (shl == &search_hl)
-	    {
-		/* don't free regprog in the match list, it's a copy */
-		vim_regfree(shl->rm.regprog);
-		SET_NO_HLSEARCH(TRUE);
-	    }
-	    shl->rm.regprog = NULL;
-	    shl->lnum = 0;
-	    got_int = FALSE;  /* avoid the "Type :quit to exit Vim" message */
-	    break;
+		    NULL
+#endif
+		    );
+	    if (called_emsg || got_int)
+	    {
+		/* Error while handling regexp: stop using this regexp. */
+		if (shl == &search_hl)
+		{
+		    /* don't free regprog in the match list, it's a copy */
+		    vim_regfree(shl->rm.regprog);
+		    SET_NO_HLSEARCH(TRUE);
+		}
+		shl->rm.regprog = NULL;
+		shl->lnum = 0;
+		got_int = FALSE;  /* avoid the "Type :quit to exit Vim"
+				     message */
+		break;
+	    }
+	}
+	else if (cur != NULL)
+	{
+	    nmatched = next_search_hl_pos(shl, lnum, &(cur->pos), matchcol);
 	}
 	if (nmatched == 0)
 	{
@@ -7453,6 +7478,60 @@
 }
 #endif
 
+    static int
+next_search_hl_pos(shl, lnum, pos, mincol)
+    match_T	    *shl;	/* points to a match */
+    linenr_T	    lnum;
+    posmatch_T	    *pos;	/* match positions */
+    colnr_T	    mincol;	/* minimal column for a match */
+{
+    int	    i;
+    int     bot = -1;
+
+    shl->lnum = 0;
+    for (i = pos->cur; i < MAXPOSMATCH; i++)
+    {
+	if (pos->m[i].lnum == 0)
+	    break;
+	if (pos->m[i].col < mincol)
+	    continue;
+	if (pos->m[i].lnum == lnum)
+	{
+	    if (shl->lnum == lnum)
+	    {
+		/* partially sort positions by column numbers
+		 * on the same line */
+		if (pos->m[i].col < pos->m[bot].col)
+		{
+		    llpos_T	tmp = pos->m[i];
+
+		    pos->m[i] = pos->m[bot];
+		    pos->m[bot] = tmp;
+		}
+	    }
+	    else
+	    {
+		bot = i;
+		shl->lnum = lnum;
+	    }
+	}
+    }
+    pos->cur = 0;
+    if (shl->lnum == lnum)
+    {
+	colnr_T	start = pos->m[bot].col == 0 ? 0 : pos->m[bot].col - 1;
+	colnr_T	end = pos->m[bot].col == 0 ? MAXCOL : start + pos->m[bot].len;
+
+	shl->rm.startpos[0].lnum = 0;
+	shl->rm.startpos[0].col = start;
+	shl->rm.endpos[0].lnum = 0;
+	shl->rm.endpos[0].col = end;
+	pos->cur = bot + 1;
+	return TRUE;
+    }
+    return FALSE;
+}
+
       static void
 screen_start_highlight(attr)
       int	attr;
diff -r bed71c37618c src/structs.h
--- a/src/structs.h	Thu May 29 14:36:29 2014 +0200
+++ b/src/structs.h	Mon Jun 02 18:58:10 2014 +0400
@@ -1927,6 +1927,31 @@
 #endif
 } match_T;
 
+#define MAXPOSMATCH 8
+
+/*
+ * Same as lpos_T, but with additional field len.
+ */
+typedef struct
+{
+    linenr_T	lnum;	/* line number */
+    colnr_T	col;	/* column number */
+    int		len;	/* length: 0 - to the end of line */
+} llpos_T;
+
+/*
+ * posmatch_T provides an array for storing match items for matchaddpos()
+ * function.
+ */
+typedef struct posmatch posmatch_T;
+struct posmatch
+{
+    llpos_T	m[MAXPOSMATCH];	    /* array of positions */
+    int		cur;		    /* internal position counter */
+    int		topl;		    /* top buffer line */
+    int		botl;		    /* bottom buffer line */
+};
+
 /*
  * matchitem_T provides a linked list for storing match items for ":match" and
  * the match functions.
@@ -1940,6 +1965,7 @@
     char_u	*pattern;   /* pattern to highlight */
     int		hlg_id;	    /* highlight group ID */
     regmmatch_T	match;	    /* regexp program for pattern */
+    posmatch_T	pos;	    /* position matches */
     match_T	hl;	    /* struct for doing the actual highlighting */
 };
 
diff -r bed71c37618c src/testdir/test63.in
--- a/src/testdir/test63.in	Thu May 29 14:36:29 2014 +0200
+++ b/src/testdir/test63.in	Mon Jun 02 18:58:10 2014 +0400
@@ -1,5 +1,5 @@
 Test for ":match", ":2match", ":3match", "clearmatches()", "getmatches()",
-"matchadd()", "matcharg()", "matchdelete()", and "setmatches()".
+"matchadd()", "matchaddpos", "matcharg()", "matchdelete()", and "setmatches()".
 
 STARTTEST
 :so small.vim
@@ -147,6 +147,27 @@
 :unlet rf1
 :unlet rf2
 :unlet rf3
+:" --- Check that "matchaddpos()" positions matches correctly
+:let @r .= "*** Test 11: "
+:set nolazyredraw
+:call setline(1, 'test()')
+:call matchaddpos("MyGroup1", [[1, 5], [1, 6]], 10, 3)
+:redraw!
+:let v1 = screenattr(1, 1)
+:let v2 = screenattr(1, 5)
+:let v3 = screenattr(1, 6)
+:let @r .= v1."\n"
+:let @r .= v2."\n"
+:let @r .= v3."\n"
+:if v1 != v2 && v2 == v3
+:  let @r .= "OK\n"
+:else
+:  let @r .= "FAILED\n"
+:endif
+:call clearmatches()
+:unlet v1
+:unlet v2
+:unlet v3
 :highlight clear MyGroup1
 :highlight clear MyGroup2
 :highlight clear MyGroup3
diff -r bed71c37618c src/window.c
--- a/src/window.c	Thu May 29 14:36:29 2014 +0200
+++ b/src/window.c	Mon Jun 02 18:58:10 2014 +0400
@@ -6729,20 +6729,22 @@
  * Return ID of added match, -1 on failure.
  */
     int
-match_add(wp, grp, pat, prio, id)
+match_add(wp, grp, pat, prio, id, pos)
     win_T	*wp;
     char_u	*grp;
     char_u	*pat;
     int		prio;
     int		id;
+    list_T	*pos;
 {
-    matchitem_T *cur;
-    matchitem_T *prev;
-    matchitem_T *m;
+    matchitem_T	*cur;
+    matchitem_T	*prev;
+    matchitem_T	*m;
     int		hlg_id;
-    regprog_T	*regprog;
-
-    if (*grp == NUL || *pat == NUL)
+    regprog_T	*regprog = NULL;
+    int		rtype = SOME_VALID;
+
+    if (*grp == NUL || (pat != NULL && *pat == NUL))
 	return -1;
     if (id < -1 || id == 0)
     {
@@ -6767,7 +6769,7 @@
 	EMSG2(_(e_nogroup), grp);
 	return -1;
     }
-    if ((regprog = vim_regcomp(pat, RE_MAGIC)) == NULL)
+    if (pat != NULL && (regprog = vim_regcomp(pat, RE_MAGIC)) == NULL)
     {
 	EMSG2(_(e_invarg2), pat);
 	return -1;
@@ -6788,12 +6790,114 @@
     m = (matchitem_T *)alloc(sizeof(matchitem_T));
     m->id = id;
     m->priority = prio;
-    m->pattern = vim_strsave(pat);
+    m->pattern = pat == NULL ? NULL : vim_strsave(pat);
+    m->pos.cur = 0;
     m->hlg_id = hlg_id;
     m->match.regprog = regprog;
     m->match.rmm_ic = FALSE;
     m->match.rmm_maxcol = 0;
 
+    /* Set up position matches */
+    if (pos != NULL)
+    {
+	int	    topl = 0;
+	int	    botl = 0;
+	listitem_T  *li = pos->lv_first;
+	int	    i;
+
+	for (i = 0; i < MAXPOSMATCH; i++)
+	{
+	    linenr_T	lnum = 0;
+	    colnr_T	col = 0;
+	    int		len = 1;
+	    list_T	*subl;
+	    listitem_T	*subli;
+	    int		error;
+
+	    if (li == NULL)
+	    {
+		m->pos.m[i].lnum = 0;
+		break;
+	    }
+	    if (li->li_tv.v_type == VAR_LIST)
+	    {
+		subl = li->li_tv.vval.v_list;
+		if (subl == NULL)
+		    goto fail;
+		subli = subl->lv_first;
+		if (subli == NULL)
+		    goto fail;
+		lnum = get_tv_number_chk(&subli->li_tv, &error);
+		if (error == TRUE)
+		    goto fail;
+		m->pos.m[i].lnum = lnum;
+		m->pos.m[i].col = col;
+		m->pos.m[i].len = len;
+		if (lnum == 0)
+		{
+		    li = li->li_next;
+		    continue;
+		}
+		subli = subli->li_next;
+		if (subli != NULL)
+		{
+		    col = get_tv_number_chk(&subli->li_tv, &error);
+		    if (error == TRUE)
+			goto fail;
+		    subli = subli->li_next;
+		    if (subli != NULL)
+		    {
+			len = get_tv_number_chk(&subli->li_tv, &error);
+			if (error == TRUE)
+			    goto fail;
+		    }
+		}
+		m->pos.m[i].col = col;
+		m->pos.m[i].len = len;
+	    }
+	    else if (li->li_tv.v_type == VAR_NUMBER)
+	    {
+		if (li->li_tv.vval.v_number == 0)
+		{
+		    li = li->li_next;
+		    continue;
+		}
+		m->pos.m[i].lnum = li->li_tv.vval.v_number;
+		m->pos.m[i].col = 0;
+	    }
+	    else
+	    {
+		EMSG(_("List or number required"));
+		goto fail;
+	    }
+	    if (topl == 0 || lnum < topl)
+		topl = lnum;
+	    if (botl == 0 || lnum > botl)
+		botl = lnum;
+	    li = li->li_next;
+	}
+	/* Calculate top and bottom lines for redrawing area */
+	if (topl != 0)
+	{
+	    if (wp->w_buffer->b_mod_set)
+	    {
+		if (wp->w_buffer->b_mod_top > topl)
+		    wp->w_buffer->b_mod_top = topl;
+		if (wp->w_buffer->b_mod_bot < botl)
+		    wp->w_buffer->b_mod_bot = botl;
+	    }
+	    else
+	    {
+		wp->w_buffer->b_mod_top = topl;
+		wp->w_buffer->b_mod_bot = botl;
+	    }
+	    m->pos.topl = topl;
+	    m->pos.botl = botl;
+	    wp->w_buffer->b_mod_set = TRUE;
+	    rtype = VALID;
+	}
+    }
+
     /* Insert new match.  The match list is in ascending order with regard to
      * the match priorities. */
     cur = wp->w_match_head;
@@ -6809,8 +6913,12 @@
 	prev->next = m;
     m->next = cur;
 
-    redraw_later(SOME_VALID);
+    redraw_later(rtype);
     return id;
+
+fail:
+    vim_free(m);
+    return -1;
 }
 
 /*
@@ -6823,8 +6931,9 @@
     int		id;
     int		perr;
 {
-    matchitem_T *cur = wp->w_match_head;
-    matchitem_T *prev = cur;
+    matchitem_T	*cur = wp->w_match_head;
+    matchitem_T	*prev = cur;
+    int		rtype = SOME_VALID;
 
     if (id < 1)
     {
@@ -6850,8 +6959,25 @@
 	prev->next = cur->next;
     vim_regfree(cur->match.regprog);
     vim_free(cur->pattern);
+    if (cur->pos.topl != 0)
+    {
+	if (wp->w_buffer->b_mod_set)
+	{
+	    if (wp->w_buffer->b_mod_top > cur->pos.topl)
+		wp->w_buffer->b_mod_top = cur->pos.topl;
+	    if (wp->w_buffer->b_mod_bot < cur->pos.botl)
+		wp->w_buffer->b_mod_bot = cur->pos.botl;
+	}
+	else
+	{
+	    wp->w_buffer->b_mod_top = cur->pos.topl;
+	    wp->w_buffer->b_mod_bot = cur->pos.botl;
+	}
+	wp->w_buffer->b_mod_set = TRUE;
+	rtype = VALID;
+    }
     vim_free(cur);
-    redraw_later(SOME_VALID);
+    redraw_later(rtype);
     return 0;
 }
 

Raspunde prin e-mail lui