]> granicus.if.org Git - vim/commitdiff
updated for version 7.1-040 v7.1.040
authorBram Moolenaar <Bram@vim.org>
Thu, 26 Jul 2007 20:58:42 +0000 (20:58 +0000)
committerBram Moolenaar <Bram@vim.org>
Thu, 26 Jul 2007 20:58:42 +0000 (20:58 +0000)
14 files changed:
runtime/doc/eval.txt
runtime/doc/pattern.txt
runtime/doc/usr_41.txt
src/eval.c
src/ex_docmd.c
src/proto/window.pro
src/screen.c
src/structs.h
src/syntax.c
src/testdir/Makefile
src/testdir/test63.in
src/testdir/test63.ok
src/version.c
src/window.c

index a18b048c77b15be878b5f05e748b69fe0bc6f12a..95ef5372b2e0977aa8b1b1d30c7b232600508eea 100644 (file)
@@ -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})
index 22c5782a8f7111535dffe70c3cfd224875bcad18..5331cfec41481fc425826f84003673303fc07080 100644 (file)
@@ -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: >
index da5bf7ce91361ea6258d5a2fae68eb3c5d5b920b..64cf78d3b239de194799c11e0376d148170a5ce7 100644 (file)
@@ -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
index 5dc6c01da8dc59b3317fce1efed4af5ee83d22b4..10df05b42a074d5bd4f35f7dbe20148a36ea2dc0 100644 (file)
@@ -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},
@@ -8242,6 +8252,20 @@ f_cindent(argvars, rettv)
        rettv->vval.v_number = -1;
 }
 
+/*
+ * "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
  */
@@ -10277,6 +10301,40 @@ f_getline(argvars, rettv)
     get_buffer_lines(curbuf, lnum, end, retlist, 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
  */
@@ -12447,6 +12505,42 @@ f_match(argvars, rettv)
     find_some_match(argvars, rettv, 1);
 }
 
+/*
+ * "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
  */
@@ -12458,19 +12552,41 @@ 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
  */
@@ -14508,6 +14624,66 @@ f_setloclist(argvars, rettv)
        set_qf_ll_list(win, &argvars[1], &argvars[2], 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
  */
index 3605a422caa5fa2476f2d60c9aca76ff6d322b81..0d889942d0abc44e8a5756d0c700462598fc19c9 100644 (file)
@@ -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;
        }
     }
index 45a90b82a58209dd466177dc0eded87ba5ebf4c5..bcf171c9e699fb0aef3ebc695f7d9771d77eaa39 100644 (file)
@@ -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 : */
index 5c4faddedb06266250c1b66f58bd4c7f78e7c7d6..11344c317d612bdf6511ca2775002e102dc64a02 100644 (file)
@@ -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;
            }
index d531f4e35bb7ed0b68ab72f0cefae0a5527463f5..c85fc05e582545b79c1807d99f2b267e644ef8c5 100644 (file)
@@ -1693,6 +1693,41 @@ struct frame_S
 #define FR_ROW 1       /* frame with a row of windows */
 #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
  *
@@ -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
 
     /*
index ef962ef7095bb33da3177eca95ae7c92e05b6051..c47a6026dc02e89f1f33a7eee806e9432af2f523 100644 (file)
@@ -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;
 }
index 747b187fa377a41a1222618b131b86c1ad66399d..667d1e9ffdad7d2580a830c4ec54dbb250d4f16f 100644 (file)
@@ -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
 
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..10956114c78d0f59b2d2c1e6dcb0e6262abbfdf9 100644 (file)
@@ -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:
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..14973985eb9a977b93d859519795956515cae05c 100644 (file)
@@ -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
index f8e40fbbdfdbb5b436a4fa4f2065fd8d4135888e..ac4e17f5ffa353616bc4cb512851f5aac608f295 100644 (file)
@@ -666,6 +666,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    40,
 /**/
     39,
 /**/
index 4083f8187151ac799d1adf092e71f80950b805f3..85a0b02ceab97316f9a0a1ec07264d234ee56ddd 100644 (file)
@@ -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));
 
@@ -4127,6 +4128,10 @@ win_alloc(after)
 #endif
 #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