On Monday, August 12, 2013 9:22:21 PM UTC+2, Christian Brabandt wrote:
> On Do, 08 Aug 2013, Dimitar DIMITROV wrote:
> 
> 
> 
> > As per the subject :)
> 
> 
> 
> Can you check, whether the attached patch fixes it for you?
> 
> 
> 
> regards,
> 
> Christian
> 
> -- 
> 
> Was die Welt in diesem Augenblick sucht, ist viel weniger ein
> 
> Gleichgewicht als eine Sprache.
> 
>               -- Jean Giraudoux

I'd like to bring this up again. I was surprised that `gUgn` wasn't repeatable 
and took a dive into the code. I solved it in a different way and found this 
topic while I wanted to submit my patch.

I discovered that the `gn` command used the `redobuff` in a differend way [1] 
than most commands. The command `dgn` would write `gnd` to the `redobuff` 
instead of the more natuaral `dgn`. To make redo work, there was some special 
code [2] needed to read the `d` after `gn` to issue the deletion.

This breaks when using two character operators. The command `gUgn` writes 
`gngU` to the stuffbuff. The `.` command would now only get one extra char 
after `gn`, leading to the repeated command `gng`, which does nothing.

Getting another extra char in that case would probably work, but instead I 
tried to reverse the `redobuff`. Instead of `gngU` from [1] I wrote `gUgn` to 
the `stuffbuff` and suddenly everything worked. When repeated, the `gU` command 
pends, `gn` selects the next match and the pending operator makes it uppercase.

After that I could remove the special behavior mentioned in [2].

Here is a small test case to demonstrate the difference. The following vim 
invocation inserts "vim vim", searches for "vim", uppercases the first match, 
but fails to uppercase the second match upon repetition. Result: "VIM vim"

    ./vim -c ':exe "norm 2Ivim \<Esc>x#gUgn."'

The same invocation with the attached `gugn_repeat.patch` applied, yields the 
expected "VIM VIM".


Bonus: In the `gn` implementation `current_search` there is an early return [3] 
that doesn't restore the 'wrapscan' option. This happens when the search 
pattern cannot be found.

So after you deleted all occurences of a pattern by repeating `dgn`, the 
'nowrapscan' option will remain set. I fixed this by restoring 'wrapscan' 
before returning.

Test case: Start vim with this invocation and execute the ex command `:set ws?` 
to verify that 'nowrapscan' is set.

    ./vim -c ':let @/="a"|norm "dgn"'

The same invocation with the attached `gn_wrapscan.patch` applied, still has 
'wrapscan' set as expected.


@ Christian Brabandt: Was there any intention in the reversed `stuffbuff` order 
that I might have missed?


[1] normal.c
1800                     /* "gn" and "gN" are a bit different */
1801                     prep_redo(oap->regname, 0L, NUL, cap->cmdchar, 
cap->nchar,
1802                                         get_op_char(oap->op_type),
1803                                         get_extra_op_char(oap->op_type));

[2] normal.c
 965             /* For "gn" from redo, need to get one more char to determine 
the
 966              * operator */
 967             if (ca.nchar == 'r' || ca.nchar == '\'' || ca.nchar == '`'
 968                                                        || ca.nchar == 
Ctrl_BSL
 969                   || ((ca.nchar == 'n' || ca.nchar == 'N') && 
!stuff_empty()))

[3] search.c
4544     /* Is the pattern is zero-width? */
4545     one_char = is_one_char(spats[last_idx].pat);
4546     if (one_char == -1)
4547         return FAIL;  /* invalid pattern */

-- 
-- 
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 vim_dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
diff -r 34a3b852ec05 src/normal.c
--- a/src/normal.c	Tue Nov 12 18:09:29 2013 +0100
+++ b/src/normal.c	Wed Nov 13 23:54:13 2013 +0100
@@ -962,11 +962,8 @@
 #ifdef FEAT_CMDL_INFO
 	    need_flushbuf |= add_to_showcmd(ca.nchar);
 #endif
-	    /* For "gn" from redo, need to get one more char to determine the
-	     * operator */
 	    if (ca.nchar == 'r' || ca.nchar == '\'' || ca.nchar == '`'
-						       || ca.nchar == Ctrl_BSL
-		  || ((ca.nchar == 'n' || ca.nchar == 'N') && !stuff_empty()))
+						       || ca.nchar == Ctrl_BSL)
 	    {
 		cp = &ca.extra_char;	/* need to get a third character */
 		if (ca.nchar != 'r')
@@ -1797,10 +1794,9 @@
 		 * otherwise it might be the second char of the operator. */
 		if (cap->cmdchar == 'g' && (cap->nchar == 'n'
 							|| cap->nchar == 'N'))
-		    /* "gn" and "gN" are a bit different */
-		    prep_redo(oap->regname, 0L, NUL, cap->cmdchar, cap->nchar,
-					get_op_char(oap->op_type),
-					get_extra_op_char(oap->op_type));
+		    prep_redo(oap->regname, cap->count0,
+			    get_op_char(oap->op_type), get_extra_op_char(oap->op_type),
+			    oap->motion_force, cap->cmdchar, cap->nchar);
 		else if (cap->cmdchar != ':')
 		    prep_redo(oap->regname, 0L, NUL, 'v',
 					get_op_char(oap->op_type),
diff -r 34a3b852ec05 src/search.c
--- a/src/search.c	Tue Nov 12 18:09:29 2013 +0100
+++ b/src/search.c	Thu Nov 14 00:10:51 2013 +0100
@@ -4543,8 +4543,10 @@
 
     /* Is the pattern is zero-width? */
     one_char = is_one_char(spats[last_idx].pat);
-    if (one_char == -1)
-	return FAIL;  /* invalid pattern */
+    if (one_char == -1) {
+	p_ws = old_p_ws;
+	return FAIL;  /* pattern not found */
+    }
 
     /*
      * The trick is to first search backwards and then search forward again,

Reply via email to