updated for version 7.4.330

Problem:    Using a regexp pattern to highlight a specific position can be
            slow.
Solution:   Add matchaddpos() to highlight specific positions efficiently.
            (Alexey Radkov)
This commit is contained in:
Bram Moolenaar
2014-06-17 17:48:32 +02:00
parent ec1561cac5
commit b3414595c7
12 changed files with 465 additions and 88 deletions

View File

@@ -1887,6 +1887,8 @@ match( {expr}, {pat}[, {start}[, {count}]])
Number position where {pat} matches in {expr} Number position where {pat} matches in {expr}
matchadd( {group}, {pattern}[, {priority}[, {id}]]) matchadd( {group}, {pattern}[, {priority}[, {id}]])
Number highlight {pattern} with {group} Number highlight {pattern} with {group}
matchaddpos( {group}, {list}[, {priority}[, {id}]])
Number highlight positions with {group}
matcharg( {nr}) List arguments of |:match| matcharg( {nr}) List arguments of |:match|
matchdelete( {id}) Number delete match identified by {id} matchdelete( {id}) Number delete match identified by {id}
matchend( {expr}, {pat}[, {start}[, {count}]]) matchend( {expr}, {pat}[, {start}[, {count}]])
@@ -4380,6 +4382,41 @@ matchadd({group}, {pattern}[, {priority}[, {id}]])
available from |getmatches()|. All matches can be deleted in available from |getmatches()|. All matches can be deleted in
one operation by |clearmatches()|. 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()* matcharg({nr}) *matcharg()*
Selects the {nr} match item, as set with a |:match|, Selects the {nr} match item, as set with a |:match|,
|:2match| or |:3match| command. |:2match| or |:3match| command.

View File

@@ -827,6 +827,7 @@ Syntax and highlighting: *syntax-functions* *highlighting-functions*
synconcealed() get info about concealing synconcealed() get info about concealing
diff_hlID() get highlight ID for diff mode at a position diff_hlID() get highlight ID for diff mode at a position
matchadd() define a pattern to highlight (a "match") matchadd() define a pattern to highlight (a "match")
matchaddpos() define a list of positions to highlight
matcharg() get info about |:match| arguments matcharg() get info about |:match| arguments
matchdelete() delete a match defined by |matchadd()| or a matchdelete() delete a match defined by |matchadd()| or a
|:match| command |:match| command

View File

@@ -1,6 +1,6 @@
" Vim plugin for showing matching parens " Vim plugin for showing matching parens
" Maintainer: Bram Moolenaar <Bram@vim.org> " Maintainer: Bram Moolenaar <Bram@vim.org>
" Last Change: 2013 May 08 " Last Change: 2014 Jun 17
" Exit quickly when: " Exit quickly when:
" - this plugin was already loaded (or disabled) " - this plugin was already loaded (or disabled)
@@ -39,7 +39,7 @@ set cpo-=C
function! s:Highlight_Matching_Pair() function! s:Highlight_Matching_Pair()
" Remove any previous match. " Remove any previous match.
if exists('w:paren_hl_on') && w:paren_hl_on if exists('w:paren_hl_on') && w:paren_hl_on
3match none silent! call matchdelete(3)
let w:paren_hl_on = 0 let w:paren_hl_on = 0
endif endif
@@ -152,14 +152,18 @@ function! s:Highlight_Matching_Pair()
" If a match is found setup match highlighting. " If a match is found setup match highlighting.
if m_lnum > 0 && m_lnum >= stoplinetop && m_lnum <= stoplinebottom if m_lnum > 0 && m_lnum >= stoplinetop && m_lnum <= stoplinebottom
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) . exe '3match MatchParen /\(\%' . c_lnum . 'l\%' . (c_col - before) .
\ 'c\)\|\(\%' . m_lnum . 'l\%' . m_col . 'c\)/' \ 'c\)\|\(\%' . m_lnum . 'l\%' . m_col . 'c\)/'
endif
let w:paren_hl_on = 1 let w:paren_hl_on = 1
endif endif
endfunction endfunction
" Define commands that will disable and enable the plugin. " 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 \ au! matchparen
command! DoMatchParen runtime plugin/matchparen.vim | windo doau CursorMoved command! DoMatchParen runtime plugin/matchparen.vim | windo doau CursorMoved

