]> granicus.if.org Git - vim/commitdiff
updated for version 7.4.330 v7.4.330
authorBram Moolenaar <Bram@vim.org>
Tue, 17 Jun 2014 15:48:32 +0000 (17:48 +0200)
committerBram Moolenaar <Bram@vim.org>
Tue, 17 Jun 2014 15:48:32 +0000 (17:48 +0200)
Problem:    Using a regexp pattern to highlight a specific position can be
            slow.
Solution:   Add matchaddpos() to highlight specific positions efficiently.
            (Alexey Radkov)

12 files changed:
runtime/doc/eval.txt
runtime/doc/usr_41.txt
runtime/plugin/matchparen.vim
src/eval.c
src/ex_docmd.c
src/proto/window.pro
src/screen.c
src/structs.h
src/testdir/test63.in
src/testdir/test63.ok
src/version.c
src/window.c

index 1ffd7ed010bba37c12d5ad0ef9b907b66d44d078..cf221070fff5c172962e176344f7ec46213b1da7 100644 (file)
@@ -1887,6 +1887,8 @@ match( {expr}, {pat}[, {start}[, {count}]])
                                Number  position where {pat} matches in {expr}
 matchadd( {group}, {pattern}[, {priority}[, {id}]])
                                Number  highlight {pattern} with {group}
+matchaddpos( {group}, {list}[, {priority}[, {id}]])
+                               Number  highlight positions with {group}
 matcharg( {nr})                        List    arguments of |:match|
 matchdelete( {id})             Number  delete match identified by {id}
 matchend( {expr}, {pat}[, {start}[, {count}]])
@@ -4380,6 +4382,41 @@ matchadd({group}, {pattern}[, {priority}[, {id}]])
                available from |getmatches()|.  All matches can be deleted in
                one operation by |clearmatches()|.
 
+matchaddpos({group}, {pos}[, {priority}[, {id}]])              *matchaddpos()*
+               Same as |matchadd()|, but requires a list of positions {pos}
+               instead of a pattern. This command is faster than |matchadd()|
+               because it does not require to handle regular expressions and
+               sets buffer line boundaries to redraw screen. It is supposed
+               to be used when fast match additions and deletions are
+               required, for example to highlight matching parentheses.
+
+               The list {pos} can contain one of these items:
+               - A number.  This while line will be highlighted.  The first
+                 line has number 1.
+               - A list with one number, e.g., [23]. The whole line with this
+                 number will be highlighted.
+               - A list with two numbers, e.g., [23, 11]. The first number is
+                 the line number, the second one the column number (first
+                 column is 1).  The character at this position will be
+                 highlighted.
+               - A list with three numbers, e.g., [23, 11, 3]. As above, but
+                 the third number gives the length of the highlight in screen
+                 cells.
+               
+               The maximum number of positions is 8.
+
+               Example: >
+                       :highlight MyGroup ctermbg=green guibg=green
+                       :let m = matchaddpos("MyGroup", [[23, 24], 34])
+<              Deletion of the pattern: >
+                       :call matchdelete(m)
+
+<              Matches added by |matchaddpos()| are returned by
+               |getmatches()| with an entry "pos1", "pos2", etc., with the
+               value a list like the {pos} item.
+               These matches cannot be set via |setmatches()|, however they
+               can still be deleted by |clearmatches()|.
+
 matcharg({nr})                                                 *matcharg()*
                Selects the {nr} match item, as set with a |:match|,
                |:2match| or |:3match| command.
index effe6db0ac6572efe1287b9a94bc23d85206af09..f30b79a2ea9d4ce2a1705228390a3083c2089044 100644 (file)
@@ -827,6 +827,7 @@ Syntax and highlighting:      *syntax-functions* *highlighting-functions*
        synconcealed()          get info about concealing
        diff_hlID()             get highlight ID for diff mode at a position
        matchadd()              define a pattern to highlight (a "match")
+       matchaddpos()           define a list of positions to highlight
        matcharg()              get info about |:match| arguments
        matchdelete()           delete a match defined by |matchadd()| or a
                                |:match| command
index 0fdfef164afb9b43a115fea5f66a03220215fde5..b490f45ebbbdf9668021206b28f4011a2d6f2e32 100644 (file)
@@ -1,6 +1,6 @@
 " Vim plugin for showing matching parens
 " Maintainer:  Bram Moolenaar <Bram@vim.org>
