Index | Thread | Search

From:
patrick keshishian <pkeshish@gmail.com>
Subject:
Re: ksh vi mode: stop 'P' command from moving the cursor
To:
Ingo Schwarze <schwarze@usta.de>
Cc:
Walter Alejandro Iglesias <wai@roquesor.com>, Anton Lindqvist <anton@basename.se>, millert@openbsd.org, tech@openbsd.org
Date:
Thu, 24 Apr 2025 10:24:16 -0700

Download raw body.

Thread
On Thu, Apr 24, 2025 at 9:38 AM Ingo Schwarze <schwarze@usta.de> wrote:
>
> Hello Walter,
>
> we have now three options what to do with 'P' in ksh(1) VI mode; one
> of them also changes the behaviour of 'p'.  So i'm asking people:
> which one of the three do you prefer?

If you are taking a survey, it would be better to move
this conversation to tech@ or misc@, rather than bugs@.
I would have missed this question if not by chance.


> If people prefer one of the two solutions proposed by Walter, i'll
> polish, test, and commit that.  Otherwise, i'll commit the diff i
> posted earlier.  Something needs to be committed because right now,
> the 'P' command misbehaves with UTF-8.

Admitting that the 'P' (paste before) command behaves
differently in various programs (e.g., nvi), as someone
who uses ksh in VI mode, the intuitive expectation, at
least for me, when pasting something before the cursor
is to leave the cursor after the pasted string.

If I really wanted the cursor at the start of the newly
pasted string, I would use the 'p' (paste after) command.
Again, stating what seems natural to me.

> Walter Alejandro Iglesias wrote on Thu, Apr 24, 2025 at 10:49:02AM +0200:
> > On Mon, Apr 21, 2025 at 11:38:01PM +0200, Ingo Schwarze wrote:
>
> >> here is a patch to change the behaviour of the "paste before" (P) command
> >> in the VI command line editing mode of ksh(1).
>
> > With your diff, after pasting with the 'P' command the cursor lands one
> > character *after* the last character in the string pasted.
>
> Correct.
> That is also the character the cursor is on before pasting.
>
> > I'm not saying this is wrong, maybe it's more convenient, but it's not
> > what the 'p' command does
>
> Correct.
> In our ksh(1), 'p' puts the cursor on the last character inserted.
>
> > or what other popular applications (vim, bash) that
> > have adopted moving the cursor to the end of the pasted string do.
> >
> > The two diffs below are *NOT TESTED* (but considering I'm not modifying
> > functions in this case, they probably won't cause regressions.)  The
> > idea is to show the difference between two behaviors with practical
> > examples; you'll decide which one you like best.
>
> I do not feel strongly about which cursor positioning after 'p' or 'P'
> might be most useful.  Opinions from people who actually use VI mode
> in our ksh(1) would be particularly appreciated.  Opinions from
> developers would be helpful even if they do not use VI mode.
>
> If nobody voicces a preference, i tend to use the diff i posted
> because it is least intrusive, and *if* there is limited interest,
> least intrusive is arguably best.
>
> > The first behavior (vi(1), nvi2 from ports, FreeBSD sh):
> >
> >   After pasting text with 'p' or 'P' the cursor lands on the first
> >   character of the string pasted.
>
> I can confirm this is what our vi(1) does.  I did not test nvi2
> or FreeBSD.
>
> > The second behavior (vim, bash and other shells):
> >
> >   After pasting text with 'p' or 'P' the cursor lands on the last
> >   character of the string pasted.
>
> I did not test vim or bash, but there is one potential (weak) argument
> supporting this behabiour: in our ksh(1), that's where the cursor
> lands when you insert text with 'a' or 'i' and press ESCAPE.
> So arguably, this option slightly improves consistency of ksh(1) VI mode.
>
> Looking at the ksh(1) manual page, i do not see any other VI mode
> commands that could be looked at as a model for what 'p' and 'P'
> should do.
>
> > (By the way, I found a bug on vi(1) paste command.  I'll report it in
> > other thread in the future.)
>
> Thanks, keeping different issues in different, well-named threads
> helps everyone.
>
> > FIRST BEHAVIOR (vi like)  # go to the first inserted character
> >
> > Index: vi.c
> > ===================================================================
> > RCS file: /cvs/src/bin/ksh/vi.c,v
> > diff -u -p -r1.61 vi.c
> > --- vi.c      21 Apr 2025 20:06:15 -0000      1.61
> > +++ vi.c      24 Apr 2025 08:36:19 -0000
> > @@ -837,8 +837,10 @@ vi_cmd(int argcnt, const char *cmd)
> >                       while (es->cursor < es->linelen)
> >                               if (!isu8cont(es->cbuf[++es->cursor]))
> >                                       break;
> > +                     any = es->cursor;
> >                       while (putbuf(ybuf, yanklen, 0) == 0 && --argcnt > 0)
> >                               ;
> > +                     es->cursor = any + 1;
> >                       while (es->cursor > 0)
> >                               if (!isu8cont(es->cbuf[--es->cursor]))
> >                                       break;
>
> From code inspection, this looks likely to do what you want.
> Probably, it would be even better to replace the last four lines
> with simply
>
>         es->cursor = any;
>
> because if the first inserted character is valid UTF-8, that does the
> same, and if the first inserted character is isu8cont (which shouldn't
> normally happen), backing up to the last character before the insertion
> feels like a dubious choice.
>
> > @@ -848,11 +850,10 @@ vi_cmd(int argcnt, const char *cmd)
> >
> >               case 'P':
> >                       modified = 1; hnum = hlast;
> > -                     any = 0;
> > +                     any = es->cursor;
> >                       while (putbuf(ybuf, yanklen, 0) == 0 && --argcnt > 0)
> > -                             any = 1;
> > -                     if (any && es->cursor != 0)
> > -                             es->cursor--;
> > +                             continue;
> > +                     es->cursor = any;
> >                       if (argcnt != 0)
> >                               return -1;
> >                       break;
>
> Yes, that might do what you want.
>
> > SECOND BEHAVIOR (vim like)  # go to the last inserted character
> >
> > Index: vi.c
> > ===================================================================
> > RCS file: /cvs/src/bin/ksh/vi.c,v
> > diff -u -p -r1.61 vi.c
> > --- vi.c      21 Apr 2025 20:06:15 -0000      1.61
> > +++ vi.c      24 Apr 2025 07:34:50 -0000
> > @@ -848,11 +848,9 @@ vi_cmd(int argcnt, const char *cmd)
> >
> >               case 'P':
> >                       modified = 1; hnum = hlast;
> > -                     any = 0;
> >                       while (putbuf(ybuf, yanklen, 0) == 0 && --argcnt > 0)
> > -                             any = 1;
> > -                     if (any && es->cursor != 0)
> > -                             es->cursor--;
> > +                             continue;
> > +                     es->cursor--;
>
> Not quite, instead of es->cursor--, here we would likely need
>
>         while (es->cursor > 0)
>                 if (!isu8cont(es->cbuf[--es->cursor]))
>                         break;
>
> such that we back up a complete character and not just a single byte.
>
> So, which behaviour do people want?
>
>  0) minimally invasive, 1P unchanged:
>     p  unchanged -> to last character inserted
>     1P unchanged -> after last character inserted
>     2P changed to match 1P -> after last character inserted
>
>  1) meximally invasive -> always to first charcter inserted
>     like in our vi(1)
>
>  2) minimally invasive, 2P unchanged -> always to last character inserted
>     p  unchanged
>     1P changed to match 2P
>     2P unchanged

As an ordinary user's opinion, I prefer option 0.
--patrick


> Yours,
>   Ingo
>