summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvimboss <devnull@localhost>2007-07-26 20:58:42 +0000
committervimboss <devnull@localhost>2007-07-26 20:58:42 +0000
commit185545ff5851e90f37c07aa1aee027a5faf09bb0 (patch)
tree499b2caf889484c944c88eafc6a7c5f7c73838cb
parent4129738516a95c36df5ee1eb3702d0bb10bf8b96 (diff)
downloadvim-185545ff5851e90f37c07aa1aee027a5faf09bb0.tar.gz
updated for version 7.1-040v7.1.040v7-1-040
-rw-r--r--runtime/doc/eval.txt89
-rw-r--r--runtime/doc/pattern.txt16
-rw-r--r--runtime/doc/usr_41.txt9
-rw-r--r--src/eval.c188
-rw-r--r--src/ex_docmd.c33
-rw-r--r--src/proto/window.pro4
-rw-r--r--src/screen.c216
-rw-r--r--src/structs.h40
-rw-r--r--src/syntax.c2
-rw-r--r--src/testdir/Makefile4
-rw-r--r--src/testdir/test63.in157
-rw-r--r--src/testdir/test63.ok11
-rw-r--r--src/version.c2
-rw-r--r--src/window.c181
14 files changed, 833 insertions, 119 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index a18b048c..95ef5372 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -1,4 +1,4 @@
-*eval.txt* For Vim version 7.1. Last change: 2007 Jul 11
+*eval.txt* For Vim version 7.1. Last change: 2007 Jul 25
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -1557,6 +1557,7 @@ call( {func}, {arglist} [, {dict}])
changenr() Number current change number
char2nr( {expr}) Number ASCII value of first char in {expr}
cindent( {lnum}) Number C indent for line {lnum}
+clearmatches() None clear all matches
col( {expr}) Number column nr of cursor or mark
complete({startcol}, {matches}) String set Insert mode completion
complete_add( {expr}) Number add completion match
@@ -1622,6 +1623,7 @@ getftype( {fname}) String description of type of file {fname}
getline( {lnum}) String line {lnum} of current buffer
getline( {lnum}, {end}) List lines {lnum} to {end} of current buffer
getloclist({nr}) List list of location list items
+getmatches() List list of current matches
getpos( {expr}) List position of cursor, mark, etc.
getqflist() List list of quickfix items
getreg( [{regname} [, 1]]) String contents of register
@@ -1676,7 +1678,10 @@ mapcheck( {name}[, {mode} [, {abbr}]])
String check for mappings matching {name}
match( {expr}, {pat}[, {start}[, {count}]])
Number position where {pat} matches in {expr}
+matchadd( {group}, {pattern}[, {priority}[, {id}]])
+ Number highlight {pattern} with {group}
matcharg( {nr}) List arguments of |:match|
+matchdelete( {id}) Number delete match identified by {id}
matchend( {expr}, {pat}[, {start}[, {count}]])
Number position where {pat} ends in {expr}
matchlist( {expr}, {pat}[, {start}[, {count}]])
@@ -1731,6 +1736,7 @@ setcmdpos( {pos}) Number set cursor position in command-line
setline( {lnum}, {line}) Number set line {lnum} to {line}
setloclist( {nr}, {list}[, {action}])
Number modify location list using {list}
+setmatches( {list}) Number restore a list of matches
setpos( {expr}, {list}) none set the {expr} position to {list}
setqflist( {list}[, {action}]) Number modify quickfix list using {list}
setreg( {n}, {v}[, {opt}]) Number set register to value and type
@@ -2012,6 +2018,10 @@ cindent({lnum}) *cindent()*
feature, -1 is returned.
See |C-indenting|.
+clearmatches() *clearmatches()*
+ Clears all matches previously defined by |matchadd()| and the
+ |:match| commands.
+
*col()*
col({expr}) The result is a Number, which is the byte index of the column
position given with {expr}. The accepted positions are:
@@ -2918,6 +2928,28 @@ getloclist({nr}) *getloclist()*
returned. For an invalid window number {nr}, an empty list is
returned. Otherwise, same as getqflist().
+getmatches() *getmatches()*
+ Returns a |List| with all matches previously defined by
+ |matchadd()| and the |:match| commands. |getmatches()| is
+ useful in combination with |setmatches()|, as |setmatches()|
+ can restore a list of matches saved by |getmatches()|.
+ Example: >
+ :echo getmatches()
+< [{'group': 'MyGroup1', 'pattern': 'TODO',
+ 'priority': 10, 'id': 1}, {'group': 'MyGroup2',
+ 'pattern': 'FIXME', 'priority': 10, 'id': 2}] >
+ :let m = getmatches()
+ :call clearmatches()
+ :echo getmatches()
+< [] >
+ :call setmatches(m)
+ :echo getmatches()
+< [{'group': 'MyGroup1', 'pattern': 'TODO',
+ 'priority': 10, 'id': 1}, {'group': 'MyGroup2',
+ 'pattern': 'FIXME', 'priority': 10, 'id': 2}] >
+ :unlet m
+<
+
getqflist() *getqflist()*
Returns a list with all the current quickfix errors. Each
list item is a dictionary with these entries:
@@ -3622,6 +3654,44 @@ match({expr}, {pat}[, {start}[, {count}]]) *match()*
the pattern. 'smartcase' is NOT used. The matching is always
done like 'magic' is set and 'cpoptions' is empty.
+ *matchadd()* *E798* *E799* *E801*
+matchadd({group}, {pattern}[, {priority}[, {id}]])
+ Defines a pattern to be highlighted in the current window (a
+ "match"). It will be highlighted with {group}. Returns an
+ identification number (ID), which can be used to delete the
+ match using |matchdelete()|.
+
+ The optional {priority} argument assigns a priority to the
+ match. A match with a high priority will have its
+ highlighting overrule that of a match with a lower priority.
+ A priority is specified as an integer (negative numbers are no
+ exception). If the {priority} argument is not specified, the
+ default priority is 10. The priority of 'hlsearch' is zero,
+ hence all matches with a priority greater than zero will
+ overrule it. Syntax highlighting (see 'syntax') is a separate
+ mechanism, and regardless of the chosen priority a match will
+ always overrule syntax highlighting.
+
+ The optional {id} argument allows the request for a specific
+ match ID. If a specified ID is already taken, an error
+ message will appear and the match will not be added. An ID
+ is specified as a positive integer (zero excluded). IDs 1, 2
+ and 3 are reserved for |:match|, |:2match| and |:3match|,
+ respectively. If the {id} argument is not specified,
+ |matchadd()| automatically chooses a free ID.
+
+ The number of matches is not limited, as it is the case with
+ the |:match| commands.
+
+ Example: >
+ :highlight MyGroup ctermbg=green guibg=green
+ :let m = matchadd("MyGroup", "TODO")
+< Deletion of the pattern: >
+ :call matchdelete(m)
+
+< A list of matches defined by |matchadd()| and |:match| are
+ available from |getmatches()|. All matches can be deleted in
+ one operation by |clearmatches()|.
matcharg({nr}) *matcharg()*
Selects the {nr} match item, as set with a |:match|,
@@ -3631,8 +3701,15 @@ matcharg({nr}) *matcharg()*
The pattern used.
When {nr} is not 1, 2 or 3 returns an empty |List|.
When there is no match item set returns ['', ''].
- This is usef to save and restore a |:match|.
+ This is useful to save and restore a |:match|.
+ Highlighting matches using the |:match| commands are limited
+ to three matches. |matchadd()| does not have this limitation.
+matchdelete({id}) *matchdelete()* *E802* *E803*
+ Deletes a match with ID {id} previously defined by |matchadd()|
+ or one of the |:match| commands. Returns 0 if succesfull,
+ otherwise -1. See example for |matchadd()|. All matches can
+ be deleted in one operation by |clearmatches()|.
matchend({expr}, {pat}[, {start}[, {count}]]) *matchend()*
Same as match(), but return the index of first character after
@@ -4385,7 +4462,13 @@ setloclist({nr}, {list} [, {action}]) *setloclist()*
When {nr} is zero the current window is used. For a location
list window, the displayed location list is modified. For an
invalid window number {nr}, -1 is returned.
- Otherwise, same as setqflist().
+ Otherwise, same as |setqflist()|.
+ Also see |location-list|.
+
+setmatches({list}) *setmatches()*
+ Restores a list of matches saved by |getmatches()|. Returns 0
+ if succesfull, otherwise -1. All current matches are cleared
+ before the list is restored. See example for |getmatches()|.
*setpos()*
setpos({expr}, {list})
diff --git a/runtime/doc/pattern.txt b/runtime/doc/pattern.txt
index 22c5782a..5331cfec 100644
--- a/runtime/doc/pattern.txt
+++ b/runtime/doc/pattern.txt
@@ -1212,7 +1212,10 @@ Finally, these constructs are unique to Perl:
{group} must exist at the moment this command is executed.
The {group} highlighting still applies when a character is
- to be highlighted for 'hlsearch'.
+ to be highlighted for 'hlsearch', as the highlighting for
+ matches is given higher priority than that of 'hlsearch'.
+ Syntax highlighting (see 'syntax') is also overruled by
+ matches.
Note that highlighting the last used search pattern with
'hlsearch' is used in all windows, while the pattern defined
@@ -1226,8 +1229,15 @@ Finally, these constructs are unique to Perl:
display you may get unexpected results. That is because Vim
looks for a match in the line where redrawing starts.
- Also see |matcharg()|, it returns the highlight group and
- pattern of a previous :match command.
+ Also see |matcharg()|and |getmatches()|. The former returns
+ the highlight group and pattern of a previous |:match|
+ command. The latter returns a list with highlight groups and
+ patterns defined by both |matchadd()| and |:match|.
+
+ Highlighting matches using |:match| are limited to three
+ matches (aside from |:match|, |:2match| and |:3match|are
+ available). |matchadd()| does not have this limitation and in
+ addition makes it possible to prioritize matches.
Another example, which highlights all characters in virtual
column 72 and more: >
diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt
index da5bf7ce..64cf78d3 100644
--- a/runtime/doc/usr_41.txt
+++ b/runtime/doc/usr_41.txt
@@ -763,13 +763,22 @@ Folding:
foldtextresult() get the text displayed for a closed fold
Syntax and highlighting:
+ clearmatches() clear all matches defined by |matchadd()| and
+ the |:match| commands
+ getmatches() get all matches defined by |matchadd()| and
+ the |:match| commands
hlexists() check if a highlight group exists
hlID() get ID of a highlight group
synID() get syntax ID at a specific position
synIDattr() get a specific attribute of a syntax ID
synIDtrans() get translated syntax ID
diff_hlID() get highlight ID for diff mode at a position
+ matchadd() define a pattern to highlight (a "match")
matcharg() get info about |:match| arguments
+ matchdelete() delete a match defined by |matchadd()| or a
+ |:match| command
+ setmatches() restore a list of matches saved by
+ |getmatches()|
Spelling:
spellbadword() locate badly spelled word at or after cursor
diff --git a/src/eval.c b/src/eval.c
index 5dc6c01d..10df05b4 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -475,6 +475,7 @@ static void f_call __ARGS((typval_T *argvars, typval_T *rettv));
static void f_changenr __ARGS((typval_T *argvars, typval_T *rettv));
static void f_char2nr __ARGS((typval_T *argvars, typval_T *rettv));
static void f_cindent __ARGS((typval_T *argvars, typval_T *rettv));
+static void f_clearmatches __ARGS((typval_T *argvars, typval_T *rettv));
static void f_col __ARGS((typval_T *argvars, typval_T *rettv));
#if defined(FEAT_INS_EXPAND)
static void f_complete __ARGS((typval_T *argvars, typval_T *rettv));
@@ -529,6 +530,7 @@ static void f_getfsize __ARGS((typval_T *argvars, typval_T *rettv));
static void f_getftime __ARGS((typval_T *argvars, typval_T *rettv));
static void f_getftype __ARGS((typval_T *argvars, typval_T *rettv));
static void f_getline __ARGS((typval_T *argvars, typval_T *rettv));
+static void f_getmatches __ARGS((typval_T *argvars, typval_T *rettv));
static void f_getpos __ARGS((typval_T *argvars, typval_T *rettv));
static void f_getqflist __ARGS((typval_T *argvars, typval_T *rettv));
static void f_getreg __ARGS((typval_T *argvars, typval_T *rettv));
@@ -577,7 +579,9 @@ static void f_map __ARGS((typval_T *argvars, typval_T *rettv));
static void f_maparg __ARGS((typval_T *argvars, typval_T *rettv));
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_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));
static void f_matchlist __ARGS((typval_T *argvars, typval_T *rettv));
static void f_matchstr __ARGS((typval_T *argvars, typval_T *rettv));
@@ -618,6 +622,7 @@ static void f_setbufvar __ARGS((typval_T *argvars, typval_T *rettv));
static void f_setcmdpos __ARGS((typval_T *argvars, typval_T *rettv));
static void f_setline __ARGS((typval_T *argvars, typval_T *rettv));
static void f_setloclist __ARGS((typval_T *argvars, typval_T *rettv));
+static void f_setmatches __ARGS((typval_T *argvars, typval_T *rettv));
static void f_setpos __ARGS((typval_T *argvars, typval_T *rettv));
static void f_setqflist __ARGS((typval_T *argvars, typval_T *rettv));
static void f_setreg __ARGS((typval_T *argvars, typval_T *rettv));
@@ -7046,6 +7051,7 @@ static struct fst
{"changenr", 0, 0, f_changenr},
{"char2nr", 1, 1, f_char2nr},
{"cindent", 1, 1, f_cindent},
+ {"clearmatches", 0, 0, f_clearmatches},
{"col", 1, 1, f_col},
#if defined(FEAT_INS_EXPAND)
{"complete", 2, 2, f_complete},
@@ -7102,6 +7108,7 @@ static struct fst
{"getftype", 1, 1, f_getftype},
{"getline", 1, 2, f_getline},
{"getloclist", 1, 1, f_getqflist},
+ {"getmatches", 0, 0, f_getmatches},
{"getpos", 1, 1, f_getpos},
{"getqflist", 0, 0, f_getqflist},
{"getreg", 0, 2, f_getreg},
@@ -7152,7 +7159,9 @@ static struct fst
{"maparg", 1, 3, f_maparg},
{"mapcheck", 1, 3, f_mapcheck},
{"match", 2, 4, f_match},
+ {"matchadd", 2, 4, f_matchadd},
{"matcharg", 1, 1, f_matcharg},
+ {"matchdelete", 1, 1, f_matchdelete},
{"matchend", 2, 4, f_matchend},
{"matchlist", 2, 4, f_matchlist},
{"matchstr", 2, 4, f_matchstr},
@@ -7193,6 +7202,7 @@ static struct fst
{"setcmdpos", 1, 1, f_setcmdpos},
{"setline", 2, 2, f_setline},
{"setloclist", 2, 3, f_setloclist},
+ {"setmatches", 1, 1, f_setmatches},
{"setpos", 2, 2, f_setpos},
{"setqflist", 1, 2, f_setqflist},
{"setreg", 2, 3, f_setreg},
@@ -8243,6 +8253,20 @@ f_cindent(argvars, rettv)
}
/*
+ * "clearmatches()" function
+ */
+/*ARGSUSED*/
+ static void
+f_clearmatches(argvars, rettv)
+ typval_T *argvars;
+ typval_T *rettv;
+{
+#ifdef FEAT_SEARCH_EXTRA
+ clear_matches(curwin);
+#endif
+}
+
+/*
* "col(string)" function
*/
static void
@@ -10278,6 +10302,40 @@ f_getline(argvars, rettv)
}
/*
+ * "getmatches()" function
+ */
+/*ARGSUSED*/
+ static void
+f_getmatches(argvars, rettv)
+ typval_T *argvars;
+ typval_T *rettv;
+{
+#ifdef FEAT_SEARCH_EXTRA
+ dict_T *dict;
+ matchitem_T *cur = curwin->w_match_head;
+
+ rettv->vval.v_number = 0;
+
+ if (rettv_list_alloc(rettv) == OK)
+ {
+ while (cur != NULL)
+ {
+ dict = dict_alloc();
+ if (dict == NULL)
+ return;
+ ++dict->dv_refcount;
+ dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id));
+ dict_add_nr_str(dict, "pattern", 0L, cur->pattern);
+ dict_add_nr_str(dict, "priority", (long)cur->priority, NULL);
+ dict_add_nr_str(dict, "id", (long)cur->id, NULL);
+ list_append_dict(rettv->vval.v_list, dict);
+ cur = cur->next;
+ }
+ }
+#endif
+}
+
+/*
* "getpos(string)" function
*/
static void
@@ -12448,6 +12506,42 @@ f_match(argvars, rettv)
}
/*
+ * "matchadd()" function
+ */
+ static void
+f_matchadd(argvars, rettv)
+ typval_T *argvars;
+ typval_T *rettv;
+{
+#ifdef FEAT_SEARCH_EXTRA
+ char_u buf[NUMBUFLEN];
+ char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */
+ char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */
+ int prio = 10; /* default priority */
+ int id = -1;
+ int error = FALSE;
+
+ rettv->vval.v_number = -1;
+
+ if (grp == NULL || pat == 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;
+ if (id >= 1 && id <= 3)
+ {
+ EMSGN("E798: ID is reserved for \":match\": %ld", id);
+ return;
+ }
+
+ rettv->vval.v_number = match_add(curwin, grp, pat, prio, id);
+#endif
+}
+
+/*
* "matcharg()" function
*/
static void
@@ -12458,20 +12552,42 @@ f_matcharg(argvars, rettv)
if (rettv_list_alloc(rettv) == OK)
{
#ifdef FEAT_SEARCH_EXTRA
- int mi = get_tv_number(&argvars[0]);
+ int id = get_tv_number(&argvars[0]);
+ matchitem_T *m;
- if (mi >= 1 && mi <= 3)
+ if (id >= 1 && id <= 3)
{
- list_append_string(rettv->vval.v_list,
- syn_id2name(curwin->w_match_id[mi - 1]), -1);
- list_append_string(rettv->vval.v_list,
- curwin->w_match_pat[mi - 1], -1);
+ if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
+ {
+ list_append_string(rettv->vval.v_list,
+ syn_id2name(m->hlg_id), -1);
+ list_append_string(rettv->vval.v_list, m->pattern, -1);
+ }
+ else
+ {
+ list_append_string(rettv->vval.v_list, NUL, -1);
+ list_append_string(rettv->vval.v_list, NUL, -1);
+ }
}
#endif
}
}
/*
+ * "matchdelete()" function
+ */
+ static void
+f_matchdelete(argvars, rettv)
+ typval_T *argvars;
+ typval_T *rettv;
+{
+#ifdef FEAT_SEARCH_EXTRA
+ rettv->vval.v_number = match_delete(curwin,
+ (int)get_tv_number(&argvars[0]), TRUE);
+#endif
+}
+
+/*
* "matchend()" function
*/
static void
@@ -14509,6 +14625,66 @@ f_setloclist(argvars, rettv)
}
/*
+ * "setmatches()" function
+ */
+ static void
+f_setmatches(argvars, rettv)
+ typval_T *argvars;
+ typval_T *rettv;
+{
+#ifdef FEAT_SEARCH_EXTRA
+ list_T *l;
+ listitem_T *li;
+ dict_T *d;
+
+ rettv->vval.v_number = -1;
+ if (argvars[0].v_type != VAR_LIST)
+ {
+ EMSG(_(e_listreq));
+ return;
+ }
+ if ((l = argvars[0].vval.v_list) != NULL)
+ {
+
+ /* To some extent make sure that we are dealing with a list from
+ * "getmatches()". */
+ li = l->lv_first;
+ while (li != NULL)
+ {
+ if (li->li_tv.v_type != VAR_DICT
+ || (d = li->li_tv.vval.v_dict) == NULL)
+ {
+ EMSG(_(e_invarg));
+ return;
+ }
+ if (!(dict_find(d, (char_u *)"group", -1) != NULL
+ && dict_find(d, (char_u *)"pattern", -1) != NULL
+ && dict_find(d, (char_u *)"priority", -1) != NULL
+ && dict_find(d, (char_u *)"id", -1) != NULL))
+ {
+ EMSG(_(e_invarg));
+ return;
+ }
+ li = li->li_next;
+ }
+
+ clear_matches(curwin);
+ li = l->lv_first;
+ while (li != NULL)
+ {
+ d = li->li_tv.vval.v_dict;
+ 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"));
+ li = li->li_next;
+ }
+ rettv->vval.v_number = 0;
+ }
+#endif
+}
+
+/*
* "setpos()" function
*/
/*ARGSUSED*/
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 3605a422..0d889942 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -10817,12 +10817,13 @@ ex_match(eap)
exarg_T *eap;
{
char_u *p;
+ char_u *g;
char_u *end;
int c;
- int mi;
+ int id;
if (eap->line2 <= 3)
- mi = eap->line2 - 1;
+ id = eap->line2;
else
{
EMSG(e_invcmd);
@@ -10831,13 +10832,7 @@ ex_match(eap)
/* First clear any old pattern. */
if (!eap->skip)
- {
- vim_free(curwin->w_match[mi].regprog);
- curwin->w_match[mi].regprog = NULL;
- vim_free(curwin->w_match_pat[mi]);
- curwin->w_match_pat[mi] = NULL;
- redraw_later(SOME_VALID); /* always need a redraw */
- }
+ match_delete(curwin, id, FALSE);
if (ends_excmd(*eap->arg))
end = eap->arg;
@@ -10848,15 +10843,7 @@ ex_match(eap)
{
p = skiptowhite(eap->arg);
if (!eap->skip)
- {
- curwin->w_match_id[mi] = syn_namen2id(eap->arg,
- (int)(p - eap->arg));
- if (curwin->w_match_id[mi] == 0)
- {
- EMSG2(_(e_nogroup), eap->arg);
- return;
- }
- }
+ g = vim_strnsave(eap->arg, (int)(p - eap->arg));
p = skipwhite(p);
if (*p == NUL)
{
@@ -10880,14 +10867,8 @@ ex_match(eap)
c = *end;
*end = NUL;
- curwin->w_match[mi].regprog = vim_regcomp(p + 1, RE_MAGIC);
- if (curwin->w_match[mi].regprog == NULL)
- {
- EMSG2(_(e_invarg2), p);
- *end = c;
- return;
- }
- curwin->w_match_pat[mi] = vim_strsave(p + 1);
+ match_add(curwin, g, p + 1, 10, id);
+ vim_free(g);
*end = c;
}
}
diff --git a/src/proto/window.pro b/src/proto/window.pro
index 45a90b82..bcf171c9 100644
--- a/src/proto/window.pro
+++ b/src/proto/window.pro
@@ -59,4 +59,8 @@ int min_rows __ARGS((void));
int only_one_window __ARGS((void));
void check_lnums __ARGS((int do_curwin));
int win_hasvertsplit __ARGS((void));
+int match_add __ARGS((win_T *wp, char_u *grp, char_u *pat, int prio, int id));
+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));
/* vim: set ft=c : */
diff --git a/src/screen.c b/src/screen.c
index 5c4fadde..11344c31 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -100,27 +100,7 @@ static int screen_attr = 0;
static int screen_cur_row, screen_cur_col; /* last known cursor position */
#ifdef FEAT_SEARCH_EXTRA
-/*
- * Struct used for highlighting 'hlsearch' matches for the last use search
- * pattern or a ":match" item.
- * For 'hlsearch' there is one pattern for all windows. For ":match" there is
- * a different pattern for each window.
- */
-typedef struct
-{
- regmmatch_T rm; /* points to the regexp program; contains last found
- match (may continue in next line) */
- buf_T *buf; /* the buffer to search for a match */
- linenr_T lnum; /* the line to search for a match */
- int attr; /* attributes to be used for a match */
- int attr_cur; /* attributes currently active in win_line() */
- linenr_T first_lnum; /* first lnum to search for multi-line pat */
- colnr_T startcol; /* in win_line() points to char where HL starts */
- colnr_T endcol; /* in win_line() points to char where HL ends */
-} match_T;
-
static match_T search_hl; /* used for 'hlsearch' highlight matching */
-static match_T match_hl[3]; /* used for ":match" highlight matching */
#endif
#ifdef FEAT_FOLDING
@@ -155,6 +135,7 @@ static void draw_vsep_win __ARGS((win_T *wp, int row));
static void redraw_custum_statusline __ARGS((win_T *wp));
#endif
#ifdef FEAT_SEARCH_EXTRA
+#define SEARCH_HL_PRIORITY 0
static void start_search_hl __ARGS((void));
static void end_search_hl __ARGS((void));
static void prepare_search_hl __ARGS((win_T *wp, linenr_T lnum));
@@ -787,6 +768,7 @@ win_update(wp)
w_topline got smaller a bit */
#endif
#ifdef FEAT_SEARCH_EXTRA
+ matchitem_T *cur; /* points to the match list */
int top_to_mod = FALSE; /* redraw above mod_top */
#endif
@@ -848,18 +830,20 @@ win_update(wp)
#endif
#ifdef FEAT_SEARCH_EXTRA
- /* Setup for ":match" and 'hlsearch' highlighting. Disable any previous
+ /* Setup for match and 'hlsearch' highlighting. Disable any previous
* match */
- for (i = 0; i < 3; ++i)
+ cur = wp->w_match_head;
+ while (cur != NULL)
{
- match_hl[i].rm = wp->w_match[i];
- if (wp->w_match_id[i] == 0)
- match_hl[i].attr = 0;
+ cur->hl.rm = cur->match;
+ if (cur->hlg_id == 0)
+ cur->hl.attr = 0;
else
- match_hl[i].attr = syn_id2attr(wp->w_match_id[i]);
- match_hl[i].buf = buf;
- match_hl[i].lnum = 0;
- match_hl[i].first_lnum = 0;
+ cur->hl.attr = syn_id2attr(cur->hlg_id);
+ cur->hl.buf = buf;
+ cur->hl.lnum = 0;
+ cur->hl.first_lnum = 0;
+ cur = cur->next;
}
search_hl.buf = buf;
search_hl.lnum = 0;
@@ -923,19 +907,25 @@ win_update(wp)
* change in one line may make the Search highlighting in a
* previous line invalid. Simple solution: redraw all visible
* lines above the change.
- * Same for a ":match" pattern.
+ * Same for a match pattern.
*/
if (search_hl.rm.regprog != NULL
&& re_multiline(search_hl.rm.regprog))
top_to_mod = TRUE;
else
- for (i = 0; i < 3; ++i)
- if (match_hl[i].rm.regprog != NULL
- && re_multiline(match_hl[i].rm.regprog))
+ {
+ cur = wp->w_match_head;
+ while (cur != NULL)
+ {
+ if (cur->match.regprog != NULL
+ && re_multiline(cur->match.regprog))
{
top_to_mod = TRUE;
break;
}
+ cur = cur->next;
+ }
+ }
#endif
}
#ifdef FEAT_FOLDING
@@ -2626,10 +2616,13 @@ win_line(wp, lnum, startrow, endrow, nochange)
int line_attr = 0; /* atrribute for the whole line */
#endif
#ifdef FEAT_SEARCH_EXTRA
- match_T *shl; /* points to search_hl or match_hl */
-#endif
-#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_MBYTE)
- int i;
+ matchitem_T *cur; /* points to the match list */
+ 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 prevcol_hl_flag; /* flag to indicate whether prevcol
+ equals startcol of search_hl or one
+ of the matches */
#endif
#ifdef FEAT_ARABIC
int prev_c = 0; /* previous Arabic character */
@@ -3074,12 +3067,20 @@ win_line(wp, lnum, startrow, endrow, nochange)
#ifdef FEAT_SEARCH_EXTRA
/*
- * Handle highlighting the last used search pattern and ":match".
- * Do this for both search_hl and match_hl[3].
+ * Handle highlighting the last used search pattern and matches.
+ * Do this for both search_hl and the match list.
*/
- for (i = 3; i >= 0; --i)
+ cur = wp->w_match_head;
+ shl_flag = FALSE;
+ while (cur != NULL || shl_flag == FALSE)
{
- shl = (i == 3) ? &search_hl : &match_hl[i];
+ if (shl_flag == FALSE)
+ {
+ shl = &search_hl;
+ shl_flag = TRUE;
+ }
+ else
+ shl = &cur->hl;
shl->startcol = MAXCOL;
shl->endcol = MAXCOL;
shl->attr_cur = 0;
@@ -3122,6 +3123,8 @@ win_line(wp, lnum, startrow, endrow, nochange)
area_highlighting = TRUE;
}
}
+ if (shl != &search_hl && cur != NULL)
+ cur = cur->next;
}
#endif
@@ -3388,13 +3391,24 @@ win_line(wp, lnum, startrow, endrow, nochange)
* After end, check for start/end of next match.
* When another match, have to check for start again.
* Watch out for matching an empty string!
- * Do this first for search_hl, then for match_hl, so that
- * ":match" overrules 'hlsearch'.
+ * Do this for 'search_hl' and the match list (ordered by
+ * priority).
*/
v = (long)(ptr - line);
- for (i = 3; i >= 0; --i)
+ cur = wp->w_match_head;
+ shl_flag = FALSE;
+ while (cur != NULL || shl_flag == FALSE)
{
- shl = (i == 3) ? &search_hl : &match_hl[i];
+ if (shl_flag == FALSE
+ && ((cur != NULL
+ && cur->priority > SEARCH_HL_PRIORITY)
+ || cur == NULL))
+ {
+ shl = &search_hl;
+ shl_flag = TRUE;
+ }
+ else
+ shl = &cur->hl;
while (shl->rm.regprog != NULL)
{
if (shl->startcol != MAXCOL
@@ -3442,17 +3456,32 @@ win_line(wp, lnum, startrow, endrow, nochange)
}
break;
}
+ if (shl != &search_hl && cur != NULL)
+ cur = cur->next;
}
- /* ":match" highlighting overrules 'hlsearch' */
- for (i = 0; i <= 3; ++i)
- if (i == 3)
- search_attr = search_hl.attr_cur;
- else if (match_hl[i].attr_cur != 0)
+ /* Use attributes from match with highest priority among
+ * 'search_hl' and the match list. */
+ search_attr = search_hl.attr_cur;
+ cur = wp->w_match_head;
+ shl_flag = FALSE;
+ while (cur != NULL || shl_flag == FALSE)
+ {
+ if (shl_flag == FALSE
+ && ((cur != NULL
+ && cur->priority > SEARCH_HL_PRIORITY)
+ || cur == NULL))
{
- search_attr = match_hl[i].attr_cur;
- break;
+ shl = &search_hl;
+ shl_flag = TRUE;
}
+ else
+ shl = &cur->hl;
+ if (shl->attr_cur != 0)
+ search_attr = shl->attr_cur;
+ if (shl != &search_hl && cur != NULL)
+ cur = cur->next;
+ }
}
#endif
@@ -3613,6 +3642,8 @@ win_line(wp, lnum, startrow, endrow, nochange)
* Draw it as a space with a composing char. */
if (utf_iscomposing(mb_c))
{
+ int i;
+
for (i = Screen_mco - 1; i > 0; --i)
u8cc[i] = u8cc[i - 1];
u8cc[0] = mb_c;
@@ -4256,14 +4287,29 @@ win_line(wp, lnum, startrow, endrow, nochange)
* highlight match at end of line. If it's beyond the last
* char on the screen, just overwrite that one (tricky!) Not
* needed when a '$' was displayed for 'list'. */
+#ifdef FEAT_SEARCH_EXTRA
+ prevcol_hl_flag = FALSE;
+ if (prevcol == (long)search_hl.startcol)
+ prevcol_hl_flag = TRUE;
+ else
+ {
+ cur = wp->w_match_head;
+ while (cur != NULL)
+ {
+ if (prevcol == (long)cur->hl.startcol)
+ {
+ prevcol_hl_flag = TRUE;
+ break;
+ }
+ cur = cur->next;
+ }
+ }
+#endif
if (lcs_eol == lcs_eol_one
&& ((area_attr != 0 && vcol == fromcol && c == NUL)
#ifdef FEAT_SEARCH_EXTRA
/* highlight 'hlsearch' match at end of line */
- || ((prevcol == (long)search_hl.startcol
- || prevcol == (long)match_hl[0].startcol
- || prevcol == (long)match_hl[1].startcol
- || prevcol == (long)match_hl[2].startcol)
+ || (prevcol_hl_flag == TRUE
# if defined(LINE_ATTR)
&& did_line_attr <= 1
# endif
@@ -4304,15 +4350,27 @@ win_line(wp, lnum, startrow, endrow, nochange)
#ifdef FEAT_SEARCH_EXTRA
if (area_attr == 0)
{
- for (i = 0; i <= 3; ++i)
+ /* Use attributes from match with highest priority among
+ * 'search_hl' and the match list. */
+ char_attr = search_hl.attr;
+ cur = wp->w_match_head;
+ shl_flag = FALSE;
+ while (cur != NULL || shl_flag == FALSE)
{
- if (i == 3)
- char_attr = search_hl.attr;
- else if ((ptr - line) - 1 == (long)match_hl[i].startcol)
+ if (shl_flag == FALSE
+ && ((cur != NULL
+ && cur->priority > SEARCH_HL_PRIORITY)
+ || cur == NULL))
{
- char_attr = match_hl[i].attr;
- break;
+ shl = &search_hl;
+ shl_flag = TRUE;
}
+ else
+ shl = &cur->hl;
+ if ((ptr - line) - 1 == (long)shl->startcol)
+ char_attr = shl->attr;
+ if (shl != &search_hl && cur != NULL)
+ cur = cur->next;
}
}
#endif
@@ -4462,6 +4520,8 @@ win_line(wp, lnum, startrow, endrow, nochange)
{
if (mb_utf8)
{
+ int i;
+
ScreenLinesUC[off] = mb_c;
if ((c & 0xff) == 0)
ScreenLines[off] = 0x80; /* avoid storing zero */
@@ -6320,7 +6380,7 @@ screen_puts_len(text, len, row, col, attr)
#ifdef FEAT_SEARCH_EXTRA
/*
- * Prepare for 'searchhl' highlighting.
+ * Prepare for 'hlsearch' highlighting.
*/
static void
start_search_hl()
@@ -6333,7 +6393,7 @@ start_search_hl()
}
/*
- * Clean up for 'searchhl' highlighting.
+ * Clean up for 'hlsearch' highlighting.
*/
static void
end_search_hl()
@@ -6353,18 +6413,28 @@ prepare_search_hl(wp, lnum)
win_T *wp;
linenr_T lnum;
{
- match_T *shl; /* points to search_hl or match_hl */
+ matchitem_T *cur; /* points to the match list */
+ 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 n;
- int i;
/*
* When using a multi-line pattern, start searching at the top
* of the window or just after a closed fold.
- * Do this both for search_hl and match_hl[3].
+ * Do this both for search_hl and the match list.
*/
- for (i = 3; i >= 0; --i)
+ cur = wp->w_match_head;
+ shl_flag = FALSE;
+ while (cur != NULL || shl_flag == FALSE)
{
- shl = (i == 3) ? &search_hl : &match_hl[i];
+ if (shl_flag == FALSE)
+ {
+ shl = &search_hl;
+ shl_flag = TRUE;
+ }
+ else
+ shl = &cur->hl;
if (shl->rm.regprog != NULL
&& shl->lnum == 0
&& re_multiline(shl->rm.regprog))
@@ -6399,11 +6469,13 @@ prepare_search_hl(wp, lnum)
}
}
}
+ if (shl != &search_hl && cur != NULL)
+ cur = cur->next;
}
}
/*
- * Search for a next 'searchl' or ":match" match.
+ * Search for a next 'hlsearch' or match.
* Uses shl->buf.
* Sets shl->lnum and shl->rm contents.
* Note: Assumes a previous match is always before "lnum", unless
@@ -6413,7 +6485,7 @@ prepare_search_hl(wp, lnum)
static void
next_search_hl(win, shl, lnum, mincol)
win_T *win;
- match_T *shl; /* points to search_hl or match_hl */
+ match_T *shl; /* points to search_hl or a match */
linenr_T lnum;
colnr_T mincol; /* minimal column for a match */
{
@@ -6481,7 +6553,7 @@ next_search_hl(win, shl, lnum, mincol)
/* Error while handling regexp: stop using this regexp. */
if (shl == &search_hl)
{
- /* don't free the regprog in match_hl[], it's a copy */
+ /* don't free regprog in the match list, it's a copy */
vim_free(shl->rm.regprog);
no_hlsearch = TRUE;
}
diff --git a/src/structs.h b/src/structs.h
index d531f4e3..c85fc05e 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1694,6 +1694,41 @@ struct frame_S
#define FR_COL 2 /* frame with a column of windows */
/*
+ * Struct used for highlighting 'hlsearch' matches, matches defined by
+ * ":match" and matches defined by match functions.
+ * For 'hlsearch' there is one pattern for all windows. For ":match" and the
+ * match functions there is a different pattern for each window.
+ */
+typedef struct
+{
+ regmmatch_T rm; /* points to the regexp program; contains last found
+ match (may continue in next line) */
+ buf_T *buf; /* the buffer to search for a match */
+ linenr_T lnum; /* the line to search for a match */
+ int attr; /* attributes to be used for a match */
+ int attr_cur; /* attributes currently active in win_line() */
+ linenr_T first_lnum; /* first lnum to search for multi-line pat */
+ colnr_T startcol; /* in win_line() points to char where HL starts */
+ colnr_T endcol; /* in win_line() points to char where HL ends */
+} match_T;
+
+/*
+ * matchitem_T provides a linked list for storing match items for ":match" and
+ * the match functions.
+ */
+typedef struct matchitem matchitem_T;
+struct matchitem
+{
+ matchitem_T *next;
+ int id; /* match ID */
+ int priority; /* match priority */
+ char_u *pattern; /* pattern to highlight */
+ int hlg_id; /* highlight group ID */
+ regmmatch_T match; /* regexp program for pattern */
+ match_T hl; /* struct for doing the actual highlighting */
+};
+
+/*
* Structure which contains all information that belongs to a window
*
* All row numbers are relative to the start of the window, except w_winrow.
@@ -1934,9 +1969,8 @@ struct window_S
#endif
#ifdef FEAT_SEARCH_EXTRA
- regmmatch_T w_match[3]; /* regexp programs for ":match" */
- char_u *(w_match_pat[3]); /* patterns for ":match" */
- int w_match_id[3]; /* highlight IDs for ":match" */
+ matchitem_T *w_match_head; /* head of match list */
+ int w_next_match_id; /* next match ID */
#endif
/*
diff --git a/src/syntax.c b/src/syntax.c
index ef962ef7..c47a6026 100644
--- a/src/syntax.c
+++ b/src/syntax.c
@@ -8504,7 +8504,7 @@ highlight_exists(name)
syn_id2name(id)
int id;
{
- if (id <= 0 || id >= highlight_ga.ga_len)
+ if (id <= 0 || id > highlight_ga.ga_len)
return (char_u *)"";
return HL_TABLE()[id - 1].sg_name;
}
diff --git a/src/testdir/Makefile b/src/testdir/Makefile
index 747b187f..667d1e9f 100644
--- a/src/testdir/Makefile
+++ b/src/testdir/Makefile
@@ -1,5 +1,5 @@
#
-# Makefile to run al tests for Vim
+# Makefile to run all tests for Vim
#
VIMPROG = ../vim
@@ -15,7 +15,7 @@ SCRIPTS = test1.out test2.out test3.out test4.out test5.out test6.out \
test43.out test44.out test45.out test46.out test47.out \
test48.out test49.out test51.out test52.out test53.out \
test54.out test55.out test56.out test57.out test58.out \
- test59.out test60.out test61.out test62.out
+ test59.out test60.out test61.out test62.out test63.out
SCRIPTS_GUI = test16.out
diff --git a/src/testdir/test63.in b/src/testdir/test63.in
index e69de29b..10956114 100644
--- a/src/testdir/test63.in
+++ b/src/testdir/test63.in
@@ -0,0 +1,157 @@
+Test for ":match", ":2match", ":3match", "clearmatches()", "getmatches()",
+"matchadd()", "matcharg()", "matchdelete()", and "setmatches()".
+
+STARTTEST
+:so small.vim
+:" --- Check that "matcharg()" returns the correct group and pattern if a match
+:" --- is defined.
+:let @r = "*** Test 1: "
+:highlight MyGroup1 ctermbg=red
+:highlight MyGroup2 ctermbg=green
+:highlight MyGroup3 ctermbg=blue
+:match MyGroup1 /TODO/
+:2match MyGroup2 /FIXME/
+:3match MyGroup3 /XXX/
+:if matcharg(1) == ['MyGroup1', 'TODO'] && matcharg(2) == ['MyGroup2', 'FIXME'] && matcharg(3) == ['MyGroup3', 'XXX']
+: let @r .= "OK\n"
+:else
+: let @r .= "FAILED\n"
+:endif
+:" --- Check that "matcharg()" returns an empty list if the argument is not 1,
+:" --- 2 or 3 (only 0 and 4 are tested).
+:let @r .= "*** Test 2: "
+:if matcharg(0) == [] && matcharg(4) == []
+: let @r .= "OK\n"
+:else
+: let @r .= "FAILED\n"
+:endif
+:" --- Check that "matcharg()" returns ['', ''] if a match is not defined.
+:let @r .= "*** Test 3: "
+:match
+:2match
+:3match
+:if matcharg(1) == ['', ''] && matcharg(2) == ['', ''] && matcharg(3) == ['', '']
+: let @r .= "OK\n"
+:else
+: let @r .= "FAILED\n"
+:endif
+:" --- Check that "matchadd()" and "getmatches()" agree on added matches and
+:" --- that default values apply.
+:let @r .= "*** Test 4: "
+:let m1 = matchadd("MyGroup1", "TODO")
+:let m2 = matchadd("MyGroup2", "FIXME", 42)
+:let m3 = matchadd("MyGroup3", "XXX", 60, 17)
+:if getmatches() == [{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 4}, {'group': 'MyGroup2', 'pattern': 'FIXME', 'priority': 42, 'id': 5}, {'group': 'MyGroup3', 'pattern': 'XXX', 'priority': 60, 'id': 17}]
+: let @r .= "OK\n"
+:else
+: let @r .= "FAILED\n"
+:endif
+:" --- Check that "matchdelete()" deletes the matches defined in the previous
+:" --- test correctly.
+:let @r .= "*** Test 5: "
+:call matchdelete(m1)
+:call matchdelete(m2)
+:call matchdelete(m3)
+:unlet m1
+:unlet m2
+:unlet m3
+:if getmatches() == []
+: let @r .= "OK\n"
+:else
+: let @r .= "FAILED\n"
+:endif
+:" --- Check that "matchdelete()" returns 0 if succesfull and otherwise -1.
+:let @r .= "*** Test 6: "
+:let m = matchadd("MyGroup1", "TODO")
+:let r1 = matchdelete(m)
+:let r2 = matchdelete(42)
+:if r1 == 0 && r2 == -1
+: let @r .= "OK\n"
+:else
+: let @r .= "FAILED\n"
+:endif
+:unlet m
+:unlet r1
+:unlet r2
+:" --- Check that "clearmatches()" clears all matches defined by ":match" and
+:" --- "matchadd()".
+:let @r .= "*** Test 7: "
+:let m1 = matchadd("MyGroup1", "TODO")
+:let m2 = matchadd("MyGroup2", "FIXME", 42)
+:let m3 = matchadd("MyGroup3", "XXX", 60, 17)
+:match MyGroup1 /COFFEE/
+:2match MyGroup2 /HUMPPA/
+:3match MyGroup3 /VIM/
+:call clearmatches()
+:if getmatches() == []
+: let @r .= "OK\n"
+:else
+: let @r .= "FAILED\n"
+:endif
+:unlet m1
+:unlet m2
+:unlet m3
+:" --- Check that "setmatches()" restores a list of matches saved by
+:" --- "getmatches()" without changes. (Matches with equal priority must also
+:" --- remain in the same order.)
+:let @r .= "*** Test 8: "
+:let m1 = matchadd("MyGroup1", "TODO")
+:let m2 = matchadd("MyGroup2", "FIXME", 42)
+:let m3 = matchadd("MyGroup3", "XXX", 60, 17)
+:match MyGroup1 /COFFEE/
+:2match MyGroup2 /HUMPPA/
+:3match MyGroup3 /VIM/
+:let ml = getmatches()
+:call clearmatches()
+:call setmatches(ml)
+:if getmatches() == ml
+: let @r .= "OK\n"
+:else
+: let @r .= "FAILED\n"
+:endif
+:call clearmatches()
+:unlet m1
+:unlet m2
+:unlet m3
+:unlet ml
+:" --- Check that "setmatches()" will not add two matches with the same ID. The
+:" --- expected behaviour (for now) is to add the first match but not the
+:" --- second and to return 0 (even though it is a matter of debate whether
+:" --- this can be considered succesfull behaviour).
+:let @r .= "*** Test 9: "
+:let r1 = setmatches([{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 1}, {'group': 'MyGroup2', 'pattern': 'FIXME', 'priority': 10, 'id': 1}])
+:if getmatches() == [{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 1}] && r1 == 0
+: let @r .= "OK\n"
+:else
+: let @r .= "FAILED\n"
+:endif
+:call clearmatches()
+:unlet r1
+:" --- Check that "setmatches()" returns 0 if succesfull and otherwise -1.
+:" --- (A range of valid and invalid input values are tried out to generate the
+:" --- return values.)
+:let @r .= "*** Test 10: "
+:let rs1 = setmatches([])
+:let rs2 = setmatches([{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 1}])
+:call clearmatches()
+:let rf1 = setmatches(0)
+:let rf2 = setmatches([0])
+:let rf3 = setmatches([{'wrong key': 'wrong value'}])
+:if rs1 == 0 && rs2 == 0 && rf1 == -1 && rf2 == -1 && rf3 == -1
+: let @r .= "OK\n"
+:else
+: let @r .= "FAILED\n"
+:endif
+:unlet rs1
+:unlet rs2
+:unlet rf1
+:unlet rf2
+:unlet rf3
+:highlight clear MyGroup1
+:highlight clear MyGroup2
+:highlight clear MyGroup3
+G"rp
+:/^Results/,$wq! test.out
+ENDTEST
+
+Results of test63:
diff --git a/src/testdir/test63.ok b/src/testdir/test63.ok
index e69de29b..14973985 100644
--- a/src/testdir/test63.ok
+++ b/src/testdir/test63.ok
@@ -0,0 +1,11 @@
+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
diff --git a/src/version.c b/src/version.c
index f8e40fbb..ac4e17f5 100644
--- a/src/version.c
+++ b/src/version.c
@@ -667,6 +667,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 40,
+/**/
39,
/**/
38,
diff --git a/src/window.c b/src/window.c
index 4083f818..85a0b02c 100644
--- a/src/window.c
+++ b/src/window.c
@@ -75,6 +75,7 @@ static int check_snapshot_rec __ARGS((frame_T *sn, frame_T *fr));
static win_T *restore_snapshot_rec __ARGS((frame_T *sn, frame_T *fr));
#endif /* FEAT_WINDOWS */
+
static win_T *win_alloc __ARGS((win_T *after));
static void win_new_height __ARGS((win_T *, int));
@@ -4128,6 +4129,10 @@ win_alloc(after)
#ifdef FEAT_AUTOCMD
--autocmd_block;
#endif
+#ifdef FEAT_SEARCH_EXTRA
+ newwin->w_match_head = NULL;
+ newwin->w_next_match_id = 4;
+#endif
}
return newwin;
}
@@ -4185,11 +4190,11 @@ win_free(wp, tp)
vim_free(wp->w_tagstack[i].tagname);
vim_free(wp->w_localdir);
+
#ifdef FEAT_SEARCH_EXTRA
- vim_free(wp->w_match[0].regprog);
- vim_free(wp->w_match[1].regprog);
- vim_free(wp->w_match[2].regprog);
+ clear_matches(wp);
#endif
+
#ifdef FEAT_JUMPLIST
free_jumplist(wp);
#endif
@@ -6174,3 +6179,173 @@ win_hasvertsplit()
return FALSE;
}
#endif
+
+#if defined(FEAT_SEARCH_EXTRA) || defined(PROTO)
+/*
+ * Add match to the match list of window 'wp'. The pattern 'pat' will be
+ * highligted with the group 'grp' with priority 'prio'.
+ * Optionally, a desired ID 'id' can be specified (greater than or equal to 1).
+ * If no particular ID is desired, -1 must be specified for 'id'.
+ * Return ID of added match, -1 on failure.
+ */
+ int
+match_add(wp, grp, pat, prio, id)
+ win_T *wp;
+ char_u *grp;
+ char_u *pat;
+ int prio;
+ int id;
+{
+ matchitem_T *cur;
+ matchitem_T *prev;
+ matchitem_T *m;
+ int hlg_id;
+ regmmatch_T match;
+
+ if (*grp == NUL || *pat == NUL)
+ return -1;
+ if (id < -1 || id == 0)
+ {
+ EMSGN("E799: Invalid ID: %ld (must be greater than or equal to 1)", id);
+ return -1;
+ }
+ if (id != -1)
+ {
+ cur = wp->w_match_head;
+ while (cur != NULL)
+ {
+ if (cur->id == id)
+ {
+ EMSGN("E801: ID already taken: %ld", id);
+ return -1;
+ }
+ cur = cur->next;
+ }
+ }
+ if ((hlg_id = syn_namen2id(grp, STRLEN(grp))) == 0)
+ {
+ EMSG2(_(e_nogroup), grp);
+ return -1;
+ }
+ if ((match.regprog = vim_regcomp(pat, RE_MAGIC)) == NULL)
+ {
+ EMSG2(_(e_invarg2), pat);
+ return -1;
+ }
+
+ /* Find available match ID. */
+ while (id == -1)
+ {
+ cur = wp->w_match_head;
+ while (cur != NULL && cur->id != wp->w_next_match_id)
+ cur = cur->next;
+ if (cur == NULL)
+ id = wp->w_next_match_id;
+ wp->w_next_match_id++;
+ }
+
+ /* Build new match. */
+ m = (matchitem_T *)alloc(sizeof(matchitem_T));
+ m->id = id;
+ m->priority = prio;
+ m->pattern = vim_strsave(pat);
+ m->hlg_id = hlg_id;
+ m->match.regprog = match.regprog;
+
+ /* Insert new match. The match list is in ascending order with regard to
+ * the match priorities. */
+ cur = wp->w_match_head;
+ prev = cur;
+ while (cur != NULL && prio >= cur->priority)
+ {
+ prev = cur;
+ cur = cur->next;
+ }
+ if (cur == prev)
+ wp->w_match_head = m;
+ else
+ prev->next = m;
+ m->next = cur;
+
+ redraw_later(SOME_VALID);
+ return id;
+}
+
+/*
+ * Delete match with ID 'id' in the match list of window 'wp'.
+ * Print error messages if 'perr' is TRUE.
+ */
+ int
+match_delete(wp, id, perr)
+ win_T *wp;
+ int id;
+ int perr;
+{
+ matchitem_T *cur = wp->w_match_head;
+ matchitem_T *prev = cur;
+
+ if (id < 1)
+ {
+ if (perr == TRUE)
+ EMSGN("E802: Invalid ID: %ld (must be greater than or equal to 1)",
+ id);
+ return -1;
+ }
+ while (cur != NULL && cur->id != id)
+ {
+ prev = cur;
+ cur = cur->next;
+ }
+ if (cur == NULL)
+ {
+ if (perr == TRUE)
+ EMSGN("E803: ID not found: %ld", id);
+ return -1;
+ }
+ if (cur == prev)
+ wp->w_match_head = cur->next;
+ else
+ prev->next = cur->next;
+ vim_free(cur->match.regprog);
+ vim_free(cur->pattern);
+ vim_free(cur);
+ redraw_later(SOME_VALID);
+ return 0;
+}
+
+/*
+ * Delete all matches in the match list of window 'wp'.
+ */
+ void
+clear_matches(wp)
+ win_T *wp;
+{
+ matchitem_T *m;
+
+ while (wp->w_match_head != NULL)
+ {
+ m = wp->w_match_head->next;
+ vim_free(wp->w_match_head->match.regprog);
+ vim_free(wp->w_match_head->pattern);
+ vim_free(wp->w_match_head);
+ wp->w_match_head = m;
+ }
+ redraw_later(SOME_VALID);
+}
+
+/*
+ * Get match from ID 'id' in window 'wp'.
+ * Return NULL if match not found.
+ */
+ matchitem_T *
+get_match(wp, id)
+ win_T *wp;
+ int id;
+{
+ matchitem_T *cur = wp->w_match_head;
+
+ while (cur != NULL && cur->id != id)
+ cur = cur->next;
+ return cur;
+}
+#endif