-" Last Change: 2013 May 08
+" Last Change: 2014 Jun 17
 
 " Exit quickly when:
 " - this plugin was already loaded (or disabled)
@@ -39,7 +39,7 @@ set cpo-=C
 function! s:Highlight_Matching_Pair()
   " Remove any previous match.
   if exists('w:paren_hl_on') && w:paren_hl_on
-    3match none
+    silent! call matchdelete(3)
     let w:paren_hl_on = 0
   endif
 
@@ -152,14 +152,18 @@ function! s:Highlight_Matching_Pair()
 
   " If a match is found setup match highlighting.
   if m_lnum > 0 && m_lnum >= stoplinetop && m_lnum <= stoplinebottom 
-    exe '3match MatchParen /\(\%' . c_lnum . 'l\%' . (c_col - before) .
-         \ 'c\)\|\(\%' . m_lnum . 'l\%' . m_col . 'c\)/'
+    if exists('*matchaddpos')
+      call matchaddpos('MatchParen', [[c_lnum, c_col - before], [m_lnum, m_col]], 10, 3)
+    else
+      exe '3match MatchParen /\(\%' . c_lnum . 'l\%' . (c_col - before) .
+           \ 'c\)\|\(\%' . m_lnum . 'l\%' . m_col . 'c\)/'
+    endif
     let w:paren_hl_on = 1
   endif
 endfunction
 
 " Define commands that will disable and enable the plugin.
-command! NoMatchParen windo 3match none | unlet! g:loaded_matchparen |
+command! NoMatchParen windo silent! call matchdelete(3) | unlet! g:loaded_matchparen |
          \ au! matchparen
 command! DoMatchParen runtime plugin/matchparen.vim | windo doau CursorMoved
 
index a350757dac8ea642c9172632a18fbafed2dc9d08..31f5c91873f7d8378c561f163b63b348c03a9cb4 100644 (file)
@@ -622,6 +622,7 @@ 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_matchaddpos __ARGS((typval_T *argvars, typval_T *rettv));
 static void f_matcharg __ARGS((typval_T *argvars, typval_T *rettv));
 static void f_matchdelete __ARGS((typval_T *argvars, typval_T *rettv));
 static void f_matchend __ARGS((typval_T *argvars, typval_T *rettv));
@@ -8054,6 +8055,7 @@ static struct fst
     {"mapcheck",       1, 3, f_mapcheck},
     {"match",          2, 4, f_match},
     {"matchadd",       2, 4, f_matchadd},
+    {"matchaddpos",    2, 4, f_matchaddpos},
     {"matcharg",       1, 1, f_matcharg},
     {"matchdelete",    1, 1, f_matchdelete},
     {"matchend",       2, 4, f_matchend},
@@ -11767,6 +11769,7 @@ f_getmatches(argvars, rettv)
 #ifdef FEAT_SEARCH_EXTRA
     dict_T     *dict;
     matchitem_T        *cur = curwin->w_match_head;
+    int                i;
 
     if (rettv_list_alloc(rettv) == OK)
     {
@@ -11775,8 +11778,36 @@ f_getmatches(argvars, rettv)
            dict = dict_alloc();
            if (dict == NULL)
                return;
+           if (cur->match.regprog == NULL)
+           {
+               /* match added with matchaddpos() */
+               for (i = 0; i < MAXPOSMATCH; ++i)
+               {
+                   llpos_T     *llpos;
+                   char        buf[6];
+                   list_T      *l;
+
+                   llpos = &cur->pos.pos[i];
+                   if (llpos->lnum == 0)
+                       break;
+                   l = list_alloc();
+                   if (l == NULL)
+                       break;
+                   list_append_number(l, (varnumber_T)llpos->lnum);
+                   if (llpos->col > 0)
+                   {
+                       list_append_number(l, (varnumber_T)llpos->col);
+                       list_append_number(l, (varnumber_T)llpos->len);
+                   }
+                   sprintf(buf, "pos%d", i + 1);
+                   dict_add_list(dict, buf, l);
+               }
+           }
+           else
+           {
+               dict_add_nr_str(dict, "pattern", 0L, cur->pattern);
+           }
            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);
@@ -14313,7 +14344,58 @@ f_matchadd(argvars, rettv)
        return;
     }
 
