1
0
forked from aniani/vim

updated for version 7.1-040

This commit is contained in:
Bram Moolenaar 2007-07-26 20:58:42 +00:00
parent f621048b53
commit 6ee10162b2
14 changed files with 833 additions and 119 deletions

View File

@ -1,4 +1,4 @@
*eval.txt* For Vim version 7.1. Last change: 2007 Jul 11
*eval.txt* For Vim version 7.1. Last change: 2007 Jul 25
VIM REFERENCE MANUAL by Bram Moolenaar
@ -1557,6 +1557,7 @@ call( {func}, {arglist} [, {dict}])
changenr() Number current change number
char2nr( {expr}) Number ASCII value of first char in {expr}
cindent( {lnum}) Number C indent for line {lnum}
clearmatches() None clear all matches
col( {expr}) Number column nr of cursor or mark
complete({startcol}, {matches}) String set Insert mode completion
complete_add( {expr}) Number add completion match
@ -1622,6 +1623,7 @@ getftype( {fname}) String description of type of file {fname}
getline( {lnum}) String line {lnum} of current buffer
getline( {lnum}, {end}) List lines {lnum} to {end} of current buffer
getloclist({nr}) List list of location list items
getmatches() List list of current matches
getpos( {expr}) List position of cursor, mark, etc.
getqflist() List list of quickfix items
getreg( [{regname} [, 1]]) String contents of register
@ -1676,7 +1678,10 @@ mapcheck( {name}[, {mode} [, {abbr}]])
String check for mappings matching {name}
match( {expr}, {pat}[, {start}[, {count}]])
Number position where {pat} matches in {expr}
matchadd( {group}, {pattern}[, {priority}[, {id}]])
Number highlight {pattern} with {group}
matcharg( {nr}) List arguments of |:match|
matchdelete( {id}) Number delete match identified by {id}
matchend( {expr}, {pat}[, {start}[, {count}]])
Number position where {pat} ends in {expr}
matchlist( {expr}, {pat}[, {start}[, {count}]])
@ -1731,6 +1736,7 @@ setcmdpos( {pos}) Number set cursor position in command-line
setline( {lnum}, {line}) Number set line {lnum} to {line}
setloclist( {nr}, {list}[, {action}])
Number modify location list using {list}
setmatches( {list}) Number restore a list of matches
setpos( {expr}, {list}) none set the {expr} position to {list}
setqflist( {list}[, {action}]) Number modify quickfix list using {list}
setreg( {n}, {v}[, {opt}]) Number set register to value and type
@ -2012,6 +2018,10 @@ cindent({lnum}) *cindent()*
feature, -1 is returned.
See |C-indenting|.
clearmatches() *clearmatches()*
Clears all matches previously defined by |matchadd()| and the
|:match| commands.
*col()*
col({expr}) The result is a Number, which is the byte index of the column
position given with {expr}. The accepted positions are:
@ -2918,6 +2928,28 @@ getloclist({nr}) *getloclist()*
returned. For an invalid window number {nr}, an empty list is
returned. Otherwise, same as getqflist().
getmatches() *getmatches()*
Returns a |List| with all matches previously defined by
|matchadd()| and the |:match| commands. |getmatches()| is
useful in combination with |setmatches()|, as |setmatches()|
can restore a list of matches saved by |getmatches()|.
Example: >
:echo getmatches()
< [{'group': 'MyGroup1', 'pattern': 'TODO',
'priority': 10, 'id': 1}, {'group': 'MyGroup2',
'pattern': 'FIXME', 'priority': 10, 'id': 2}] >
:let m = getmatches()
:call clearmatches()
:echo getmatches()
< [] >
:call setmatches(m)
:echo getmatches()
< [{'group': 'MyGroup1', 'pattern': 'TODO',
'priority': 10, 'id': 1}, {'group': 'MyGroup2',
'pattern': 'FIXME', 'priority': 10, 'id': 2}] >
:unlet m
<
getqflist() *getqflist()*
Returns a list with all the current quickfix errors. Each
list item is a dictionary with these entries:
@ -3622,6 +3654,44 @@ match({expr}, {pat}[, {start}[, {count}]]) *match()*
the pattern. 'smartcase' is NOT used. The matching is always
done like 'magic' is set and 'cpoptions' is empty.
*matchadd()* *E798* *E799* *E801*
matchadd({group}, {pattern}[, {priority}[, {id}]])
Defines a pattern to be highlighted in the current window (a
"match"). It will be highlighted with {group}. Returns an
identification number (ID), which can be used to delete the
match using |matchdelete()|.
The optional {priority} argument assigns a priority to the
match. A match with a high priority will have its
highlighting overrule that of a match with a lower priority.
A priority is specified as an integer (negative numbers are no
exception). If the {priority} argument is not specified, the
default priority is 10. The priority of 'hlsearch' is zero,
hence all matches with a priority greater than zero will
overrule it. Syntax highlighting (see 'syntax') is a separate
mechanism, and regardless of the chosen priority a match will
always overrule syntax highlighting.
The optional {id} argument allows the request for a specific
match ID. If a specified ID is already taken, an error
message will appear and the match will not be added. An ID
is specified as a positive integer (zero excluded). IDs 1, 2
and 3 are reserved for |:match|, |:2match| and |:3match|,
respectively. If the {id} argument is not specified,
|matchadd()| automatically chooses a free ID.
The number of matches is not limited, as it is the case with
the |:match| commands.
Example: >
:highlight MyGroup ctermbg=green guibg=green
:let m = matchadd("MyGroup", "TODO")
< Deletion of the pattern: >
:call matchdelete(m)
< A list of matches defined by |matchadd()| and |:match| are
available from |getmatches()|. All matches can be deleted in
one operation by |clearmatches()|.
matcharg({nr}) *matcharg()*
Selects the {nr} match item, as set with a |:match|,
@ -3631,8 +3701,15 @@ matcharg({nr}) *matcharg()*
The pattern used.
When {nr} is not 1, 2 or 3 returns an empty |List|.
When there is no match item set returns ['', ''].
This is usef to save and restore a |:match|.
This is useful to save and restore a |:match|.
Highlighting matches using the |:match| commands are limited
to three matches. |matchadd()| does not have this limitation.
matchdelete({id}) *matchdelete()* *E802* *E803*
Deletes a match with ID {id} previously defined by |matchadd()|
or one of the |:match| commands. Returns 0 if succesfull,
otherwise -1. See example for |matchadd()|. All matches can
be deleted in one operation by |clearmatches()|.
matchend({expr}, {pat}[, {start}[, {count}]]) *matchend()*
Same as match(), but return the index of first character after
@ -4385,7 +4462,13 @@ setloclist({nr}, {list} [, {action}]) *setloclist()*
When {nr} is zero the current window is used. For a location
list window, the displayed location list is modified. For an
invalid window number {nr}, -1 is returned.
Otherwise, same as setqflist().
Otherwise, same as |setqflist()|.
Also see |location-list|.
setmatches({list}) *setmatches()*
Restores a list of matches saved by |getmatches()|. Returns 0
if succesfull, otherwise -1. All current matches are cleared
before the list is restored. See example for |getmatches()|.
*setpos()*
setpos({expr}, {list})

