changeset 18426:3b80bdbdc832 v8.1.2207

patch 8.1.2207: "gn" doesn't work quite right Commit: https://github.com/vim/vim/commit/edaad6e0a0e3c1fcb6a5c2771e647c52475bb19c Author: Bram Moolenaar <Bram@vim.org> Date: Thu Oct 24 15:23:37 2019 +0200 patch 8.1.2207: "gn" doesn't work quite right Problem: "gn" doesn't work quite right. (Jaehwang Jerry Jung) Solution: Improve and simplify the search logic. (Christian Brabandt, closes #5103, closes #5075)
author Bram Moolenaar <Bram@vim.org>
date Thu, 24 Oct 2019 15:30:03 +0200
parents d58c4ff92b3f
children 089d9b0658cc
files src/search.c src/testdir/test_gn.vim src/version.c
diffstat 3 files changed, 101 insertions(+), 92 deletions(-) [+]
line wrap: on
line diff
--- a/src/search.c
+++ b/src/search.c
@@ -4676,7 +4676,73 @@ abort_search:
 
 #endif /* FEAT_TEXTOBJ */
 
-static int is_one_char(char_u *pattern, int move, pos_T *cur, int direction);
+/*
+ * Check if the pattern is one character long or zero-width.
+ * If move is TRUE, check from the beginning of the buffer, else from position
+ * "cur".
+ * "direction" is FORWARD or BACKWARD.
+ * Returns TRUE, FALSE or -1 for failure.
+ */
+    static int
+is_zero_width(char_u *pattern, int move, pos_T *cur, int direction)
+{
+    regmmatch_T	regmatch;
+    int		nmatched = 0;
+    int		result = -1;
+    pos_T	pos;
+    int		save_called_emsg = called_emsg;
+    int		flag = 0;
+
+    if (pattern == NULL)
+	pattern = spats[last_idx].pat;
+
+    if (search_regcomp(pattern, RE_SEARCH, RE_SEARCH,
+					      SEARCH_KEEP, &regmatch) == FAIL)
+	return -1;
+
+    // init startcol correctly
+    regmatch.startpos[0].col = -1;
+    // move to match
+    if (move)
+    {
+	CLEAR_POS(&pos);
+    }
+    else
+    {
+	pos = *cur;
+	// accept a match at the cursor position
+	flag = SEARCH_START;
+    }
+
+    if (searchit(curwin, curbuf, &pos, NULL, direction, pattern, 1,
+				  SEARCH_KEEP + flag, RE_SEARCH, NULL) != FAIL)
+    {
+	// Zero-width pattern should match somewhere, then we can check if
+	// start and end are in the same position.
+	called_emsg = FALSE;
+	do
+	{
+	    regmatch.startpos[0].col++;
+	    nmatched = vim_regexec_multi(&regmatch, curwin, curbuf,
+			       pos.lnum, regmatch.startpos[0].col, NULL, NULL);
+	    if (nmatched != 0)
+		break;
+	} while (direction == FORWARD ? regmatch.startpos[0].col < pos.col
+				      : regmatch.startpos[0].col > pos.col);
+
+	if (!called_emsg)
+	{
+	    result = (nmatched != 0
+		&& regmatch.startpos[0].lnum == regmatch.endpos[0].lnum
+		&& regmatch.startpos[0].col == regmatch.endpos[0].col);
+	}
+    }
+
+    called_emsg |= save_called_emsg;
+    vim_regfree(regmatch.regprog);
+    return result;
+}
+
 
 /*
  * Find next search match under cursor, cursor at end.
@@ -4697,7 +4763,7 @@ current_search(
     char_u	old_p_ws = p_ws;
     int		flags = 0;
     pos_T	save_VIsual = VIsual;
-    int		one_char;
+    int		zero_width;
 
     /* wrapping should not occur */
     p_ws = FALSE;
