vim-patch:9.0.0620: matchaddpos() can only add up to 8 matches

Problem:    matchaddpos() can only add up to 8 matches.
Solution:   Allocate the array of positions. (closes vim/vim#11248)
50faf02f43
This commit is contained in:
zeertzjq 2022-10-01 18:32:08 +08:00
parent 01721aaa66
commit 85c7d4f7a9
6 changed files with 203 additions and 153 deletions

View File

@ -5068,8 +5068,6 @@ matchaddpos({group}, {pos} [, {priority} [, {id} [, {dict}]]])
ignored, as well as entries with negative column numbers and ignored, as well as entries with negative column numbers and
lengths. lengths.
The maximum number of positions in {pos} is 8.
Returns -1 on error. Returns -1 on error.
Example: > Example: >

View File

@ -984,9 +984,6 @@ typedef struct {
proftime_T tm; // for a time limit proftime_T tm; // for a time limit
} match_T; } match_T;
/// number of positions supported by matchaddpos()
#define MAXPOSMATCH 8
/// Same as lpos_T, but with additional field len. /// Same as lpos_T, but with additional field len.
typedef struct { typedef struct {
linenr_T lnum; ///< line number linenr_T lnum; ///< line number
@ -994,29 +991,28 @@ typedef struct {
int len; ///< length: 0 - to the end of line int len; ///< length: 0 - to the end of line
} llpos_T; } llpos_T;
/// posmatch_T provides an array for storing match items for matchaddpos() /// matchitem_T provides a linked list for storing match items for ":match",
/// function. /// matchadd() and matchaddpos().
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.
typedef struct matchitem matchitem_T; typedef struct matchitem matchitem_T;
struct matchitem { struct matchitem {
matchitem_T *next; matchitem_T *mit_next;
int id; ///< match ID int mit_id; ///< match ID
int priority; ///< match priority int mit_priority; ///< match priority
char *pattern; ///< pattern to highlight
regmmatch_T match; ///< regexp program for pattern // Either a pattern is defined (mit_pattern is not NUL) or a list of
posmatch_T pos; ///< position matches // positions is given (mit_pos is not NULL and mit_pos_count > 0).
match_T hl; ///< struct for doing the actual highlighting char *mit_pattern; ///< pattern to highlight
int hlg_id; ///< highlight group ID regmmatch_T mit_match; ///< regexp program for pattern
int conceal_char; ///< cchar for Conceal highlighting
llpos_T *mit_pos_array; ///< array of positions
int mit_pos_count; ///< nr of entries in mit_pos
int mit_pos_cur; ///< internal position counter
linenr_T mit_toplnum; ///< top buffer line
linenr_T mit_botlnum; ///< bottom buffer line
match_T mit_hl; ///< struct for doing the actual highlighting
int mit_hlg_id; ///< highlight group ID
int mit_conceal_char; ///< cchar for Conceal highlighting
}; };
typedef int FloatAnchor; typedef int FloatAnchor;

View File

@ -1126,12 +1126,12 @@ win_update_start:
} else { } else {
const matchitem_T *cur = wp->w_match_head; const matchitem_T *cur = wp->w_match_head;
while (cur != NULL) { while (cur != NULL) {
if (cur->match.regprog != NULL if (cur->mit_match.regprog != NULL
&& re_multiline(cur->match.regprog)) { && re_multiline(cur->mit_match.regprog)) {
top_to_mod = true; top_to_mod = true;
break; break;
} }
cur = cur->next; cur = cur->mit_next;
} }
} }
} }

View File

