comparison src/screen.c @ 5979:f9fa2e506b9f v7.4.330

updated for version 7.4.330 Problem: Using a regexp pattern to highlight a specific position can be slow. Solution: Add matchaddpos() to highlight specific positions efficiently. (Alexey Radkov)
author Bram Moolenaar <bram@vim.org>
date Tue, 17 Jun 2014 17:48:32 +0200
parents 4d7af1962d6c
children 8ae50e3ef8bf
comparison
equal deleted inserted replaced
5978:4f8d7e5811e0 5979:f9fa2e506b9f
142 #define SEARCH_HL_PRIORITY 0 142 #define SEARCH_HL_PRIORITY 0
143 static void start_search_hl __ARGS((void)); 143 static void start_search_hl __ARGS((void));
144 static void end_search_hl __ARGS((void)); 144 static void end_search_hl __ARGS((void));
145 static void init_search_hl __ARGS((win_T *wp)); 145 static void init_search_hl __ARGS((win_T *wp));
146 static void prepare_search_hl __ARGS((win_T *wp, linenr_T lnum)); 146 static void prepare_search_hl __ARGS((win_T *wp, linenr_T lnum));
147 static void next_search_hl __ARGS((win_T *win, match_T *shl, linenr_T lnum, colnr_T mincol)); 147 static void next_search_hl __ARGS((win_T *win, match_T *shl, linenr_T lnum, colnr_T mincol, matchitem_T *cur));
148 static int next_search_hl_pos __ARGS((match_T *shl, linenr_T lnum, posmatch_T *pos, colnr_T mincol));
148 #endif 149 #endif
149 static void screen_start_highlight __ARGS((int attr)); 150 static void screen_start_highlight __ARGS((int attr));
150 static void screen_char __ARGS((unsigned off, int row, int col)); 151 static void screen_char __ARGS((unsigned off, int row, int col));
151 #ifdef FEAT_MBYTE 152 #ifdef FEAT_MBYTE
152 static void screen_char_2 __ARGS((unsigned off, int row, int col)); 153 static void screen_char_2 __ARGS((unsigned off, int row, int col));
2927 #ifdef FEAT_SEARCH_EXTRA 2928 #ifdef FEAT_SEARCH_EXTRA
2928 matchitem_T *cur; /* points to the match list */ 2929 matchitem_T *cur; /* points to the match list */
2929 match_T *shl; /* points to search_hl or a match */ 2930 match_T *shl; /* points to search_hl or a match */
2930 int shl_flag; /* flag to indicate whether search_hl 2931 int shl_flag; /* flag to indicate whether search_hl
2931 has been processed or not */ 2932 has been processed or not */
2933 int pos_inprogress; /* marks that position match search is
2934 in progress */
2932 int prevcol_hl_flag; /* flag to indicate whether prevcol 2935 int prevcol_hl_flag; /* flag to indicate whether prevcol
2933 equals startcol of search_hl or one 2936 equals startcol of search_hl or one
2934 of the matches */ 2937 of the matches */
2935 #endif 2938 #endif
2936 #ifdef FEAT_ARABIC 2939 #ifdef FEAT_ARABIC
3437 else 3440 else
3438 shl = &cur->hl; 3441 shl = &cur->hl;
3439 shl->startcol = MAXCOL; 3442 shl->startcol = MAXCOL;
3440 shl->endcol = MAXCOL; 3443 shl->endcol = MAXCOL;
3441 shl->attr_cur = 0; 3444 shl->attr_cur = 0;
3442 if (shl->rm.regprog != NULL) 3445 v = (long)(ptr - line);
3443 { 3446 if (cur != NULL)
3444 v = (long)(ptr - line); 3447 cur->pos.cur = 0;
3445 next_search_hl(wp, shl, lnum, (colnr_T)v); 3448 next_search_hl(wp, shl, lnum, (colnr_T)v, cur);
3446 3449
3447 /* Need to get the line again, a multi-line regexp may have made it 3450 /* Need to get the line again, a multi-line regexp may have made it
3448 * invalid. */ 3451 * invalid. */
3449 line = ml_get_buf(wp->w_buffer, lnum, FALSE); 3452 line = ml_get_buf(wp->w_buffer, lnum, FALSE);
3450 ptr = line + v; 3453 ptr = line + v;
3451 3454
3452 if (shl->lnum != 0 && shl->lnum <= lnum) 3455 if (shl->lnum != 0 && shl->lnum <= lnum)
3453 { 3456 {
3454 if (shl->lnum == lnum) 3457 if (shl->lnum == lnum)
3455 shl->startcol = shl->rm.startpos[0].col; 3458 shl->startcol = shl->rm.startpos[0].col;
3459 else
3460 shl->startcol = 0;
3461 if (lnum == shl->lnum + shl->rm.endpos[0].lnum
3462 - shl->rm.startpos[0].lnum)
3463 shl->endcol = shl->rm.endpos[0].col;
3464 else
3465 shl->endcol = MAXCOL;
3466 /* Highlight one character for an empty match. */
3467 if (shl->startcol == shl->endcol)
3468 {
3469 #ifdef FEAT_MBYTE
3470 if (has_mbyte && line[shl->endcol] != NUL)
3471 shl->endcol += (*mb_ptr2len)(line + shl->endcol);
3456 else 3472 else
3457 shl->startcol = 0; 3473 #endif
3458 if (lnum == shl->lnum + shl->rm.endpos[0].lnum 3474 ++shl->endcol;
3459 - shl->rm.startpos[0].lnum) 3475 }
3460 shl->endcol = shl->rm.endpos[0].col; 3476 if ((long)shl->startcol < v) /* match at leftcol */
3461 else 3477 {
3462 shl->endcol = MAXCOL; 3478 shl->attr_cur = shl->attr;
3463 /* Highlight one character for an empty match. */ 3479 search_attr = shl->attr;
3464 if (shl->startcol == shl->endcol) 3480 }
3465 { 3481 area_highlighting = TRUE;
3466 #ifdef FEAT_MBYTE
3467 if (has_mbyte && line[shl->endcol] != NUL)
3468 shl->endcol += (*mb_ptr2len)(line + shl->endcol);
3469 else
3470 #endif
3471 ++shl->endcol;
3472 }
3473 if ((long)shl->startcol < v) /* match at leftcol */
3474 {
3475 shl->attr_cur = shl->attr;
3476 search_attr = shl->attr;
3477 }
3478 area_highlighting = TRUE;
3479 }
3480 } 3482 }
3481 if (shl != &search_hl && cur != NULL) 3483 if (shl != &search_hl && cur != NULL)
3482 cur = cur->next; 3484 cur = cur->next;
3483 } 3485 }
3484 #endif 3486 #endif
3486 #ifdef FEAT_SYN_HL 3488 #ifdef FEAT_SYN_HL
3487 /* Cursor line highlighting for 'cursorline' in the current window. Not 3489 /* Cursor line highlighting for 'cursorline' in the current window. Not
3488 * when Visual mode is active, because it's not clear what is selected 3490 * when Visual mode is active, because it's not clear what is selected
3489 * then. */ 3491 * then. */
3490 if (wp->w_p_cul && lnum == wp->w_cursor.lnum 3492 if (wp->w_p_cul && lnum == wp->w_cursor.lnum
3491 && !(wp == curwin && VIsual_active)) 3493 && !(wp == curwin && VIsual_active))
3492 { 3494 {
3493 line_attr = hl_attr(HLF_CUL); 3495 line_attr = hl_attr(HLF_CUL);
3494 area_highlighting = TRUE; 3496 area_highlighting = TRUE;
3495 } 3497 }
3496 #endif 3498 #endif
3790 shl = &search_hl; 3792 shl = &search_hl;
3791 shl_flag = TRUE; 3793 shl_flag = TRUE;
3792 } 3794 }
3793 else 3795 else
3794 shl = &cur->hl; 3796 shl = &cur->hl;
3795 while (shl->rm.regprog != NULL) 3797 if (cur != NULL)
3798 cur->pos.cur = 0;
3799 pos_inprogress = TRUE;
3800 while (shl->rm.regprog != NULL
3801 || (cur != NULL && pos_inprogress))
3796 { 3802 {
3797 if (shl->startcol != MAXCOL 3803 if (shl->startcol != MAXCOL
3798 && v >= (long)shl->startcol 3804 && v >= (long)shl->startcol
3799 && v < (long)shl->endcol) 3805 && v < (long)shl->endcol)
3800 { 3806 {
3801 shl->attr_cur = shl->attr; 3807 shl->attr_cur = shl->attr;
3802 } 3808 }
3803 else if (v == (long)shl->endcol) 3809 else if (v == (long)shl->endcol)
3804 { 3810 {
3805 shl->attr_cur = 0; 3811 shl->attr_cur = 0;
3806 3812 next_search_hl(wp, shl, lnum, (colnr_T)v, cur);
3807 next_search_hl(wp, shl, lnum, (colnr_T)v); 3813 pos_inprogress = cur == NULL || cur->pos.cur == 0
3814 ? FALSE : TRUE;
3808 3815
3809 /* Need to get the line again, a multi-line regexp 3816 /* Need to get the line again, a multi-line regexp
3810 * may have made it invalid. */ 3817 * may have made it invalid. */
3811 line = ml_get_buf(wp->w_buffer, lnum, FALSE); 3818 line = ml_get_buf(wp->w_buffer, lnum, FALSE);
3812 ptr = line + v; 3819 ptr = line + v;
7275 { 7282 {
7276 matchitem_T *cur; /* points to the match list */ 7283 matchitem_T *cur; /* points to the match list */
7277 match_T *shl; /* points to search_hl or a match */ 7284 match_T *shl; /* points to search_hl or a match */
7278 int shl_flag; /* flag to indicate whether search_hl 7285 int shl_flag; /* flag to indicate whether search_hl
7279 has been processed or not */ 7286 has been processed or not */
7287 int pos_inprogress; /* marks that position match search is
7288 in progress */
7280 int n; 7289 int n;
7281 7290
7282 /* 7291 /*
7283 * When using a multi-line pattern, start searching at the top 7292 * When using a multi-line pattern, start searching at the top
7284 * of the window or just after a closed fold. 7293 * of the window or just after a closed fold.
7309 break; 7318 break;
7310 # else 7319 # else
7311 shl->first_lnum = wp->w_topline; 7320 shl->first_lnum = wp->w_topline;
7312 # endif 7321 # endif
7313 } 7322 }
7323 if (cur != NULL)
7324 cur->pos.cur = 0;
7325 pos_inprogress = TRUE;
7314 n = 0; 7326 n = 0;
7315 while (shl->first_lnum < lnum && shl->rm.regprog != NULL) 7327 while (shl->first_lnum < lnum && (shl->rm.regprog != NULL
7316 { 7328 || (cur != NULL && pos_inprogress)))
7317 next_search_hl(wp, shl, shl->first_lnum, (colnr_T)n); 7329 {
7330 next_search_hl(wp, shl, shl->first_lnum, (colnr_T)n, cur);
7331 pos_inprogress = cur == NULL || cur->pos.cur == 0
7332 ? FALSE : TRUE;
7318 if (shl->lnum != 0) 7333 if (shl->lnum != 0)
7319 { 7334 {
7320 shl->first_lnum = shl->lnum 7335 shl->first_lnum = shl->lnum
7321 + shl->rm.endpos[0].lnum 7336 + shl->rm.endpos[0].lnum
7322 - shl->rm.startpos[0].lnum; 7337 - shl->rm.startpos[0].lnum;
7341 * Note: Assumes a previous match is always before "lnum", unless 7356 * Note: Assumes a previous match is always before "lnum", unless
7342 * shl->lnum is zero. 7357 * shl->lnum is zero.
7343 * Careful: Any pointers for buffer lines will become invalid. 7358 * Careful: Any pointers for buffer lines will become invalid.
7344 */ 7359 */
7345 static void 7360 static void
7346 next_search_hl(win, shl, lnum, mincol) 7361 next_search_hl(win, shl, lnum, mincol, cur)
7347 win_T *win; 7362 win_T *win;
7348 match_T *shl; /* points to search_hl or a match */ 7363 match_T *shl; /* points to search_hl or a match */
7349 linenr_T lnum; 7364 linenr_T lnum;
7350 colnr_T mincol; /* minimal column for a match */ 7365 colnr_T mincol; /* minimal column for a match */
7366 matchitem_T *cur; /* to retrieve match postions if any */
7351 { 7367 {
7352 linenr_T l; 7368 linenr_T l;
7353 colnr_T matchcol; 7369 colnr_T matchcol;
7354 long nmatched; 7370 long nmatched;
7355 7371
7413 } 7429 }
7414 else 7430 else
7415 matchcol = shl->rm.endpos[0].col; 7431 matchcol = shl->rm.endpos[0].col;
7416 7432
7417 shl->lnum = lnum; 7433 shl->lnum = lnum;
7418 nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum, matchcol, 7434 if (shl->rm.regprog != NULL)
7435 {
7436 nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum,
7437 matchcol,
7419 #ifdef FEAT_RELTIME 7438 #ifdef FEAT_RELTIME
7420 &(shl->tm) 7439 &(shl->tm)
7421 #else 7440 #else
7422 NULL 7441 NULL
7423 #endif 7442 #endif
7424 ); 7443 );
7425 if (called_emsg || got_int) 7444 if (called_emsg || got_int)
7426 { 7445 {
7427 /* Error while handling regexp: stop using this regexp. */ 7446 /* Error while handling regexp: stop using this regexp. */
7428 if (shl == &search_hl) 7447 if (shl == &search_hl)
7429 { 7448 {
7430 /* don't free regprog in the match list, it's a copy */ 7449 /* don't free regprog in the match list, it's a copy */
7431 vim_regfree(shl->rm.regprog); 7450 vim_regfree(shl->rm.regprog);
7432 SET_NO_HLSEARCH(TRUE); 7451 SET_NO_HLSEARCH(TRUE);
7433 } 7452 }
7434 shl->rm.regprog = NULL; 7453 shl->rm.regprog = NULL;
7435 shl->lnum = 0; 7454 shl->lnum = 0;
7436 got_int = FALSE; /* avoid the "Type :quit to exit Vim" message */ 7455 got_int = FALSE; /* avoid the "Type :quit to exit Vim"
7437 break; 7456 message */
7457 break;
7458 }
7459 }
7460 else if (cur != NULL)
7461 {
7462 nmatched = next_search_hl_pos(shl, lnum, &(cur->pos), matchcol);
7438 } 7463 }
7439 if (nmatched == 0) 7464 if (nmatched == 0)
7440 { 7465 {
7441 shl->lnum = 0; /* no match found */ 7466 shl->lnum = 0; /* no match found */
7442 break; 7467 break;
7450 break; /* useful match found */ 7475 break; /* useful match found */
7451 } 7476 }
7452 } 7477 }
7453 } 7478 }
7454 #endif 7479 #endif
7480
7481 static int
7482 next_search_hl_pos(shl, lnum, posmatch, mincol)
7483 match_T *shl; /* points to a match */
7484 linenr_T lnum;
7485 posmatch_T *posmatch; /* match positions */
7486 colnr_T mincol; /* minimal column for a match */
7487 {
7488 int i;
7489 int bot = -1;
7490
7491 shl->lnum = 0;
7492 for (i = posmatch->cur; i < MAXPOSMATCH; i++)
7493 {
7494 if (posmatch->pos[i].lnum == 0)
7495 break;
7496 if (posmatch->pos[i].col < mincol)
7497 continue;
7498 if (posmatch->pos[i].lnum == lnum)
7499 {
7500 if (shl->lnum == lnum)
7501 {
7502 /* partially sort positions by column numbers
7503 * on the same line */
7504 if (posmatch->pos[i].col < posmatch->pos[bot].col)
7505 {
7506 llpos_T tmp = posmatch->pos[i];
7507
7508 posmatch->pos[i] = posmatch->pos[bot];
7509 posmatch->pos[bot] = tmp;
7510 }
7511 }
7512 else
7513 {
7514 bot = i;
7515 shl->lnum = lnum;
7516 }
7517 }
7518 }
7519 posmatch->cur = 0;
7520 if (shl->lnum == lnum)
7521 {
7522 colnr_T start = posmatch->pos[bot].col == 0
7523 ? 0 : posmatch->pos[bot].col - 1;
7524 colnr_T end = posmatch->pos[bot].col == 0
7525 ? MAXCOL : start + posmatch->pos[bot].len;
7526
7527 shl->rm.startpos[0].lnum = 0;
7528 shl->rm.startpos[0].col = start;
7529 shl->rm.endpos[0].lnum = 0;
7530 shl->rm.endpos[0].col = end;
7531 posmatch->cur = bot + 1;
7532 return TRUE;
7533 }
7534 return FALSE;
7535 }
7455 7536
7456 static void 7537 static void
7457 screen_start_highlight(attr) 7538 screen_start_highlight(attr)
7458 int attr; 7539 int attr;
7459 { 7540 {