View 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_mapcheck __ARGS((typval_T *argvars, typval_T *rettv));
static void f_match __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_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_matcharg __ARGS((typval_T *argvars, typval_T *rettv));
static void f_matchdelete __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_matchend __ARGS((typval_T *argvars, typval_T *rettv));
@@ -8054,6 +8055,7 @@ static struct fst
{"mapcheck", 1, 3, f_mapcheck}, {"mapcheck", 1, 3, f_mapcheck},
{"match", 2, 4, f_match}, {"match", 2, 4, f_match},
{"matchadd", 2, 4, f_matchadd}, {"matchadd", 2, 4, f_matchadd},
{"matchaddpos", 2, 4, f_matchaddpos},
{"matcharg", 1, 1, f_matcharg}, {"matcharg", 1, 1, f_matcharg},
{"matchdelete", 1, 1, f_matchdelete}, {"matchdelete", 1, 1, f_matchdelete},
{"matchend", 2, 4, f_matchend}, {"matchend", 2, 4, f_matchend},
@@ -11767,6 +11769,7 @@ f_getmatches(argvars, rettv)
#ifdef FEAT_SEARCH_EXTRA #ifdef FEAT_SEARCH_EXTRA
dict_T *dict; dict_T *dict;
matchitem_T *cur = curwin->w_match_head; matchitem_T *cur = curwin->w_match_head;
int i;
if (rettv_list_alloc(rettv) == OK) if (rettv_list_alloc(rettv) == OK)
{ {
@@ -11775,8 +11778,36 @@ f_getmatches(argvars, rettv)
dict = dict_alloc(); dict = dict_alloc();
if (dict == NULL) if (dict == NULL)
return; return;
dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id)); 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, "pattern", 0L, cur->pattern);
}
dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id));
dict_add_nr_str(dict, "priority", (long)cur->priority, NULL); dict_add_nr_str(dict, "priority", (long)cur->priority, NULL);
dict_add_nr_str(dict, "id", (long)cur->id, NULL); dict_add_nr_str(dict, "id", (long)cur->id, NULL);
list_append_dict(rettv->vval.v_list, dict); list_append_dict(rettv->vval.v_list, dict);
@@ -14313,7 +14344,58 @@ f_matchadd(argvars, rettv)
return; 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 #endif
} }
@@ -16816,7 +16898,7 @@ f_setmatches(argvars, rettv)
match_add(curwin, get_dict_string(d, (char_u *)"group", FALSE), match_add(curwin, get_dict_string(d, (char_u *)"group", FALSE),
get_dict_string(d, (char_u *)"pattern", FALSE), get_dict_string(d, (char_u *)"pattern", FALSE),
(int)get_dict_number(d, (char_u *)"priority"), (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; li = li->li_next;
} }
rettv->vval.v_number = 0; rettv->vval.v_number = 0;

View File

@@ -11489,7 +11489,7 @@ ex_match(eap)
c = *end; c = *end;
*end = NUL; *end = NUL;
match_add(curwin, g, p + 1, 10, id); match_add(curwin, g, p + 1, 10, id, NULL);
vim_free(g); vim_free(g);
*end = c; *end = c;
} }

View 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 switch_buffer __ARGS((buf_T **save_curbuf, buf_T *buf));
void restore_buffer __ARGS((buf_T *save_curbuf)); void restore_buffer __ARGS((buf_T *save_curbuf));
int win_hasvertsplit __ARGS((void)); 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)); int match_delete __ARGS((win_T *wp, int id, int perr));
void clear_matches __ARGS((win_T *wp)); void clear_matches __ARGS((win_T *wp));
matchitem_T *get_match __ARGS((win_T *wp, int id)); matchitem_T *get_match __ARGS((win_T *wp, int id));

View File

