Hi,
attached patch, enables skip expressions similar to what searchpairpos()
already does for search() and searchpos() functions. Patch includes
updated documentation and an updated test.
I think this is useful, so you can search for e.g. "pattern" only in
syntax group "Comment" or the other way around. Currently there is no
way to do that, other than making a loop and manually checking each
match.
Best,
Christian
--
Begehrst du sie, so sagen sie, du seist vulgär wie alle anderen
Männer; begehrst du sie nicht, so sagen sie, du seist impotent.
-- Pitigrilli
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index abc022d..02eefb1 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -5652,7 +5652,8 @@ screenrow() *screenrow()*
Note: Same restrictions as with |screencol()|.
-search({pattern} [, {flags} [, {stopline} [, {timeout}]]]) *search()*
+ *search()*
+search({pattern} [, {flags} [, {stopline} [, {timeout} [, {skip}]]]])
Search for regexp pattern {pattern}. The search starts at the
cursor position (you can use |cursor()| to set it).
@@ -5700,6 +5701,14 @@ search({pattern} [, {flags} [, {stopline} [, {timeout}]]]) *search()*
giving the argument.
{only available when compiled with the |+reltime| feature}
+ {skip} expression is evaluated with the cursor positioned on
+ the start of the match. It should return non-zero if this
+ match is to be skipped. E.g., because it is inside a comment
+ or a string.
+ When {skip} is omitted or empty, every match is accepted.
+ When evaluating {skip} causes an error the search is aborted
+ and -1 returned.
+
*search()-sub-match*
With the 'p' flag the returned value is one more than the
first sub-match in \(\). One if none of them matched but the
@@ -5854,7 +5863,8 @@ searchpairpos({start}, {middle}, {end} [, {flags} [, {skip}
<
See |match-parens| for a bigger and more useful example.
-searchpos({pattern} [, {flags} [, {stopline} [, {timeout}]]]) *searchpos()*
+ *searchpos()*
+searchpos({pattern} [, {flags} [, {stopline} [, {timeout} [, {skip}]]]])
Same as |search()|, but returns a |List| with the line and
column position of the match. The first element of the |List|
is the line number and the second element is the byte index of
diff --git a/src/eval.c b/src/eval.c
index b04b6c2..74839a3 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -8424,11 +8424,11 @@ static struct fst
{"screenchar", 2, 2, f_screenchar},
{"screencol", 0, 0, f_screencol},
{"screenrow", 0, 0, f_screenrow},
- {"search", 1, 4, f_search},
+ {"search", 1, 5, f_search},
{"searchdecl", 1, 3, f_searchdecl},
{"searchpair", 3, 7, f_searchpair},
{"searchpairpos", 3, 7, f_searchpairpos},
- {"searchpos", 1, 4, f_searchpos},
+ {"searchpos", 1, 5, f_searchpos},
{"server2client", 2, 2, f_server2client},
{"serverlist", 0, 0, f_serverlist},
{"setbufvar", 3, 3, f_setbufvar},
@@ -17500,6 +17500,7 @@ search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
char_u *pat;
pos_T pos;
pos_T save_cursor;
+ pos_T save_pos;
int save_p_ws = p_ws;
int dir;
int retval = 0; /* default: FAIL */
@@ -17510,6 +17511,9 @@ search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
#endif
int options = SEARCH_KEEP;
int subpatnum;
+ pos_T firstpos;
+ char_u *skip = (char_u *)"";
+ char_u nbuf[NUMBUFLEN];
pat = get_tv_string(&argvars[0]);
dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
@@ -17523,8 +17527,10 @@ search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
if (flags & SP_COLUMN)
options |= SEARCH_COL;
- /* Optional arguments: line number to stop searching and timeout. */
- if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
+ /* Optional arguments: line number to stop searching,
+ * timeout and skip expression. */
+ if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN
+ && argvars[3].v_type != VAR_UNKNOWN)
{
lnum_stop = get_tv_number_chk(&argvars[2], NULL);
if (lnum_stop < 0)
@@ -17537,6 +17543,11 @@ search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
goto theend;
}
#endif
+ if (argvars[4].v_type != VAR_UNKNOWN)
+ skip = get_tv_string_buf_chk(&argvars[4], nbuf);
+
+ if (skip == NULL)
+ goto theend;
}
#ifdef FEAT_RELTIME
@@ -17558,10 +17569,37 @@ search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
}
pos = save_cursor = curwin->w_cursor;
- subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L,
- options, RE_SEARCH, (linenr_T)lnum_stop, &tm);
- if (subpatnum != FAIL)
+ clearpos(&firstpos);
+ for (;;)
{
+ subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L,
+ options, RE_SEARCH, (linenr_T)lnum_stop, &tm);
+
+ if (subpatnum == FAIL || (firstpos.lnum != 0 && equalpos(pos, firstpos)))
+ /* didn't find it or found the first match again: FAIL */
+ break;
+
+ /* If the skip pattern matches, ignore this match. */
+ if (*skip != NUL)
+ {
+ int r;
+ int err;
+
+ save_pos = curwin->w_cursor;
+ curwin->w_cursor = pos;
+ r = eval_to_bool(skip, &err, NULL, FALSE);
+ curwin->w_cursor = save_pos;
+ if (err)
+ {
+ /* Evaluating {skip} caused an error, break here. */
+ curwin->w_cursor = save_cursor;
+ retval = 0;
+ break;
+ }
+ if (r)
+ continue;
+ }
+
if (flags & SP_SUBPAT)
retval = subpatnum;
else
@@ -17575,9 +17613,7 @@ search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
match_pos->lnum = pos.lnum;
match_pos->col = pos.col + 1;
}
- /* "/$" will put the cursor after the end of the line, may need to
- * correct that here */
- check_cursor();
+ break;
}
/* If 'n' flag is used: restore cursor position. */
@@ -17585,6 +17621,10 @@ search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
curwin->w_cursor = save_cursor;
else
curwin->w_set_curswant = TRUE;
+
+ /* "/$" will put the cursor after the end of the line, may need to
+ * correct that here */
+ check_cursor();
theend:
p_ws = save_p_ws;
diff --git a/src/testdir/test_syntax.vim b/src/testdir/test_syntax.vim
index 297e835..31078d4 100644
--- a/src/testdir/test_syntax.vim
+++ b/src/testdir/test_syntax.vim
@@ -65,3 +65,22 @@ func Test_syn_iskeyword()
quit!
endfunc
+
+func Test_search_syntax()
+ new
+ call setline(1, [
+ \ '',
+ \ '/* This is VIM */',
+ \ 'Another Text for VIM',
+ \ ' let a="VIM"',
+ \ ''])
+ syntax on
+ syntax match Comment "^/\*.*\*/"
+ syntax match String '".*"'
+ :1
+ call search('VIM', 'w', '', 0, 'synIDattr(synID(line("."),col("."),1),"name")=~?"comment"')
+ call assert_equal('Another Text for VIM', getline('.'))
+ call search('VIM', 'w', '', 0, 'synIDattr(synID(line("."),col("."),1),"name")!~?"string"')
+ call assert_equal(' let a="VIM"', getline('.'))
+ :quit!
+endfu