zsh-users
 help / color / mirror / code / Atom feed
From: Oliver Kiddle <okiddle@yahoo.co.uk>
To: Sebastian Gniazdowski <sgniazdowski@gmail.com>
Cc: Zsh Users <zsh-users@zsh.org>
Subject: Re: Why the widget bound to menuselect isn't called?
Date: Sat, 13 Jul 2019 10:59:19 +0200	[thread overview]
Message-ID: <33999-1563008359.364082@ccgB.SxHS.A_VB> (raw)
In-Reply-To: <CAKc7PVAyX6-J1r-E-pRbzdajofQ4CG8tK3WxpD3N0vR9+zoECQ@mail.gmail.com>

Sebastian Gniazdowski wrote:
> function double-accept { echo 1 >> /tmp/reply; }
> zle -N double-accept
> bindkey -M menuselect ' ' double-accept
>
> Why?

Because custom widgets aren't supported by complist and never have been.
In the documentation for the complist module, just before the effect of
the various zle widgets are described, it states:

       The following zle functions have special meaning during menu
       selection.  Note that the following always perform the same
       task within the menu selection map and cannot be replaced
       by user defined widgets, nor can the set of functions be
       extended:

That doesn't really answer your question of "Why?" but this isn't easy
to explain briefly. What follows is more suited to -workers:

It is a feature to give "special meaning" to existing widgets
for something like menu selection. Consider something like
accept-and-infer-next-history: accepting the current selection and
allowing menu selection to continue is conceptually very similar
to accepting a line from history and moving to the next one. So
the special meaning allows whatever key a user configured to
accept-and-infer-next-history to do something similar in menu selection.
Note that the menuselect keymap is a local keymap so only acts to
override bindings in whatever your main keymap is.

complist is implemented as a module so the code for
accept-and-infer-next-history can't check whether menu selection
is active unlike the checks for, e.g. the region being active.

So the complist code does stuff like:

   cmd = getkeycmd();
   ...
   if (cmd == TH(z_viinsert)) {
      /* enter interactive mode */
      ...
   } else if (cmd ==  Th(z_acceptandinfernexthistory) {
      /* special meaning code for accept-and-infer-next-history */
      ...
   } else if ....
      ...
   } else /* any other widget */
      ungetkeycmd();
      /* accept selected match */

If you search for getkeycmd() in zle_main.c, you'll see it followed
by a call to execzlefunc().

It isn't just menuselect but also the command, isearch, listscroll
keymaps where this happens. When incremental history was implemented, we
didn't have local keymaps or user defined widgets so the implementation
there was perfectly natural at the time.

If you're wondering what it would take to make this work while not
breaking exist user's keybindings, the short answer is quite a lot.
Primarily, we need to handle keymap specific special meanings some other
way:

We could take the concepts embodied in Functions/Zle/keymap+widget and
enshrine it in the C code. I'm not sure I entirely like that because
you end up with menuselect+forward-char and menuselect+vi-forward-char
widgets rather than a single menuselect-next-match. And how do you
reassign forward-char to be column-right rather than next-match (we've
had user questions in the past about right-cursor moving to the next row
from the last column). A user might just rebind l or cursor-right or
whatever but a plugin may want to act independently of the actual keys.
Perhaps menuselect+forward-char etc could be aliases.

We could allow zle widget aliases to be keymap specific. So we'd
predefine the aliases and they could be changed, e.g:
  zle -A forward-char -M menuselect menuselect-column-right

A more flexible approach might be to allow conditional zle widget
aliases. The condition could be zstyle-like encompassing things like
whether the region is active, keymap, PS2 active, completion active,
lastwidget. Does that sound useful or over-complicated? keymap+widget
might be a useful just as a naming convention.

Once before when this was vaguely discussed, Bart mentioned emacs minor
modes. Does anyone know how those are implemented underneath?

Aside from that new mechanism, there'd be lots of factoring out of
special widgets into their own functions and making sure they don't
crash the shell if invoked in the wrong context. It'd inevitably also
lead to some extra APIs to allow finer control of menu selection such as
the example I gave about moving right when already on the last column.

Oliver

PS. bindkey -s will work. Does the following do what you wanted with double-accept?

  bindkey -M menuselect -s ' ' '^@^M'
  bindkey -M menuselect '^@' auto-suffix-remove

  parent reply	other threads:[~2019-07-13  9:00 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-07-11 20:55 Sebastian Gniazdowski
2019-07-12 18:44 ` Sebastian Gniazdowski
2019-07-12 19:36   ` Bart Schaefer
2019-07-13  1:23     ` Sebastian Gniazdowski
2019-07-13  2:29       ` Ben Klein
2019-07-13  8:59 ` Oliver Kiddle [this message]
2019-07-13 12:19   ` Sebastian Gniazdowski
2019-07-13 12:23     ` Sebastian Gniazdowski
2019-07-13 16:39     ` Bart Schaefer
2019-07-13 16:42       ` Bart Schaefer
2019-07-14 10:38     ` Oliver Kiddle
2019-07-14 21:56       ` Sebastian Gniazdowski

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=33999-1563008359.364082@ccgB.SxHS.A_VB \
    --to=okiddle@yahoo.co.uk \
    --cc=sgniazdowski@gmail.com \
    --cc=zsh-users@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).