@@ -4706,29 +4772,20 @@ current_search(
     if (VIsual_active && *p_sel == 'e' && LT_POS(VIsual, curwin->w_cursor))
 	dec_cursor();
 
+    orig_pos = pos = curwin->w_cursor;
     if (VIsual_active)
     {
-	orig_pos = curwin->w_cursor;
-
-	pos = curwin->w_cursor;
-
-	/* make sure, searching further will extend the match */
-	if (VIsual_active)
-	{
-	    if (forward)
-		incl(&pos);
-	    else
-		decl(&pos);
-	}
+	if (forward)
+	    incl(&pos);
+	else
+	    decl(&pos);
     }
-    else
-	orig_pos = pos = curwin->w_cursor;
 
     /* Is the pattern is zero-width?, this time, don't care about the direction
      */
-    one_char = is_one_char(spats[last_idx].pat, TRUE, &curwin->w_cursor,
+    zero_width = is_zero_width(spats[last_idx].pat, TRUE, &curwin->w_cursor,
 								      FORWARD);
-    if (one_char == -1)
+    if (zero_width == -1)
     {
 	p_ws = old_p_ws;
 	return FAIL;  /* pattern not found */
@@ -4747,7 +4804,7 @@ current_search(
 	    dir = !i;
 
 	flags = 0;
-	if (!dir && !one_char)
+	if (!dir && !zero_width)
 	    flags = SEARCH_END;
 	end_pos = pos;
 
@@ -4784,7 +4841,6 @@ current_search(
 				ml_get(curwin->w_buffer->b_ml.ml_line_count));
 	    }
 	}
-	p_ws = old_p_ws;
     }
 
     start_pos = pos;
@@ -4797,10 +4853,11 @@ current_search(
     curwin->w_cursor = end_pos;
     if (LT_POS(VIsual, end_pos))
 	dec_cursor();
+    else if (VIsual_active && LT_POS(curwin->w_cursor, VIsual))
+	curwin->w_cursor = pos;   // put the cursor on the start of the match
     VIsual_active = TRUE;
     VIsual_mode = 'v';
 
-    redraw_curbuf_later(INVERTED);	/* update the inversion */
     if (*p_sel == 'e')
     {
 	/* Correction for exclusive selection depends on the direction. */
@@ -4828,77 +4885,6 @@ current_search(
     return OK;
 }
 
-/*
- * Check if the pattern is one character long or zero-width.
- * If move is TRUE, check from the beginning of the buffer, else from position
- * "cur".
- * "direction" is FORWARD or BACKWARD.
- * Returns TRUE, FALSE or -1 for failure.
- */
-    static int
-is_one_char(char_u *pattern, int move, pos_T *cur, int direction)
-{
-    regmmatch_T	regmatch;
-    int		nmatched = 0;
-    int		result = -1;
-    pos_T	pos;
-    int		save_called_emsg = called_emsg;
-    int		flag = 0;
-
-    if (pattern == NULL)
-	pattern = spats[last_idx].pat;
-
-    if (search_regcomp(pattern, RE_SEARCH, RE_SEARCH,
-					      SEARCH_KEEP, &regmatch) == FAIL)
-	return -1;
-
-    /* init startcol correctly */
-    regmatch.startpos[0].col = -1;
-    /* move to match */
-    if (move)
-    {
-	CLEAR_POS(&pos);
-    }
-    else
-    {
-	pos = *cur;
-	/* accept a match at the cursor position */
-	flag = SEARCH_START;
-    }
-
-    if (searchit(curwin, curbuf, &pos, NULL, direction, pattern, 1,
-			 SEARCH_KEEP + flag, RE_SEARCH, NULL) != FAIL)
-    {
-	/* Zero-width pattern should match somewhere, then we can check if
-	 * start and end are in the same position. */
-	called_emsg = FALSE;
-	do
-	{
-	    regmatch.startpos[0].col++;
-	    nmatched = vim_regexec_multi(&regmatch, curwin, curbuf,
-			       pos.lnum, regmatch.startpos[0].col, NULL, NULL);
-	    if (nmatched != 0)
-		break;
-	} while (direction == FORWARD ? regmatch.startpos[0].col < pos.col
-				      : regmatch.startpos[0].col > pos.col);
-
-	if (!called_emsg)
-	{
-	    result = (nmatched != 0
-		&& regmatch.startpos[0].lnum == regmatch.endpos[0].lnum
-		&& regmatch.startpos[0].col == regmatch.endpos[0].col);
-	    // one char width
-	    if (!result && nmatched != 0
-			&& inc(&pos) >= 0 && pos.col == regmatch.endpos[0].col)
-		result = TRUE;
-	}
-    }
-
-    called_emsg |= save_called_emsg;
-    vim_regfree(regmatch.regprog);
-    return result;
-}
-
 #if defined(FEAT_LISP) || defined(FEAT_CINDENT) || defined(FEAT_TEXTOBJ) \
 	|| defined(PROTO)
 /*
--- a/src/testdir/test_gn.vim
+++ b/src/testdir/test_gn.vim
@@ -128,6 +128,27 @@ func Test_gn_command()
   call assert_equal([' nnoremap', '', 'match'], getline(1,'$'))
   sil! %d_
 
+  " make sure it works correctly for one-char wide search items
+  call setline('.', ['abcdefghi'])
+  let @/ = 'a'
+  exe "norm! 0fhvhhgNgU"
+  call assert_equal(['ABCDEFGHi'], getline(1,'$'))
+  call setline('.', ['abcdefghi'])
+  let @/ = 'b'
+  exe "norm! 0fhvhhgngU"
+  call assert_equal(['abcdefghi'], getline(1,'$'))
+  sil! %d _
+  call setline('.', ['abcdefghi'])
+  let @/ = 'f'
+  exe "norm! 0vllgngU"
+  call assert_equal(['ABCDEFghi'], getline(1,'$'))
+  sil! %d _
+  call setline('.', ['12345678'])
+  let @/ = '5'
+  norm! gg0f7vhhhhgnd
+  call assert_equal(['12348'], getline(1,'$'))
+  sil! %d _
+
   set wrapscan&vim
 endfu
 
--- a/src/version.c
+++ b/src/version.c
@@ -742,6 +742,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    2207,
+/**/
     2206,
 /**/
     2205,