Mercurial > vim
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) |