From: Pascal Stumpf Subject: Re: ksh vi mode: stop 'P' command from moving the cursor To: Ingo Schwarze Cc: Walter Alejandro Iglesias , Anton Lindqvist , millert@openbsd.org, tech@openbsd.org Date: Thu, 24 Apr 2025 22:46:53 +0200 Hi Ingo, On Thu, 24 Apr 2025 17:39:56 +0200, Ingo Schwarze 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 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. > > 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 a user of vi mode, I must say that I prefer option 2). It is consistent among both the p and P commands, and also the behaviour of the ksh93 package, as well as all historical ksh versions I tested on sdf.org. That is probably also the reason bash behaves this way. pdksh is the one that has an inaccuracy here in its implementation. > Yours, > Ingo >