sed と vi の :s の違いハック

s/hoge/meso/3

としたとき、sed は行内で3番目の hoge を置換するが、vi はカレント行から3行以内の hoge を置換する。
sed 流の方がうれしいので vim もそうなるようにハックにチャレンジしてみた。
複数行にわたる検索パターンが指定されたときは考えないことに。

--- ../src.orig/ex_cmds.c	Sun Apr 23 03:56:56 2006
+++ ex_cmds.c	Thu Dec  7 23:38:08 2006
@@ -4142,6 +4144,8 @@
     linenr_T	old_line_count = curbuf->b_ml.ml_line_count;
     linenr_T	line2;
     long	nmatch;			/* number of lines in match */
+    int		matchcount;		
+    int		nth = 0;
     linenr_T	sub_firstlnum;		/* nr of first sub line */
     char_u	*sub_firstline;		/* allocated copy of first sub line */
     int		endcolumn = FALSE;	/* cursor in last column when done */
@@ -4326,10 +4331,13 @@
 	    EMSG(_(e_zerocount));
 	    return;
 	}
+	/*
 	eap->line1 = eap->line2;
 	eap->line2 += i - 1;
 	if (eap->line2 > curbuf->b_ml.ml_line_count)
 	    eap->line2 = curbuf->b_ml.ml_line_count;
+	*/
+	nth = i;
     }
 
     /*
@@ -4389,6 +4397,8 @@
 #endif
 		); ++lnum)
     {
+	matchcount = 0;
+
 	sub_firstlnum = lnum;
 	nmatch = vim_regexec_multi(&regmatch, curwin, curbuf, lnum, (colnr_T)0);
 	if (nmatch)
@@ -4475,6 +4485,8 @@
 	     */
 	    for (;;)
 	    {
+		matchcount += 1;
+
 		/* Save the line number of the last change for the final
 		 * cursor position (just like Vi). */
 		curwin->w_cursor.lnum = lnum;
@@ -4523,6 +4535,11 @@
 		    goto skip;
 		}
 
+		if (nth && matchcount < nth) {
+		    do_again = TRUE;
+		    goto skip;
+		}
+
 		if (do_ask)
 		{
 		    /* change State to CONFIRM, so that the mouse works


[追記:2007-01-13]
ed は sed と同じ挙動になる。
vi になって改悪されたわけだ。
ex-050325 のソースを見ると
ex_re.c

445                         setcount();
446                         newline();

としているのでバグではないようだが…