summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-07-24 18:13:16 +0200
committerBram Moolenaar <Bram@vim.org>2019-07-24 18:13:16 +0200
commitbbca7732e8a3deb6e5dcf84739579a2667a75475 (patch)
treee254132f375b6c1b798e37923185d919dbe85c2b
parent7dfb016d25e3e3e1f4411026dda21d1536f21acc (diff)
downloadvim-git-bbca7732e8a3deb6e5dcf84739579a2667a75475.tar.gz
patch 8.1.1743: 'hlsearch' and match highlighting in the wrong placev8.1.1743
Problem: 'hlsearch' and match highlighting in the wrong place. Solution: Move highlighting from inside screen functions to highlight.c.
-rw-r--r--src/highlight.c606
-rw-r--r--src/proto/highlight.pro6
-rw-r--r--src/screen.c597
-rw-r--r--src/version.c2
4 files changed, 641 insertions, 570 deletions
diff --git a/src/highlight.c b/src/highlight.c
index fb3aede76..d02df1b38 100644
--- a/src/highlight.c
+++ b/src/highlight.c
@@ -3657,6 +3657,9 @@ free_highlight_fonts(void)
#if defined(FEAT_SEARCH_EXTRA) || defined(PROTO)
+
+# define SEARCH_HL_PRIORITY 0
+
/*
* Add match to the match list of window 'wp'. The pattern 'pat' will be
* highlighted with the group 'grp' with priority 'prio'.
@@ -3948,7 +3951,610 @@ get_match(win_T *wp, int id)
cur = cur->next;
return cur;
}
+
+/*
+ * Init for calling prepare_search_hl().
+ */
+ void
+init_search_hl(win_T *wp, match_T *search_hl)
+{
+ matchitem_T *cur;
+
+ /* Setup for match and 'hlsearch' highlighting. Disable any previous
+ * match */
+ cur = wp->w_match_head;
+ while (cur != NULL)
+ {
+ cur->hl.rm = cur->match;
+ if (cur->hlg_id == 0)
+ cur->hl.attr = 0;
+ else
+ cur->hl.attr = syn_id2attr(cur->hlg_id);
+ cur->hl.buf = wp->w_buffer;
+ cur->hl.lnum = 0;
+ cur->hl.first_lnum = 0;
+# ifdef FEAT_RELTIME
+ /* Set the time limit to 'redrawtime'. */
+ profile_setlimit(p_rdt, &(cur->hl.tm));
+# endif
+ cur = cur->next;
+ }
+ search_hl->buf = wp->w_buffer;
+ search_hl->lnum = 0;
+ search_hl->first_lnum = 0;
+ /* time limit is set at the toplevel, for all windows */
+}
+
+/*
+ * If there is a match fill "shl" and return one.
+ * Return zero otherwise.
+ */
+ static int
+next_search_hl_pos(
+ 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 found = -1;
+
+ for (i = posmatch->cur; i < MAXPOSMATCH; i++)
+ {
+ llpos_T *pos = &posmatch->pos[i];
+
+ if (pos->lnum == 0)
+ break;
+ if (pos->len == 0 && pos->col < mincol)
+ continue;
+ if (pos->lnum == lnum)
+ {
+ if (found >= 0)
+ {
+ /* if this match comes before the one at "found" then swap
+ * them */
+ if (pos->col < posmatch->pos[found].col)
+ {
+ llpos_T tmp = *pos;
+
+ *pos = posmatch->pos[found];
+ posmatch->pos[found] = tmp;
+ }
+ }
+ else
+ found = i;
+ }
+ }
+ posmatch->cur = 0;
+ if (found >= 0)
+ {
+ colnr_T start = posmatch->pos[found].col == 0
+ ? 0 : posmatch->pos[found].col - 1;
+ colnr_T end = posmatch->pos[found].col == 0
+ ? MAXCOL : start + posmatch->pos[found].len;
+
+ shl->lnum = lnum;
+ shl->rm.startpos[0].lnum = 0;
+ shl->rm.startpos[0].col = start;
+ shl->rm.endpos[0].lnum = 0;
+ shl->rm.endpos[0].col = end;
+ shl->is_addpos = TRUE;
+ posmatch->cur = found + 1;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Search for a next 'hlsearch' or match.
+ * Uses shl->buf.
+ * Sets shl->lnum and shl->rm contents.
+ * Note: Assumes a previous match is always before "lnum", unless
+ * shl->lnum is zero.
+ * Careful: Any pointers for buffer lines will become invalid.
+ */
+ static void
+next_search_hl(
+ win_T *win,
+ match_T *search_hl,
+ 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 positions if any
+{
+ linenr_T l;
+ colnr_T matchcol;
+ long nmatched;
+ int save_called_emsg = called_emsg;
+
+ // for :{range}s/pat only highlight inside the range
+ if (lnum < search_first_line || lnum > search_last_line)
+ {
+ shl->lnum = 0;
+ return;
+ }
+
+ if (shl->lnum != 0)
+ {
+ /* Check for three situations:
+ * 1. If the "lnum" is below a previous match, start a new search.
+ * 2. If the previous match includes "mincol", use it.
+ * 3. Continue after the previous match.
+ */
+ l = shl->lnum + shl->rm.endpos[0].lnum - shl->rm.startpos[0].lnum;
+ if (lnum > l)
+ shl->lnum = 0;
+ else if (lnum < l || shl->rm.endpos[0].col > mincol)
+ return;
+ }
+
+ /*
+ * Repeat searching for a match until one is found that includes "mincol"
+ * or none is found in this line.
+ */
+ called_emsg = FALSE;
+ for (;;)
+ {
+# ifdef FEAT_RELTIME
+ /* Stop searching after passing the time limit. */
+ if (profile_passed_limit(&(shl->tm)))
+ {
+ shl->lnum = 0; /* no match found in time */
+ break;
+ }
+# endif
+ /* Three situations:
+ * 1. No useful previous match: search from start of line.
+ * 2. Not Vi compatible or empty match: continue at next character.
+ * Break the loop if this is beyond the end of the line.
+ * 3. Vi compatible searching: continue at end of previous match.
+ */
+ if (shl->lnum == 0)
+ matchcol = 0;
+ else if (vim_strchr(p_cpo, CPO_SEARCH) == NULL
+ || (shl->rm.endpos[0].lnum == 0
+ && shl->rm.endpos[0].col <= shl->rm.startpos[0].col))
+ {
+ char_u *ml;
+
+ matchcol = shl->rm.startpos[0].col;
+ ml = ml_get_buf(shl->buf, lnum, FALSE) + matchcol;
+ if (*ml == NUL)
+ {
+ ++matchcol;
+ shl->lnum = 0;
+ break;
+ }
+ if (has_mbyte)
+ matchcol += mb_ptr2len(ml);
+ else
+ ++matchcol;
+ }
+ else
+ matchcol = shl->rm.endpos[0].col;
+
+ shl->lnum = lnum;
+ if (shl->rm.regprog != NULL)
+ {
+ /* Remember whether shl->rm is using a copy of the regprog in
+ * cur->match. */
+ int regprog_is_copy = (shl != search_hl && cur != NULL
+ && shl == &cur->hl
+ && cur->match.regprog == cur->hl.rm.regprog);
+ int timed_out = FALSE;
+
+ nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum,
+ matchcol,
+#ifdef FEAT_RELTIME
+ &(shl->tm), &timed_out
+#else
+ NULL, NULL
#endif
+ );
+ /* Copy the regprog, in case it got freed and recompiled. */
+ if (regprog_is_copy)
+ cur->match.regprog = cur->hl.rm.regprog;
+
+ if (called_emsg || got_int || timed_out)
+ {
+ /* 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;
+ }
+ }
+ else if (cur != NULL)
+ nmatched = next_search_hl_pos(shl, lnum, &(cur->pos), matchcol);
+ else
+ nmatched = 0;
+ if (nmatched == 0)
+ {
+ shl->lnum = 0; /* no match found */
+ break;
+ }
+ if (shl->rm.startpos[0].lnum > 0
+ || shl->rm.startpos[0].col >= mincol
+ || nmatched > 1
+ || shl->rm.endpos[0].col > mincol)
+ {
+ shl->lnum += shl->rm.startpos[0].lnum;
+ break; /* useful match found */
+ }
+ }
+
+ // Restore called_emsg for assert_fails().
+ called_emsg = save_called_emsg;
+}
+
+/*
+ * Advance to the match in window "wp" line "lnum" or past it.
+ */
+ void
+prepare_search_hl(win_T *wp, match_T *search_hl, linenr_T lnum)
+{
+ matchitem_T *cur; /* points to the match list */
+ match_T *shl; /* points to search_hl or a match */
+ int shl_flag; /* flag to indicate whether search_hl
+ has been processed or not */
+ int pos_inprogress; /* marks that position match search is
+ in progress */
+ int n;
+
+ /*
+ * When using a multi-line pattern, start searching at the top
+ * of the window or just after a closed fold.
+ * Do this both for search_hl and the match list.
+ */
+ cur = wp->w_match_head;
+ shl_flag = WIN_IS_POPUP(wp); // skip search_hl in a popup window
+ while (cur != NULL || shl_flag == FALSE)
+ {
+ if (shl_flag == FALSE)
+ {
+ shl = search_hl;
+ shl_flag = TRUE;
+ }
+ else
+ shl = &cur->hl;
+ if (shl->rm.regprog != NULL
+ && shl->lnum == 0
+ && re_multiline(shl->rm.regprog))
+ {
+ if (shl->first_lnum == 0)
+ {
+# ifdef FEAT_FOLDING
+ for (shl->first_lnum = lnum;
+ shl->first_lnum > wp->w_topline; --shl->first_lnum)
+ if (hasFoldingWin(wp, shl->first_lnum - 1,
+ NULL, NULL, TRUE, NULL))
+ break;
+# else
+ 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
+ || (cur != NULL && pos_inprogress)))
+ {
+ next_search_hl(wp, search_hl, shl, shl->first_lnum, (colnr_T)n,
+ shl == search_hl ? NULL : cur);
+ pos_inprogress = cur == NULL || cur->pos.cur == 0
+ ? FALSE : TRUE;
+ if (shl->lnum != 0)
+ {
+ shl->first_lnum = shl->lnum
+ + shl->rm.endpos[0].lnum
+ - shl->rm.startpos[0].lnum;
+ n = shl->rm.endpos[0].col;
+ }
+ else
+ {
+ ++shl->first_lnum;
+ n = 0;
+ }
+ }
+ }
+ if (shl != search_hl && cur != NULL)
+ cur = cur->next;
+ }
+}
+
+/*
+ * Prepare for 'hlsearch' and match highlighting in one window line.
+ * Return TRUE if there is such highlighting and set "search_attr" to the
+ * current highlight attribute.
+ */
+ int
+prepare_search_hl_line(
+ win_T *wp,
+ linenr_T lnum,
+ colnr_T mincol,
+ char_u **line,
+ match_T *search_hl,
+ int *search_attr)
+{
+ matchitem_T *cur; // points to the match list
+ match_T *shl; // points to search_hl or a match
+ int shl_flag; // flag to indicate whether search_hl
+ // has been processed or not
+ int area_highlighting = FALSE;
+
+ /*
+ * Handle highlighting the last used search pattern and matches.
+ * Do this for both search_hl and the match list.
+ * Do not use search_hl in a popup window.
+ */
+ cur = wp->w_match_head;
+ shl_flag = WIN_IS_POPUP(wp);
+ while (cur != NULL || shl_flag == FALSE)
+ {
+ if (shl_flag == FALSE)
+ {
+ shl = search_hl;
+ shl_flag = TRUE;
+ }
+ else
+ shl = &cur->hl;
+ shl->startcol = MAXCOL;
+ shl->endcol = MAXCOL;
+ shl->attr_cur = 0;
+ shl->is_addpos = FALSE;
+ if (cur != NULL)
+ cur->pos.cur = 0;
+ next_search_hl(wp, search_hl, shl, lnum, mincol,
+ shl == search_hl ? NULL : 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);
+
+ 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 (has_mbyte && (*line)[shl->endcol] != NUL)
+ shl->endcol += (*mb_ptr2len)((*line) + shl->endcol);
+ else
+ ++shl->endcol;
+ }
+ if ((long)shl->startcol < mincol) /* match at leftcol */
+ {
+ shl->attr_cur = shl->attr;
+ *search_attr = shl->attr;
+ }
+ area_highlighting = TRUE;
+ }
+ if (shl != search_hl && cur != NULL)
+ cur = cur->next;
+ }
+ return area_highlighting;
+}
+
+/*
+ * For a position in a line: Check for start/end of 'hlsearch' and other
+ * matches.
+ * After end, check for start/end of next match.
+ * When another match, have to check for start again.
+ * Watch out for matching an empty string!
+ * Return the udpated search_attr.
+ */
+ int
+update_search_hl(
+ win_T *wp,
+ linenr_T lnum,
+ colnr_T col,
+ char_u **line,
+ match_T *search_hl,
+ int *has_match_conc,
+ int *match_conc,
+ int did_line_attr,
+ int lcs_eol_one)
+{
+ matchitem_T *cur; // points to the match list
+ match_T *shl; // points to search_hl or a match
+ int shl_flag; // flag to indicate whether search_hl
+ // has been processed or not
+ int pos_inprogress; // marks that position match search is in
+ // progress
+ int search_attr = 0;
+
+
+ // Do this for 'search_hl' and the match list (ordered by priority).
+ cur = wp->w_match_head;
+ shl_flag = WIN_IS_POPUP(wp);
+ while (cur != NULL || shl_flag == FALSE)
+ {
+ if (shl_flag == FALSE
+ && ((cur != NULL
+ && cur->priority > SEARCH_HL_PRIORITY)
+ || cur == NULL))
+ {
+ shl = search_hl;
+ shl_flag = TRUE;
+ }
+ else
+ shl = &cur->hl;
+ if (cur != NULL)
+ cur->pos.cur = 0;
+ pos_inprogress = TRUE;
+ while (shl->rm.regprog != NULL || (cur != NULL && pos_inprogress))
+ {
+ if (shl->startcol != MAXCOL
+ && col >= shl->startcol
+ && col < shl->endcol)
+ {
+ int next_col = col + MB_PTR2LEN(*line + col);
+
+ if (shl->endcol < next_col)
+ shl->endcol = next_col;
+ shl->attr_cur = shl->attr;
+# ifdef FEAT_CONCEAL
+ // Match with the "Conceal" group results in hiding
+ // the match.
+ if (cur != NULL
+ && shl != search_hl
+ && syn_name2id((char_u *)"Conceal") == cur->hlg_id)
+ {
+ *has_match_conc = col == shl->startcol ? 2 : 1;
+ *match_conc = cur->conceal_char;
+ }
+ else
+ *has_match_conc = *match_conc = 0;
+# endif
+ }
+ else if (col == shl->endcol)
+ {
+ shl->attr_cur = 0;
+ next_search_hl(wp, search_hl, shl, lnum, col,
+ shl == search_hl ? NULL : cur);
+ pos_inprogress = !(cur == NULL || cur->pos.cur == 0);
+
+ // Need to get the line again, a multi-line regexp may have
+ // made it invalid.
+ *line = ml_get_buf(wp->w_buffer, lnum, FALSE);
+
+ if (shl->lnum == lnum)
+ {
+ shl->startcol = shl->rm.startpos[0].col;
+ if (shl->rm.endpos[0].lnum == 0)
+ shl->endcol = shl->rm.endpos[0].col;
+ else
+ shl->endcol = MAXCOL;
+
+ if (shl->startcol == shl->endcol)
+ {
+ /* highlight empty match, try again after
+ * it */
+ if (has_mbyte)
+ shl->endcol += (*mb_ptr2len)(*line + shl->endcol);
+ else
+ ++shl->endcol;
+ }
+
+ /* Loop to check if the match starts at the
+ * current position */
+ continue;
+ }
+ }
+ break;
+ }
+ if (shl != search_hl && cur != NULL)
+ cur = cur->next;
+ }
+
+ // Use attributes from match with highest priority among 'search_hl' and
+ // the match list.
+ cur = wp->w_match_head;
+ shl_flag = WIN_IS_POPUP(wp);
+ while (cur != NULL || shl_flag == FALSE)
+ {
+ if (shl_flag == FALSE
+ && ((cur != NULL
+ && cur->priority > SEARCH_HL_PRIORITY)
+ || cur == NULL))
+ {
+ shl = search_hl;
+ shl_flag = TRUE;
+ }
+ else
+ shl = &cur->hl;
+ if (shl->attr_cur != 0)
+ search_attr = shl->attr_cur;
+ if (shl != search_hl && cur != NULL)
+ cur = cur->next;
+ }
+ /* Only highlight one character after the last column. */
+ if (*(*line + col) == NUL && (did_line_attr >= 1
+ || (wp->w_p_list && lcs_eol_one == -1)))
+ search_attr = 0;
+ return search_attr;
+}
+
+ int
+get_prevcol_hl_flag(win_T *wp, match_T *search_hl, long curcol)
+{
+ long prevcol = curcol;
+ int prevcol_hl_flag = FALSE;
+ matchitem_T *cur; // points to the match list
+
+ // we're not really at that column when skipping some text
+ if ((long)(wp->w_p_wrap ? wp->w_skipcol : wp->w_leftcol) > prevcol)
+ ++prevcol;
+
+ if (!search_hl->is_addpos && prevcol == (long)search_hl->startcol)
+ prevcol_hl_flag = TRUE;
+ else
+ {
+ cur = wp->w_match_head;
+ while (cur != NULL)
+ {
+ if (!cur->hl.is_addpos && prevcol == (long)cur->hl.startcol)
+ {
+ prevcol_hl_flag = TRUE;
+ break;
+ }
+ cur = cur->next;
+ }
+ }
+ return prevcol_hl_flag;
+}
+
+/*
+ * Get highlighting for the char after the text in "char_attr" from 'hlsearch'
+ * or match highlighting.
+ */
+ void
+get_search_match_hl(win_T *wp, match_T *search_hl, long col, int *char_attr)
+{
+ matchitem_T *cur; // points to the match list
+ match_T *shl; // points to search_hl or a match
+ int shl_flag; // flag to indicate whether search_hl
+ // has been processed or not
+
+ cur = wp->w_match_head;
+ shl_flag = WIN_IS_POPUP(wp);
+ while (cur != NULL || shl_flag == FALSE)
+ {
+ if (shl_flag == FALSE
+ && ((cur != NULL
+ && cur->priority > SEARCH_HL_PRIORITY)
+ || cur == NULL))
+ {
+ shl = search_hl;
+ shl_flag = TRUE;
+ }
+ else
+ shl = &cur->hl;
+ if (col - 1 == (long)shl->startcol
+ && (shl == search_hl || !shl->is_addpos))
+ *char_attr = shl->attr;
+ if (shl != search_hl && cur != NULL)
+ cur = cur->next;
+ }
+}
+
+#endif // FEAT_SEARCH_EXTRA
#if defined(FEAT_EVAL) || defined(PROTO)
# ifdef FEAT_SEARCH_EXTRA
diff --git a/src/proto/highlight.pro b/src/proto/highlight.pro
index 61cea3655..4a8ea3cca 100644
--- a/src/proto/highlight.pro
+++ b/src/proto/highlight.pro
@@ -44,6 +44,12 @@ char_u *get_highlight_name(expand_T *xp, int idx);
char_u *get_highlight_name_ext(expand_T *xp, int idx, int skip_cleared);
void free_highlight_fonts(void);
void clear_matches(win_T *wp);
+void init_search_hl(win_T *wp, match_T *search_hl);
+void prepare_search_hl(win_T *wp, match_T *search_hl, linenr_T lnum);
+int prepare_search_hl_line(win_T *wp, linenr_T lnum, colnr_T mincol, char_u **line, match_T *search_hl, int *search_attr);
+int update_search_hl(win_T *wp, linenr_T lnum, colnr_T col, char_u **line, match_T *search_hl, int *has_match_conc, int *match_conc, int did_line_attr, int lcs_eol_one);
+int get_prevcol_hl_flag(win_T *wp, match_T *search_hl, long curcol);
+void get_search_match_hl(win_T *wp, match_T *search_hl, long col, int *char_attr);
void f_clearmatches(typval_T *argvars, typval_T *rettv);
void f_getmatches(typval_T *argvars, typval_T *rettv);
void f_setmatches(typval_T *argvars, typval_T *rettv);
diff --git a/src/screen.c b/src/screen.c
index bd76f7ba5..bdc4b47c3 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -104,7 +104,7 @@ static int screen_attr = 0;
static int screen_cur_row, screen_cur_col; /* last known cursor position */
#ifdef FEAT_SEARCH_EXTRA
-static match_T search_hl; /* used for 'hlsearch' highlight matching */
+static match_T search_hl; // used for 'hlsearch' highlight matching
#endif
#ifdef FEAT_FOLDING
@@ -135,13 +135,8 @@ static void draw_vsep_win(win_T *wp, int row);
static void redraw_custom_statusline(win_T *wp);
#endif
#ifdef FEAT_SEARCH_EXTRA
-# define SEARCH_HL_PRIORITY 0
static void start_search_hl(void);
static void end_search_hl(void);
-static void init_search_hl(win_T *wp);
-static void prepare_search_hl(win_T *wp, linenr_T lnum);
-static void next_search_hl(win_T *win, match_T *shl, linenr_T lnum, colnr_T mincol, matchitem_T *cur);
-static int next_search_hl_pos(match_T *shl, linenr_T lnum, posmatch_T *pos, colnr_T mincol);
#endif
static void screen_char(unsigned off, int row, int col);
static void screen_char_2(unsigned off, int row, int col);
@@ -1172,7 +1167,7 @@ win_update(win_T *wp)
#endif
#ifdef FEAT_SEARCH_EXTRA
- init_search_hl(wp);
+ init_search_hl(wp, &search_hl);
#endif
#ifdef FEAT_LINEBREAK
@@ -2090,7 +2085,7 @@ win_update(win_T *wp)
else
{
#ifdef FEAT_SEARCH_EXTRA
- prepare_search_hl(wp, lnum);
+ prepare_search_hl(wp, &search_hl, lnum);
#endif
#ifdef FEAT_SYN_HL
/* Let the syntax stuff know we skipped a few lines. */
@@ -3273,17 +3268,6 @@ win_line(
int sign_present = FALSE;
sign_attrs_T sattr;
#endif
-#ifdef FEAT_SEARCH_EXTRA
- matchitem_T *cur; /* points to the match list */
- match_T *shl; /* points to search_hl or a match */
- int shl_flag; /* flag to indicate whether search_hl
- has been processed or not */
- int 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 */
-#endif
#ifdef FEAT_ARABIC
int prev_c = 0; /* previous Arabic character */
int prev_c1 = 0; /* first composing char for prev_c */
@@ -3808,65 +3792,12 @@ win_line(
}
#ifdef FEAT_SEARCH_EXTRA
- /*
- * Handle highlighting the last used search pattern and matches.
- * Do this for both search_hl and the match list.
- * Do not use search_hl in a popup window.
- */
- cur = wp->w_match_head;
- shl_flag = (screen_line_flags & SLF_POPUP);
- while ((cur != NULL || shl_flag == FALSE) && !number_only)
+ if (!number_only)
{
- if (shl_flag == FALSE)
- {
- shl = &search_hl;
- shl_flag = TRUE;
- }
- else
- shl = &cur->hl;
- shl->startcol = MAXCOL;
- shl->endcol = MAXCOL;
- shl->attr_cur = 0;
- shl->is_addpos = FALSE;
v = (long)(ptr - line);
- if (cur != NULL)
- cur->pos.cur = 0;
- next_search_hl(wp, shl, lnum, (colnr_T)v,
- shl == &search_hl ? NULL : 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;
-
- 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 (has_mbyte && line[shl->endcol] != NUL)
- shl->endcol += (*mb_ptr2len)(line + shl->endcol);
- else
- ++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;
+ area_highlighting |= prepare_search_hl_line(wp, lnum, (colnr_T)v,
+ &line, &search_hl, &search_attr);
+ ptr = line + v; // "line" may have been updated
}
#endif
@@ -4247,132 +4178,15 @@ win_line(
if (!n_extra)
{
/*
- * Check for start/end of search pattern match.
+ * Check for start/end of 'hlsearch' and other matches.
* After end, check for start/end of next match.
* When another match, have to check for start again.
- * Watch out for matching an empty string!
- * Do this for 'search_hl' and the match list (ordered by
- * priority).
*/
v = (long)(ptr - line);
- cur = wp->w_match_head;
- shl_flag = FALSE;
- while (cur != NULL || shl_flag == FALSE)
- {
- if (shl_flag == FALSE
- && ((cur != NULL
- && cur->priority > SEARCH_HL_PRIORITY)
- || cur == NULL))
- {
- shl = &search_hl;
- shl_flag = TRUE;
- if (screen_line_flags & SLF_POPUP)
- continue; // do not use search_hl
- }
- else
- shl = &cur->hl;
- 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
- && v < (long)shl->endcol)
- {
- int tmp_col = v + MB_PTR2LEN(ptr);
-
- if (shl->endcol < tmp_col)
- shl->endcol = tmp_col;
- shl->attr_cur = shl->attr;
-#ifdef FEAT_CONCEAL
- // Match with the "Conceal" group results in hiding
- // the match.
- if (cur != NULL
- && shl != &search_hl
- && syn_name2id((char_u *)"Conceal")
- == cur->hlg_id)
- {
- has_match_conc =
- v == (long)shl->startcol ? 2 : 1;
- match_conc = cur->conceal_char;
- }
- else
- has_match_conc = match_conc = 0;
-#endif
- }
- else if (v == (long)shl->endcol)
- {
- shl->attr_cur = 0;
- next_search_hl(wp, shl, lnum, (colnr_T)v,
- shl == &search_hl ? NULL : 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. */
- line = ml_get_buf(wp->w_buffer, lnum, FALSE);
- ptr = line + v;
-
- if (shl->lnum == lnum)
- {
- shl->startcol = shl->rm.startpos[0].col;
- if (shl->rm.endpos[0].lnum == 0)
- shl->endcol = shl->rm.endpos[0].col;
- else
- shl->endcol = MAXCOL;
-
- if (shl->startcol == shl->endcol)
- {
- /* highlight empty match, try again after
- * it */
- if (has_mbyte)
- shl->endcol += (*mb_ptr2len)(line
- + shl->endcol);
- else
- ++shl->endcol;
- }
-
- /* Loop to check if the match starts at the
- * current position */
- continue;
- }
- }
- break;
- }
- if (shl != &search_hl && cur != NULL)
- cur = cur->next;
- }
-
- /* Use attributes from match with highest priority among
- * 'search_hl' and the match list. */
- cur = wp->w_match_head;
- shl_flag = FALSE;
- search_attr = 0;
- while (cur != NULL || shl_flag == FALSE)
- {
- if (shl_flag == FALSE
- && ((cur != NULL
- && cur->priority > SEARCH_HL_PRIORITY)
- || cur == NULL))
- {
- shl = &search_hl;
- shl_flag = TRUE;
- if (screen_line_flags & SLF_POPUP)
- continue; // do not use search_hl
- }
- else
- shl = &cur->hl;
- if (shl->attr_cur != 0)
- search_attr = shl->attr_cur;
- if (shl != &search_hl && cur != NULL)
- cur = cur->next;
- }
- /* Only highlight one character after the last column. */
- if (*ptr == NUL && (did_line_attr >= 1
- || (wp->w_p_list && lcs_eol_one == -1)))
- search_attr = 0;
+ search_attr = update_search_hl(wp, lnum, (colnr_T)v, &line,
+ &search_hl, &has_match_conc, &match_conc,
+ did_line_attr, lcs_eol_one);
+ ptr = line + v; // "line" may have been changed
}
#endif
@@ -5561,35 +5375,15 @@ win_line(
) && eol_hl_off == 0)
{
#ifdef FEAT_SEARCH_EXTRA
- long prevcol = (long)(ptr - line) - (c == NUL);
-
- /* we're not really at that column when skipping some text */
- if ((long)(wp->w_p_wrap ? wp->w_skipcol : wp->w_leftcol) > prevcol)
- ++prevcol;
-#endif
-
- /* Invert at least one char, used for Visual and empty line or
- * highlight match at end of line. If it's beyond the last
- * char on the screen, just overwrite that one (tricky!) Not
- * needed when a '$' was displayed for 'list'. */
-#ifdef FEAT_SEARCH_EXTRA
- prevcol_hl_flag = FALSE;
- if (!search_hl.is_addpos && prevcol == (long)search_hl.startcol)
- prevcol_hl_flag = TRUE;
- else
- {
- cur = wp->w_match_head;
- while (cur != NULL)
- {
- if (!cur->hl.is_addpos && prevcol == (long)cur->hl.startcol)
- {
- prevcol_hl_flag = TRUE;
- break;
- }
- cur = cur->next;
- }
- }
-#endif
+ // flag to indicate whether prevcol equals startcol of search_hl or
+ // one of the matches
+ int prevcol_hl_flag = get_prevcol_hl_flag(wp, &search_hl,
+ (long)(ptr - line) - (c == NUL));
+#endif
+ // Invert at least one char, used for Visual and empty line or
+ // highlight match at end of line. If it's beyond the last
+ // char on the screen, just overwrite that one (tricky!) Not
+ // needed when a '$' was displayed for 'list'.
if (lcs_eol == lcs_eol_one
&& ((area_attr != 0 && vcol == fromcol
&& (VIsual_mode != Ctrl_V
@@ -5597,8 +5391,8 @@ win_line(
|| lnum == curwin->w_cursor.lnum)
&& c == NUL)
#ifdef FEAT_SEARCH_EXTRA
- /* highlight 'hlsearch' match at end of line */
- || (prevcol_hl_flag == TRUE
+ // highlight 'hlsearch' match at end of line
+ || (prevcol_hl_flag
# ifdef FEAT_SYN_HL
&& !(wp->w_p_cul && lnum == wp->w_cursor.lnum
&& !(wp == curwin && VIsual_active))
@@ -5644,30 +5438,10 @@ win_line(
#ifdef FEAT_SEARCH_EXTRA
if (area_attr == 0)
{
- /* Use attributes from match with highest priority among
- * 'search_hl' and the match list. */
- cur = wp->w_match_head;
- shl_flag = FALSE;
- while (cur != NULL || shl_flag == FALSE)
- {
- if (shl_flag == FALSE
- && ((cur != NULL
- && cur->priority > SEARCH_HL_PRIORITY)
- || cur == NULL))
- {
- shl = &search_hl;
- shl_flag = TRUE;
- if (screen_line_flags & SLF_POPUP)
- continue; // do not use search_hl
- }
- else
- shl = &cur->hl;
- if ((ptr - line) - 1 == (long)shl->startcol
- && (shl == &search_hl || !shl->is_addpos))
- char_attr = shl->attr;
- if (shl != &search_hl && cur != NULL)
- cur = cur->next;
- }
+ // Use attributes from match with highest priority among
+ // 'search_hl' and the match list.
+ get_search_match_hl(wp, &search_hl,
+ (long)(ptr - line), &char_attr);
}
#endif
ScreenAttrs[off] = char_attr;
@@ -7892,323 +7666,6 @@ end_search_hl(void)
search_hl.rm.regprog = NULL;
}
}
-
-/*
- * Init for calling prepare_search_hl().
- */
- static void
-init_search_hl(win_T *wp)
-{
- matchitem_T *cur;
-
- /* Setup for match and 'hlsearch' highlighting. Disable any previous
- * match */
- cur = wp->w_match_head;
- while (cur != NULL)
- {
- cur->hl.rm = cur->match;
- if (cur->hlg_id == 0)
- cur->hl.attr = 0;
- else
- cur->hl.attr = syn_id2attr(cur->hlg_id);
- cur->hl.buf = wp->w_buffer;
- cur->hl.lnum = 0;
- cur->hl.first_lnum = 0;
-# ifdef FEAT_RELTIME
- /* Set the time limit to 'redrawtime'. */
- profile_setlimit(p_rdt, &(cur->hl.tm));
-# endif
- cur = cur->next;
- }
- search_hl.buf = wp->w_buffer;
- search_hl.lnum = 0;
- search_hl.first_lnum = 0;
- /* time limit is set at the toplevel, for all windows */
-}
-
-/*
- * Advance to the match in window "wp" line "lnum" or past it.
- */
- static void
-prepare_search_hl(win_T *wp, linenr_T lnum)
-{
- matchitem_T *cur; /* points to the match list */
- match_T *shl; /* points to search_hl or a match */
- int shl_flag; /* flag to indicate whether search_hl
- has been processed or not */
- int pos_inprogress; /* marks that position match search is
- in progress */
- int n;
-
- /*
- * When using a multi-line pattern, start searching at the top
- * of the window or just after a closed fold.
- * Do this both for search_hl and the match list.
- */
- cur = wp->w_match_head;
- shl_flag = FALSE;
- while (cur != NULL || shl_flag == FALSE)
- {
- if (shl_flag == FALSE)
- {
- shl = &search_hl;
- shl_flag = TRUE;
- }
- else
- shl = &cur->hl;
- if (shl->rm.regprog != NULL
- && shl->lnum == 0
- && re_multiline(shl->rm.regprog))
- {
- if (shl->first_lnum == 0)
- {
-# ifdef FEAT_FOLDING
- for (shl->first_lnum = lnum;
- shl->first_lnum > wp->w_topline; --shl->first_lnum)
- if (hasFoldingWin(wp, shl->first_lnum - 1,
- NULL, NULL, TRUE, NULL))
- break;
-# else
- 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
- || (cur != NULL && pos_inprogress)))
- {
- next_search_hl(wp, shl, shl->first_lnum, (colnr_T)n,
- shl == &search_hl ? NULL : cur);
- pos_inprogress = cur == NULL || cur->pos.cur == 0
- ? FALSE : TRUE;
- if (shl->lnum != 0)
- {
- shl->first_lnum = shl->lnum
- + shl->rm.endpos[0].lnum
- - shl->rm.startpos[0].lnum;
- n = shl->rm.endpos[0].col;
- }
- else
- {
- ++shl->first_lnum;
- n = 0;
- }
- }
- }
- if (shl != &search_hl && cur != NULL)
- cur = cur->next;
- }
-}
-
-/*
- * Search for a next 'hlsearch' or match.
- * Uses shl->buf.
- * Sets shl->lnum and shl->rm contents.
- * Note: Assumes a previous match is always before "lnum", unless
- * shl->lnum is zero.
- * Careful: Any pointers for buffer lines will become invalid.
- */
- static void
-next_search_hl(
- 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 positions if any */
-{
- linenr_T l;
- colnr_T matchcol;
- long nmatched;
- int save_called_emsg = called_emsg;
-
- // for :{range}s/pat only highlight inside the range
- if (lnum < search_first_line || lnum > search_last_line)
- {
- shl->lnum = 0;
- return;
- }
-
- if (shl->lnum != 0)
- {
- /* Check for three situations:
- * 1. If the "lnum" is below a previous match, start a new search.
- * 2. If the previous match includes "mincol", use it.
- * 3. Continue after the previous match.
- */
- l = shl->lnum + shl->rm.endpos[0].lnum - shl->rm.startpos[0].lnum;
- if (lnum > l)
- shl->lnum = 0;
- else if (lnum < l || shl->rm.endpos[0].col > mincol)
- return;
- }
-
- /*
- * Repeat searching for a match until one is found that includes "mincol"
- * or none is found in this line.
- */
- called_emsg = FALSE;
- for (;;)
- {
-#ifdef FEAT_RELTIME
- /* Stop searching after passing the time limit. */
- if (profile_passed_limit(&(shl->tm)))
- {
- shl->lnum = 0; /* no match found in time */
- break;
- }
-#endif
- /* Three situations:
- * 1. No useful previous match: search from start of line.
- * 2. Not Vi compatible or empty match: continue at next character.
- * Break the loop if this is beyond the end of the line.
- * 3. Vi compatible searching: continue at end of previous match.
- */
- if (shl->lnum == 0)
- matchcol = 0;
- else if (vim_strchr(p_cpo, CPO_SEARCH) == NULL
- || (shl->rm.endpos[0].lnum == 0
- && shl->rm.endpos[0].col <= shl->rm.startpos[0].col))
- {
- char_u *ml;
-
- matchcol = shl->rm.startpos[0].col;
- ml = ml_get_buf(shl->buf, lnum, FALSE) + matchcol;
- if (*ml == NUL)
- {
- ++matchcol;
- shl->lnum = 0;
- break;
- }
- if (has_mbyte)
- matchcol += mb_ptr2len(ml);
- else
- ++matchcol;
- }
- else
- matchcol = shl->rm.endpos[0].col;
-
- shl->lnum = lnum;
- if (shl->rm.regprog != NULL)
- {
- /* Remember whether shl->rm is using a copy of the regprog in
- * cur->match. */
- int regprog_is_copy = (shl != &search_hl && cur != NULL
- && shl == &cur->hl
- && cur->match.regprog == cur->hl.rm.regprog);
- int timed_out = FALSE;
-
- nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum,
- matchcol,
-#ifdef FEAT_RELTIME
- &(shl->tm), &timed_out
-#else
- NULL, NULL
-#endif
- );
- /* Copy the regprog, in case it got freed and recompiled. */
- if (regprog_is_copy)
- cur->match.regprog = cur->hl.rm.regprog;
-
- if (called_emsg || got_int || timed_out)
- {
- /* 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;
- }
- }
- else if (cur != NULL)
- nmatched = next_search_hl_pos(shl, lnum, &(cur->pos), matchcol);
- else
- nmatched = 0;
- if (nmatched == 0)
- {
- shl->lnum = 0; /* no match found */
- break;
- }
- if (shl->rm.startpos[0].lnum > 0
- || shl->rm.startpos[0].col >= mincol
- || nmatched > 1
- || shl->rm.endpos[0].col > mincol)
- {
- shl->lnum += shl->rm.startpos[0].lnum;
- break; /* useful match found */
- }
- }
-
- // Restore called_emsg for assert_fails().
- called_emsg = save_called_emsg;
-}
-
-/*
- * If there is a match fill "shl" and return one.
- * Return zero otherwise.
- */
- static int
-next_search_hl_pos(
- 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 found = -1;
-
- for (i = posmatch->cur; i < MAXPOSMATCH; i++)
- {
- llpos_T *pos = &posmatch->pos[i];
-
- if (pos->lnum == 0)
- break;
- if (pos->len == 0 && pos->col < mincol)
- continue;
- if (pos->lnum == lnum)
- {
- if (found >= 0)
- {
- /* if this match comes before the one at "found" then swap
- * them */
- if (pos->col < posmatch->pos[found].col)
- {
- llpos_T tmp = *pos;
-
- *pos = posmatch->pos[found];
- posmatch->pos[found] = tmp;
- }
- }
- else
- found = i;
- }
- }
- posmatch->cur = 0;
- if (found >= 0)
- {
- colnr_T start = posmatch->pos[found].col == 0
- ? 0 : posmatch->pos[found].col - 1;
- colnr_T end = posmatch->pos[found].col == 0
- ? MAXCOL : start + posmatch->pos[found].len;
-
- shl->lnum = lnum;
- shl->rm.startpos[0].lnum = 0;
- shl->rm.startpos[0].col = start;
- shl->rm.endpos[0].lnum = 0;
- shl->rm.endpos[0].col = end;
- shl->is_addpos = TRUE;
- posmatch->cur = found + 1;
- return 1;
- }
- return 0;
-}
#endif
static void
diff --git a/src/version.c b/src/version.c
index c674702e0..1253846de 100644
--- a/src/version.c
+++ b/src/version.c
@@ -778,6 +778,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1743,
+/**/
1742,
/**/
1741,