summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2014-06-17 17:48:32 +0200
committerBram Moolenaar <Bram@vim.org>2014-06-17 17:48:32 +0200
commitb3414595c713ca161f082776f89417faddec7d2d (patch)
tree5f03f600e04a2455ce84033c49db30b680d571c6
parentec1561cac59006213dd5405d164a94dc7d002806 (diff)
downloadvim-git-b3414595c713ca161f082776f89417faddec7d2d.tar.gz
updated for version 7.4.330v7.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)
-rw-r--r--runtime/doc/eval.txt37
-rw-r--r--runtime/doc/usr_41.txt1
-rw-r--r--runtime/plugin/matchparen.vim14
-rw-r--r--src/eval.c88
-rw-r--r--src/ex_docmd.c2
-rw-r--r--src/proto/window.pro2
-rw-r--r--src/screen.c199
-rw-r--r--src/structs.h27
-rw-r--r--src/testdir/test63.in25
-rw-r--r--src/testdir/test63.ok3
-rw-r--r--src/version.c2
-rw-r--r--src/window.c147
12 files changed, 462 insertions, 85 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 1ffd7ed01..cf221070f 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -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.
diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt
index effe6db0a..f30b79a2e 100644
--- a/runtime/doc/usr_41.txt
+++ b/runtime/doc/usr_41.txt
@@ -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
diff --git a/runtime/plugin/matchparen.vim b/runtime/plugin/matchparen.vim
index 0fdfef164..b490f45eb 100644
--- a/runtime/plugin/matchparen.vim
+++ b/runtime/plugin/matchparen.vim
@@ -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
diff --git a/src/eval.c b/src/eval.c
index a350757da..31f5c9187 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -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;
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 04c9a61cf..083693b64 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -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;
}
diff --git a/src/proto/window.pro b/src/proto/window.pro
index cecc66852..2d33c1757 100644
--- a/src/proto/window.pro
+++ b/src/proto/window.pro
@@ -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));
diff --git a/src/screen.c b/src/screen.c
index 87b125911..dd8d9a541 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -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;
diff --git a/src/structs.h b/src/structs.h
index 6f953002d..c3d55cb30 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -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 */
};
diff --git a/src/testdir/test63.in b/src/testdir/test63.in
index 74339c3e3..87f5ef6b5 100644
--- a/src/testdir/test63.in
+++ b/src/testdir/test63.in
@@ -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
diff --git a/src/testdir/test63.ok b/src/testdir/test63.ok
index 14973985e..f804b693a 100644
--- a/src/testdir/test63.ok
+++ b/src/testdir/test63.ok
@@ -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
diff --git a/src/version.c b/src/version.c
index b60a8213f..63ff8a1a7 100644
--- a/src/version.c
+++ b/src/version.c
@@ -735,6 +735,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 330,
+/**/
329,
/**/
328,
diff --git a/src/window.c b/src/window.c
index 5215bb8e5..f76812a0e 100644
--- a/src/window.c
+++ b/src/window.c
@@ -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;
}