From ad4d8a192abf44b89371af87d70b971cd654b799 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 28 Dec 2015 19:20:36 +0100 Subject: [PATCH] patch 7.4.984 Problem: searchpos() always starts searching in the first column, which is not what some people expect. (Brett Stahlman) Solution: Add the 'z' flag: start at the specified column. --- runtime/doc/eval.txt | 21 ++++++++++++++------- src/eval.c | 6 +++++- src/search.c | 11 ++++++++--- src/testdir/test_alot.vim | 1 + src/testdir/test_searchpos.vim | 28 ++++++++++++++++++++++++++++ src/version.c | 2 ++ src/vim.h | 1 + 7 files changed, 59 insertions(+), 11 deletions(-) create mode 100644 src/testdir/test_searchpos.vim diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index f59c7f4ebe562..cb612caaafa3e 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1,4 +1,4 @@ -*eval.txt* For Vim version 7.4. Last change: 2015 Dec 03 +*eval.txt* For Vim version 7.4. Last change: 2015 Dec 28 VIM REFERENCE MANUAL by Bram Moolenaar @@ -5228,14 +5228,15 @@ search({pattern} [, {flags} [, {stopline} [, {timeout}]]]) *search()* move. No error message is given. {flags} is a String, which can contain these character flags: - 'b' search backward instead of forward - 'c' accept a match at the cursor position + 'b' search Backward instead of forward + 'c' accept a match at the Cursor position 'e' move to the End of the match 'n' do Not move the cursor - 'p' return number of matching sub-pattern (see below) - 's' set the ' mark at the previous location of the cursor - 'w' wrap around the end of the file - 'W' don't wrap around the end of the file + 'p' return number of matching sub-Pattern (see below) + 's' Set the ' mark at the previous location of the cursor + 'w' Wrap around the end of the file + 'W' don't Wrap around the end of the file + 'z' start searching at the cursor column instead of zero If neither 'w' or 'W' is given, the 'wrapscan' option applies. If the 's' flag is supplied, the ' mark is set, only if the @@ -5243,6 +5244,12 @@ search({pattern} [, {flags} [, {stopline} [, {timeout}]]]) *search()* flag. 'ignorecase', 'smartcase' and 'magic' are used. + + When the 'z' flag is not given seaching always starts in + column zero and then matches before the cursor are skipped. + When the 'c' flag is present in 'cpo' the next search starts + after the match. Without the 'c' flag the next search starts + one column further. When the {stopline} argument is given then the search stops after searching this line. This is useful to restrict the diff --git a/src/eval.c b/src/eval.c index 2668f3db5bade..a2d2939ba236f 100644 --- a/src/eval.c +++ b/src/eval.c @@ -16471,6 +16471,7 @@ f_reverse(argvars, rettv) #define SP_START 0x10 /* accept match at start position */ #define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */ #define SP_END 0x40 /* leave cursor at end of match */ +#define SP_COLUMN 0x80 /* start at cursor column */ static int get_search_arg __ARGS((typval_T *varp, int *flagsp)); @@ -16512,6 +16513,7 @@ get_search_arg(varp, flagsp) case 'p': mask = SP_SUBPAT; break; case 'r': mask = SP_REPEAT; break; case 's': mask = SP_SETPCMARK; break; + case 'z': mask = SP_COLUMN; break; } if (mask == 0) { @@ -16530,7 +16532,7 @@ get_search_arg(varp, flagsp) } /* - * Shared by search() and searchpos() functions + * Shared by search() and searchpos() functions. */ static int search_cmn(argvars, match_pos, flagsp) @@ -16562,6 +16564,8 @@ search_cmn(argvars, match_pos, flagsp) options |= SEARCH_START; if (flags & SP_END) options |= SEARCH_END; + 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) diff --git a/src/search.c b/src/search.c index 74398e39e8265..1145558a6924d 100644 --- a/src/search.c +++ b/src/search.c @@ -578,6 +578,7 @@ last_pat_prog(regmatch) * if (options & SEARCH_KEEP) keep previous search pattern * if (options & SEARCH_FOLD) match only once in a closed fold * if (options & SEARCH_PEEK) check for typed char, cancel search + * if (options & SEARCH_COL) start at pos->col instead of zero * * Return FAIL (zero) for failure, non-zero for success. * When FEAT_EVAL is defined, returns the index of the first matching @@ -599,6 +600,7 @@ searchit(win, buf, pos, dir, pat, count, options, pat_use, stop_lnum, tm) { int found; linenr_T lnum; /* no init to shut up Apollo cc */ + colnr_T col; regmmatch_T regmatch; char_u *ptr; colnr_T matchcol; @@ -711,12 +713,14 @@ searchit(win, buf, pos, dir, pat, count, options, pat_use, stop_lnum, tm) /* * Look for a match somewhere in line "lnum". */ + col = at_first_line && (options & SEARCH_COL) ? pos->col + : (colnr_T)0; nmatched = vim_regexec_multi(®match, win, buf, - lnum, (colnr_T)0, + lnum, col, #ifdef FEAT_RELTIME - tm + tm #else - NULL + NULL #endif ); /* Abort searching on an error (e.g., out of stack). */ @@ -1098,6 +1102,7 @@ set_vv_searchforward() /* * Return the number of the first subpat that matched. + * Return zero if none of them matched. */ static int first_submatch(rp) diff --git a/src/testdir/test_alot.vim b/src/testdir/test_alot.vim index 21a524116b59f..f15a2dce2cebc 100644 --- a/src/testdir/test_alot.vim +++ b/src/testdir/test_alot.vim @@ -2,5 +2,6 @@ " This makes testing go faster, since Vim doesn't need to restart. source test_lispwords.vim +source test_searchpos.vim source test_sort.vim source test_undolevels.vim diff --git a/src/testdir/test_searchpos.vim b/src/testdir/test_searchpos.vim new file mode 100644 index 0000000000000..4a1e024ce7143 --- /dev/null +++ b/src/testdir/test_searchpos.vim @@ -0,0 +1,28 @@ +" Tests for searchpos() + +func Test_searchpos() + new one + 0put ='1a3' + 1put ='123xyz' + call cursor(1, 1) + call assert_equal([1, 1, 2], searchpos('\%(\([a-z]\)\|\_.\)\{-}xyz', 'pcW')) + call cursor(1, 2) + call assert_equal([2, 1, 1], searchpos('\%(\([a-z]\)\|\_.\)\{-}xyz', 'pcW')) + set cpo-=c + call cursor(1, 2) + call assert_equal([1, 2, 2], searchpos('\%(\([a-z]\)\|\_.\)\{-}xyz', 'pcW')) + call cursor(1, 3) + call assert_equal([1, 3, 1], searchpos('\%(\([a-z]\)\|\_.\)\{-}xyz', 'pcW')) + + " Now with \zs, first match is in column 0, "a" is matched. + call cursor(1. 3) + call assert_equal([2, 4, 2], searchpos('\%(\([a-z]\)\|\_.\)\{-}\zsxyz', 'pcW')) + " With z flag start at cursor column, don't see the "a". + call cursor(1. 3) + call assert_equal([2, 4, 1], searchpos('\%(\([a-z]\)\|\_.\)\{-}\zsxyz', 'pcWz')) + + set cpo+=c + " close the window + q! + +endfunc diff --git a/src/version.c b/src/version.c index 67f8d77f09fab..5a5a59c8a6f5d 100644 --- a/src/version.c +++ b/src/version.c @@ -741,6 +741,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 984, /**/ 983, /**/ diff --git a/src/vim.h b/src/vim.h index 729c45a54d358..11b9119f2ee23 100644 --- a/src/vim.h +++ b/src/vim.h @@ -930,6 +930,7 @@ extern char *(*dyn_libintl_textdomain)(const char *domainname); #define SEARCH_MARK 0x200 /* set previous context mark */ #define SEARCH_KEEP 0x400 /* keep previous search pattern */ #define SEARCH_PEEK 0x800 /* peek for typed char, cancel search */ +#define SEARCH_COL 0x1000 /* start at specified column instead of zero */ /* Values for find_ident_under_cursor() */ #define FIND_IDENT 1 /* find identifier (word) */