nvi2 icon indicating copy to clipboard operation
nvi2 copied to clipboard

Counterintuitive outcome of 'p' with numeral prefix

Open lichray opened this issue 8 months ago • 1 comments

From Walter Alejandro Iglesias [email protected]

When you yank a word and paste it with 'p' using a numeric prefix, the first character of the string yanked in the last occurrence is pasted at the beginning of the entire string.

In the following example I copied the word "Hello" with the command 'ye' and pasted it on the same line (leaving a space in between to make the example more readable) first using the command '2p' then using '3p':

Hello HHelloHello HHelloHelloHello

In the code, numeral prefixes are handled with a for loop (file vi/v_put.c). The diff at bottom partially solves the issue, it just removes the following line in the v_put() function:

vp->p_start = vp->m_final;

But, I guess that line must be there for a reason ;-). I said "partially" because even after you remove that line the issue is still reproducible when you paste the word in an empty line. For example:

Hello
HHelloHello
--- vi/v_put.c  Thu Apr 24 15:13:56 2025
+++ vi/v_put.c.orig Thu Apr 24 15:13:41 2025
@@ -77,6 +77,7 @@
    {
        if (F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL,
            vp->p_start, &vp->m_final, 1))
            return (1);
+       vp->p_start = vp->m_final;
        if (INTERP(vsp))
            return (1);
    }

lichray avatar May 12 '25 00:05 lichray

Historical notes

https://github.com/lichray/nvi2/blob/16de509a8b44fb50acd475473f6829baf2b3ef2c/common/put.c#L137-L150

Observation

'2P' seems to work "fine."

Discussion

The following discussion of how it's implemented in OpenBSD's ksh vi-mode is interesting:

https://marc.info/?t=174527132800001&r=1&w=2

Take a look especially to this message:

https://marc.info/?l=openbsd-tech&m=174551571311274&w=2

It's very likely that whoever designed or corrected the vi mode in OpenBSD's ksh realized what NilsOla Nilsson pointed out, and improved those commands. However Ingo Schwarze end opting for the behavior you see in vim, bash or ksh93 from ports.

lichray avatar May 12 '25 00:05 lichray

From Walter Alejandro Iglesias

suppose we want to paste "Hello" two times times with '2p'. Currently, this takes to the code the following steps (roughly):

  1. Load "Hello" to the buffer.
  2. Decide where to move the cursor.
  3. Paste "Hello" and move the cursor.
  4. Load second occurrence of "Hello" to the buffer.
  5. Decide where to move the cursor.
  6. Paste the second occurrence of "Hello" and move the cursor.

[...] I moved the loop with the counter to the put() function itself, which means that all occurrences of "Hello" are loaded into the buffer before the cursor movement is decided. The '2p' command above is reduced to:

  1. Load "HelloHello" to the buffer.
  2. Decide where to move the cursor.
  3. Paste "HelloHello" and move the cursor.

lichray avatar Aug 14 '25 00:08 lichray