Mercurial > vim
diff 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 |
line wrap: on
line diff
--- a/src/screen.c +++ b/src/screen.c @@ -144,7 +144,8 @@ static void start_search_hl __ARGS((void static void end_search_hl __ARGS((void)); static void init_search_hl __ARGS((win_T *wp)); static void prepare_search_hl __ARGS((win_T *wp, linenr_T lnum)); -static void next_search_hl __ARGS((win_T *win, match_T *shl, linenr_T lnum, colnr_T mincol)); +static void next_search_hl __ARGS((win_T *win, match_T *shl, linenr_T lnum, colnr_T mincol, matchitem_T *cur)); +static int next_search_hl_pos __ARGS((match_T *shl, linenr_T lnum, posmatch_T *pos, colnr_T mincol)); #endif static void screen_start_highlight __ARGS((int attr)); static void screen_char __ARGS((unsigned off, int row, int col)); @@ -2929,6 +2930,8 @@ win_line(wp, lnum, startrow, endrow, noc 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 */ @@ -3439,44 +3442,43 @@ win_line(wp, lnum, startrow, endrow, noc shl->startcol = MAXCOL; shl->endcol = MAXCOL; shl->attr_cur = 0; - if (shl->rm.regprog != NULL) - { - v = (long)(ptr - line); - next_search_hl(wp, shl, lnum, (colnr_T)v); - - /* 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; + v = (long)(ptr - line); + if (cur != NULL) + cur->pos.cur = 0; + next_search_hl(wp, shl, lnum, (colnr_T)v, 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) + { +#ifdef FEAT_MBYTE + if (has_mbyte && line[shl->endcol] != NUL) + shl->endcol += (*mb_ptr2len)(line + shl->endcol); 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) - { -#ifdef FEAT_MBYTE - if (has_mbyte && line[shl->endcol] != NUL) - shl->endcol += (*mb_ptr2len)(line + shl->endcol); - else -#endif - ++shl->endcol; - } - if ((long)shl->startcol < v) /* match at leftcol */ - { - shl->attr_cur = shl->attr; - search_attr = shl->attr; - } - area_highlighting = TRUE; - } +#endif + ++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; @@ -3488,7 +3490,7 @@ win_line(wp, lnum, startrow, endrow, noc * when Visual mode is active, because it's not clear what is selected * then. */ if (wp->w_p_cul && lnum == wp->w_cursor.lnum - && !(wp == curwin && VIsual_active)) + && !(wp == curwin && VIsual_active)) { line_attr = hl_attr(HLF_CUL); area_highlighting = TRUE; @@ -3792,7 +3794,11 @@ win_line(wp, lnum, startrow, endrow, noc } else shl = &cur->hl; - while (shl->rm.regprog != NULL) + 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 @@ -3803,8 +3809,9 @@ win_line(wp, lnum, startrow, endrow, noc else if (v == (long)shl->endcol) { shl->attr_cur = 0; - - next_search_hl(wp, shl, lnum, (colnr_T)v); + next_search_hl(wp, shl, lnum, (colnr_T)v, 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. */ @@ -7277,6 +7284,8 @@ prepare_search_hl(wp, lnum) 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; /* @@ -7311,10 +7320,16 @@ prepare_search_hl(wp, lnum) 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) - { - next_search_hl(wp, shl, shl->first_lnum, (colnr_T)n); + while (shl->first_lnum < lnum && (shl->rm.regprog != NULL + || (cur != NULL && pos_inprogress))) + { + next_search_hl(wp, shl, shl->first_lnum, (colnr_T)n, cur); + pos_inprogress = cur == NULL || cur->pos.cur == 0 + ? FALSE : TRUE; if (shl->lnum != 0) { shl->first_lnum = shl->lnum @@ -7343,11 +7358,12 @@ prepare_search_hl(wp, lnum) * Careful: Any pointers for buffer lines will become invalid. */ static void -next_search_hl(win, shl, lnum, mincol) - win_T *win; - match_T *shl; /* points to search_hl or a match */ - linenr_T lnum; - colnr_T mincol; /* minimal column for a match */ +next_search_hl(win, shl, lnum, mincol, cur) + 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 postions if any */ { linenr_T l; colnr_T matchcol; @@ -7415,26 +7431,35 @@ next_search_hl(win, shl, lnum, mincol) matchcol = shl->rm.endpos[0].col; shl->lnum = lnum; - nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum, matchcol, + if (shl->rm.regprog != NULL) + { + nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum, + matchcol, #ifdef FEAT_RELTIME - &(shl->tm) + &(shl->tm) #else - NULL -#endif - ); - if (called_emsg || got_int) - { - /* 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; + NULL +#endif + ); + if (called_emsg || got_int) + { + /* 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); } if (nmatched == 0) { @@ -7453,6 +7478,62 @@ next_search_hl(win, shl, lnum, mincol) } #endif + static int +next_search_hl_pos(shl, lnum, posmatch, mincol) + 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 bot = -1; + + shl->lnum = 0; + for (i = posmatch->cur; i < MAXPOSMATCH; i++) + { + if (posmatch->pos[i].lnum == 0) + break; + if (posmatch->pos[i].col < mincol) + continue; + if (posmatch->pos[i].lnum == lnum) + { + if (shl->lnum == lnum) + { + /* partially sort positions by column numbers + * on the same line */ + if (posmatch->pos[i].col < posmatch->pos[bot].col) + { + llpos_T tmp = posmatch->pos[i]; + + posmatch->pos[i] = posmatch->pos[bot]; + posmatch->pos[bot] = tmp; + } + } + else + { + bot = i; + shl->lnum = lnum; + } + } + } + posmatch->cur = 0; + if (shl->lnum == lnum) + { + colnr_T start = posmatch->pos[bot].col == 0 + ? 0 : posmatch->pos[bot].col - 1; + colnr_T end = posmatch->pos[bot].col == 0 + ? MAXCOL : start + posmatch->pos[bot].len; + + shl->rm.startpos[0].lnum = 0; + shl->rm.startpos[0].col = start; + shl->rm.endpos[0].lnum = 0; + shl->rm.endpos[0].col = end; + posmatch->cur = bot + 1; + return TRUE; + } + return FALSE; +} + static void screen_start_highlight(attr) int attr;