View File

@ -1212,7 +1212,10 @@ Finally, these constructs are unique to Perl:
{group} must exist at the moment this command is executed.
The {group} highlighting still applies when a character is
to be highlighted for 'hlsearch'.
to be highlighted for 'hlsearch', as the highlighting for
matches is given higher priority than that of 'hlsearch'.
Syntax highlighting (see 'syntax') is also overruled by
matches.
Note that highlighting the last used search pattern with
'hlsearch' is used in all windows, while the pattern defined
@ -1226,8 +1229,15 @@ Finally, these constructs are unique to Perl:
display you may get unexpected results. That is because Vim
looks for a match in the line where redrawing starts.
Also see |matcharg()|, it returns the highlight group and
pattern of a previous :match command.
Also see |matcharg()|and |getmatches()|. The former returns
the highlight group and pattern of a previous |:match|
command. The latter returns a list with highlight groups and
patterns defined by both |matchadd()| and |:match|.
Highlighting matches using |:match| are limited to three
matches (aside from |:match|, |:2match| and |:3match|are
available). |matchadd()| does not have this limitation and in
addition makes it possible to prioritize matches.
Another example, which highlights all characters in virtual
column 72 and more: >

View File

@ -763,13 +763,22 @@ Folding:
foldtextresult() get the text displayed for a closed fold
Syntax and highlighting:
clearmatches() clear all matches defined by |matchadd()| and
the |:match| commands
getmatches() get all matches defined by |matchadd()| and
the |:match| commands
hlexists() check if a highlight group exists
hlID() get ID of a highlight group
synID() get syntax ID at a specific position
synIDattr() get a specific attribute of a syntax ID
synIDtrans() get translated syntax ID
diff_hlID() get highlight ID for diff mode at a position
matchadd() define a pattern to highlight (a "match")
matcharg() get info about |:match| arguments
matchdelete() delete a match defined by |matchadd()| or a
|:match| command
setmatches() restore a list of matches saved by
|getmatches()|
Spelling:
spellbadword() locate badly spelled word at or after cursor

View File

