| To: vim_dev@googlegroups.com |
| Subject: Patch 7.4.330 |
| Fcc: outbox |
| From: Bram Moolenaar <Bram@moolenaar.net> |
| 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 |
| |
| |
| |
| |
| |
| *** 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. |
| |
| |
| |
| *** 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 |
| |
| |
| |
| *** 1,6 **** |
| " Vim plugin for showing matching parens |
| " Maintainer: Bram Moolenaar <Bram@vim.org> |
| ! " 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 <Bram@vim.org> |
| ! " 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 |
| |
| |
| |
| |
| *** 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; |
| |
| |
| |
| *** 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; |
| } |
| |
| |
| |
| *** 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)); |
| |
| |
| |
| *** 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; |
| |
| |
| |
| *** 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 */ |
| }; |
| |
| |
| |
| |
| *** 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 |
| |
| |
| |
| *** 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 |
| |
| |
| |
| *** 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; |
| } |
| |
| |
| |
| |
| *** 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 /// |