On Mo, 14 Dez 2015, John Beckett wrote:

> Thanks Christian for the excellent gn added in 7.3.610. However,
> using Vim 7.4.972 I'm seeing this problem with cgn after search.
> 
> Put the cursor at beginning of line:
> 
> abc x def x ghi x jkl
> 
> Type /x and press Enter to find first x.
> 
> Type cgn"x" and press Esc to replace search hit with "x" (three
> characters).
> 
> Press n to find next x then press . to repeat change.
> 
> Expected result:
> 
> abc "x" def "x" ghi x jkl
> 
> Actual result:
> 
> abc "x" def "x" jkl
> 
> The problem occurs when the search is for a single character,
> and the replacement text ("x" above) includes the search.
> 
> The problem can also be seen by simply trying cgn on the
> second x.

Hm, so this happens, when the replacement also matches the search 
expression.

I see the problem in is_one_char():

,----
|  4793         nmatched = vim_regexec_multi(&regmatch, curwin, curbuf,
|  4794                     pos.lnum, (colnr_T)0, NULL);
`----

Note the 0? That is the problem, vim tries to match from the first 
column. On a first thought, it looks like replacing 0 with pos.col would 
be correct, and while this fixes your example, it breaks for more 
complex search patterns like in the test:

a:0\@!\zs\d\+
and a sample input like this:
a:10

because then pos.col would be at the first digit and the search pattern 
would not match from there on. I don't know the best way to fix this. A 
fix is attached, but it is ugly.

Best,
Christian
-- 
Nur eine Kette ist es, die uns gebunden hält: Die Liebe zum Leben.
                -- Lucius Annaeus Seneca (an Lucilius)

-- 
-- 
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/src/search.c b/src/search.c
--- a/src/search.c
+++ b/src/search.c
@@ -4753,7 +4753,7 @@ current_search(count, forward)
 }
 
 /*
- * Check if the pattern is one character or zero-width.
+ * Check if the pattern is one character long or zero-width.
  * If move is TRUE, check from the beginning of the buffer, else from the
  * current cursor position.
  * Returns TRUE, FALSE or -1 for failure.
@@ -4769,6 +4769,11 @@ is_one_char(pattern, move)
     pos_T	pos;
     int		save_called_emsg = called_emsg;
     int		flag = 0;
+    pos_T	endpos;
+    pos_T	t;
+
+    if (pattern == NULL)
+	pattern = spats[last_idx].pat;
 
     if (search_regcomp(pattern, RE_SEARCH, RE_SEARCH,
 					      SEARCH_KEEP, &regmatch) == FAIL)
@@ -4784,22 +4789,31 @@ is_one_char(pattern, move)
 	flag = SEARCH_START;
     }
 
-    if (searchit(curwin, curbuf, &pos, FORWARD, spats[last_idx].pat, 1,
+    if (searchit(curwin, curbuf, &pos, FORWARD, pattern, 1,
 			      SEARCH_KEEP + flag, RE_SEARCH, 0, NULL) != FAIL)
     {
 	/* Zero-width pattern should match somewhere, then we can check if
 	 * start and end are in the same position. */
 	called_emsg = FALSE;
 	nmatched = vim_regexec_multi(&regmatch, curwin, curbuf,
-						  pos.lnum, (colnr_T)0, NULL);
-
+					    pos.lnum, (colnr_T)0, NULL);
+
+	t = endpos = pos;
 	if (!called_emsg)
+	{
 	    result = (nmatched != 0
 		&& regmatch.startpos[0].lnum == regmatch.endpos[0].lnum
 		&& regmatch.startpos[0].col == regmatch.endpos[0].col);
-
-	if (!result && inc(&pos) >= 0 && pos.col == regmatch.endpos[0].col)
-	    result = TRUE;
+	    /* one char width */
+	    if (!result && inc(&t) >= 0 && t.col == regmatch.endpos[0].col)
+		result = TRUE;
+
+	    /* move to end of match and check position again */
+	    if (!result && searchit(curwin, curbuf, &endpos, FORWARD, pattern, 1,
+		flag + SEARCH_KEEP + SEARCH_END, RE_SEARCH, 0, NULL) != FAIL &&
+		pos.col == endpos.col)
+		result = TRUE;
+	}
     }
 
     called_emsg |= save_called_emsg;
diff --git a/src/testdir/test53.in b/src/testdir/test53.in
--- a/src/testdir/test53.in
+++ b/src/testdir/test53.in
@@ -53,6 +53,7 @@ dit
 :put =match('abc', '\zs', 2, 1) " 2
 :put =match('abc', '\zs', 3, 1) " 3
 :put =match('abc', '\zs', 4, 1) " -1
+:" Tests for gn
 /^foobar
 gncsearchmatch/one\_s*two\_s
 :1
@@ -82,6 +83,9 @@ ggdgn.
 gggUgn.
 gg/a:0\@!\zs\d\+
 nygnop
+/^abc x
+0/x
+cgn'x'..
 :/^start:/,/^end:/wq! test.out
 ENDTEST
 
@@ -131,4 +135,5 @@ Depp
 --4
 Depp
 --5
+abc x def x ghi x jkl
 end:
diff --git a/src/testdir/test53.ok b/src/testdir/test53.ok
--- a/src/testdir/test53.ok
+++ b/src/testdir/test53.ok
@@ -68,4 +68,5 @@ DEPP
 --4
 DEPP
 --5
+abc 'x' def 'x' ghi 'x' jkl
 end:

Raspunde prin e-mail lui