@@ -144,7 +144,8 @@ static void start_search_hl __ARGS((void));
static void end_search_hl __ARGS((void)); static void end_search_hl __ARGS((void));
static void init_search_hl __ARGS((win_T *wp)); static void init_search_hl __ARGS((win_T *wp));
static void prepare_search_hl __ARGS((win_T *wp, linenr_T lnum)); 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 #endif
static void screen_start_highlight __ARGS((int attr)); static void screen_start_highlight __ARGS((int attr));
static void screen_char __ARGS((unsigned off, int row, int col)); 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 */ match_T *shl; /* points to search_hl or a match */
int shl_flag; /* flag to indicate whether search_hl int shl_flag; /* flag to indicate whether search_hl
has been processed or not */ 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 int prevcol_hl_flag; /* flag to indicate whether prevcol
equals startcol of search_hl or one equals startcol of search_hl or one
of the matches */ of the matches */
@@ -3439,10 +3442,10 @@ win_line(wp, lnum, startrow, endrow, nochange)
shl->startcol = MAXCOL; shl->startcol = MAXCOL;
shl->endcol = MAXCOL; shl->endcol = MAXCOL;
shl->attr_cur = 0; shl->attr_cur = 0;
if (shl->rm.regprog != NULL)
{
v = (long)(ptr - line); v = (long)(ptr - line);
next_search_hl(wp, shl, lnum, (colnr_T)v); 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 /* Need to get the line again, a multi-line regexp may have made it
* invalid. */ * invalid. */
@@ -3477,7 +3480,6 @@ win_line(wp, lnum, startrow, endrow, nochange)
} }
area_highlighting = TRUE; area_highlighting = TRUE;
} }
}
if (shl != &search_hl && cur != NULL) if (shl != &search_hl && cur != NULL)
cur = cur->next; cur = cur->next;
} }
@@ -3792,7 +3794,11 @@ win_line(wp, lnum, startrow, endrow, nochange)
} }
else else
shl = &cur->hl; 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 if (shl->startcol != MAXCOL
&& v >= (long)shl->startcol && v >= (long)shl->startcol
@@ -3803,8 +3809,9 @@ win_line(wp, lnum, startrow, endrow, nochange)
else if (v == (long)shl->endcol) else if (v == (long)shl->endcol)
{ {
shl->attr_cur = 0; shl->attr_cur = 0;
next_search_hl(wp, shl, lnum, (colnr_T)v, cur);
next_search_hl(wp, shl, lnum, (colnr_T)v); pos_inprogress = cur == NULL || cur->pos.cur == 0
? FALSE : TRUE;
/* Need to get the line again, a multi-line regexp /* Need to get the line again, a multi-line regexp
* may have made it invalid. */ * may have made it invalid. */
@@ -7277,6 +7284,8 @@ prepare_search_hl(wp, lnum)
match_T *shl; /* points to search_hl or a match */ match_T *shl; /* points to search_hl or a match */
int shl_flag; /* flag to indicate whether search_hl int shl_flag; /* flag to indicate whether search_hl
has been processed or not */ has been processed or not */
int pos_inprogress; /* marks that position match search is
in progress */
int n; int n;
/* /*
@@ -7311,10 +7320,16 @@ prepare_search_hl(wp, lnum)
shl->first_lnum = wp->w_topline; shl->first_lnum = wp->w_topline;
# endif # endif
} }
if (cur != NULL)
cur->pos.cur = 0;
pos_inprogress = TRUE;
n = 0; 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) if (shl->lnum != 0)
{ {
shl->first_lnum = shl->lnum shl->first_lnum = shl->lnum
@@ -7343,11 +7358,12 @@ prepare_search_hl(wp, lnum)
* Careful: Any pointers for buffer lines will become invalid. * Careful: Any pointers for buffer lines will become invalid.
*/ */
static void static void
next_search_hl(win, shl, lnum, mincol) next_search_hl(win, shl, lnum, mincol, cur)
win_T *win; win_T *win;
match_T *shl; /* points to search_hl or a match */ match_T *shl; /* points to search_hl or a match */
linenr_T lnum; linenr_T lnum;
colnr_T mincol; /* minimal column for a match */ colnr_T mincol; /* minimal column for a match */
matchitem_T *cur; /* to retrieve match postions if any */
{ {
linenr_T l; linenr_T l;
colnr_T matchcol; colnr_T matchcol;
@@ -7415,7 +7431,10 @@ next_search_hl(win, shl, lnum, mincol)
matchcol = shl->rm.endpos[0].col; matchcol = shl->rm.endpos[0].col;
shl->lnum = lnum; 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 #ifdef FEAT_RELTIME
&(shl->tm) &(shl->tm)
#else #else
@@ -7433,9 +7452,15 @@ next_search_hl(win, shl, lnum, mincol)
} }
shl->rm.regprog = NULL; shl->rm.regprog = NULL;
shl->lnum = 0; shl->lnum = 0;
got_int = FALSE; /* avoid the "Type :quit to exit Vim" message */ got_int = FALSE; /* avoid the "Type :quit to exit Vim"
message */
break; break;
} }
}
else if (cur != NULL)
{
nmatched = next_search_hl_pos(shl, lnum, &(cur->pos), matchcol);
}
if (nmatched == 0) if (nmatched == 0)
{ {
shl->lnum = 0; /* no match found */ shl->lnum = 0; /* no match found */
@@ -7453,6 +7478,62 @@ next_search_hl(win, shl, lnum, mincol)
} }
#endif #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 static void
screen_start_highlight(attr) screen_start_highlight(attr)
int attr; int attr;

View File

@@ -1927,6 +1927,32 @@ typedef struct
#endif #endif
} match_T; } 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 * matchitem_T provides a linked list for storing match items for ":match" and
* the match functions. * the match functions.
@@ -1940,6 +1966,7 @@ struct matchitem
char_u *pattern; /* pattern to highlight */ char_u *pattern; /* pattern to highlight */
int hlg_id; /* highlight group ID */ int hlg_id; /* highlight group ID */
regmmatch_T match; /* regexp program for pattern */ regmmatch_T match; /* regexp program for pattern */
posmatch_T pos; /* position matches */
match_T hl; /* struct for doing the actual highlighting */ match_T hl; /* struct for doing the actual highlighting */
}; };

