comparison src/screen.c @ 17490:367ef00c6258 v8.1.1743

patch 8.1.1743: 'hlsearch' and match highlighting in the wrong place commit https://github.com/vim/vim/commit/bbca7732e8a3deb6e5dcf84739579a2667a75475 Author: Bram Moolenaar <Bram@vim.org> Date: Wed Jul 24 18:13:16 2019 +0200 patch 8.1.1743: 'hlsearch' and match highlighting in the wrong place Problem: 'hlsearch' and match highlighting in the wrong place. Solution: Move highlighting from inside screen functions to highlight.c.
author Bram Moolenaar <Bram@vim.org>
date Wed, 24 Jul 2019 18:15:06 +0200
parents f12745505a23
children 523591cf1b70
comparison
equal deleted inserted replaced
17489:b2d4523cda0a 17490:367ef00c6258
102 * Mostly used by windgoto() and screen_char(). 102 * Mostly used by windgoto() and screen_char().
103 */ 103 */
104 static int screen_cur_row, screen_cur_col; /* last known cursor position */ 104 static int screen_cur_row, screen_cur_col; /* last known cursor position */
105 105
106 #ifdef FEAT_SEARCH_EXTRA 106 #ifdef FEAT_SEARCH_EXTRA
107 static match_T search_hl; /* used for 'hlsearch' highlight matching */ 107 static match_T search_hl; // used for 'hlsearch' highlight matching
108 #endif 108 #endif
109 109
110 #ifdef FEAT_FOLDING 110 #ifdef FEAT_FOLDING
111 static foldinfo_T win_foldinfo; /* info for 'foldcolumn' */ 111 static foldinfo_T win_foldinfo; /* info for 'foldcolumn' */
112 static int compute_foldcolumn(win_T *wp, int col); 112 static int compute_foldcolumn(win_T *wp, int col);
133 static void draw_vsep_win(win_T *wp, int row); 133 static void draw_vsep_win(win_T *wp, int row);
134 #ifdef FEAT_STL_OPT 134 #ifdef FEAT_STL_OPT
135 static void redraw_custom_statusline(win_T *wp); 135 static void redraw_custom_statusline(win_T *wp);
136 #endif 136 #endif
137 #ifdef FEAT_SEARCH_EXTRA 137 #ifdef FEAT_SEARCH_EXTRA
138 # define SEARCH_HL_PRIORITY 0
139 static void start_search_hl(void); 138 static void start_search_hl(void);
140 static void end_search_hl(void); 139 static void end_search_hl(void);
141 static void init_search_hl(win_T *wp);
142 static void prepare_search_hl(win_T *wp, linenr_T lnum);
143 static void next_search_hl(win_T *win, match_T *shl, linenr_T lnum, colnr_T mincol, matchitem_T *cur);
144 static int next_search_hl_pos(match_T *shl, linenr_T lnum, posmatch_T *pos, colnr_T mincol);
145 #endif 140 #endif
146 static void screen_char(unsigned off, int row, int col); 141 static void screen_char(unsigned off, int row, int col);
147 static void screen_char_2(unsigned off, int row, int col); 142 static void screen_char_2(unsigned off, int row, int col);
148 static void screenclear2(void); 143 static void screenclear2(void);
149 static void lineclear(unsigned off, int width, int attr); 144 static void lineclear(unsigned off, int width, int attr);
1170 return; 1165 return;
1171 } 1166 }
1172 #endif 1167 #endif
1173 1168
1174 #ifdef FEAT_SEARCH_EXTRA 1169 #ifdef FEAT_SEARCH_EXTRA
1175 init_search_hl(wp); 1170 init_search_hl(wp, &search_hl);
1176 #endif 1171 #endif
1177 1172
1178 #ifdef FEAT_LINEBREAK 1173 #ifdef FEAT_LINEBREAK
1179 /* Force redraw when width of 'number' or 'relativenumber' column 1174 /* Force redraw when width of 'number' or 'relativenumber' column
1180 * changes. */ 1175 * changes. */
2088 row = wp->w_height + 1; 2083 row = wp->w_height + 1;
2089 } 2084 }
2090 else 2085 else
2091 { 2086 {
2092 #ifdef FEAT_SEARCH_EXTRA 2087 #ifdef FEAT_SEARCH_EXTRA
2093 prepare_search_hl(wp, lnum); 2088 prepare_search_hl(wp, &search_hl, lnum);
2094 #endif 2089 #endif
2095 #ifdef FEAT_SYN_HL 2090 #ifdef FEAT_SYN_HL
2096 /* Let the syntax stuff know we skipped a few lines. */ 2091 /* Let the syntax stuff know we skipped a few lines. */
2097 if (syntax_last_parsed != 0 && syntax_last_parsed + 1 < lnum 2092 if (syntax_last_parsed != 0 && syntax_last_parsed + 1 < lnum
2098 && syntax_present(wp)) 2093 && syntax_present(wp))
3271 #endif 3266 #endif
3272 #ifdef FEAT_SIGNS 3267 #ifdef FEAT_SIGNS
3273 int sign_present = FALSE; 3268 int sign_present = FALSE;
3274 sign_attrs_T sattr; 3269 sign_attrs_T sattr;
3275 #endif 3270 #endif
3276 #ifdef FEAT_SEARCH_EXTRA
3277 matchitem_T *cur; /* points to the match list */
3278 match_T *shl; /* points to search_hl or a match */
3279 int shl_flag; /* flag to indicate whether search_hl
3280 has been processed or not */
3281 int pos_inprogress; /* marks that position match search is
3282 in progress */
3283 int prevcol_hl_flag; /* flag to indicate whether prevcol
3284 equals startcol of search_hl or one
3285 of the matches */
3286 #endif
3287 #ifdef FEAT_ARABIC 3271 #ifdef FEAT_ARABIC
3288 int prev_c = 0; /* previous Arabic character */ 3272 int prev_c = 0; /* previous Arabic character */
3289 int prev_c1 = 0; /* first composing char for prev_c */ 3273 int prev_c1 = 0; /* first composing char for prev_c */
3290 #endif 3274 #endif
3291 #if defined(LINE_ATTR) 3275 #if defined(LINE_ATTR)
3806 if (fromcol >= tocol) 3790 if (fromcol >= tocol)
3807 fromcol = -1; 3791 fromcol = -1;
3808 } 3792 }
3809 3793
3810 #ifdef FEAT_SEARCH_EXTRA 3794 #ifdef FEAT_SEARCH_EXTRA
3811 /* 3795 if (!number_only)
3812 * Handle highlighting the last used search pattern and matches. 3796 {
3813 * Do this for both search_hl and the match list.
3814 * Do not use search_hl in a popup window.
3815 */
3816 cur = wp->w_match_head;
3817 shl_flag = (screen_line_flags & SLF_POPUP);
3818 while ((cur != NULL || shl_flag == FALSE) && !number_only)
3819 {
3820 if (shl_flag == FALSE)
3821 {
3822 shl = &search_hl;
3823 shl_flag = TRUE;
3824 }
3825 else
3826 shl = &cur->hl;
3827 shl->startcol = MAXCOL;
3828 shl->endcol = MAXCOL;
3829 shl->attr_cur = 0;
3830 shl->is_addpos = FALSE;
3831 v = (long)(ptr - line); 3797 v = (long)(ptr - line);
3832 if (cur != NULL) 3798 area_highlighting |= prepare_search_hl_line(wp, lnum, (colnr_T)v,
3833 cur->pos.cur = 0; 3799 &line, &search_hl, &search_attr);
3834 next_search_hl(wp, shl, lnum, (colnr_T)v, 3800 ptr = line + v; // "line" may have been updated
3835 shl == &search_hl ? NULL : cur);
3836
3837 /* Need to get the line again, a multi-line regexp may have made it
3838 * invalid. */
3839 line = ml_get_buf(wp->w_buffer, lnum, FALSE);
3840 ptr = line + v;
3841
3842 if (shl->lnum != 0 && shl->lnum <= lnum)
3843 {
3844 if (shl->lnum == lnum)
3845 shl->startcol = shl->rm.startpos[0].col;
3846 else
3847 shl->startcol = 0;
3848 if (lnum == shl->lnum + shl->rm.endpos[0].lnum
3849 - shl->rm.startpos[0].lnum)
3850 shl->endcol = shl->rm.endpos[0].col;
3851 else
3852 shl->endcol = MAXCOL;
3853 /* Highlight one character for an empty match. */
3854 if (shl->startcol == shl->endcol)
3855 {
3856 if (has_mbyte && line[shl->endcol] != NUL)
3857 shl->endcol += (*mb_ptr2len)(line + shl->endcol);
3858 else
3859 ++shl->endcol;
3860 }
3861 if ((long)shl->startcol < v) /* match at leftcol */
3862 {
3863 shl->attr_cur = shl->attr;
3864 search_attr = shl->attr;
3865 }
3866 area_highlighting = TRUE;
3867 }
3868 if (shl != &search_hl && cur != NULL)
3869 cur = cur->next;
3870 } 3801 }
3871 #endif 3802 #endif
3872 3803
3873 #ifdef FEAT_SYN_HL 3804 #ifdef FEAT_SYN_HL
3874 // Cursor line highlighting for 'cursorline' in the current window. 3805 // Cursor line highlighting for 'cursorline' in the current window.
4245 4176
4246 #ifdef FEAT_SEARCH_EXTRA 4177 #ifdef FEAT_SEARCH_EXTRA
4247 if (!n_extra) 4178 if (!n_extra)
4248 { 4179 {
4249 /* 4180 /*
4250 * Check for start/end of search pattern match. 4181 * Check for start/end of 'hlsearch' and other matches.
4251 * After end, check for start/end of next match. 4182 * After end, check for start/end of next match.
4252 * When another match, have to check for start again. 4183 * When another match, have to check for start again.
4253 * Watch out for matching an empty string!
4254 * Do this for 'search_hl' and the match list (ordered by
4255 * priority).
4256 */ 4184 */
4257 v = (long)(ptr - line); 4185 v = (long)(ptr - line);
4258 cur = wp->w_match_head; 4186 search_attr = update_search_hl(wp, lnum, (colnr_T)v, &line,
4259 shl_flag = FALSE; 4187 &search_hl, &has_match_conc, &match_conc,
4260 while (cur != NULL || shl_flag == FALSE) 4188 did_line_attr, lcs_eol_one);
4261 { 4189 ptr = line + v; // "line" may have been changed
4262 if (shl_flag == FALSE
4263 && ((cur != NULL
4264 && cur->priority > SEARCH_HL_PRIORITY)
4265 || cur == NULL))
4266 {
4267 shl = &search_hl;
4268 shl_flag = TRUE;
4269 if (screen_line_flags & SLF_POPUP)
4270 continue; // do not use search_hl
4271 }
4272 else
4273 shl = &cur->hl;
4274 if (cur != NULL)
4275 cur->pos.cur = 0;
4276 pos_inprogress = TRUE;
4277 while (shl->rm.regprog != NULL
4278 || (cur != NULL && pos_inprogress))
4279 {
4280 if (shl->startcol != MAXCOL
4281 && v >= (long)shl->startcol
4282 && v < (long)shl->endcol)
4283 {
4284 int tmp_col = v + MB_PTR2LEN(ptr);
4285
4286 if (shl->endcol < tmp_col)
4287 shl->endcol = tmp_col;
4288 shl->attr_cur = shl->attr;
4289 #ifdef FEAT_CONCEAL
4290 // Match with the "Conceal" group results in hiding
4291 // the match.
4292 if (cur != NULL
4293 && shl != &search_hl
4294 && syn_name2id((char_u *)"Conceal")
4295 == cur->hlg_id)
4296 {
4297 has_match_conc =
4298 v == (long)shl->startcol ? 2 : 1;
4299 match_conc = cur->conceal_char;
4300 }
4301 else
4302 has_match_conc = match_conc = 0;
4303 #endif
4304 }
4305 else if (v == (long)shl->endcol)
4306 {
4307 shl->attr_cur = 0;
4308 next_search_hl(wp, shl, lnum, (colnr_T)v,
4309 shl == &search_hl ? NULL : cur);
4310 pos_inprogress = cur == NULL || cur->pos.cur == 0
4311 ? FALSE : TRUE;
4312
4313 /* Need to get the line again, a multi-line regexp
4314 * may have made it invalid. */
4315 line = ml_get_buf(wp->w_buffer, lnum, FALSE);
4316 ptr = line + v;
4317
4318 if (shl->lnum == lnum)
4319 {
4320 shl->startcol = shl->rm.startpos[0].col;
4321 if (shl->rm.endpos[0].lnum == 0)
4322 shl->endcol = shl->rm.endpos[0].col;
4323 else
4324 shl->endcol = MAXCOL;
4325
4326 if (shl->startcol == shl->endcol)
4327 {
4328 /* highlight empty match, try again after
4329 * it */
4330 if (has_mbyte)
4331 shl->endcol += (*mb_ptr2len)(line
4332 + shl->endcol);
4333 else
4334 ++shl->endcol;
4335 }
4336
4337 /* Loop to check if the match starts at the
4338 * current position */
4339 continue;
4340 }
4341 }
4342 break;
4343 }
4344 if (shl != &search_hl && cur != NULL)
4345 cur = cur->next;
4346 }
4347
4348 /* Use attributes from match with highest priority among
4349 * 'search_hl' and the match list. */
4350 cur = wp->w_match_head;
4351 shl_flag = FALSE;
4352 search_attr = 0;
4353 while (cur != NULL || shl_flag == FALSE)
4354 {
4355 if (shl_flag == FALSE
4356 && ((cur != NULL
4357 && cur->priority > SEARCH_HL_PRIORITY)
4358 || cur == NULL))
4359 {
4360 shl = &search_hl;
4361 shl_flag = TRUE;
4362 if (screen_line_flags & SLF_POPUP)
4363 continue; // do not use search_hl
4364 }
4365 else
4366 shl = &cur->hl;
4367 if (shl->attr_cur != 0)
4368 search_attr = shl->attr_cur;
4369 if (shl != &search_hl && cur != NULL)
4370 cur = cur->next;
4371 }
4372 /* Only highlight one character after the last column. */
4373 if (*ptr == NUL && (did_line_attr >= 1
4374 || (wp->w_p_list && lcs_eol_one == -1)))
4375 search_attr = 0;
4376 } 4190 }
4377 #endif 4191 #endif
4378 4192
4379 #ifdef FEAT_DIFF 4193 #ifdef FEAT_DIFF
4380 if (diff_hlf != (hlf_T)0) 4194 if (diff_hlf != (hlf_T)0)
5559 || did_line_attr == 1 5373 || did_line_attr == 1
5560 #endif 5374 #endif
5561 ) && eol_hl_off == 0) 5375 ) && eol_hl_off == 0)
5562 { 5376 {
5563 #ifdef FEAT_SEARCH_EXTRA 5377 #ifdef FEAT_SEARCH_EXTRA
5564 long prevcol = (long)(ptr - line) - (c == NUL); 5378 // flag to indicate whether prevcol equals startcol of search_hl or
5565 5379 // one of the matches
5566 /* we're not really at that column when skipping some text */ 5380 int prevcol_hl_flag = get_prevcol_hl_flag(wp, &search_hl,
5567 if ((long)(wp->w_p_wrap ? wp->w_skipcol : wp->w_leftcol) > prevcol) 5381 (long)(ptr - line) - (c == NUL));
5568 ++prevcol; 5382 #endif
5569 #endif 5383 // Invert at least one char, used for Visual and empty line or
5570 5384 // highlight match at end of line. If it's beyond the last
5571 /* Invert at least one char, used for Visual and empty line or 5385 // char on the screen, just overwrite that one (tricky!) Not
5572 * highlight match at end of line. If it's beyond the last 5386 // needed when a '$' was displayed for 'list'.
5573 * char on the screen, just overwrite that one (tricky!) Not
5574 * needed when a '$' was displayed for 'list'. */
5575 #ifdef FEAT_SEARCH_EXTRA
5576 prevcol_hl_flag = FALSE;
5577 if (!search_hl.is_addpos && prevcol == (long)search_hl.startcol)
5578 prevcol_hl_flag = TRUE;
5579 else
5580 {
5581 cur = wp->w_match_head;
5582 while (cur != NULL)
5583 {
5584 if (!cur->hl.is_addpos && prevcol == (long)cur->hl.startcol)
5585 {
5586 prevcol_hl_flag = TRUE;
5587 break;
5588 }
5589 cur = cur->next;
5590 }
5591 }
5592 #endif
5593 if (lcs_eol == lcs_eol_one 5387 if (lcs_eol == lcs_eol_one
5594 && ((area_attr != 0 && vcol == fromcol 5388 && ((area_attr != 0 && vcol == fromcol
5595 && (VIsual_mode != Ctrl_V 5389 && (VIsual_mode != Ctrl_V
5596 || lnum == VIsual.lnum 5390 || lnum == VIsual.lnum
5597 || lnum == curwin->w_cursor.lnum) 5391 || lnum == curwin->w_cursor.lnum)
5598 && c == NUL) 5392 && c == NUL)
5599 #ifdef FEAT_SEARCH_EXTRA 5393 #ifdef FEAT_SEARCH_EXTRA
5600 /* highlight 'hlsearch' match at end of line */ 5394 // highlight 'hlsearch' match at end of line
5601 || (prevcol_hl_flag == TRUE 5395 || (prevcol_hl_flag
5602 # ifdef FEAT_SYN_HL 5396 # ifdef FEAT_SYN_HL
5603 && !(wp->w_p_cul && lnum == wp->w_cursor.lnum 5397 && !(wp->w_p_cul && lnum == wp->w_cursor.lnum
5604 && !(wp == curwin && VIsual_active)) 5398 && !(wp == curwin && VIsual_active))
5605 # endif 5399 # endif
5606 # ifdef FEAT_DIFF 5400 # ifdef FEAT_DIFF
5642 ScreenLinesUC[off] = 0; 5436 ScreenLinesUC[off] = 0;
5643 } 5437 }
5644 #ifdef FEAT_SEARCH_EXTRA 5438 #ifdef FEAT_SEARCH_EXTRA
5645 if (area_attr == 0) 5439 if (area_attr == 0)
5646 { 5440 {
5647 /* Use attributes from match with highest priority among 5441 // Use attributes from match with highest priority among
5648 * 'search_hl' and the match list. */ 5442 // 'search_hl' and the match list.
5649 cur = wp->w_match_head; 5443 get_search_match_hl(wp, &search_hl,
5650 shl_flag = FALSE; 5444 (long)(ptr - line), &char_attr);
5651 while (cur != NULL || shl_flag == FALSE)
5652 {
5653 if (shl_flag == FALSE
5654 && ((cur != NULL
5655 && cur->priority > SEARCH_HL_PRIORITY)
5656 || cur == NULL))
5657 {
5658 shl = &search_hl;
5659 shl_flag = TRUE;
5660 if (screen_line_flags & SLF_POPUP)
5661 continue; // do not use search_hl
5662 }
5663 else
5664 shl = &cur->hl;
5665 if ((ptr - line) - 1 == (long)shl->startcol
5666 && (shl == &search_hl || !shl->is_addpos))
5667 char_attr = shl->attr;
5668 if (shl != &search_hl && cur != NULL)
5669 cur = cur->next;
5670 }
5671 } 5445 }
5672 #endif 5446 #endif
5673 ScreenAttrs[off] = char_attr; 5447 ScreenAttrs[off] = char_attr;
5674 #ifdef FEAT_RIGHTLEFT 5448 #ifdef FEAT_RIGHTLEFT
5675 if (wp->w_p_rl) 5449 if (wp->w_p_rl)
7889 if (search_hl.rm.regprog != NULL) 7663 if (search_hl.rm.regprog != NULL)
7890 { 7664 {
7891 vim_regfree(search_hl.rm.regprog); 7665 vim_regfree(search_hl.rm.regprog);
7892 search_hl.rm.regprog = NULL; 7666 search_hl.rm.regprog = NULL;
7893 } 7667 }
7894 }
7895
7896 /*
7897 * Init for calling prepare_search_hl().
7898 */
7899 static void
7900 init_search_hl(win_T *wp)
7901 {
7902 matchitem_T *cur;
7903
7904 /* Setup for match and 'hlsearch' highlighting. Disable any previous
7905 * match */
7906 cur = wp->w_match_head;
7907 while (cur != NULL)
7908 {
7909 cur->hl.rm = cur->match;
7910 if (cur->hlg_id == 0)
7911 cur->hl.attr = 0;
7912 else
7913 cur->hl.attr = syn_id2attr(cur->hlg_id);
7914 cur->hl.buf = wp->w_buffer;
7915 cur->hl.lnum = 0;
7916 cur->hl.first_lnum = 0;
7917 # ifdef FEAT_RELTIME
7918 /* Set the time limit to 'redrawtime'. */
7919 profile_setlimit(p_rdt, &(cur->hl.tm));
7920 # endif
7921 cur = cur->next;
7922 }
7923 search_hl.buf = wp->w_buffer;
7924 search_hl.lnum = 0;
7925 search_hl.first_lnum = 0;
7926 /* time limit is set at the toplevel, for all windows */
7927 }
7928
7929 /*
7930 * Advance to the match in window "wp" line "lnum" or past it.
7931 */
7932 static void
7933 prepare_search_hl(win_T *wp, linenr_T lnum)
7934 {
7935 matchitem_T *cur; /* points to the match list */
7936 match_T *shl; /* points to search_hl or a match */
7937 int shl_flag; /* flag to indicate whether search_hl
7938 has been processed or not */
7939 int pos_inprogress; /* marks that position match search is
7940 in progress */
7941 int n;
7942
7943 /*
7944 * When using a multi-line pattern, start searching at the top
7945 * of the window or just after a closed fold.
7946 * Do this both for search_hl and the match list.
7947 */
7948 cur = wp->w_match_head;
7949 shl_flag = FALSE;
7950 while (cur != NULL || shl_flag == FALSE)
7951 {
7952 if (shl_flag == FALSE)
7953 {
7954 shl = &search_hl;
7955 shl_flag = TRUE;
7956 }
7957 else
7958 shl = &cur->hl;
7959 if (shl->rm.regprog != NULL
7960 && shl->lnum == 0
7961 && re_multiline(shl->rm.regprog))
7962 {
7963 if (shl->first_lnum == 0)
7964 {
7965 # ifdef FEAT_FOLDING
7966 for (shl->first_lnum = lnum;
7967 shl->first_lnum > wp->w_topline; --shl->first_lnum)
7968 if (hasFoldingWin(wp, shl->first_lnum - 1,
7969 NULL, NULL, TRUE, NULL))
7970 break;
7971 # else
7972 shl->first_lnum = wp->w_topline;
7973 # endif
7974 }
7975 if (cur != NULL)
7976 cur->pos.cur = 0;
7977 pos_inprogress = TRUE;
7978 n = 0;
7979 while (shl->first_lnum < lnum && (shl->rm.regprog != NULL
7980 || (cur != NULL && pos_inprogress)))
7981 {
7982 next_search_hl(wp, shl, shl->first_lnum, (colnr_T)n,
7983 shl == &search_hl ? NULL : cur);
7984 pos_inprogress = cur == NULL || cur->pos.cur == 0
7985 ? FALSE : TRUE;
7986 if (shl->lnum != 0)
7987 {
7988 shl->first_lnum = shl->lnum
7989 + shl->rm.endpos[0].lnum
7990 - shl->rm.startpos[0].lnum;
7991 n = shl->rm.endpos[0].col;
7992 }
7993 else
7994 {
7995 ++shl->first_lnum;
7996 n = 0;
7997 }
7998 }
7999 }
8000 if (shl != &search_hl && cur != NULL)
8001 cur = cur->next;
8002 }
8003 }
8004
8005 /*
8006 * Search for a next 'hlsearch' or match.
8007 * Uses shl->buf.
8008 * Sets shl->lnum and shl->rm contents.
8009 * Note: Assumes a previous match is always before "lnum", unless
8010 * shl->lnum is zero.
8011 * Careful: Any pointers for buffer lines will become invalid.
8012 */
8013 static void
8014 next_search_hl(
8015 win_T *win,
8016 match_T *shl, /* points to search_hl or a match */
8017 linenr_T lnum,
8018 colnr_T mincol, /* minimal column for a match */
8019 matchitem_T *cur) /* to retrieve match positions if any */
8020 {
8021 linenr_T l;
8022 colnr_T matchcol;
8023 long nmatched;
8024 int save_called_emsg = called_emsg;
8025
8026 // for :{range}s/pat only highlight inside the range
8027 if (lnum < search_first_line || lnum > search_last_line)
8028 {
8029 shl->lnum = 0;
8030 return;
8031 }
8032
8033 if (shl->lnum != 0)
8034 {
8035 /* Check for three situations:
8036 * 1. If the "lnum" is below a previous match, start a new search.
8037 * 2. If the previous match includes "mincol", use it.
8038 * 3. Continue after the previous match.
8039 */
8040 l = shl->lnum + shl->rm.endpos[0].lnum - shl->rm.startpos[0].lnum;
8041 if (lnum > l)
8042 shl->lnum = 0;
8043 else if (lnum < l || shl->rm.endpos[0].col > mincol)
8044 return;
8045 }
8046
8047 /*
8048 * Repeat searching for a match until one is found that includes "mincol"
8049 * or none is found in this line.
8050 */
8051 called_emsg = FALSE;
8052 for (;;)
8053 {
8054 #ifdef FEAT_RELTIME
8055 /* Stop searching after passing the time limit. */
8056 if (profile_passed_limit(&(shl->tm)))
8057 {
8058 shl->lnum = 0; /* no match found in time */
8059 break;
8060 }
8061 #endif
8062 /* Three situations:
8063 * 1. No useful previous match: search from start of line.
8064 * 2. Not Vi compatible or empty match: continue at next character.
8065 * Break the loop if this is beyond the end of the line.
8066 * 3. Vi compatible searching: continue at end of previous match.
8067 */
8068 if (shl->lnum == 0)
8069 matchcol = 0;
8070 else if (vim_strchr(p_cpo, CPO_SEARCH) == NULL
8071 || (shl->rm.endpos[0].lnum == 0
8072 && shl->rm.endpos[0].col <= shl->rm.startpos[0].col))
8073 {
8074 char_u *ml;
8075
8076 matchcol = shl->rm.startpos[0].col;
8077 ml = ml_get_buf(shl->buf, lnum, FALSE) + matchcol;
8078 if (*ml == NUL)
8079 {
8080 ++matchcol;
8081 shl->lnum = 0;
8082 break;
8083 }
8084 if (has_mbyte)
8085 matchcol += mb_ptr2len(ml);
8086 else
8087 ++matchcol;
8088 }
8089 else
8090 matchcol = shl->rm.endpos[0].col;
8091
8092 shl->lnum = lnum;
8093 if (shl->rm.regprog != NULL)
8094 {
8095 /* Remember whether shl->rm is using a copy of the regprog in
8096 * cur->match. */
8097 int regprog_is_copy = (shl != &search_hl && cur != NULL
8098 && shl == &cur->hl
8099 && cur->match.regprog == cur->hl.rm.regprog);
8100 int timed_out = FALSE;
8101
8102 nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum,
8103 matchcol,
8104 #ifdef FEAT_RELTIME
8105 &(shl->tm), &timed_out
8106 #else
8107 NULL, NULL
8108 #endif
8109 );
8110 /* Copy the regprog, in case it got freed and recompiled. */
8111 if (regprog_is_copy)
8112 cur->match.regprog = cur->hl.rm.regprog;
8113
8114 if (called_emsg || got_int || timed_out)
8115 {
8116 /* Error while handling regexp: stop using this regexp. */
8117 if (shl == &search_hl)
8118 {
8119 /* don't free regprog in the match list, it's a copy */
8120 vim_regfree(shl->rm.regprog);
8121 set_no_hlsearch(TRUE);
8122 }
8123 shl->rm.regprog = NULL;
8124 shl->lnum = 0;
8125 got_int = FALSE; /* avoid the "Type :quit to exit Vim"
8126 message */
8127 break;
8128 }
8129 }
8130 else if (cur != NULL)
8131 nmatched = next_search_hl_pos(shl, lnum, &(cur->pos), matchcol);
8132 else
8133 nmatched = 0;
8134 if (nmatched == 0)
8135 {
8136 shl->lnum = 0; /* no match found */
8137 break;
8138 }
8139 if (shl->rm.startpos[0].lnum > 0
8140 || shl->rm.startpos[0].col >= mincol
8141 || nmatched > 1
8142 || shl->rm.endpos[0].col > mincol)
8143 {
8144 shl->lnum += shl->rm.startpos[0].lnum;
8145 break; /* useful match found */
8146 }
8147 }
8148
8149 // Restore called_emsg for assert_fails().
8150 called_emsg = save_called_emsg;
8151 }
8152
8153 /*
8154 * If there is a match fill "shl" and return one.
8155 * Return zero otherwise.
8156 */
8157 static int
8158 next_search_hl_pos(
8159 match_T *shl, /* points to a match */
8160 linenr_T lnum,
8161 posmatch_T *posmatch, /* match positions */
8162 colnr_T mincol) /* minimal column for a match */
8163 {
8164 int i;
8165 int found = -1;
8166
8167 for (i = posmatch->cur; i < MAXPOSMATCH; i++)
8168 {
8169 llpos_T *pos = &posmatch->pos[i];
8170
8171 if (pos->lnum == 0)
8172 break;
8173 if (pos->len == 0 && pos->col < mincol)
8174 continue;
8175 if (pos->lnum == lnum)
8176 {
8177 if (found >= 0)
8178 {
8179 /* if this match comes before the one at "found" then swap
8180 * them */
8181 if (pos->col < posmatch->pos[found].col)
8182 {
8183 llpos_T tmp = *pos;
8184
8185 *pos = posmatch->pos[found];
8186 posmatch->pos[found] = tmp;
8187 }
8188 }
8189 else
8190 found = i;
8191 }
8192 }
8193 posmatch->cur = 0;
8194 if (found >= 0)
8195 {
8196 colnr_T start = posmatch->pos[found].col == 0
8197 ? 0 : posmatch->pos[found].col - 1;
8198 colnr_T end = posmatch->pos[found].col == 0
8199 ? MAXCOL : start + posmatch->pos[found].len;
8200
8201 shl->lnum = lnum;
8202 shl->rm.startpos[0].lnum = 0;
8203 shl->rm.startpos[0].col = start;
8204 shl->rm.endpos[0].lnum = 0;
8205 shl->rm.endpos[0].col = end;
8206 shl->is_addpos = TRUE;
8207 posmatch->cur = found + 1;
8208 return 1;
8209 }
8210 return 0;
8211 } 7668 }
8212 #endif 7669 #endif
8213 7670
8214 static void 7671 static void
8215 screen_start_highlight(int attr) 7672 screen_start_highlight(int attr)