zsh-workers
 help / color / mirror / code / Atom feed
From: Bart Schaefer <schaefer@brasslantern.com>
To: Zsh hackers list <zsh-workers@zsh.org>
Subject: Re: [BUG] complist interactive mode overwrites command line
Date: Thu, 16 Nov 2023 19:35:40 -0800	[thread overview]
Message-ID: <CAH+w=7YeSp-NOVs7-eCP2RZuKz_OAkyHN_TCVVjAPZt4rkrL_w@mail.gmail.com> (raw)
In-Reply-To: <CAH+w=7Zq-0X1DnSW7vORP5B64PN0pzQ2UX2bDfWk8405YDXfrA@mail.gmail.com>

Another thread rising from the grave:

On Sat, Jul 16, 2022 at 11:11 AM Bart Schaefer
<schaefer@brasslantern.com> wrote:
>
> > On Wed, 4 Aug 2021 19:30:10 +0300 Marlon Richert <marlon.richert@xxxxxxxxx> wrote:
> > > % zmodload zsh/complist
> > > % bindkey '^I' menu-select
> > > % MENUMODE=interactive
> > > % touch test{1,2}
> > > % : ; foobar
> >
> > >     ^ 1. Type the above line in its entirety.
> > >       2. Place the cursor before the ;
> > >       3. Press Tab.
> > >       4. Press Enter.
> > > % : test1 bar
> > >     ^ Completion is written over existing buffer contents.
>
> The issue seems to be that interactive mode assumes you're going to
> use it interactively -- as in, type a single character at a time until
> you've reduced the set to only one match -- so it only adjusts the
> buffer spacing on single keystrokes.  When you accept with TAB (or
> ENTER) domenuselect() is relying on do_single() to fix everything up,
> but the state required by do_single() is not fully populated.

This entirely seems to come down to minfo.len causing the wrong thing
to happen in compresult.c:do_single(), specifically here:

    /* If we are already in a menu-completion or if we have done a *
     * glob completion, we have to delete some of the stuff on the *
     * command line.                                               */
    if (minfo.cur)
        l = minfo.len + minfo.insc;
    else
        l = we - wb;

    minfo.insc = 0;
    zlemetacs = minfo.pos;
    foredel(l, CUT_RAW);

In normal menu completion, when entering the menu, the first match is
already inserted on the command line.  This code is used in common by
interactive completion, so when accept-line is invoked, minfo.len is
the length of that first completion.  However, what minfo.len is
supposed to represent is how many characters have already been
inserted on the line, which in this case is zero because interactively
nothing gets inserted until you type a matching character.  Thus the
foredel() call there deletes what it thinks is the completion already
on the command line, but instead deletes other stuff after the cursor.

This can trivially be fixed for Marlon's specific example by setting
minfo.len = 0 in the "if (first)" block in domenuselect(), but that's
only correct for this specific case.  Anything that resets the
appearance of the line -- such as hitting TAB again after accept-line,
because (as in the "user defined widget doesn't execute suffix
removal" thread), we are actually still in menu completion at that
point even though we've left interactive completion -- also loses
track of the fact that the original line is back the way it was, and
so minfo.len becomes wrong again and things like navigating the menu
with the arrow keys start foredel()-ing too much.

Interactive completion gets in its own way here a bit, because there
are several cases where it attempts to restore the original state and
gets it subtly wrong.

If anyone thinks they have a better grasp of all the special cases and
widget handling in complist.c, please chime in.  Of course 2/3 of the
lines of complist.c are Sven W's and a good chunk of the rest is
comments from other people trying to explain what Sven did, so I'm not
very hopeful.


  parent reply	other threads:[~2023-11-17  3:36 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <8964126.CDJkKcVGEf.ref@phy-nordri>
2022-07-15 13:39 ` Andrea Manenti
2022-07-16 18:11   ` Bart Schaefer
2022-07-16 22:57     ` Bart Schaefer
     [not found]       ` <2844417.e9J7NaK4W3@phy-nordri>
2022-07-22 16:32         ` Bart Schaefer
2022-07-22 17:55           ` Bart Schaefer
2022-07-22 18:23             ` Bart Schaefer
2022-07-22 19:10               ` Andrea Manenti
2023-11-17  3:35     ` Bart Schaefer [this message]
2021-08-04 16:30 Marlon Richert
2024-03-04  1:44 ` Samy Dulor
2024-03-04  2:05   ` Bart Schaefer
2024-03-04  6:33     ` Bart Schaefer
2024-03-04 11:30       ` Samy Dulor
2024-03-04 22:38         ` Bart Schaefer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAH+w=7YeSp-NOVs7-eCP2RZuKz_OAkyHN_TCVVjAPZt4rkrL_w@mail.gmail.com' \
    --to=schaefer@brasslantern.com \
    --cc=zsh-workers@zsh.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).