View File

@@ -1,5 +1,5 @@
Test for ":match", ":2match", ":3match", "clearmatches()", "getmatches()", Test for ":match", ":2match", ":3match", "clearmatches()", "getmatches()",
"matchadd()", "matcharg()", "matchdelete()", and "setmatches()". "matchadd()", "matchaddpos", "matcharg()", "matchdelete()", and "setmatches()".
STARTTEST STARTTEST
:so small.vim :so small.vim
@@ -147,9 +147,26 @@ STARTTEST
:unlet rf1 :unlet rf1
:unlet rf2 :unlet rf2
:unlet rf3 :unlet rf3
:highlight clear MyGroup1 :" --- Check that "matchaddpos()" positions matches correctly
:highlight clear MyGroup2 :let @r .= "*** Test 11:\n"
:highlight clear MyGroup3 :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 G"rp
:/^Results/,$wq! test.out :/^Results/,$wq! test.out
ENDTEST ENDTEST

View File

@@ -9,3 +9,6 @@ Results of test63:
*** Test 8: OK *** Test 8: OK
*** Test 9: OK *** Test 9: OK
*** Test 10: OK *** Test 10: OK
*** Test 11:
[{'group': 'MyGroup1', 'id': 3, 'priority': 10, 'pos1': [1, 5, 1], 'pos2': [1, 8, 3]}]
OK

View File

@@ -734,6 +734,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
330,
/**/ /**/
329, 329,
/**/ /**/

View File

@@ -6751,20 +6751,22 @@ win_hasvertsplit()
* Return ID of added match, -1 on failure. * Return ID of added match, -1 on failure.
*/ */
int int
match_add(wp, grp, pat, prio, id) match_add(wp, grp, pat, prio, id, pos_list)
win_T *wp; win_T *wp;
char_u *grp; char_u *grp;
char_u *pat; char_u *pat;
int prio; int prio;
int id; int id;
list_T *pos_list;
{ {
matchitem_T *cur; matchitem_T *cur;
matchitem_T *prev; matchitem_T *prev;
matchitem_T *m; matchitem_T *m;
int hlg_id; 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; return -1;
if (id < -1 || id == 0) if (id < -1 || id == 0)
{ {
@@ -6789,7 +6791,7 @@ match_add(wp, grp, pat, prio, id)
EMSG2(_(e_nogroup), grp); EMSG2(_(e_nogroup), grp);
return -1; return -1;
} }
if ((regprog = vim_regcomp(pat, RE_MAGIC)) == NULL) if (pat != NULL && (regprog = vim_regcomp(pat, RE_MAGIC)) == NULL)
{ {
EMSG2(_(e_invarg2), pat); EMSG2(_(e_invarg2), pat);
return -1; return -1;
@@ -6810,12 +6812,111 @@ match_add(wp, grp, pat, prio, id)
m = (matchitem_T *)alloc(sizeof(matchitem_T)); m = (matchitem_T *)alloc(sizeof(matchitem_T));
m->id = id; m->id = id;
m->priority = prio; 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->hlg_id = hlg_id;
m->match.regprog = regprog; m->match.regprog = regprog;
m->match.rmm_ic = FALSE; m->match.rmm_ic = FALSE;
m->match.rmm_maxcol = 0; 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 /* Insert new match. The match list is in ascending order with regard to
* the match priorities. */ * the match priorities. */
cur = wp->w_match_head; cur = wp->w_match_head;
@@ -6831,8 +6932,12 @@ match_add(wp, grp, pat, prio, id)
prev->next = m; prev->next = m;
m->next = cur; m->next = cur;
redraw_later(SOME_VALID); redraw_later(rtype);
return id; return id;
fail:
vim_free(m);
return -1;
} }
/* /*
@@ -6847,6 +6952,7 @@ match_delete(wp, id, perr)
{ {
matchitem_T *cur = wp->w_match_head; matchitem_T *cur = wp->w_match_head;
matchitem_T *prev = cur; matchitem_T *prev = cur;
int rtype = SOME_VALID;
if (id < 1) if (id < 1)
{ {
@@ -6872,8 +6978,25 @@ match_delete(wp, id, perr)
prev->next = cur->next; prev->next = cur->next;
vim_regfree(cur->match.regprog); vim_regfree(cur->match.regprog);
vim_free(cur->pattern); 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); vim_free(cur);
redraw_later(SOME_VALID); redraw_later(rtype);
return 0; return 0;
} }