@ -29,13 +29,13 @@ static char *e_invalwindow = N_("E957: Invalid window number");
#define SEARCH_HL_PRIORITY 0 #define SEARCH_HL_PRIORITY 0
/// Add match to the match list of window 'wp'. The pattern 'pat' will be /// Add match to the match list of window "wp".
/// highlighted with the group 'grp' with priority 'prio'. /// If "pat" is not NULL the pattern will be highlighted with the group "grp"
/// Optionally, a desired ID 'id' can be specified (greater than or equal to 1). /// with priority "prio".
/// If "pos_list" is not NULL the list of posisions defines the highlights.
/// 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".
/// ///
/// @param[in] id a desired ID 'id' can be specified
/// (greater than or equal to 1). -1 must be specified if no
/// particular ID is desired
/// @param[in] conceal_char pointer to conceal replacement char /// @param[in] conceal_char pointer to conceal replacement char
/// @return ID of added match, -1 on failure. /// @return ID of added match, -1 on failure.
static int match_add(win_T *wp, const char *const grp, const char *const pat, int prio, int id, static int match_add(win_T *wp, const char *const grp, const char *const pat, int prio, int id,
@ -61,11 +61,11 @@ static int match_add(win_T *wp, const char *const grp, const char *const pat, in
if (id != -1) { if (id != -1) {
cur = wp->w_match_head; cur = wp->w_match_head;
while (cur != NULL) { while (cur != NULL) {
if (cur->id == id) { if (cur->mit_id == id) {
semsg(_("E801: ID already taken: %" PRId64), (int64_t)id); semsg(_("E801: ID already taken: %" PRId64), (int64_t)id);
return -1; return -1;
} }
cur = cur->next; cur = cur->mit_next;
} }
} }
if ((hlg_id = syn_check_group(grp, strlen(grp))) == 0) { if ((hlg_id = syn_check_group(grp, strlen(grp))) == 0) {
@ -79,8 +79,8 @@ static int match_add(win_T *wp, const char *const grp, const char *const pat, in
// Find available match ID. // Find available match ID.
while (id == -1) { while (id == -1) {
cur = wp->w_match_head; cur = wp->w_match_head;
while (cur != NULL && cur->id != wp->w_next_match_id) { while (cur != NULL && cur->mit_id != wp->w_next_match_id) {
cur = cur->next; cur = cur->mit_next;
} }
if (cur == NULL) { if (cur == NULL) {
id = wp->w_next_match_id; id = wp->w_next_match_id;
@ -90,16 +90,20 @@ static int match_add(win_T *wp, const char *const grp, const char *const pat, in
// Build new match. // Build new match.
m = xcalloc(1, sizeof(matchitem_T)); m = xcalloc(1, sizeof(matchitem_T));
m->id = id; if (pos_list != NULL) {
m->priority = prio; m->mit_pos_array = xcalloc((size_t)tv_list_len(pos_list), sizeof(llpos_T));
m->pattern = pat == NULL ? NULL: xstrdup(pat); m->mit_pos_count = tv_list_len(pos_list);
m->hlg_id = hlg_id; }
m->match.regprog = regprog; m->mit_id = id;
m->match.rmm_ic = false; m->mit_priority = prio;
m->match.rmm_maxcol = 0; m->mit_pattern = pat == NULL ? NULL: xstrdup(pat);
m->conceal_char = 0; m->mit_hlg_id = hlg_id;
m->mit_match.regprog = regprog;
m->mit_match.rmm_ic = false;
m->mit_match.rmm_maxcol = 0;
m->mit_conceal_char = 0;
if (conceal_char != NULL) { if (conceal_char != NULL) {
m->conceal_char = utf_ptr2char(conceal_char); m->mit_conceal_char = utf_ptr2char(conceal_char);
} }
// Set up position matches // Set up position matches
@ -129,7 +133,7 @@ static int match_add(win_T *wp, const char *const grp, const char *const pat, in
if (lnum <= 0) { if (lnum <= 0) {
continue; continue;
} }
m->pos.pos[i].lnum = lnum; m->mit_pos_array[i].lnum = lnum;
subli = TV_LIST_ITEM_NEXT(subl, subli); subli = TV_LIST_ITEM_NEXT(subl, subli);
if (subli != NULL) { if (subli != NULL) {
col = (colnr_T)tv_get_number_chk(TV_LIST_ITEM_TV(subli), &error); col = (colnr_T)tv_get_number_chk(TV_LIST_ITEM_TV(subli), &error);
@ -150,15 +154,15 @@ static int match_add(win_T *wp, const char *const grp, const char *const pat, in
} }
} }
} }
m->pos.pos[i].col = col; m->mit_pos_array[i].col = col;
m->pos.pos[i].len = len; m->mit_pos_array[i].len = len;
} else if (TV_LIST_ITEM_TV(li)->v_type == VAR_NUMBER) { } else if (TV_LIST_ITEM_TV(li)->v_type == VAR_NUMBER) {
if (TV_LIST_ITEM_TV(li)->vval.v_number <= 0) { if (TV_LIST_ITEM_TV(li)->vval.v_number <= 0) {
continue; continue;
} }
m->pos.pos[i].lnum = (linenr_T)TV_LIST_ITEM_TV(li)->vval.v_number; m->mit_pos_array[i].lnum = (linenr_T)TV_LIST_ITEM_TV(li)->vval.v_number;
m->pos.pos[i].col = 0; m->mit_pos_array[i].col = 0;
m->pos.pos[i].len = 0; m->mit_pos_array[i].len = 0;
} else { } else {
semsg(_("E5031: List or number required at position %d"), semsg(_("E5031: List or number required at position %d"),
(int)tv_list_idx_of_item(pos_list, li)); (int)tv_list_idx_of_item(pos_list, li));
@ -171,9 +175,6 @@ static int match_add(win_T *wp, const char *const grp, const char *const pat, in
botlnum = lnum + 1; botlnum = lnum + 1;
} }
i++; i++;
if (i >= MAXPOSMATCH) {
break;
}
}); });
// Calculate top and bottom lines for redrawing area // Calculate top and bottom lines for redrawing area
@ -191,8 +192,8 @@ static int match_add(win_T *wp, const char *const grp, const char *const pat, in
wp->w_buffer->b_mod_bot = botlnum; wp->w_buffer->b_mod_bot = botlnum;
wp->w_buffer->b_mod_xlines = 0; wp->w_buffer->b_mod_xlines = 0;
} }
m->pos.toplnum = toplnum; m->mit_toplnum = toplnum;
m->pos.botlnum = botlnum; m->mit_botlnum = botlnum;
rtype = UPD_VALID; rtype = UPD_VALID;
} }
} }
@ -201,21 +202,23 @@ static int match_add(win_T *wp, const char *const grp, const char *const pat, in
// the match priorities. // the match priorities.
cur = wp->w_match_head; cur = wp->w_match_head;
prev = cur; prev = cur;
while (cur != NULL && prio >= cur->priority) { while (cur != NULL && prio >= cur->mit_priority) {
prev = cur; prev = cur;
cur = cur->next; cur = cur->mit_next;
} }
if (cur == prev) { if (cur == prev) {
wp->w_match_head = m; wp->w_match_head = m;
} else { } else {
prev->next = m; prev->mit_next = m;
} }
m->next = cur; m->mit_next = cur;
redraw_later(wp, rtype); redraw_later(wp, rtype);
return id; return id;
fail: fail:
xfree(m->mit_pattern);
xfree(m->mit_pos_array);
xfree(m); xfree(m);
return -1; return -1;
} }
@ -231,15 +234,14 @@ static int match_delete(win_T *wp, int id, bool perr)
if (id < 1) { if (id < 1) {
if (perr) { if (perr) {
semsg(_("E802: Invalid ID: %" PRId64 semsg(_("E802: Invalid ID: %" PRId64 " (must be greater than or equal to 1)"),
" (must be greater than or equal to 1)"),
(int64_t)id); (int64_t)id);
} }
return -1; return -1;
} }
while (cur != NULL && cur->id != id) { while (cur != NULL && cur->mit_id != id) {
prev = cur; prev = cur;
cur = cur->next; cur = cur->mit_next;
} }
if (cur == NULL) { if (cur == NULL) {
if (perr) { if (perr) {
@ -248,28 +250,29 @@ static int match_delete(win_T *wp, int id, bool perr)
return -1; return -1;
} }
if (cur == prev) { if (cur == prev) {
wp->w_match_head = cur->next; wp->w_match_head = cur->mit_next;
} else { } else {
prev->next = cur->next; prev->mit_next = cur->mit_next;
} }
vim_regfree(cur->match.regprog); vim_regfree(cur->mit_match.regprog);
xfree(cur->pattern); xfree(cur->mit_pattern);
if (cur->pos.toplnum != 0) { if (cur->mit_toplnum != 0) {
if (wp->w_buffer->b_mod_set) { if (wp->w_buffer->b_mod_set) {
if (wp->w_buffer->b_mod_top > cur->pos.toplnum) { if (wp->w_buffer->b_mod_top > cur->mit_toplnum) {
wp->w_buffer->b_mod_top = cur->pos.toplnum; wp->w_buffer->b_mod_top = cur->mit_toplnum;
} }
if (wp->w_buffer->b_mod_bot < cur->pos.botlnum) { if (wp->w_buffer->b_mod_bot < cur->mit_botlnum) {
wp->w_buffer->b_mod_bot = cur->pos.botlnum; wp->w_buffer->b_mod_bot = cur->mit_botlnum;
} }
} else { } else {
wp->w_buffer->b_mod_set = true; wp->w_buffer->b_mod_set = true;
wp->w_buffer->b_mod_top = cur->pos.toplnum; wp->w_buffer->b_mod_top = cur->mit_toplnum;
wp->w_buffer->b_mod_bot = cur->pos.botlnum; wp->w_buffer->b_mod_bot = cur->mit_botlnum;
wp->w_buffer->b_mod_xlines = 0; wp->w_buffer->b_mod_xlines = 0;
} }
rtype = UPD_VALID; rtype = UPD_VALID;
} }
xfree(cur->mit_pos_array);
xfree(cur); xfree(cur);
redraw_later(wp, rtype); redraw_later(wp, rtype);
return 0; return 0;
@ -281,9 +284,10 @@ void clear_matches(win_T *wp)
matchitem_T *m; matchitem_T *m;
while (wp->w_match_head != NULL) { while (wp->w_match_head != NULL) {
m = wp->w_match_head->next; m = wp->w_match_head->mit_next;
vim_regfree(wp->w_match_head->match.regprog); vim_regfree(wp->w_match_head->mit_match.regprog);
xfree(wp->w_match_head->pattern); xfree(wp->w_match_head->mit_pattern);
xfree(wp->w_match_head->mit_pos_array);
xfree(wp->w_match_head); xfree(wp->w_match_head);
wp->w_match_head = m; wp->w_match_head = m;
} }
@ -292,12 +296,12 @@ void clear_matches(win_T *wp)
/// Get match from ID 'id' in window 'wp'. /// Get match from ID 'id' in window 'wp'.
/// Return NULL if match not found. /// Return NULL if match not found.
matchitem_T *get_match(win_T *wp, int id) static matchitem_T *get_match(win_T *wp, int id)
{ {
matchitem_T *cur = wp->w_match_head; matchitem_T *cur = wp->w_match_head;
while (cur != NULL && cur->id != id) { while (cur != NULL && cur->mit_id != id) {
cur = cur->next; cur = cur->mit_next;
} }
return cur; return cur;
} }
@ -310,18 +314,18 @@ void init_search_hl(win_T *wp, match_T *search_hl)
// match // match
matchitem_T *cur = wp->w_match_head; matchitem_T *cur = wp->w_match_head;
while (cur != NULL) { while (cur != NULL) {
cur->hl.rm = cur->match; cur->mit_hl.rm = cur->mit_match;
if (cur->hlg_id == 0) { if (cur->mit_hlg_id == 0) {
cur->hl.attr = 0; cur->mit_hl.attr = 0;
} else { } else {
cur->hl.attr = syn_id2attr(cur->hlg_id); cur->mit_hl.attr = syn_id2attr(cur->mit_hlg_id);
} }
cur->hl.buf = wp->w_buffer; cur->mit_hl.buf = wp->w_buffer;
cur->hl.lnum = 0; cur->mit_hl.lnum = 0;
cur->hl.first_lnum = 0; cur->mit_hl.first_lnum = 0;
// Set the time limit to 'redrawtime'. // Set the time limit to 'redrawtime'.
cur->hl.tm = profile_setlimit(p_rdt); cur->mit_hl.tm = profile_setlimit(p_rdt);
cur = cur->next; cur = cur->mit_next;
} }
search_hl->buf = wp->w_buffer; search_hl->buf = wp->w_buffer;
search_hl->lnum = 0; search_hl->lnum = 0;
@ -332,19 +336,19 @@ void init_search_hl(win_T *wp, match_T *search_hl)
} }
/// @param shl points to a match. Fill on match. /// @param shl points to a match. Fill on match.
/// @param posmatch match positions /// @param posmatch match item with positions
/// @param mincol minimal column for a match /// @param mincol minimal column for a match
/// ///
/// @return one on match, otherwise return zero. /// @return one on match, otherwise return zero.
static int next_search_hl_pos(match_T *shl, linenr_T lnum, posmatch_T *posmatch, colnr_T mincol) static int next_search_hl_pos(match_T *shl, linenr_T lnum, matchitem_T *match, colnr_T mincol)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
int i; int i;
int found = -1; int found = -1;
shl->lnum = 0; shl->lnum = 0;
for (i = posmatch->cur; i < MAXPOSMATCH; i++) { for (i = match->mit_pos_cur; i < match->mit_pos_count; i++) {
llpos_T *pos = &posmatch->pos[i]; llpos_T *pos = &match->mit_pos_array[i];
if (pos->lnum == 0) { if (pos->lnum == 0) {
break; break;
@ -354,25 +358,24 @@ static int next_search_hl_pos(match_T *shl, linenr_T lnum, posmatch_T *posmatch,
} }
if (pos->lnum == lnum) { if (pos->lnum == lnum) {
if (found >= 0) { if (found >= 0) {
// if this match comes before the one at "found" then swap // if this match comes before the one at "found" then swap them
// them if (pos->col < match->mit_pos_array[found].col) {
if (pos->col < posmatch->pos[found].col) {
llpos_T tmp = *pos; llpos_T tmp = *pos;
*pos = posmatch->pos[found]; *pos = match->mit_pos_array[found];
posmatch->pos[found] = tmp; match->mit_pos_array[found] = tmp;
} }
} else { } else {
found = i; found = i;
} }
} }
} }
posmatch->cur = 0; match->mit_pos_cur = 0;
if (found >= 0) { if (found >= 0) {
colnr_T start = posmatch->pos[found].col == 0 colnr_T start = match->mit_pos_array[found].col == 0
? 0: posmatch->pos[found].col - 1; ? 0: match->mit_pos_array[found].col - 1;
colnr_T end = posmatch->pos[found].col == 0 colnr_T end = match->mit_pos_array[found].col == 0
? MAXCOL : start + posmatch->pos[found].len; ? MAXCOL : start + match->mit_pos_array[found].len;
shl->lnum = lnum; shl->lnum = lnum;
shl->rm.startpos[0].lnum = 0; shl->rm.startpos[0].lnum = 0;
@ -381,7 +384,7 @@ static int next_search_hl_pos(match_T *shl, linenr_T lnum, posmatch_T *posmatch,
shl->rm.endpos[0].col = end; shl->rm.endpos[0].col = end;
shl->is_addpos = true; shl->is_addpos = true;
shl->has_cursor = false; shl->has_cursor = false;
posmatch->cur = found + 1; match->mit_pos_cur = found + 1;
return 1; return 1;
} }
return 0; return 0;
@ -460,18 +463,17 @@ static void next_search_hl(win_T *win, match_T *search_hl, match_T *shl, linenr_
shl->lnum = lnum; shl->lnum = lnum;
if (shl->rm.regprog != NULL) { if (shl->rm.regprog != NULL) {
// Remember whether shl->rm is using a copy of the regprog in // Remember whether shl->rm is using a copy of the regprog in
// cur->match. // cur->mit_match.
bool regprog_is_copy = (shl != search_hl bool regprog_is_copy = (shl != search_hl && cur != NULL
&& cur != NULL && shl == &cur->mit_hl
&& shl == &cur->hl && cur->mit_match.regprog == cur->mit_hl.rm.regprog);
&& cur->match.regprog == cur->hl.rm.regprog);
int timed_out = false; int timed_out = false;
nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum, matchcol, nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum, matchcol,
&(shl->tm), &timed_out); &(shl->tm), &timed_out);
// Copy the regprog, in case it got freed and recompiled. // Copy the regprog, in case it got freed and recompiled.
if (regprog_is_copy) { if (regprog_is_copy) {
cur->match.regprog = cur->hl.rm.regprog; cur->mit_match.regprog = cur->mit_hl.rm.regprog;
} }
if (called_emsg > called_emsg_before || got_int || timed_out) { if (called_emsg > called_emsg_before || got_int || timed_out) {
// Error while handling regexp: stop using this regexp. // Error while handling regexp: stop using this regexp.
@ -486,7 +488,7 @@ static void next_search_hl(win_T *win, match_T *search_hl, match_T *shl, linenr_
break; break;
} }
} else if (cur != NULL) { } else if (cur != NULL) {
nmatched = next_search_hl_pos(shl, lnum, &(cur->pos), matchcol); nmatched = next_search_hl_pos(shl, lnum, cur, matchcol);
} }
if (nmatched == 0) { if (nmatched == 0) {
shl->lnum = 0; // no match found shl->lnum = 0; // no match found
@ -521,7 +523,7 @@ void prepare_search_hl(win_T *wp, match_T *search_hl, linenr_T lnum)
shl = search_hl; shl = search_hl;
shl_flag = true; shl_flag = true;
} else { } else {
shl = &cur->hl; // -V595 shl = &cur->mit_hl; // -V595
} }
if (shl->rm.regprog != NULL if (shl->rm.regprog != NULL
&& shl->lnum == 0 && shl->lnum == 0
@ -536,7 +538,7 @@ void prepare_search_hl(win_T *wp, match_T *search_hl, linenr_T lnum)
} }
} }
if (cur != NULL) { if (cur != NULL) {
cur->pos.cur = 0; cur->mit_pos_cur = 0;
} }
bool pos_inprogress = true; // mark that a position match search is bool pos_inprogress = true; // mark that a position match search is
// in progress // in progress
@ -545,7 +547,7 @@ void prepare_search_hl(win_T *wp, match_T *search_hl, linenr_T lnum)
|| (cur != NULL && pos_inprogress))) { || (cur != NULL && pos_inprogress))) {
next_search_hl(wp, search_hl, shl, shl->first_lnum, (colnr_T)n, next_search_hl(wp, search_hl, shl, shl->first_lnum, (colnr_T)n,
shl == search_hl ? NULL : cur); shl == search_hl ? NULL : cur);
pos_inprogress = !(cur == NULL || cur->pos.cur == 0); pos_inprogress = !(cur == NULL || cur->mit_pos_cur == 0);
if (shl->lnum != 0) { if (shl->lnum != 0) {
shl->first_lnum = shl->lnum shl->first_lnum = shl->lnum
+ shl->rm.endpos[0].lnum + shl->rm.endpos[0].lnum
@ -558,7 +560,7 @@ void prepare_search_hl(win_T *wp, match_T *search_hl, linenr_T lnum)
} }
} }
if (shl != search_hl && cur != NULL) { if (shl != search_hl && cur != NULL) {
cur = cur->next; cur = cur->mit_next;
} }
} }
} }
@ -598,7 +600,7 @@ bool prepare_search_hl_line(win_T *wp, linenr_T lnum, colnr_T mincol, char_u **l
shl = search_hl; shl = search_hl;
shl_flag = true; shl_flag = true;
} else { } else {
shl = &cur->hl; // -V595 shl = &cur->mit_hl; // -V595
} }
shl->startcol = MAXCOL; shl->startcol = MAXCOL;
shl->endcol = MAXCOL; shl->endcol = MAXCOL;
@ -606,7 +608,7 @@ bool prepare_search_hl_line(win_T *wp, linenr_T lnum, colnr_T mincol, char_u **l
shl->is_addpos = false; shl->is_addpos = false;
shl->has_cursor = false; shl->has_cursor = false;
if (cur != NULL) { if (cur != NULL) {
cur->pos.cur = 0; cur->mit_pos_cur = 0;
} }
next_search_hl(wp, search_hl, shl, lnum, mincol, next_search_hl(wp, search_hl, shl, lnum, mincol,
shl == search_hl ? NULL : cur); shl == search_hl ? NULL : cur);
@ -649,7 +651,7 @@ bool prepare_search_hl_line(win_T *wp, linenr_T lnum, colnr_T mincol, char_u **l
area_highlighting = true; area_highlighting = true;
} }
if (shl != search_hl && cur != NULL) { if (shl != search_hl && cur != NULL) {
cur = cur->next; cur = cur->mit_next;
} }
} }
return area_highlighting; return area_highlighting;
@ -674,14 +676,14 @@ int update_search_hl(win_T *wp, linenr_T lnum, colnr_T col, char_u **line, match
// Do this for 'search_hl' and the match list (ordered by priority). // Do this for 'search_hl' and the match list (ordered by priority).
while (cur != NULL || !shl_flag) { while (cur != NULL || !shl_flag) {
if (!shl_flag if (!shl_flag
&& (cur == NULL || cur->priority > SEARCH_HL_PRIORITY)) { && (cur == NULL || cur->mit_priority > SEARCH_HL_PRIORITY)) {
shl = search_hl; shl = search_hl;
shl_flag = true; shl_flag = true;
} else { } else {
shl = &cur->hl; shl = &cur->mit_hl;
} }
if (cur != NULL) { if (cur != NULL) {
cur->pos.cur = 0; cur->mit_pos_cur = 0;
} }
bool pos_inprogress = true; // mark that a position match search is bool pos_inprogress = true; // mark that a position match search is
// in progress // in progress
@ -706,9 +708,9 @@ int update_search_hl(win_T *wp, linenr_T lnum, colnr_T col, char_u **line, match
// the match. // the match.
if (cur != NULL if (cur != NULL
&& shl != search_hl && shl != search_hl
&& syn_name2id("Conceal") == cur->hlg_id) { && syn_name2id("Conceal") == cur->mit_hlg_id) {
*has_match_conc = col == shl->startcol ? 2 : 1; *has_match_conc = col == shl->startcol ? 2 : 1;
*match_conc = cur->conceal_char; *match_conc = cur->mit_conceal_char;
} else { } else {
*has_match_conc = 0; *has_match_conc = 0;
} }
@ -717,7 +719,7 @@ int update_search_hl(win_T *wp, linenr_T lnum, colnr_T col, char_u **line, match
next_search_hl(wp, search_hl, shl, lnum, col, next_search_hl(wp, search_hl, shl, lnum, col,
shl == search_hl ? NULL : cur); shl == search_hl ? NULL : cur);
pos_inprogress = !(cur == NULL || cur->pos.cur == 0); pos_inprogress = !(cur == NULL || cur->mit_pos_cur == 0);
// 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.
@ -755,30 +757,30 @@ int update_search_hl(win_T *wp, linenr_T lnum, colnr_T col, char_u **line, match
break; break;
} }
if (shl != search_hl && cur != NULL) { if (shl != search_hl && cur != NULL) {
cur = cur->next; cur = cur->mit_next;
} }
} }
// Use attributes from match with highest priority among // Use attributes from match with highest priority among 'search_hl' and
// 'search_hl' and the match list. // the match list.
*search_attr_from_match = false; *search_attr_from_match = false;
search_attr = search_hl->attr_cur; search_attr = search_hl->attr_cur;
cur = wp->w_match_head; cur = wp->w_match_head;
shl_flag = false; shl_flag = false;
while (cur != NULL || !shl_flag) { while (cur != NULL || !shl_flag) {
if (!shl_flag if (!shl_flag
&& (cur == NULL || cur->priority > SEARCH_HL_PRIORITY)) { && (cur == NULL || cur->mit_priority > SEARCH_HL_PRIORITY)) {
shl = search_hl; shl = search_hl;
shl_flag = true; shl_flag = true;
} else { } else {
shl = &cur->hl; shl = &cur->mit_hl;
} }
if (shl->attr_cur != 0) { if (shl->attr_cur != 0) {
search_attr = shl->attr_cur; search_attr = shl->attr_cur;
*search_attr_from_match = shl != search_hl; *search_attr_from_match = shl != search_hl;
} }
if (shl != search_hl && cur != NULL) { if (shl != search_hl && cur != NULL) {
cur = cur->next; cur = cur->mit_next;
} }
} }
// Only highlight one character after the last column. // Only highlight one character after the last column.
@ -808,12 +810,12 @@ bool get_prevcol_hl_flag(win_T *wp, match_T *search_hl, long curcol)
} else { } else {
cur = wp->w_match_head; cur = wp->w_match_head;
while (cur != NULL) { while (cur != NULL) {
if (!cur->hl.is_addpos && (prevcol == (long)cur->hl.startcol if (!cur->mit_hl.is_addpos && (prevcol == (long)cur->mit_hl.startcol
|| (prevcol > (long)cur->hl.startcol || (prevcol > (long)cur->mit_hl.startcol
&& cur->hl.endcol == MAXCOL))) { && cur->mit_hl.endcol == MAXCOL))) {
return true; return true;
} }
cur = cur->next; cur = cur->mit_next;
} }
} }
return false; return false;
@ -830,18 +832,18 @@ void get_search_match_hl(win_T *wp, match_T *search_hl, long col, int *char_attr
while (cur != NULL || !shl_flag) { while (cur != NULL || !shl_flag) {
if (!shl_flag if (!shl_flag
&& (cur == NULL || cur->priority > SEARCH_HL_PRIORITY)) { && (cur == NULL || cur->mit_priority > SEARCH_HL_PRIORITY)) {
shl = search_hl; shl = search_hl;
shl_flag = true; shl_flag = true;
} else { } else {
shl = &cur->hl; shl = &cur->mit_hl;
} }
if (col - 1 == (long)shl->startcol if (col - 1 == (long)shl->startcol
&& (shl == search_hl || !shl->is_addpos)) { && (shl == search_hl || !shl->is_addpos)) {
*char_attr = shl->attr; *char_attr = shl->attr;
} }
if (shl != search_hl && cur != NULL) { if (shl != search_hl && cur != NULL) {
cur = cur->next; cur = cur->mit_next;
} }
} }
} }
@ -895,13 +897,13 @@ void f_getmatches(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
cur = win->w_match_head; cur = win->w_match_head;
while (cur != NULL) { while (cur != NULL) {
dict_T *dict = tv_dict_alloc(); dict_T *dict = tv_dict_alloc();
if (cur->match.regprog == NULL) { if (cur->mit_match.regprog == NULL) {
// match added with matchaddpos() // match added with matchaddpos()
for (i = 0; i < MAXPOSMATCH; i++) { for (i = 0; i < cur->mit_pos_count; i++) {
llpos_T *llpos; llpos_T *llpos;
char buf[30]; // use 30 to avoid compiler warning char buf[30]; // use 30 to avoid compiler warning
llpos = &cur->pos.pos[i]; llpos = &cur->mit_pos_array[i];
if (llpos->lnum == 0) { if (llpos->lnum == 0) {
break; break;
} }
@ -916,22 +918,22 @@ void f_getmatches(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
tv_dict_add_list(dict, buf, (size_t)len, l); tv_dict_add_list(dict, buf, (size_t)len, l);
} }
} else { } else {
tv_dict_add_str(dict, S_LEN("pattern"), (const char *)cur->pattern); tv_dict_add_str(dict, S_LEN("pattern"), (const char *)cur->mit_pattern);
} }
tv_dict_add_str(dict, S_LEN("group"), tv_dict_add_str(dict, S_LEN("group"),
(const char *)syn_id2name(cur->hlg_id)); (const char *)syn_id2name(cur->mit_hlg_id));
tv_dict_add_nr(dict, S_LEN("priority"), (varnumber_T)cur->priority); tv_dict_add_nr(dict, S_LEN("priority"), (varnumber_T)cur->mit_priority);
tv_dict_add_nr(dict, S_LEN("id"), (varnumber_T)cur->id); tv_dict_add_nr(dict, S_LEN("id"), (varnumber_T)cur->mit_id);
if (cur->conceal_char) { if (cur->mit_conceal_char) {
char buf[MB_MAXBYTES + 1]; char buf[MB_MAXBYTES + 1];
buf[utf_char2bytes(cur->conceal_char, buf)] = NUL; buf[utf_char2bytes(cur->mit_conceal_char, buf)] = NUL;
tv_dict_add_str(dict, S_LEN("conceal"), buf); tv_dict_add_str(dict, S_LEN("conceal"), buf);
} }
tv_list_append_dict(rettv->vval.v_list, dict); tv_list_append_dict(rettv->vval.v_list, dict);
cur = cur->next; cur = cur->mit_next;
} }
} }
@ -1145,8 +1147,8 @@ void f_matcharg(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
if (m != NULL) { if (m != NULL) {
tv_list_append_string(rettv->vval.v_list, tv_list_append_string(rettv->vval.v_list,
(const char *)syn_id2name(m->hlg_id), -1); (const char *)syn_id2name(m->mit_hlg_id), -1);
tv_list_append_string(rettv->vval.v_list, (const char *)m->pattern, -1); tv_list_append_string(rettv->vval.v_list, (const char *)m->mit_pattern, -1);
} else { } else {
tv_list_append_string(rettv->vval.v_list, NULL, 0); tv_list_append_string(rettv->vval.v_list, NULL, 0);
tv_list_append_string(rettv->vval.v_list, NULL, 0); tv_list_append_string(rettv->vval.v_list, NULL, 0);

View File

@ -2,6 +2,7 @@
" matchaddpos(), matcharg(), matchdelete(), and setmatches(). " matchaddpos(), matcharg(), matchdelete(), and setmatches().
source screendump.vim source screendump.vim
source check.vim
function Test_match() function Test_match()
highlight MyGroup1 term=bold ctermbg=red guibg=red highlight MyGroup1 term=bold ctermbg=red guibg=red
@ -219,6 +220,21 @@ func Test_matchaddpos()
set hlsearch& set hlsearch&
endfunc endfunc
" Add 12 match positions (previously the limit was 8 positions).
func Test_matchaddpos_dump()
CheckScreendump
let lines =<< trim END
call setline(1, ['1234567890123']->repeat(14))
call matchaddpos('Search', range(1, 12)->map({i, v -> [v, v]}))
END
call writefile(lines, 'Xmatchaddpos', 'D')
let buf = RunVimInTerminal('-S Xmatchaddpos', #{rows: 14})
call VerifyScreenDump(buf, 'Test_matchaddpos_1', {})
call StopVimInTerminal(buf)
endfunc
func Test_matchaddpos_otherwin() func Test_matchaddpos_otherwin()
syntax on syntax on
new new

View File

@ -0,0 +1,38 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear = helpers.clear
local exec = helpers.exec
before_each(clear)
describe('matchaddpos()', function()
-- oldtest: Test_matchaddpos_dump()
it('can add more than 8 match positions vim-patch:9.0.0620', function()
local screen = Screen.new(60, 14)
screen:set_default_attr_ids({
[0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
[1] = {background = Screen.colors.Yellow}, -- Search
})
screen:attach()
exec([[
call setline(1, ['1234567890123']->repeat(14))
call matchaddpos('Search', range(1, 12)->map({i, v -> [v, v]}))
]])
screen:expect([[
{1:^1}234567890123 |
1{1:2}34567890123 |
12{1:3}4567890123 |
123{1:4}567890123 |
1234{1:5}67890123 |
12345{1:6}7890123 |
123456{1:7}890123 |
1234567{1:8}90123 |
12345678{1:9}0123 |
123456789{1:0}123 |
1234567890{1:1}23 |
12345678901{1:2}3 |
1234567890123 |
|
]])
end)
end)