-    rettv->vval.v_number = match_add(curwin, grp, pat, prio, id);
+    rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL);
+#endif
+}
+
+/*
+ * "matchaddpos()" function
+ */
+    static void
+f_matchaddpos(argvars, rettv)
+    typval_T   *argvars UNUSED;
+    typval_T   *rettv UNUSED;
+{
+#ifdef FEAT_SEARCH_EXTRA
+    char_u     buf[NUMBUFLEN];
+    char_u     *group;
+    int                prio = 10;
+    int                id = -1;
+    int                error = FALSE;
+    list_T     *l;
+
+    rettv->vval.v_number = -1;
+
+    group = get_tv_string_buf_chk(&argvars[0], buf);
+    if (group == NULL)
+       return;
+
+    if (argvars[1].v_type != VAR_LIST)
+    {
+       EMSG2(_(e_listarg), "matchaddpos()");
+       return;
+    }
+    l = argvars[1].vval.v_list;
+    if (l == NULL)
+       return;
+
+    if (argvars[2].v_type != VAR_UNKNOWN)
+    {
+       prio = get_tv_number_chk(&argvars[2], &error);
+       if (argvars[3].v_type != VAR_UNKNOWN)
+           id = get_tv_number_chk(&argvars[3], &error);
+    }
+    if (error == TRUE)
+       return;
+
+    /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
+    if (id == 1 || id == 2)
+    {
+       EMSGN("E798: ID is reserved for \":match\": %ld", id);
+       return;
+    }
+
+    rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l);
 #endif
 }
 
@@ -16816,7 +16898,7 @@ f_setmatches(argvars, rettv)
            match_add(curwin, get_dict_string(d, (char_u *)"group", FALSE),
                    get_dict_string(d, (char_u *)"pattern", FALSE),
                    (int)get_dict_number(d, (char_u *)"priority"),
-                   (int)get_dict_number(d, (char_u *)"id"));
+                   (int)get_dict_number(d, (char_u *)"id"), NULL);
            li = li->li_next;
        }
        rettv->vval.v_number = 0;
index 04c9a61cfa1f1ef5560919d6179ccf91936270d4..083693b64058e38770c9ce33d78e7ec1cc53db46 100644 (file)
@@ -11489,7 +11489,7 @@ ex_match(eap)
 
            c = *end;
            *end = NUL;
-           match_add(curwin, g, p + 1, 10, id);
+           match_add(curwin, g, p + 1, 10, id, NULL);
            vim_free(g);
            *end = c;
        }
