Some months ago I discovered this bug in vi(1). I mentioned it in a
thread about ksh(1) vi-mode but I had no time until now to find a
solution. The 'p' command with a count does something weird. First
write some word:
Hello
Then put the cursor at the beginning of the word and yank the whole word
with 'ye'. Finally put the cursor at the end of the word (in this case
in the last 'o' of Hello) and paste the content of the buffer with '2p'.
This is the result:
HelloHHelloello
^
In case you'll be willing to try variants to my diff below it's
necessary to also do the following test. Yank "Hello" as above but this
time move the cursor to the next empty line and run '2p' there:
Hello
HHelloello
^
(First column)
You won't notice the difference with the current behavior (nor after
applying my patch, since I've taken care of these details,) you'll do if
you try to make your own changes to the code: for the way the function
put() (common/put.c) is designed, it's not the same to yank or paste
when the cursor is at the first column than when it is in any other
place.
Another case example, this time yanking and pasting whole lines. Put
the cursor in "One", then yank the three lines with '3yy'.
One
Two
Three
Finally, move the cursor to "Three" and paste with '2p'. You'll see
this:
One
Two
Three
>One
One
Two
Three
Two
Three
The diff below fixes the above issues.
In case my patch is at least considered (I haven't had much success here
lately ;-)) I will post a second one, an alternative that fix the above
issue and also introduce a change in the paste behavior imitating what
ksh(1) does (also bash and vim) where the cursor lands on the *last*
character of the pasted string.
Index: vi/v_put.c
===================================================================
RCS file: /cvs/src/usr.bin/vi/vi/v_put.c,v
diff -u -p -r1.8 v_put.c
--- vi/v_put.c 27 May 2016 09:18:12 -0000 1.8
+++ vi/v_put.c 4 Aug 2025 19:20:33 -0000
@@ -65,6 +65,7 @@ int
v_put(SCR *sp, VICMD *vp)
{
u_long cnt;
+ int append;
if (F_ISSET(vp, VC_ISDOT))
inc_buf(sp, vp);
@@ -74,12 +75,16 @@ v_put(SCR *sp, VICMD *vp)
* Historic vi did not support a count with the 'p' and 'P'
* commands. It's useful, so we do.
*/
+ append = 1;
for (cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
if (put(sp, NULL,
F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
- &vp->m_start, &vp->m_final, 1))
+ &vp->m_start, &vp->m_final, append))
return (1);
- vp->m_start = vp->m_final;
+ if (sp->cno == 0) {
+ append = 0;
+ vp->m_start = vp->m_final;
+ }
if (INTERRUPTED(sp))
return (1);
}
--
Walter