To: vim_dev@googlegroups.com Subject: Patch 7.4.330 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 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) Files: runtime/doc/eval.txt, runtime/doc/usr_41.txt, runtime/plugin/matchparen.vim, src/eval.c, src/ex_docmd.c, src/proto/window.pro, src/screen.c, src/structs.h, src/testdir/test63.in, src/testdir/test63.ok, src/window.c *** ../vim-7.4.329/runtime/doc/eval.txt 2014-05-28 20:31:37.500292805 +0200 --- runtime/doc/eval.txt 2014-06-17 16:31:35.572453748 +0200 *************** *** 1887,1892 **** --- 1887,1894 ---- Number position where {pat} matches in {expr} matchadd( {group}, {pattern}[, {priority}[, {id}]]) Number highlight {pattern} with {group} + matchaddpos( {group}, {list}[, {priority}[, {id}]]) + Number highlight positions with {group} matcharg( {nr}) List arguments of |:match| matchdelete( {id}) Number delete match identified by {id} matchend( {expr}, {pat}[, {start}[, {count}]]) *************** *** 4342,4347 **** --- 4382,4422 ---- available from |getmatches()|. All matches can be deleted in one operation by |clearmatches()|. + matchaddpos({group}, {pos}[, {priority}[, {id}]]) *matchaddpos()* + Same as |matchadd()|, but requires a list of positions {pos} + instead of a pattern. This command is faster than |matchadd()| + because it does not require to handle regular expressions and + sets buffer line boundaries to redraw screen. It is supposed + to be used when fast match additions and deletions are + required, for example to highlight matching parentheses. + + The list {pos} can contain one of these items: + - A number. This while line will be highlighted. The first + line has number 1. + - A list with one number, e.g., [23]. The whole line with this + number will be highlighted. + - A list with two numbers, e.g., [23, 11]. The first number is + the line number, the second one the column number (first + column is 1). The character at this position will be + highlighted. + - A list with three numbers, e.g., [23, 11, 3]. As above, but + the third number gives the length of the highlight in screen + cells. + + The maximum number of positions is 8. + + Example: > + :highlight MyGroup ctermbg=green guibg=green + :let m = matchaddpos("MyGroup", [[23, 24], 34]) + < Deletion of the pattern: > + :call matchdelete(m) + + < Matches added by |matchaddpos()| are returned by + |getmatches()| with an entry "pos1", "pos2", etc., with the + value a list like the {pos} item. + These matches cannot be set via |setmatches()|, however they + can still be deleted by |clearmatches()|. + matcharg({nr}) *matcharg()* Selects the {nr} match item, as set with a |:match|, |:2match| or |:3match| command. *** ../vim-7.4.329/runtime/doc/usr_41.txt 2014-05-28 18:22:37.872225054 +0200 --- runtime/doc/usr_41.txt 2014-06-17 14:06:44.836124965 +0200 *************** *** 824,829 **** --- 827,833 ---- synconcealed() get info about concealing diff_hlID() get highlight ID for diff mode at a position matchadd() define a pattern to highlight (a "match") + matchaddpos() define a list of positions to highlight matcharg() get info about |:match| arguments matchdelete() delete a match defined by |matchadd()| or a |:match| command *** ../vim-7.4.329/runtime/plugin/matchparen.vim 2013-05-08 05:15:53.000000000 +0200 --- runtime/plugin/matchparen.vim 2014-06-17 14:14:45.712143158 +0200 *************** *** 1,6 **** " Vim plugin for showing matching parens " Maintainer: Bram Moolenaar ! " Last Change: 2013 May 08 " Exit quickly when: " - this plugin was already loaded (or disabled) --- 1,6 ---- " Vim plugin for showing matching parens " Maintainer: Bram Moolenaar ! " Last Change: 2014 Jun 17 " Exit quickly when: " - this plugin was already loaded (or disabled) *************** *** 39,45 **** function! s:Highlight_Matching_Pair() " Remove any previous match. if exists('w:paren_hl_on') && w:paren_hl_on ! 3match none let w:paren_hl_on = 0 endif --- 39,45 ---- function! s:Highlight_Matching_Pair() " Remove any previous match. if exists('w:paren_hl_on') && w:paren_hl_on ! silent! call matchdelete(3) let w:paren_hl_on = 0 endif *************** *** 152,165 **** " If a match is found setup match highlighting. if m_lnum > 0 && m_lnum >= stoplinetop && m_lnum <= stoplinebottom ! exe '3match MatchParen /\(\%' . c_lnum . 'l\%' . (c_col - before) . ! \ 'c\)\|\(\%' . m_lnum . 'l\%' . m_col . 'c\)/' let w:paren_hl_on = 1 endif endfunction " Define commands that will disable and enable the plugin. ! command! NoMatchParen windo 3match none | unlet! g:loaded_matchparen | \ au! matchparen command! DoMatchParen runtime plugin/matchparen.vim | windo doau CursorMoved --- 152,169 ---- " If a match is found setup match highlighting. if m_lnum > 0 && m_lnum >= stoplinetop && m_lnum <= stoplinebottom ! if exists('*matchaddpos') ! call matchaddpos('MatchParen', [[c_lnum, c_col - before], [m_lnum, m_col]], 10, 3) ! else ! exe '3match MatchParen /\(\%' . c_lnum . 'l\%' . (c_col - before) . ! \ 'c\)\|\(\%' . m_lnum . 'l\%' . m_col . 'c\)/' ! endif let w:paren_hl_on = 1 endif endfunction " Define commands that will disable and enable the plugin. ! command! NoMatchParen windo silent! call matchdelete(3) | unlet! g:loaded_matchparen | \ au! matchparen command! DoMatchParen runtime plugin/matchparen.vim | windo doau CursorMoved *** ../vim-7.4.329/src/eval.c 2014-06-17 12:51:13.207953527 +0200 --- src/eval.c 2014-06-17 17:02:25.388523729 +0200 *************** *** 622,627 **** --- 622,628 ---- static void f_mapcheck __ARGS((typval_T *argvars, typval_T *rettv)); static void f_match __ARGS((typval_T *argvars, typval_T *rettv)); static void f_matchadd __ARGS((typval_T *argvars, typval_T *rettv)); + static void f_matchaddpos __ARGS((typval_T *argvars, typval_T *rettv)); static void f_matcharg __ARGS((typval_T *argvars, typval_T *rettv)); static void f_matchdelete __ARGS((typval_T *argvars, typval_T *rettv)); static void f_matchend __ARGS((typval_T *argvars, typval_T *rettv)); *************** *** 8054,8059 **** --- 8055,8061 ---- {"mapcheck", 1, 3, f_mapcheck}, {"match", 2, 4, f_match}, {"matchadd", 2, 4, f_matchadd}, + {"matchaddpos", 2, 4, f_matchaddpos}, {"matcharg", 1, 1, f_matcharg}, {"matchdelete", 1, 1, f_matchdelete}, {"matchend", 2, 4, f_matchend}, *************** *** 11767,11772 **** --- 11769,11775 ---- #ifdef FEAT_SEARCH_EXTRA dict_T *dict; matchitem_T *cur = curwin->w_match_head; + int i; if (rettv_list_alloc(rettv) == OK) { *************** *** 11775,11782 **** dict = dict_alloc(); if (dict == NULL) return; dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id)); - dict_add_nr_str(dict, "pattern", 0L, cur->pattern); dict_add_nr_str(dict, "priority", (long)cur->priority, NULL); dict_add_nr_str(dict, "id", (long)cur->id, NULL); list_append_dict(rettv->vval.v_list, dict); --- 11778,11813 ---- dict = dict_alloc(); if (dict == NULL) return; + if (cur->match.regprog == NULL) + { + /* match added with matchaddpos() */ + for (i = 0; i < MAXPOSMATCH; ++i) + { + llpos_T *llpos; + char buf[6]; + list_T *l; + + llpos = &cur->pos.pos[i]; + if (llpos->lnum == 0) + break; + l = list_alloc(); + if (l == NULL) + break; + list_append_number(l, (varnumber_T)llpos->lnum); + if (llpos->col > 0) + { + list_append_number(l, (varnumber_T)llpos->col); + list_append_number(l, (varnumber_T)llpos->len); + } + sprintf(buf, "pos%d", i + 1); + dict_add_list(dict, buf, l); + } + } + else + { + dict_add_nr_str(dict, "pattern", 0L, cur->pattern); + } dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id)); dict_add_nr_str(dict, "priority", (long)cur->priority, NULL); dict_add_nr_str(dict, "id", (long)cur->id, NULL); list_append_dict(rettv->vval.v_list, dict); *************** *** 14313,14319 **** return; } ! rettv->vval.v_number = match_add(curwin, grp, pat, prio, id); #endif } --- 14344,14401 ---- return; } ! rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL); ! #endif ! } ! ! /* ! * "matchaddpos()" function ! */ ! static void ! f_matchaddpos(argvars, rettv) ! typval_T *argvars UNUSED; ! typval_T *rettv UNUSED; ! { ! #ifdef FEAT_SEARCH_EXTRA ! char_u buf[NUMBUFLEN]; ! char_u *group; ! int prio = 10; ! int id = -1; ! int error = FALSE; ! list_T *l; ! ! rettv->vval.v_number = -1; ! ! group = get_tv_string_buf_chk(&argvars[0], buf); ! if (group == NULL) ! return; ! ! if (argvars[1].v_type != VAR_LIST) ! { ! EMSG2(_(e_listarg), "matchaddpos()"); ! return; ! } ! l = argvars[1].vval.v_list; ! if (l == NULL) ! return; ! ! if (argvars[2].v_type != VAR_UNKNOWN) ! { ! prio = get_tv_number_chk(&argvars[2], &error); ! if (argvars[3].v_type != VAR_UNKNOWN) ! id = get_tv_number_chk(&argvars[3], &error); ! } ! if (error == TRUE) ! return; ! ! /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */ ! if (id == 1 || id == 2) ! { ! EMSGN("E798: ID is reserved for \":match\": %ld", id); ! return; ! } ! ! rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l); #endif } *************** *** 16816,16822 **** match_add(curwin, get_dict_string(d, (char_u *)"group", FALSE), get_dict_string(d, (char_u *)"pattern", FALSE), (int)get_dict_number(d, (char_u *)"priority"), ! (int)get_dict_number(d, (char_u *)"id")); li = li->li_next; } rettv->vval.v_number = 0; --- 16898,16904 ---- match_add(curwin, get_dict_string(d, (char_u *)"group", FALSE), get_dict_string(d, (char_u *)"pattern", FALSE), (int)get_dict_number(d, (char_u *)"priority"), ! (int)get_dict_number(d, (char_u *)"id"), NULL); li = li->li_next; } rettv->vval.v_number = 0; *** ../vim-7.4.329/src/ex_docmd.c 2014-05-28 18:22:37.876225054 +0200 --- src/ex_docmd.c 2014-06-17 14:06:44.844124966 +0200 *************** *** 11489,11495 **** c = *end; *end = NUL; ! match_add(curwin, g, p + 1, 10, id); vim_free(g); *end = c; } --- 11489,11495 ---- c = *end; *end = NUL; ! match_add(curwin, g, p + 1, 10, id, NULL); vim_free(g); *end = c; } *** ../vim-7.4.329/src/proto/window.pro 2013-08-14 17:11:14.000000000 +0200 --- src/proto/window.pro 2014-06-17 14:06:44.844124966 +0200 *************** *** 75,81 **** void switch_buffer __ARGS((buf_T **save_curbuf, buf_T *buf)); void restore_buffer __ARGS((buf_T *save_curbuf)); int win_hasvertsplit __ARGS((void)); ! int match_add __ARGS((win_T *wp, char_u *grp, char_u *pat, int prio, int id)); int match_delete __ARGS((win_T *wp, int id, int perr)); void clear_matches __ARGS((win_T *wp)); matchitem_T *get_match __ARGS((win_T *wp, int id)); --- 75,81 ---- void switch_buffer __ARGS((buf_T **save_curbuf, buf_T *buf)); void restore_buffer __ARGS((buf_T *save_curbuf)); int win_hasvertsplit __ARGS((void)); ! int match_add __ARGS((win_T *wp, char_u *grp, char_u *pat, int prio, int id, list_T *pos)); int match_delete __ARGS((win_T *wp, int id, int perr)); void clear_matches __ARGS((win_T *wp)); matchitem_T *get_match __ARGS((win_T *wp, int id)); *** ../vim-7.4.329/src/screen.c 2014-05-28 21:40:47.092329130 +0200 --- src/screen.c 2014-06-17 17:04:08.064527614 +0200 *************** *** 144,150 **** 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)); #endif static void screen_start_highlight __ARGS((int attr)); static void screen_char __ARGS((unsigned off, int row, int col)); --- 144,151 ---- 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, 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,2934 **** --- 2930,2937 ---- 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,3482 **** 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; - 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; } } if (shl != &search_hl && cur != NULL) cur = cur->next; --- 3442,3484 ---- shl->startcol = MAXCOL; shl->endcol = MAXCOL; shl->attr_cur = 0; ! 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 #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,3494 **** * 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)) { line_attr = hl_attr(HLF_CUL); area_highlighting = TRUE; --- 3490,3496 ---- * 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)) { line_attr = hl_attr(HLF_CUL); area_highlighting = TRUE; *************** *** 3792,3798 **** } else shl = &cur->hl; ! while (shl->rm.regprog != NULL) { if (shl->startcol != MAXCOL && v >= (long)shl->startcol --- 3794,3804 ---- } 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 *************** *** 3803,3810 **** else if (v == (long)shl->endcol) { shl->attr_cur = 0; ! ! next_search_hl(wp, shl, lnum, (colnr_T)v); /* Need to get the line again, a multi-line regexp * may have made it invalid. */ --- 3809,3817 ---- else if (v == (long)shl->endcol) { shl->attr_cur = 0; ! 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,7282 **** --- 7284,7291 ---- 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,7320 **** shl->first_lnum = wp->w_topline; # endif } n = 0; ! while (shl->first_lnum < lnum && shl->rm.regprog != NULL) { ! next_search_hl(wp, shl, shl->first_lnum, (colnr_T)n); if (shl->lnum != 0) { shl->first_lnum = shl->lnum --- 7320,7335 ---- 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, cur); ! pos_inprogress = cur == NULL || cur->pos.cur == 0 ! ? FALSE : TRUE; if (shl->lnum != 0) { shl->first_lnum = shl->lnum *************** *** 7343,7353 **** * 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 */ { linenr_T l; colnr_T matchcol; --- 7358,7369 ---- * Careful: Any pointers for buffer lines will become invalid. */ static void ! 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,7440 **** matchcol = shl->rm.endpos[0].col; shl->lnum = lnum; ! nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum, matchcol, #ifdef FEAT_RELTIME ! &(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; } if (nmatched == 0) { --- 7431,7465 ---- matchcol = shl->rm.endpos[0].col; shl->lnum = lnum; ! if (shl->rm.regprog != NULL) ! { ! nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum, ! matchcol, #ifdef FEAT_RELTIME ! &(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; } ! } ! else if (cur != NULL) ! { ! nmatched = next_search_hl_pos(shl, lnum, &(cur->pos), matchcol); } if (nmatched == 0) { *************** *** 7453,7458 **** --- 7478,7539 ---- } #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; *** ../vim-7.4.329/src/structs.h 2014-05-28 18:22:37.876225054 +0200 --- src/structs.h 2014-06-17 17:00:55.524520330 +0200 *************** *** 1927,1932 **** --- 1927,1958 ---- #endif } match_T; + /* number of positions supported by matchaddpos() */ + #define MAXPOSMATCH 8 + + /* + * Same as lpos_T, but with additional field len. + */ + typedef struct + { + linenr_T lnum; /* line number */ + colnr_T col; /* column number */ + int len; /* length: 0 - to the end of line */ + } llpos_T; + + /* + * posmatch_T provides an array for storing match items for matchaddpos() + * function. + */ + typedef struct posmatch posmatch_T; + struct posmatch + { + llpos_T pos[MAXPOSMATCH]; /* array of positions */ + int cur; /* internal position counter */ + linenr_T toplnum; /* top buffer line */ + linenr_T botlnum; /* bottom buffer line */ + }; + /* * matchitem_T provides a linked list for storing match items for ":match" and * the match functions. *************** *** 1940,1945 **** --- 1966,1972 ---- char_u *pattern; /* pattern to highlight */ int hlg_id; /* highlight group ID */ regmmatch_T match; /* regexp program for pattern */ + posmatch_T pos; /* position matches */ match_T hl; /* struct for doing the actual highlighting */ }; *** ../vim-7.4.329/src/testdir/test63.in 2010-05-15 13:04:10.000000000 +0200 --- src/testdir/test63.in 2014-06-17 16:29:36.056449227 +0200 *************** *** 1,5 **** Test for ":match", ":2match", ":3match", "clearmatches()", "getmatches()", ! "matchadd()", "matcharg()", "matchdelete()", and "setmatches()". STARTTEST :so small.vim --- 1,5 ---- Test for ":match", ":2match", ":3match", "clearmatches()", "getmatches()", ! "matchadd()", "matchaddpos", "matcharg()", "matchdelete()", and "setmatches()". STARTTEST :so small.vim *************** *** 147,155 **** :unlet rf1 :unlet rf2 :unlet rf3 ! :highlight clear MyGroup1 ! :highlight clear MyGroup2 ! :highlight clear MyGroup3 G"rp :/^Results/,$wq! test.out ENDTEST --- 147,172 ---- :unlet rf1 :unlet rf2 :unlet rf3 ! :" --- Check that "matchaddpos()" positions matches correctly ! :let @r .= "*** Test 11:\n" ! :set nolazyredraw ! :call setline(1, 'abcdefghijklmnopq') ! :call matchaddpos("MyGroup1", [[1, 5], [1, 8, 3]], 10, 3) ! :1 ! :redraw! ! :let v1 = screenattr(1, 1) ! :let v5 = screenattr(1, 5) ! :let v6 = screenattr(1, 6) ! :let v8 = screenattr(1, 8) ! :let v10 = screenattr(1, 10) ! :let v11 = screenattr(1, 11) ! :let @r .= string(getmatches())."\n" ! :if v1 != v5 && v6 == v1 && v8 == v5 && v10 == v5 && v11 == v1 ! : let @r .= "OK\n" ! :else ! : let @r .= "FAILED\n" ! :endif ! :call clearmatches() G"rp :/^Results/,$wq! test.out ENDTEST *** ../vim-7.4.329/src/testdir/test63.ok 2010-05-15 13:04:10.000000000 +0200 --- src/testdir/test63.ok 2014-06-17 17:32:57.036593023 +0200 *************** *** 9,11 **** --- 9,14 ---- *** Test 8: OK *** Test 9: OK *** Test 10: OK + *** Test 11: + [{'group': 'MyGroup1', 'id': 3, 'priority': 10, 'pos1': [1, 5, 1], 'pos2': [1, 8, 3]}] + OK *** ../vim-7.4.329/src/window.c 2014-06-17 13:52:35.868092848 +0200 --- src/window.c 2014-06-17 17:04:51.060529240 +0200 *************** *** 6751,6770 **** * Return ID of added match, -1 on failure. */ int ! match_add(wp, grp, pat, prio, id) win_T *wp; char_u *grp; char_u *pat; int prio; int id; { ! matchitem_T *cur; ! matchitem_T *prev; ! matchitem_T *m; int hlg_id; ! regprog_T *regprog; ! if (*grp == NUL || *pat == NUL) return -1; if (id < -1 || id == 0) { --- 6751,6772 ---- * Return ID of added match, -1 on failure. */ int ! match_add(wp, grp, pat, prio, id, pos_list) win_T *wp; char_u *grp; char_u *pat; int prio; int id; + list_T *pos_list; { ! matchitem_T *cur; ! matchitem_T *prev; ! matchitem_T *m; int hlg_id; ! regprog_T *regprog = NULL; ! int rtype = SOME_VALID; ! if (*grp == NUL || (pat != NULL && *pat == NUL)) return -1; if (id < -1 || id == 0) { *************** *** 6789,6795 **** EMSG2(_(e_nogroup), grp); return -1; } ! if ((regprog = vim_regcomp(pat, RE_MAGIC)) == NULL) { EMSG2(_(e_invarg2), pat); return -1; --- 6791,6797 ---- EMSG2(_(e_nogroup), grp); return -1; } ! if (pat != NULL && (regprog = vim_regcomp(pat, RE_MAGIC)) == NULL) { EMSG2(_(e_invarg2), pat); return -1; *************** *** 6810,6821 **** m = (matchitem_T *)alloc(sizeof(matchitem_T)); m->id = id; m->priority = prio; ! m->pattern = vim_strsave(pat); m->hlg_id = hlg_id; m->match.regprog = regprog; m->match.rmm_ic = FALSE; m->match.rmm_maxcol = 0; /* Insert new match. The match list is in ascending order with regard to * the match priorities. */ cur = wp->w_match_head; --- 6812,6922 ---- m = (matchitem_T *)alloc(sizeof(matchitem_T)); m->id = id; m->priority = prio; ! m->pattern = pat == NULL ? NULL : vim_strsave(pat); ! m->pos.cur = 0; m->hlg_id = hlg_id; m->match.regprog = regprog; m->match.rmm_ic = FALSE; m->match.rmm_maxcol = 0; + /* Set up position matches */ + if (pos_list != NULL) + { + linenr_T toplnum = 0; + linenr_T botlnum = 0; + listitem_T *li; + int i; + + for (i = 0, li = pos_list->lv_first; i < MAXPOSMATCH; + i++, li = li->li_next) + { + linenr_T lnum = 0; + colnr_T col = 0; + int len = 1; + list_T *subl; + listitem_T *subli; + int error; + + if (li == NULL) + { + m->pos.pos[i].lnum = 0; + break; + } + if (li->li_tv.v_type == VAR_LIST) + { + subl = li->li_tv.vval.v_list; + if (subl == NULL) + goto fail; + subli = subl->lv_first; + if (subli == NULL) + goto fail; + lnum = get_tv_number_chk(&subli->li_tv, &error); + if (error == TRUE) + goto fail; + m->pos.pos[i].lnum = lnum; + if (lnum == 0) + { + --i; + continue; + } + subli = subli->li_next; + if (subli != NULL) + { + col = get_tv_number_chk(&subli->li_tv, &error); + if (error == TRUE) + goto fail; + subli = subli->li_next; + if (subli != NULL) + { + len = get_tv_number_chk(&subli->li_tv, &error); + if (error == TRUE) + goto fail; + } + } + m->pos.pos[i].col = col; + m->pos.pos[i].len = len; + } + else if (li->li_tv.v_type == VAR_NUMBER) + { + if (li->li_tv.vval.v_number == 0) + continue; + m->pos.pos[i].lnum = li->li_tv.vval.v_number; + m->pos.pos[i].col = 0; + m->pos.pos[i].len = 0; + } + else + { + EMSG(_("List or number required")); + goto fail; + } + if (toplnum == 0 || lnum < toplnum) + toplnum = lnum; + if (botlnum == 0 || lnum > botlnum) + botlnum = lnum; + } + + /* Calculate top and bottom lines for redrawing area */ + if (toplnum != 0) + { + if (wp->w_buffer->b_mod_set) + { + if (wp->w_buffer->b_mod_top > toplnum) + wp->w_buffer->b_mod_top = toplnum; + if (wp->w_buffer->b_mod_bot < botlnum) + wp->w_buffer->b_mod_bot = botlnum; + } + else + { + wp->w_buffer->b_mod_top = toplnum; + wp->w_buffer->b_mod_bot = botlnum; + } + m->pos.toplnum = toplnum; + m->pos.botlnum = botlnum; + wp->w_buffer->b_mod_set = TRUE; + rtype = VALID; + } + } + /* Insert new match. The match list is in ascending order with regard to * the match priorities. */ cur = wp->w_match_head; *************** *** 6831,6838 **** prev->next = m; m->next = cur; ! redraw_later(SOME_VALID); return id; } /* --- 6932,6943 ---- prev->next = m; m->next = cur; ! redraw_later(rtype); return id; + + fail: + vim_free(m); + return -1; } /* *************** *** 6845,6852 **** int id; int perr; { ! matchitem_T *cur = wp->w_match_head; ! matchitem_T *prev = cur; if (id < 1) { --- 6950,6958 ---- int id; int perr; { ! matchitem_T *cur = wp->w_match_head; ! matchitem_T *prev = cur; ! int rtype = SOME_VALID; if (id < 1) { *************** *** 6872,6879 **** prev->next = cur->next; vim_regfree(cur->match.regprog); vim_free(cur->pattern); vim_free(cur); ! redraw_later(SOME_VALID); return 0; } --- 6978,7002 ---- prev->next = cur->next; vim_regfree(cur->match.regprog); vim_free(cur->pattern); + if (cur->pos.toplnum != 0) + { + if (wp->w_buffer->b_mod_set) + { + if (wp->w_buffer->b_mod_top > cur->pos.toplnum) + wp->w_buffer->b_mod_top = cur->pos.toplnum; + if (wp->w_buffer->b_mod_bot < cur->pos.botlnum) + wp->w_buffer->b_mod_bot = cur->pos.botlnum; + } + else + { + wp->w_buffer->b_mod_top = cur->pos.toplnum; + wp->w_buffer->b_mod_bot = cur->pos.botlnum; + } + wp->w_buffer->b_mod_set = TRUE; + rtype = VALID; + } vim_free(cur); ! redraw_later(rtype); return 0; } *** ../vim-7.4.329/src/version.c 2014-06-17 13:52:35.868092848 +0200 --- src/version.c 2014-06-17 14:11:53.764136653 +0200 *************** *** 736,737 **** --- 736,739 ---- { /* Add new patch number below this line */ + /**/ + 330, /**/ -- I'd like to meet the man who invented sex and see what he's working on now. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///