index cecc668528718770b1a672b6e058fa2a14de8095..2d33c17576bff246db7b40bf48bfc7eac3c0826b 100644 (file)
@@ -75,7 +75,7 @@ void restore_win __ARGS((win_T *save_curwin, tabpage_T *save_curtab, int no_disp
 void switch_buffer __ARGS((buf_T **save_curbuf, buf_T *buf));
 void restore_buffer __ARGS((buf_T *save_curbuf));
 int win_hasvertsplit __ARGS((void));
-int match_add __ARGS((win_T *wp, char_u *grp, char_u *pat, int prio, int id));
+int match_add __ARGS((win_T *wp, char_u *grp, char_u *pat, int prio, int id, list_T *pos));
 int match_delete __ARGS((win_T *wp, int id, int perr));
 void clear_matches __ARGS((win_T *wp));
 matchitem_T *get_match __ARGS((win_T *wp, int id));
index 87b12591101e4e483e46a10a9f17e6df33869aa6..dd8d9a54181a59f9fdc30680b87d514b16c43b85 100644 (file)
@@ -144,7 +144,8 @@ static void start_search_hl __ARGS((void));
 static void end_search_hl __ARGS((void));
 static void init_search_hl __ARGS((win_T *wp));
 static void prepare_search_hl __ARGS((win_T *wp, linenr_T lnum));
-static void next_search_hl __ARGS((win_T *win, match_T *shl, linenr_T lnum, colnr_T mincol));
+static void next_search_hl __ARGS((win_T *win, match_T *shl, linenr_T lnum, colnr_T mincol, matchitem_T *cur));
+static int next_search_hl_pos __ARGS((match_T *shl, linenr_T lnum, posmatch_T *pos, colnr_T mincol));
 #endif
 static void screen_start_highlight __ARGS((int attr));
 static void screen_char __ARGS((unsigned off, int row, int col));
@@ -2929,6 +2930,8 @@ win_line(wp, lnum, startrow, endrow, nochange)
     match_T    *shl;                   /* points to search_hl or a match */
     int                shl_flag;               /* flag to indicate whether search_hl
                                           has been processed or not */
+    int                pos_inprogress;         /* marks that position match search is
+                                          in progress */
     int                prevcol_hl_flag;        /* flag to indicate whether prevcol
                                           equals startcol of search_hl or one
                                           of the matches */
@@ -3439,44 +3442,43 @@ win_line(wp, lnum, startrow, endrow, nochange)
        shl->startcol = MAXCOL;
        shl->endcol = MAXCOL;
        shl->attr_cur = 0;
-       if (shl->rm.regprog != NULL)
-       {
-           v = (long)(ptr - line);
-           next_search_hl(wp, shl, lnum, (colnr_T)v);
+       v = (long)(ptr - line);
+       if (cur != NULL)
+           cur->pos.cur = 0;
+       next_search_hl(wp, shl, lnum, (colnr_T)v, cur);
 
-           /* Need to get the line again, a multi-line regexp may have made it
-            * invalid. */
-           line = ml_get_buf(wp->w_buffer, lnum, FALSE);
-           ptr = line + v;
+       /* Need to get the line again, a multi-line regexp may have made it
+        * invalid. */
+       line = ml_get_buf(wp->w_buffer, lnum, FALSE);
+       ptr = line + v;
 
-           if (shl->lnum != 0 && shl->lnum <= lnum)
+       if (shl->lnum != 0 && shl->lnum <= lnum)
+       {
+           if (shl->lnum == lnum)
+               shl->startcol = shl->rm.startpos[0].col;
+           else
+               shl->startcol = 0;
+           if (lnum == shl->lnum + shl->rm.endpos[0].lnum
+                                               - shl->rm.startpos[0].lnum)
+               shl->endcol = shl->rm.endpos[0].col;
+           else
+               shl->endcol = MAXCOL;
+           /* Highlight one character for an empty match. */
+           if (shl->startcol == shl->endcol)
            {
-               if (shl->lnum == lnum)
-                   shl->startcol = shl->rm.startpos[0].col;
-               else
-                   shl->startcol = 0;
-               if (lnum == shl->lnum + shl->rm.endpos[0].lnum
-                                                 - shl->rm.startpos[0].lnum)
-                   shl->endcol = shl->rm.endpos[0].col;
-               else
-                   shl->endcol = MAXCOL;
-               /* Highlight one character for an empty match. */
-               if (shl->startcol == shl->endcol)
-               {
 #ifdef FEAT_MBYTE
-                   if (has_mbyte && line[shl->endcol] != NUL)
-                       shl->endcol += (*mb_ptr2len)(line + shl->endcol);
-                   else
+               if (has_mbyte && line[shl->endcol] != NUL)
+                   shl->endcol += (*mb_ptr2len)(line + shl->endcol);
+               else
 #endif
-                       ++shl->endcol;
-               }
-               if ((long)shl->startcol < v)  /* match at leftcol */
-               {
-                   shl->attr_cur = shl->attr;
-                   search_attr = shl->attr;
-               }
-               area_highlighting = TRUE;
+                   ++shl->endcol;
            }
+           if ((long)shl->startcol < v)  /* match at leftcol */
+           {
+               shl->attr_cur = shl->attr;
+               search_attr = shl->attr;
+           }
+           area_highlighting = TRUE;
        }
        if (shl != &search_hl && cur != NULL)
            cur = cur->next;
@@ -3488,7 +3490,7 @@ win_line(wp, lnum, startrow, endrow, nochange)
      * when Visual mode is active, because it's not clear what is selected
      * then. */
     if (wp->w_p_cul && lnum == wp->w_cursor.lnum
-                                        && !(wp == curwin  && VIsual_active))
+                                        && !(wp == curwin && VIsual_active))
     {
        line_attr = hl_attr(HLF_CUL);
        area_highlighting = TRUE;
@@ -3792,7 +3794,11 @@ win_line(wp, lnum, startrow, endrow, nochange)
                    }
                    else
                        shl = &cur->hl;
-                   while (shl->rm.regprog != NULL)
+                   if (cur != NULL)
+                       cur->pos.cur = 0;
+                   pos_inprogress = TRUE;
+                   while (shl->rm.regprog != NULL
+                                          || (cur != NULL && pos_inprogress))
                    {
                        if (shl->startcol != MAXCOL
                                && v >= (long)shl->startcol
@@ -3803,8 +3809,9 @@ win_line(wp, lnum, startrow, endrow, nochange)
                        else if (v == (long)shl->endcol)
                        {
                            shl->attr_cur = 0;
-
-                           next_search_hl(wp, shl, lnum, (colnr_T)v);
+                           next_search_hl(wp, shl, lnum, (colnr_T)v, cur);
+                           pos_inprogress = cur == NULL || cur->pos.cur == 0
+                                                             ? FALSE : TRUE;
 
                            /* Need to get the line again, a multi-line regexp
                             * may have made it invalid. */
@@ -7277,6 +7284,8 @@ prepare_search_hl(wp, lnum)
     match_T    *shl;           /* points to search_hl or a match */
     int                shl_flag;       /* flag to indicate whether search_hl
                                   has been processed or not */
+    int                pos_inprogress; /* marks that position match search is
+                                  in progress */
     int                n;
 
     /*
@@ -7311,10 +7320,16 @@ prepare_search_hl(wp, lnum)
                shl->first_lnum = wp->w_topline;
 # endif
            }
+           if (cur != NULL)
+               cur->pos.cur = 0;
+           pos_inprogress = TRUE;
            n = 0;
-           while (shl->first_lnum < lnum && shl->rm.regprog != NULL)
+           while (shl->first_lnum < lnum && (shl->rm.regprog != NULL
+                                         || (cur != NULL && pos_inprogress)))
            {
-               next_search_hl(wp, shl, shl->first_lnum, (colnr_T)n);
+               next_search_hl(wp, shl, shl->first_lnum, (colnr_T)n, cur);
+               pos_inprogress = cur == NULL || cur->pos.cur == 0
+                                                             ? FALSE : TRUE;
                if (shl->lnum != 0)
                {
                    shl->first_lnum = shl->lnum
@@ -7343,11 +7358,12 @@ prepare_search_hl(wp, lnum)
  * Careful: Any pointers for buffer lines will become invalid.
  */
     static void
-next_search_hl(win, shl, lnum, mincol)
-    win_T      *win;
-    match_T    *shl;           /* points to search_hl or a match */
-    linenr_T   lnum;
-    colnr_T    mincol;         /* minimal column for a match */
+next_search_hl(win, shl, lnum, mincol, cur)
+    win_T          *win;
+    match_T        *shl;       /* points to search_hl or a match */
+    linenr_T       lnum;
+    colnr_T        mincol;     /* minimal column for a match */
+    matchitem_T            *cur;       /* to retrieve match postions if any */
 {
     linenr_T   l;
     colnr_T    matchcol;
@@ -7415,26 +7431,35 @@ next_search_hl(win, shl, lnum, mincol)
            matchcol = shl->rm.endpos[0].col;
 
        shl->lnum = lnum;
-       nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum, matchcol,
+       if (shl->rm.regprog != NULL)
+       {
+           nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum,
+                   matchcol,
 #ifdef FEAT_RELTIME
-               &(shl->tm)
+                   &(shl->tm)
 #else
-               NULL
+                   NULL
 #endif
-               );
-       if (called_emsg || got_int)
-       {
-           /* Error while handling regexp: stop using this regexp. */
-           if (shl == &search_hl)
+                   );
+           if (called_emsg || got_int)
            {
-               /* don't free regprog in the match list, it's a copy */
-               vim_regfree(shl->rm.regprog);
-               SET_NO_HLSEARCH(TRUE);
+               /* Error while handling regexp: stop using this regexp. */
+               if (shl == &search_hl)
+               {
+                   /* don't free regprog in the match list, it's a copy */
+                   vim_regfree(shl->rm.regprog);
+                   SET_NO_HLSEARCH(TRUE);
+               }
+               shl->rm.regprog = NULL;
+               shl->lnum = 0;
+               got_int = FALSE;  /* avoid the "Type :quit to exit Vim"
+                                    message */
+               break;
            }
-           shl->rm.regprog = NULL;
-           shl->lnum = 0;
-           got_int = FALSE;  /* avoid the "Type :quit to exit Vim" message */
-           break;
+       }
+       else if (cur != NULL)
+       {
+           nmatched = next_search_hl_pos(shl, lnum, &(cur->pos), matchcol);
        }
        if (nmatched == 0)
        {
@@ -7453,6 +7478,62 @@ next_search_hl(win, shl, lnum, mincol)
 }
 #endif
 
+    static int
+next_search_hl_pos(shl, lnum, posmatch, mincol)
+    match_T        *shl;       /* points to a match */
+    linenr_T       lnum;
+    posmatch_T     *posmatch;  /* match positions */
+    colnr_T        mincol;     /* minimal column for a match */
+{
+    int            i;
+    int     bot = -1;
+
+    shl->lnum = 0;
+    for (i = posmatch->cur; i < MAXPOSMATCH; i++)
+    {
+       if (posmatch->pos[i].lnum == 0)
+           break;
+       if (posmatch->pos[i].col < mincol)
+           continue;
+       if (posmatch->pos[i].lnum == lnum)
+       {
+           if (shl->lnum == lnum)
+           {
+               /* partially sort positions by column numbers
+                * on the same line */
+               if (posmatch->pos[i].col < posmatch->pos[bot].col)
+               {
+                   llpos_T     tmp = posmatch->pos[i];
+
+                   posmatch->pos[i] = posmatch->pos[bot];
+                   posmatch->pos[bot] = tmp;
+               }
+           }
+           else
+           {
+               bot = i;
+               shl->lnum = lnum;
+           }
+       }
+    }
+    posmatch->cur = 0;
+    if (shl->lnum == lnum)
+    {
+       colnr_T start = posmatch->pos[bot].col == 0
+                                            ? 0 : posmatch->pos[bot].col - 1;
+       colnr_T end = posmatch->pos[bot].col == 0
+                                   ? MAXCOL : start + posmatch->pos[bot].len;
+
+       shl->rm.startpos[0].lnum = 0;
+       shl->rm.startpos[0].col = start;
+       shl->rm.endpos[0].lnum = 0;
+       shl->rm.endpos[0].col = end;
+       posmatch->cur = bot + 1;
+       return TRUE;
+    }
+    return FALSE;
+}
+
       static void
 screen_start_highlight(attr)
       int      attr;
index 6f953002d20ddfc3a13a8a3484e8018643f89bbb..c3d55cb30e60e27c7439a6e1dcc5232150a2c4e5 100644 (file)
@@ -1927,6 +1927,32 @@ typedef struct
 #endif
 } match_T;
 
+/* number of positions supported by matchaddpos() */
+#define MAXPOSMATCH 8
+
+/*
+ * Same as lpos_T, but with additional field len.
+ */
+typedef struct
+{
+    linenr_T   lnum;   /* line number */
+    colnr_T    col;    /* column number */
+    int                len;    /* length: 0 - to the end of line */
+} llpos_T;
+
+/*
+ * posmatch_T provides an array for storing match items for matchaddpos()
+ * function.
+ */
+typedef struct posmatch posmatch_T;
+struct posmatch
+{
+    llpos_T    pos[MAXPOSMATCH];       /* array of positions */
+    int                cur;                    /* internal position counter */
+    linenr_T   toplnum;                /* top buffer line */
+    linenr_T   botlnum;                /* bottom buffer line */
+};
+
 /*
  * matchitem_T provides a linked list for storing match items for ":match" and
  * the match functions.
@@ -1940,6 +1966,7 @@ struct matchitem
     char_u     *pattern;   /* pattern to highlight */
     int                hlg_id;     /* highlight group ID */
     regmmatch_T        match;      /* regexp program for pattern */
+    posmatch_T pos;        /* position matches */
     match_T    hl;         /* struct for doing the actual highlighting */
 };
 
index 74339c3e35281bad12de09aec14cb261e538a6f3..87f5ef6b545ea89c52a9fb6b290ba4b02be4258a 100644 (file)
@@ -1,5 +1,5 @@
 Test for ":match", ":2match", ":3match", "clearmatches()", "getmatches()",
-"matchadd()", "matcharg()", "matchdelete()", and "setmatches()".
+"matchadd()", "matchaddpos", "matcharg()", "matchdelete()", and "setmatches()".
 
 STARTTEST
 :so small.vim
@@ -147,9 +147,26 @@ STARTTEST
 :unlet rf1
 :unlet rf2
 :unlet rf3
-:highlight clear MyGroup1
-:highlight clear MyGroup2
-:highlight clear MyGroup3
+:" --- Check that "matchaddpos()" positions matches correctly
+:let @r .= "*** Test 11:\n"
+:set nolazyredraw
+:call setline(1, 'abcdefghijklmnopq')
+:call matchaddpos("MyGroup1", [[1, 5], [1, 8, 3]], 10, 3)
+:1
+:redraw!
+:let v1 = screenattr(1, 1)
+:let v5 = screenattr(1, 5)
+:let v6 = screenattr(1, 6)
+:let v8 = screenattr(1, 8)
+:let v10 = screenattr(1, 10)
+:let v11 = screenattr(1, 11)
+:let @r .= string(getmatches())."\n"
+:if v1 != v5 && v6 == v1 && v8 == v5 && v10 == v5 && v11 == v1
+:  let @r .= "OK\n"
+:else
+:  let @r .= "FAILED\n"
+:endif
+:call clearmatches()
 G"rp
 :/^Results/,$wq! test.out
 ENDTEST
index 14973985eb9a977b93d859519795956515cae05c..f804b693accb28c69c23f437e6bdcaa7cd549efe 100644 (file)
@@ -9,3 +9,6 @@ Results of test63:
 *** Test 8: OK
 *** Test 9: OK
 *** Test 10: OK
+*** Test 11:
+[{'group': 'MyGroup1', 'id': 3, 'priority': 10, 'pos1': [1, 5, 1], 'pos2': [1, 8, 3]}]
+OK
index b60a8213fe713a22934a0c2e8af9143008a92530..63ff8a1a79d1babe873d6c7b22fb3a10a4eb7637 100644 (file)
@@ -734,6 +734,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    330,
 /**/
     329,
 /**/
index 5215bb8e51d5f66a1e9c66a00bb1fcd75afac39d..f76812a0ea904d8eac1279494820a673a147e2fa 100644 (file)
@@ -6751,20 +6751,22 @@ win_hasvertsplit()
  * Return ID of added match, -1 on failure.
  */
     int
-match_add(wp, grp, pat, prio, id)
+match_add(wp, grp, pat, prio, id, pos_list)
     win_T      *wp;
     char_u     *grp;
     char_u     *pat;
     int                prio;
     int                id;
+    list_T     *pos_list;
 {
-    matchitem_T *cur;
-    matchitem_T *prev;
-    matchitem_T *m;
+    matchitem_T        *cur;
+    matchitem_T        *prev;
+    matchitem_T        *m;
     int                hlg_id;
-    regprog_T  *regprog;
+    regprog_T  *regprog = NULL;
+    int                rtype = SOME_VALID;
 
-    if (*grp == NUL || *pat == NUL)
+    if (*grp == NUL || (pat != NULL && *pat == NUL))
        return -1;
     if (id < -1 || id == 0)
     {
@@ -6789,7 +6791,7 @@ match_add(wp, grp, pat, prio, id)
        EMSG2(_(e_nogroup), grp);
        return -1;
     }
-    if ((regprog = vim_regcomp(pat, RE_MAGIC)) == NULL)
+    if (pat != NULL && (regprog = vim_regcomp(pat, RE_MAGIC)) == NULL)
     {
        EMSG2(_(e_invarg2), pat);
        return -1;
@@ -6810,12 +6812,111 @@ match_add(wp, grp, pat, prio, id)
     m = (matchitem_T *)alloc(sizeof(matchitem_T));
     m->id = id;
     m->priority = prio;
-    m->pattern = vim_strsave(pat);
+    m->pattern = pat == NULL ? NULL : vim_strsave(pat);
+    m->pos.cur = 0;
     m->hlg_id = hlg_id;
     m->match.regprog = regprog;
     m->match.rmm_ic = FALSE;
     m->match.rmm_maxcol = 0;
 
+    /* Set up position matches */
+    if (pos_list != NULL)
+    {
+       linenr_T        toplnum = 0;
+       linenr_T        botlnum = 0;
+       listitem_T      *li;
+       int             i;
+
+       for (i = 0, li = pos_list->lv_first; i < MAXPOSMATCH;
+                                                       i++, li = li->li_next)
+       {
+           linenr_T    lnum = 0;
+           colnr_T     col = 0;
+           int         len = 1;
+           list_T      *subl;
+           listitem_T  *subli;
+           int         error;
+
+           if (li == NULL)
+           {
+               m->pos.pos[i].lnum = 0;
+               break;
+           }
+           if (li->li_tv.v_type == VAR_LIST)
+           {
+               subl = li->li_tv.vval.v_list;
+               if (subl == NULL)
+                   goto fail;
+               subli = subl->lv_first;
+               if (subli == NULL)
+                   goto fail;
+               lnum = get_tv_number_chk(&subli->li_tv, &error);
+               if (error == TRUE)
+                   goto fail;
+               m->pos.pos[i].lnum = lnum;
+               if (lnum == 0)
+               {
+                   --i;
+                   continue;
+               }
+               subli = subli->li_next;
+               if (subli != NULL)
+               {
+                   col = get_tv_number_chk(&subli->li_tv, &error);
+                   if (error == TRUE)
+                       goto fail;
+                   subli = subli->li_next;
+                   if (subli != NULL)
+                   {
+                       len = get_tv_number_chk(&subli->li_tv, &error);
+                       if (error == TRUE)
+                           goto fail;
+                   }
+               }
+               m->pos.pos[i].col = col;
+               m->pos.pos[i].len = len;
+           }
+           else if (li->li_tv.v_type == VAR_NUMBER)
+           {
+               if (li->li_tv.vval.v_number == 0)
+                   continue;
+               m->pos.pos[i].lnum = li->li_tv.vval.v_number;
+               m->pos.pos[i].col = 0;
+               m->pos.pos[i].len = 0;
+           }
+           else
+           {
+               EMSG(_("List or number required"));
+               goto fail;
+           }
+           if (toplnum == 0 || lnum < toplnum)
+               toplnum = lnum;
+           if (botlnum == 0 || lnum > botlnum)
+               botlnum = lnum;
+       }
+
+       /* Calculate top and bottom lines for redrawing area */
+       if (toplnum != 0)
+       {
+           if (wp->w_buffer->b_mod_set)
+           {
+               if (wp->w_buffer->b_mod_top > toplnum)
+                   wp->w_buffer->b_mod_top = toplnum;
+               if (wp->w_buffer->b_mod_bot < botlnum)
+                   wp->w_buffer->b_mod_bot = botlnum;
+           }
+           else
+           {
+               wp->w_buffer->b_mod_top = toplnum;
+               wp->w_buffer->b_mod_bot = botlnum;
+           }
+           m->pos.toplnum = toplnum;
+           m->pos.botlnum = botlnum;
+           wp->w_buffer->b_mod_set = TRUE;
+           rtype = VALID;
+       }
+    }
+
     /* Insert new match.  The match list is in ascending order with regard to
      * the match priorities. */
     cur = wp->w_match_head;
@@ -6831,8 +6932,12 @@ match_add(wp, grp, pat, prio, id)
        prev->next = m;
     m->next = cur;
 
-    redraw_later(SOME_VALID);
+    redraw_later(rtype);
     return id;
+
+fail:
+    vim_free(m);
+    return -1;
 }
 
 /*
@@ -6845,8 +6950,9 @@ match_delete(wp, id, perr)
     int                id;
     int                perr;
 {
-    matchitem_T *cur = wp->w_match_head;
-    matchitem_T *prev = cur;
+    matchitem_T        *cur = wp->w_match_head;
+    matchitem_T        *prev = cur;
+    int                rtype = SOME_VALID;
 
     if (id < 1)
     {
@@ -6872,8 +6978,25 @@ match_delete(wp, id, perr)
        prev->next = cur->next;
     vim_regfree(cur->match.regprog);
     vim_free(cur->pattern);
+    if (cur->pos.toplnum != 0)
+    {
+       if (wp->w_buffer->b_mod_set)
+       {
+           if (wp->w_buffer->b_mod_top > cur->pos.toplnum)
+               wp->w_buffer->b_mod_top = cur->pos.toplnum;
+           if (wp->w_buffer->b_mod_bot < cur->pos.botlnum)
+               wp->w_buffer->b_mod_bot = cur->pos.botlnum;
+       }
+       else
+       {
+           wp->w_buffer->b_mod_top = cur->pos.toplnum;
+           wp->w_buffer->b_mod_bot = cur->pos.botlnum;
+       }
+       wp->w_buffer->b_mod_set = TRUE;
+       rtype = VALID;
+    }
     vim_free(cur);
-    redraw_later(SOME_VALID);
+    redraw_later(rtype);
     return 0;
 }