From: Walter Alejandro Iglesias Subject: Another vi(1) paste improvement To: tech@openbsd.org Cc: "Todd C. Miller" Date: Fri, 29 Aug 2025 09:50:53 +0200 This improvement: https://marc.info/?l=openbsd-cvs&m=175598284729256&w=2 https://github.com/lichray/nvi2/commit/95c6b23d2f8eb32858698bae46c71392f1d90562 paved the rode for another improvement. Now that cursor movement doesn't affect count+paste anymore we can modify where the cursor lands after character mode pasting safely and indepenently. The interest in doing this is to circumvent the inconvenience described here by Nils Ola Nilsson: https://marc.info/?l=openbsd-tech&m=174551571311274&w=2 And, since now we're talking about vi(1), were we also have to consider *line* mode pasting, where happens something analogous, as the following example shows. One <- First put your cursor here and hit '3yy' Two Three <- Then, put your cursor here and hit 'p' several times consecutively (without manually repositioning the cursor between each 'p'.) The result: One Two Three One <- The cursor lands here the first time One <- The cursor lands here the second time (and so on) Two Three Two Three To test *cursor* mode pasting just yank some word (eg "Hello") with 'ye' and hit 'p' several times. (In any case you can also repeat the command with '.'). Now, apply the diff at bottom, perform again those tests and compare the results. The results will speak for themselves. Regarding *line* mode pasting there's another interesting comparison to do. In a file where text reaches or surpasses the bottom of the window, put the cursor in the last visible line and hit 'p'. With the new behavior the buffer is scrolled automatically in the same action, letting you see the whole text you pasted. Where is the trick? As clearly explained in the comments I added to the code, what the diff below does is to modify only the 'p' command to move the cursor to the last character pasted in cursor mode pasting and to the last line pasted in line mode pasting. 'P' preserves its current behavior in both cases. Index: common/put.c =================================================================== RCS file: /cvs/src/usr.bin/vi/common/put.c,v diff -u -p -r1.17 put.c --- common/put.c 23 Aug 2025 21:02:10 -0000 1.17 +++ common/put.c 25 Aug 2025 06:10:17 -0000 @@ -70,9 +70,6 @@ put(SCR *sp, CB *cbp, CHAR_T *namep, MAR * historic vi couldn't deal with a file that had no lines in it. This * implementation treats that as a bug, and does not retain the blank * line. - * - * Historical practice is that the cursor ends at the first character - * in the file. */ if (cp->lno == 1) { if (db_last(sp, &lno)) @@ -86,7 +83,18 @@ put(SCR *sp, CB *cbp, CHAR_T *namep, MAR return (1); tp = TAILQ_FIRST(&cbp->textq); } - rp->lno = 1; + + /* + * Historical practice was that the cursor ends at the + * first character in the file. This is preserved only + * for the 'P' command. With 'p', now the cursor is + * moved to the last line pasted. + */ + if (append) + rp->lno = lno; + else + rp->lno = 1; + rp->cno = 0; return (0); } @@ -104,7 +112,15 @@ put(SCR *sp, CB *cbp, CHAR_T *namep, MAR return (1); tp = TAILQ_FIRST(&cbp->textq); } + + /* + * With the 'p' command move the cursor to the last line + * pasted. + */ + if (append) + rp->lno = lno; rp->cno = 0; + (void)nonblank(sp, rp->lno, &rp->cno); return (0); } @@ -158,9 +174,19 @@ put(SCR *sp, CB *cbp, CHAR_T *namep, MAR * of vi, character mode puts that cross line boundaries leave the * cursor on the first character. Nvi implements the System III/V * behavior, and expect POSIX.2 to do so as well. + * + * Update (Aug 24, 2025): Now, with the 'p' command, the cursor + * moves to the last character of the pasted string. The 'P' + * command hasn't been modified; the cursor still rests on the + * first character of the pasted string. This is convenient when + * running 'p' or 'P' consecutive times or by hitting '.' (dot). */ rp->lno = lno; - rp->cno = len == 0 ? 0 : sp->cno + (append && tp->len ? 1 : 0); + if (append == 0) + rp->cno = len == 0 ? 0 : sp->cno; + else + rp->cno = len == 0 ? (tp->len * cnt) - 1 : sp->cno + + append + (tp->len * cnt) - 1; /* * If no more lines in the CB, append the rest of the original -- Walter