@ -475,6 +475,7 @@ static void f_call __ARGS((typval_T *argvars, typval_T *rettv));
static void f_changenr __ARGS((typval_T *argvars, typval_T *rettv));
static void f_char2nr __ARGS((typval_T *argvars, typval_T *rettv));
static void f_cindent __ARGS((typval_T *argvars, typval_T *rettv));
static void f_clearmatches __ARGS((typval_T *argvars, typval_T *rettv));
static void f_col __ARGS((typval_T *argvars, typval_T *rettv));
#if defined(FEAT_INS_EXPAND)
static void f_complete __ARGS((typval_T *argvars, typval_T *rettv));
@ -529,6 +530,7 @@ static void f_getfsize __ARGS((typval_T *argvars, typval_T *rettv));
static void f_getftime __ARGS((typval_T *argvars, typval_T *rettv));
static void f_getftype __ARGS((typval_T *argvars, typval_T *rettv));
static void f_getline __ARGS((typval_T *argvars, typval_T *rettv));
static void f_getmatches __ARGS((typval_T *argvars, typval_T *rettv));
static void f_getpos __ARGS((typval_T *argvars, typval_T *rettv));
static void f_getqflist __ARGS((typval_T *argvars, typval_T *rettv));
static void f_getreg __ARGS((typval_T *argvars, typval_T *rettv));
@ -577,7 +579,9 @@ static void f_map __ARGS((typval_T *argvars, typval_T *rettv));
static void f_maparg __ARGS((typval_T *argvars, typval_T *rettv));
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_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));
static void f_matchlist __ARGS((typval_T *argvars, typval_T *rettv));
static void f_matchstr __ARGS((typval_T *argvars, typval_T *rettv));
@ -618,6 +622,7 @@ static void f_setbufvar __ARGS((typval_T *argvars, typval_T *rettv));
static void f_setcmdpos __ARGS((typval_T *argvars, typval_T *rettv));
static void f_setline __ARGS((typval_T *argvars, typval_T *rettv));
static void f_setloclist __ARGS((typval_T *argvars, typval_T *rettv));
static void f_setmatches __ARGS((typval_T *argvars, typval_T *rettv));
static void f_setpos __ARGS((typval_T *argvars, typval_T *rettv));
static void f_setqflist __ARGS((typval_T *argvars, typval_T *rettv));
static void f_setreg __ARGS((typval_T *argvars, typval_T *rettv));
@ -7046,6 +7051,7 @@ static struct fst
{"changenr", 0, 0, f_changenr},
{"char2nr", 1, 1, f_char2nr},
{"cindent", 1, 1, f_cindent},
{"clearmatches", 0, 0, f_clearmatches},
{"col", 1, 1, f_col},
#if defined(FEAT_INS_EXPAND)
{"complete", 2, 2, f_complete},
@ -7102,6 +7108,7 @@ static struct fst
{"getftype", 1, 1, f_getftype},
{"getline", 1, 2, f_getline},
{"getloclist", 1, 1, f_getqflist},
{"getmatches", 0, 0, f_getmatches},
{"getpos", 1, 1, f_getpos},
{"getqflist", 0, 0, f_getqflist},
{"getreg", 0, 2, f_getreg},
@ -7152,7 +7159,9 @@ static struct fst
{"maparg", 1, 3, f_maparg},
{"mapcheck", 1, 3, f_mapcheck},
{"match", 2, 4, f_match},
{"matchadd", 2, 4, f_matchadd},
{"matcharg", 1, 1, f_matcharg},
{"matchdelete", 1, 1, f_matchdelete},
{"matchend", 2, 4, f_matchend},
{"matchlist", 2, 4, f_matchlist},
{"matchstr", 2, 4, f_matchstr},
@ -7193,6 +7202,7 @@ static struct fst
{"setcmdpos", 1, 1, f_setcmdpos},
{"setline", 2, 2, f_setline},
{"setloclist", 2, 3, f_setloclist},
{"setmatches", 1, 1, f_setmatches},
{"setpos", 2, 2, f_setpos},
{"setqflist", 1, 2, f_setqflist},
{"setreg", 2, 3, f_setreg},
@ -8242,6 +8252,20 @@ f_cindent(argvars, rettv)
rettv->vval.v_number = -1;
}
/*
* "clearmatches()" function
*/
/*ARGSUSED*/
static void
f_clearmatches(argvars, rettv)
typval_T *argvars;
typval_T *rettv;
{
#ifdef FEAT_SEARCH_EXTRA
clear_matches(curwin);
#endif
}
/*
* "col(string)" function
*/
@ -10277,6 +10301,40 @@ f_getline(argvars, rettv)
get_buffer_lines(curbuf, lnum, end, retlist, rettv);
}
/*
* "getmatches()" function
*/
/*ARGSUSED*/
static void
f_getmatches(argvars, rettv)
typval_T *argvars;
typval_T *rettv;
{
#ifdef FEAT_SEARCH_EXTRA
dict_T *dict;
matchitem_T *cur = curwin->w_match_head;
rettv->vval.v_number = 0;
if (rettv_list_alloc(rettv) == OK)
{
while (cur != NULL)
{
dict = dict_alloc();
if (dict == NULL)
return;
++dict->dv_refcount;
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);
cur = cur->next;
}
}
#endif
}
/*
* "getpos(string)" function
*/
@ -12447,6 +12505,42 @@ f_match(argvars, rettv)
find_some_match(argvars, rettv, 1);
}
/*
* "matchadd()" function
*/
static void
f_matchadd(argvars, rettv)
typval_T *argvars;
typval_T *rettv;
{
#ifdef FEAT_SEARCH_EXTRA
char_u buf[NUMBUFLEN];
char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */
char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */
int prio = 10; /* default priority */
int id = -1;
int error = FALSE;
rettv->vval.v_number = -1;
if (grp == NULL || pat == 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;
if (id >= 1 && id <= 3)
{
EMSGN("E798: ID is reserved for \":match\": %ld", id);
return;
}
rettv->vval.v_number = match_add(curwin, grp, pat, prio, id);
#endif
}
/*
* "matcharg()" function
*/
@ -12458,19 +12552,41 @@ f_matcharg(argvars, rettv)
if (rettv_list_alloc(rettv) == OK)
{
#ifdef FEAT_SEARCH_EXTRA
int mi = get_tv_number(&argvars[0]);
int id = get_tv_number(&argvars[0]);
matchitem_T *m;
if (mi >= 1 && mi <= 3)
if (id >= 1 && id <= 3)
{
list_append_string(rettv->vval.v_list,
syn_id2name(curwin->w_match_id[mi - 1]), -1);
list_append_string(rettv->vval.v_list,
curwin->w_match_pat[mi - 1], -1);
if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
{
list_append_string(rettv->vval.v_list,
syn_id2name(m->hlg_id), -1);
list_append_string(rettv->vval.v_list, m->pattern, -1);
}
else
{
list_append_string(rettv->vval.v_list, NUL, -1);
list_append_string(rettv->vval.v_list, NUL, -1);
}
}
#endif
}
}
/*
* "matchdelete()" function
*/
static void
f_matchdelete(argvars, rettv)
typval_T *argvars;
typval_T *rettv;
{
#ifdef FEAT_SEARCH_EXTRA
rettv->vval.v_number = match_delete(curwin,
(int)get_tv_number(&argvars[0]), TRUE);
#endif
}
/*
* "matchend()" function
*/
@ -14508,6 +14624,66 @@ f_setloclist(argvars, rettv)
set_qf_ll_list(win, &argvars[1], &argvars[2], rettv);
}
/*
* "setmatches()" function
*/
static void
f_setmatches(argvars, rettv)
typval_T *argvars;
typval_T *rettv;
{
#ifdef FEAT_SEARCH_EXTRA
list_T *l;
listitem_T *li;
dict_T *d;
rettv->vval.v_number = -1;
if (argvars[0].v_type != VAR_LIST)
{
EMSG(_(e_listreq));
return;
}
if ((l = argvars[0].vval.v_list) != NULL)
{
/* To some extent make sure that we are dealing with a list from
* "getmatches()". */
li = l->lv_first;
while (li != NULL)
{
if (li->li_tv.v_type != VAR_DICT
|| (d = li->li_tv.vval.v_dict) == NULL)
{
EMSG(_(e_invarg));
return;
}
if (!(dict_find(d, (char_u *)"group", -1) != NULL
&& dict_find(d, (char_u *)"pattern", -1) != NULL
&& dict_find(d, (char_u *)"priority", -1) != NULL
&& dict_find(d, (char_u *)"id", -1) != NULL))
{
EMSG(_(e_invarg));
return;
}
li = li->li_next;
}
clear_matches(curwin);
li = l->lv_first;
while (li != NULL)
{
d = li->li_tv.vval.v_dict;
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;
}
#endif
}
/*
* "setpos()" function
*/

View File

@ -10817,12 +10817,13 @@ ex_match(eap)
exarg_T *eap;
{
char_u *p;
char_u *g;
char_u *end;
int c;
int mi;
int id;
if (eap->line2 <= 3)
mi = eap->line2 - 1;
id = eap->line2;
else
{
EMSG(e_invcmd);
@ -10831,13 +10832,7 @@ ex_match(eap)
/* First clear any old pattern. */
if (!eap->skip)
{
vim_free(curwin->w_match[mi].regprog);
curwin->w_match[mi].regprog = NULL;
vim_free(curwin->w_match_pat[mi]);
curwin->w_match_pat[mi] = NULL;
redraw_later(SOME_VALID); /* always need a redraw */
}
match_delete(curwin, id, FALSE);
if (ends_excmd(*eap->arg))
end = eap->arg;
@ -10848,15 +10843,7 @@ ex_match(eap)
{
p = skiptowhite(eap->arg);
if (!eap->skip)
{
curwin->w_match_id[mi] = syn_namen2id(eap->arg,
(int)(p - eap->arg));
if (curwin->w_match_id[mi] == 0)
{
EMSG2(_(e_nogroup), eap->arg);
return;
}
}
g = vim_strnsave(eap->arg, (int)(p - eap->arg));
p = skipwhite(p);
if (*p == NUL)
{
@ -10880,14 +10867,8 @@ ex_match(eap)
c = *end;
*end = NUL;
curwin->w_match[mi].regprog = vim_regcomp(p + 1, RE_MAGIC);
if (curwin->w_match[mi].regprog == NULL)
{
EMSG2(_(e_invarg2), p);
*end = c;
return;
}
curwin->w_match_pat[mi] = vim_strsave(p + 1);
match_add(curwin, g, p + 1, 10, id);
vim_free(g);
*end = c;
}
}

View File

@ -59,4 +59,8 @@ int min_rows __ARGS((void));
int only_one_window __ARGS((void));
void check_lnums __ARGS((int do_curwin));
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));
/* vim: set ft=c : */

View File

@ -100,27 +100,7 @@ static int screen_attr = 0;
static int screen_cur_row, screen_cur_col; /* last known cursor position */
#ifdef FEAT_SEARCH_EXTRA
/*
* Struct used for highlighting 'hlsearch' matches for the last use search
* pattern or a ":match" item.
* For 'hlsearch' there is one pattern for all windows. For ":match" there is
* a different pattern for each window.
*/
typedef struct
{
regmmatch_T rm; /* points to the regexp program; contains last found
match (may continue in next line) */
buf_T *buf; /* the buffer to search for a match */
linenr_T lnum; /* the line to search for a match */
int attr; /* attributes to be used for a match */
int attr_cur; /* attributes currently active in win_line() */
linenr_T first_lnum; /* first lnum to search for multi-line pat */
colnr_T startcol; /* in win_line() points to char where HL starts */
colnr_T endcol; /* in win_line() points to char where HL ends */
} match_T;
static match_T search_hl; /* used for 'hlsearch' highlight matching */
static match_T match_hl[3]; /* used for ":match" highlight matching */
#endif
#ifdef FEAT_FOLDING
@ -155,6 +135,7 @@ static void draw_vsep_win __ARGS((win_T *wp, int row));
static void redraw_custum_statusline __ARGS((win_T *wp));
#endif
#ifdef FEAT_SEARCH_EXTRA
#define SEARCH_HL_PRIORITY 0
static void start_search_hl __ARGS((void));
static void end_search_hl __ARGS((void));
static void prepare_search_hl __ARGS((win_T *wp, linenr_T lnum));
@ -787,6 +768,7 @@ win_update(wp)
w_topline got smaller a bit */
#endif
#ifdef FEAT_SEARCH_EXTRA
matchitem_T *cur; /* points to the match list */
int top_to_mod = FALSE; /* redraw above mod_top */
#endif
@ -848,18 +830,20 @@ win_update(wp)
#endif
#ifdef FEAT_SEARCH_EXTRA
/* Setup for ":match" and 'hlsearch' highlighting. Disable any previous
/* Setup for match and 'hlsearch' highlighting. Disable any previous
* match */
for (i = 0; i < 3; ++i)
cur = wp->w_match_head;
while (cur != NULL)
{
match_hl[i].rm = wp->w_match[i];
if (wp->w_match_id[i] == 0)
match_hl[i].attr = 0;
cur->hl.rm = cur->match;
if (cur->hlg_id == 0)
cur->hl.attr = 0;
else
match_hl[i].attr = syn_id2attr(wp->w_match_id[i]);
match_hl[i].buf = buf;
match_hl[i].lnum = 0;
match_hl[i].first_lnum = 0;
cur->hl.attr = syn_id2attr(cur->hlg_id);
cur->hl.buf = buf;
cur->hl.lnum = 0;
cur->hl.first_lnum = 0;
cur = cur->next;
}
search_hl.buf = buf;
search_hl.lnum = 0;
@ -923,19 +907,25 @@ win_update(wp)
* change in one line may make the Search highlighting in a
* previous line invalid. Simple solution: redraw all visible
* lines above the change.
* Same for a ":match" pattern.
* Same for a match pattern.
*/
if (search_hl.rm.regprog != NULL
&& re_multiline(search_hl.rm.regprog))
top_to_mod = TRUE;
else
for (i = 0; i < 3; ++i)
if (match_hl[i].rm.regprog != NULL
&& re_multiline(match_hl[i].rm.regprog))
{
cur = wp->w_match_head;
while (cur != NULL)
{
if (cur->match.regprog != NULL
&& re_multiline(cur->match.regprog))
{
top_to_mod = TRUE;
break;
}
cur = cur->next;
}
}
#endif
}
#ifdef FEAT_FOLDING
@ -2626,10 +2616,13 @@ win_line(wp, lnum, startrow, endrow, nochange)
int line_attr = 0; /* atrribute for the whole line */
#endif
#ifdef FEAT_SEARCH_EXTRA
match_T *shl; /* points to search_hl or match_hl */
#endif
#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_MBYTE)
int i;
matchitem_T *cur; /* points to the match list */
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 prevcol_hl_flag; /* flag to indicate whether prevcol
equals startcol of search_hl or one
of the matches */
#endif
#ifdef FEAT_ARABIC
int prev_c = 0; /* previous Arabic character */
@ -3074,12 +3067,20 @@ win_line(wp, lnum, startrow, endrow, nochange)
#ifdef FEAT_SEARCH_EXTRA
/*
* Handle highlighting the last used search pattern and ":match".
* Do this for both search_hl and match_hl[3].
* Handle highlighting the last used search pattern and matches.
* Do this for both search_hl and the match list.
*/
for (i = 3; i >= 0; --i)
cur = wp->w_match_head;
shl_flag = FALSE;
while (cur != NULL || shl_flag == FALSE)
{
shl = (i == 3) ? &search_hl : &match_hl[i];
if (shl_flag == FALSE)
{
shl = &search_hl;
shl_flag = TRUE;
}
else
shl = &cur->hl;
shl->startcol = MAXCOL;
shl->endcol = MAXCOL;
shl->attr_cur = 0;
@ -3122,6 +3123,8 @@ win_line(wp, lnum, startrow, endrow, nochange)
area_highlighting = TRUE;
}
}
if (shl != &search_hl && cur != NULL)
cur = cur->next;
}
#endif
@ -3388,13 +3391,24 @@ win_line(wp, lnum, startrow, endrow, nochange)
* After end, check for start/end of next match.
* When another match, have to check for start again.
* Watch out for matching an empty string!
* Do this first for search_hl, then for match_hl, so that
* ":match" overrules 'hlsearch'.
* Do this for 'search_hl' and the match list (ordered by
* priority).
*/
v = (long)(ptr - line);
for (i = 3; i >= 0; --i)
cur = wp->w_match_head;
shl_flag = FALSE;
while (cur != NULL || shl_flag == FALSE)
{
shl = (i == 3) ? &search_hl : &match_hl[i];
if (shl_flag == FALSE
&& ((cur != NULL
&& cur->priority > SEARCH_HL_PRIORITY)
|| cur == NULL))
{
shl = &search_hl;
shl_flag = TRUE;
}
else
shl = &cur->hl;
while (shl->rm.regprog != NULL)
{
if (shl->startcol != MAXCOL
@ -3442,17 +3456,32 @@ win_line(wp, lnum, startrow, endrow, nochange)
}
break;
}
if (shl != &search_hl && cur != NULL)
cur = cur->next;
}
/* ":match" highlighting overrules 'hlsearch' */
for (i = 0; i <= 3; ++i)
if (i == 3)
search_attr = search_hl.attr_cur;
else if (match_hl[i].attr_cur != 0)
/* Use attributes from match with highest priority among
* 'search_hl' and the match list. */
search_attr = search_hl.attr_cur;
cur = wp->w_match_head;
shl_flag = FALSE;
while (cur != NULL || shl_flag == FALSE)
{
if (shl_flag == FALSE
&& ((cur != NULL
&& cur->priority > SEARCH_HL_PRIORITY)
|| cur == NULL))
{
search_attr = match_hl[i].attr_cur;
break;
shl = &search_hl;
shl_flag = TRUE;
}
else
shl = &cur->hl;
if (shl->attr_cur != 0)
search_attr = shl->attr_cur;
if (shl != &search_hl && cur != NULL)
cur = cur->next;
}
}
#endif
@ -3613,6 +3642,8 @@ win_line(wp, lnum, startrow, endrow, nochange)
* Draw it as a space with a composing char. */
if (utf_iscomposing(mb_c))
{
int i;
for (i = Screen_mco - 1; i > 0; --i)
u8cc[i] = u8cc[i - 1];
u8cc[0] = mb_c;
@ -4256,14 +4287,29 @@ win_line(wp, lnum, startrow, endrow, nochange)
* highlight match at end of line. If it's beyond the last
* char on the screen, just overwrite that one (tricky!) Not
* needed when a '$' was displayed for 'list'. */
#ifdef FEAT_SEARCH_EXTRA
prevcol_hl_flag = FALSE;
if (prevcol == (long)search_hl.startcol)
prevcol_hl_flag = TRUE;
else
{
cur = wp->w_match_head;
while (cur != NULL)
{
if (prevcol == (long)cur->hl.startcol)
{
prevcol_hl_flag = TRUE;
break;
}
cur = cur->next;
}
}
#endif
if (lcs_eol == lcs_eol_one
&& ((area_attr != 0 && vcol == fromcol && c == NUL)
#ifdef FEAT_SEARCH_EXTRA
/* highlight 'hlsearch' match at end of line */
|| ((prevcol == (long)search_hl.startcol
|| prevcol == (long)match_hl[0].startcol
|| prevcol == (long)match_hl[1].startcol
|| prevcol == (long)match_hl[2].startcol)
|| (prevcol_hl_flag == TRUE
# if defined(LINE_ATTR)
&& did_line_attr <= 1
# endif
@ -4304,15 +4350,27 @@ win_line(wp, lnum, startrow, endrow, nochange)
#ifdef FEAT_SEARCH_EXTRA
if (area_attr == 0)
{
for (i = 0; i <= 3; ++i)
/* Use attributes from match with highest priority among
* 'search_hl' and the match list. */
char_attr = search_hl.attr;
cur = wp->w_match_head;
shl_flag = FALSE;
while (cur != NULL || shl_flag == FALSE)
{
if (i == 3)
char_attr = search_hl.attr;
else if ((ptr - line) - 1 == (long)match_hl[i].startcol)
if (shl_flag == FALSE
&& ((cur != NULL
&& cur->priority > SEARCH_HL_PRIORITY)
|| cur == NULL))
{
char_attr = match_hl[i].attr;
break;
shl = &search_hl;
shl_flag = TRUE;
}
else
shl = &cur->hl;
if ((ptr - line) - 1 == (long)shl->startcol)
char_attr = shl->attr;
if (shl != &search_hl && cur != NULL)
cur = cur->next;
}
}
#endif
@ -4462,6 +4520,8 @@ win_line(wp, lnum, startrow, endrow, nochange)
{
if (mb_utf8)
{
int i;
ScreenLinesUC[off] = mb_c;
if ((c & 0xff) == 0)
ScreenLines[off] = 0x80; /* avoid storing zero */
@ -6320,7 +6380,7 @@ screen_puts_len(text, len, row, col, attr)
#ifdef FEAT_SEARCH_EXTRA
/*
* Prepare for 'searchhl' highlighting.
* Prepare for 'hlsearch' highlighting.
*/
static void
start_search_hl()
@ -6333,7 +6393,7 @@ start_search_hl()
}
/*
* Clean up for 'searchhl' highlighting.
* Clean up for 'hlsearch' highlighting.
*/
static void
end_search_hl()
@ -6353,18 +6413,28 @@ prepare_search_hl(wp, lnum)
win_T *wp;
linenr_T lnum;
{
match_T *shl; /* points to search_hl or match_hl */
matchitem_T *cur; /* points to the match list */
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 n;
int i;
/*
* When using a multi-line pattern, start searching at the top
* of the window or just after a closed fold.
* Do this both for search_hl and match_hl[3].
* Do this both for search_hl and the match list.
*/
for (i = 3; i >= 0; --i)
cur = wp->w_match_head;
shl_flag = FALSE;
while (cur != NULL || shl_flag == FALSE)
{
shl = (i == 3) ? &search_hl : &match_hl[i];
if (shl_flag == FALSE)
{
shl = &search_hl;
shl_flag = TRUE;
}
else
shl = &cur->hl;
if (shl->rm.regprog != NULL
&& shl->lnum == 0
&& re_multiline(shl->rm.regprog))
@ -6399,11 +6469,13 @@ prepare_search_hl(wp, lnum)
}
}
}
if (shl != &search_hl && cur != NULL)
cur = cur->next;
}
}
/*
* Search for a next 'searchl' or ":match" match.
* Search for a next 'hlsearch' or match.
* Uses shl->buf.
* Sets shl->lnum and shl->rm contents.
* Note: Assumes a previous match is always before "lnum", unless
@ -6413,7 +6485,7 @@ prepare_search_hl(wp, lnum)
static void
next_search_hl(win, shl, lnum, mincol)
win_T *win;
match_T *shl; /* points to search_hl or match_hl */
match_T *shl; /* points to search_hl or a match */
linenr_T lnum;
colnr_T mincol; /* minimal column for a match */
{
@ -6481,7 +6553,7 @@ next_search_hl(win, shl, lnum, mincol)
/* Error while handling regexp: stop using this regexp. */
if (shl == &search_hl)
{
/* don't free the regprog in match_hl[], it's a copy */
/* don't free regprog in the match list, it's a copy */
vim_free(shl->rm.regprog);
no_hlsearch = TRUE;
}

View File

@ -1693,6 +1693,41 @@ struct frame_S
#define FR_ROW 1 /* frame with a row of windows */
#define FR_COL 2 /* frame with a column of windows */
/*
* Struct used for highlighting 'hlsearch' matches, matches defined by
* ":match" and matches defined by match functions.
* For 'hlsearch' there is one pattern for all windows. For ":match" and the
* match functions there is a different pattern for each window.
*/
typedef struct
{
regmmatch_T rm; /* points to the regexp program; contains last found
match (may continue in next line) */
buf_T *buf; /* the buffer to search for a match */
linenr_T lnum; /* the line to search for a match */
int attr; /* attributes to be used for a match */
int attr_cur; /* attributes currently active in win_line() */
linenr_T first_lnum; /* first lnum to search for multi-line pat */
colnr_T startcol; /* in win_line() points to char where HL starts */
colnr_T endcol; /* in win_line() points to char where HL ends */
} match_T;
/*
* matchitem_T provides a linked list for storing match items for ":match" and
* the match functions.
*/
typedef struct matchitem matchitem_T;
struct matchitem
{
matchitem_T *next;
int id; /* match ID */
int priority; /* match priority */
char_u *pattern; /* pattern to highlight */
int hlg_id; /* highlight group ID */
regmmatch_T match; /* regexp program for pattern */
match_T hl; /* struct for doing the actual highlighting */
};
/*
* Structure which contains all information that belongs to a window
*
@ -1934,9 +1969,8 @@ struct window_S
#endif
#ifdef FEAT_SEARCH_EXTRA
regmmatch_T w_match[3]; /* regexp programs for ":match" */
char_u *(w_match_pat[3]); /* patterns for ":match" */
int w_match_id[3]; /* highlight IDs for ":match" */
matchitem_T *w_match_head; /* head of match list */
int w_next_match_id; /* next match ID */
#endif
/*

View File

@ -8504,7 +8504,7 @@ highlight_exists(name)
syn_id2name(id)
int id;
{
if (id <= 0 || id >= highlight_ga.ga_len)
if (id <= 0 || id > highlight_ga.ga_len)
return (char_u *)"";
return HL_TABLE()[id - 1].sg_name;
}

View File

@ -1,5 +1,5 @@
#
# Makefile to run al tests for Vim
# Makefile to run all tests for Vim
#
VIMPROG = ../vim
@ -15,7 +15,7 @@ SCRIPTS = test1.out test2.out test3.out test4.out test5.out test6.out \
test43.out test44.out test45.out test46.out test47.out \
test48.out test49.out test51.out test52.out test53.out \
test54.out test55.out test56.out test57.out test58.out \
test59.out test60.out test61.out test62.out
test59.out test60.out test61.out test62.out test63.out
SCRIPTS_GUI = test16.out

View File

@ -0,0 +1,157 @@
Test for ":match", ":2match", ":3match", "clearmatches()", "getmatches()",
"matchadd()", "matcharg()", "matchdelete()", and "setmatches()".
STARTTEST
:so small.vim
:" --- Check that "matcharg()" returns the correct group and pattern if a match
:" --- is defined.
:let @r = "*** Test 1: "
:highlight MyGroup1 ctermbg=red
:highlight MyGroup2 ctermbg=green
:highlight MyGroup3 ctermbg=blue
:match MyGroup1 /TODO/
:2match MyGroup2 /FIXME/
:3match MyGroup3 /XXX/
:if matcharg(1) == ['MyGroup1', 'TODO'] && matcharg(2) == ['MyGroup2', 'FIXME'] && matcharg(3) == ['MyGroup3', 'XXX']
: let @r .= "OK\n"
:else
: let @r .= "FAILED\n"
:endif
:" --- Check that "matcharg()" returns an empty list if the argument is not 1,
:" --- 2 or 3 (only 0 and 4 are tested).
:let @r .= "*** Test 2: "
:if matcharg(0) == [] && matcharg(4) == []
: let @r .= "OK\n"
:else
: let @r .= "FAILED\n"
:endif
:" --- Check that "matcharg()" returns ['', ''] if a match is not defined.
:let @r .= "*** Test 3: "
:match
:2match
:3match
:if matcharg(1) == ['', ''] && matcharg(2) == ['', ''] && matcharg(3) == ['', '']
: let @r .= "OK\n"
:else
: let @r .= "FAILED\n"
:endif
:" --- Check that "matchadd()" and "getmatches()" agree on added matches and
:" --- that default values apply.
:let @r .= "*** Test 4: "
:let m1 = matchadd("MyGroup1", "TODO")
:let m2 = matchadd("MyGroup2", "FIXME", 42)
:let m3 = matchadd("MyGroup3", "XXX", 60, 17)
:if getmatches() == [{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 4}, {'group': 'MyGroup2', 'pattern': 'FIXME', 'priority': 42, 'id': 5}, {'group': 'MyGroup3', 'pattern': 'XXX', 'priority': 60, 'id': 17}]
: let @r .= "OK\n"
:else
: let @r .= "FAILED\n"
:endif
:" --- Check that "matchdelete()" deletes the matches defined in the previous
:" --- test correctly.
:let @r .= "*** Test 5: "
:call matchdelete(m1)
:call matchdelete(m2)
:call matchdelete(m3)
:unlet m1
:unlet m2
:unlet m3
:if getmatches() == []
: let @r .= "OK\n"
:else
: let @r .= "FAILED\n"
:endif
:" --- Check that "matchdelete()" returns 0 if succesfull and otherwise -1.
:let @r .= "*** Test 6: "
:let m = matchadd("MyGroup1", "TODO")
:let r1 = matchdelete(m)
:let r2 = matchdelete(42)
:if r1 == 0 && r2 == -1
: let @r .= "OK\n"
:else
: let @r .= "FAILED\n"
:endif
:unlet m
:unlet r1
:unlet r2
:" --- Check that "clearmatches()" clears all matches defined by ":match" and
:" --- "matchadd()".
:let @r .= "*** Test 7: "
:let m1 = matchadd("MyGroup1", "TODO")
:let m2 = matchadd("MyGroup2", "FIXME", 42)
:let m3 = matchadd("MyGroup3", "XXX", 60, 17)
:match MyGroup1 /COFFEE/
:2match MyGroup2 /HUMPPA/
:3match MyGroup3 /VIM/
:call clearmatches()
:if getmatches() == []
: let @r .= "OK\n"
:else
: let @r .= "FAILED\n"
:endif
:unlet m1
:unlet m2
:unlet m3
:" --- Check that "setmatches()" restores a list of matches saved by
:" --- "getmatches()" without changes. (Matches with equal priority must also
:" --- remain in the same order.)
:let @r .= "*** Test 8: "
:let m1 = matchadd("MyGroup1", "TODO")
:let m2 = matchadd("MyGroup2", "FIXME", 42)
:let m3 = matchadd("MyGroup3", "XXX", 60, 17)
:match MyGroup1 /COFFEE/
:2match MyGroup2 /HUMPPA/
:3match MyGroup3 /VIM/
:let ml = getmatches()
:call clearmatches()
:call setmatches(ml)
:if getmatches() == ml
: let @r .= "OK\n"
:else
: let @r .= "FAILED\n"
:endif
:call clearmatches()
:unlet m1
:unlet m2
:unlet m3
:unlet ml
:" --- Check that "setmatches()" will not add two matches with the same ID. The
:" --- expected behaviour (for now) is to add the first match but not the
:" --- second and to return 0 (even though it is a matter of debate whether
:" --- this can be considered succesfull behaviour).
:let @r .= "*** Test 9: "
:let r1 = setmatches([{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 1}, {'group': 'MyGroup2', 'pattern': 'FIXME', 'priority': 10, 'id': 1}])
:if getmatches() == [{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 1}] && r1 == 0
: let @r .= "OK\n"
:else
: let @r .= "FAILED\n"
:endif
:call clearmatches()
:unlet r1
:" --- Check that "setmatches()" returns 0 if succesfull and otherwise -1.
:" --- (A range of valid and invalid input values are tried out to generate the
:" --- return values.)
:let @r .= "*** Test 10: "
:let rs1 = setmatches([])
:let rs2 = setmatches([{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 1}])
:call clearmatches()
:let rf1 = setmatches(0)
:let rf2 = setmatches([0])
:let rf3 = setmatches([{'wrong key': 'wrong value'}])
:if rs1 == 0 && rs2 == 0 && rf1 == -1 && rf2 == -1 && rf3 == -1
: let @r .= "OK\n"
:else
: let @r .= "FAILED\n"
:endif
:unlet rs1
:unlet rs2
:unlet rf1
:unlet rf2
:unlet rf3
:highlight clear MyGroup1
:highlight clear MyGroup2
:highlight clear MyGroup3
G"rp
:/^Results/,$wq! test.out
ENDTEST
Results of test63:

View File

@ -0,0 +1,11 @@
Results of test63:
*** Test 1: OK
*** Test 2: OK
*** Test 3: OK
*** Test 4: OK
*** Test 5: OK
*** Test 6: OK
*** Test 7: OK
*** Test 8: OK
*** Test 9: OK
*** Test 10: OK

View File

@ -666,6 +666,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
40,
/**/
39,
/**/

View File

@ -75,6 +75,7 @@ static int check_snapshot_rec __ARGS((frame_T *sn, frame_T *fr));
static win_T *restore_snapshot_rec __ARGS((frame_T *sn, frame_T *fr));
#endif /* FEAT_WINDOWS */
static win_T *win_alloc __ARGS((win_T *after));
static void win_new_height __ARGS((win_T *, int));
@ -4127,6 +4128,10 @@ win_alloc(after)
#endif
#ifdef FEAT_AUTOCMD
--autocmd_block;
#endif
#ifdef FEAT_SEARCH_EXTRA
newwin->w_match_head = NULL;
newwin->w_next_match_id = 4;
#endif
}
return newwin;
@ -4185,11 +4190,11 @@ win_free(wp, tp)
vim_free(wp->w_tagstack[i].tagname);
vim_free(wp->w_localdir);
#ifdef FEAT_SEARCH_EXTRA
vim_free(wp->w_match[0].regprog);
vim_free(wp->w_match[1].regprog);
vim_free(wp->w_match[2].regprog);
clear_matches(wp);
#endif
#ifdef FEAT_JUMPLIST
free_jumplist(wp);
#endif
@ -6174,3 +6179,173 @@ win_hasvertsplit()
return FALSE;
}
#endif
#if defined(FEAT_SEARCH_EXTRA) || defined(PROTO)
/*
* Add match to the match list of window 'wp'. The pattern 'pat' will be
* highligted with the group 'grp' with priority 'prio'.
* Optionally, a desired ID 'id' can be specified (greater than or equal to 1).
* If no particular ID is desired, -1 must be specified for 'id'.
* 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;
regmmatch_T match;
if (*grp == NUL || *pat == NUL)
return -1;
if (id < -1 || id == 0)
{
EMSGN("E799: Invalid ID: %ld (must be greater than or equal to 1)", id);
return -1;
}
if (id != -1)
{
cur = wp->w_match_head;
while (cur != NULL)
{
if (cur->id == id)
{
EMSGN("E801: ID already taken: %ld", id);
return -1;
}
cur = cur->next;
}
}
if ((hlg_id = syn_namen2id(grp, STRLEN(grp))) == 0)
{
EMSG2(_(e_nogroup), grp);
return -1;
}
if ((match.regprog = vim_regcomp(pat, RE_MAGIC)) == NULL)
{
EMSG2(_(e_invarg2), pat);
return -1;
}
/* Find available match ID. */
while (id == -1)
{
cur = wp->w_match_head;
while (cur != NULL && cur->id != wp->w_next_match_id)
cur = cur->next;
if (cur == NULL)
id = wp->w_next_match_id;
wp->w_next_match_id++;
}
/* Build new match. */
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 = match.regprog;
/* Insert new match. The match list is in ascending order with regard to
* the match priorities. */
cur = wp->w_match_head;
prev = cur;
while (cur != NULL && prio >= cur->priority)
{
prev = cur;
cur = cur->next;
}
if (cur == prev)
wp->w_match_head = m;
else
prev->next = m;
m->next = cur;
redraw_later(SOME_VALID);
return id;
}
/*
* Delete match with ID 'id' in the match list of window 'wp'.
* Print error messages if 'perr' is TRUE.
*/
int
match_delete(wp, id, perr)
win_T *wp;
int id;
int perr;
{
matchitem_T *cur = wp->w_match_head;
matchitem_T *prev = cur;
if (id < 1)
{
if (perr == TRUE)
EMSGN("E802: Invalid ID: %ld (must be greater than or equal to 1)",
id);
return -1;
}
while (cur != NULL && cur->id != id)
{
prev = cur;
cur = cur->next;
}
if (cur == NULL)
{
if (perr == TRUE)
EMSGN("E803: ID not found: %ld", id);
return -1;
}
if (cur == prev)
wp->w_match_head = cur->next;
else
prev->next = cur->next;
vim_free(cur->match.regprog);
vim_free(cur->pattern);
vim_free(cur);
redraw_later(SOME_VALID);
return 0;
}
/*
* Delete all matches in the match list of window 'wp'.
*/
void
clear_matches(wp)
win_T *wp;
{
matchitem_T *m;
while (wp->w_match_head != NULL)
{
m = wp->w_match_head->next;
vim_free(wp->w_match_head->match.regprog);
vim_free(wp->w_match_head->pattern);
vim_free(wp->w_match_head);
wp->w_match_head = m;
}
redraw_later(SOME_VALID);
}
/*
* Get match from ID 'id' in window 'wp'.
* Return NULL if match not found.
*/
matchitem_T *
get_match(wp, id)
win_T *wp;
int id;
{
matchitem_T *cur = wp->w_match_head;
while (cur != NULL && cur->id != id)
cur = cur->next;
return cur;
}
#endif