zsh-users
 help / color / mirror / Atom feed
* How to complete with _arguments() depending on an option and within a loop
@ 2021-05-10 17:30 Philippe Proulx
  2021-05-11 14:12 ` Daniel Shahaf
  0 siblings, 1 reply; 7+ messages in thread
From: Philippe Proulx @ 2021-05-10 17:30 UTC (permalink / raw)
  To: zsh-users

I'm in the process of writing a Zsh completion script.

Consider this command line:

    $ prog --state=foo --meow --state=bar cola --mix --lol=34 \
           --state=foo --meow --zoom

In a Zsh completion script, how would you complete the options above,
knowing that:

* You can specify one or more _groups_.

* A group starts with the `--state` option which accepts an argument.

* The accepted options depend on the argument of the preceding `--state`
  option.

  For example:

  * With `--state=foo`, you can pass `--meow` (only once) and
    `--zoom` (only once).

  * With `--state=bar`:

    * You can pass `--mix` (only once), `--lol` (only once).

    * You must pass a non-option argument (`cola` in this example).

* Wherever you are, Zsh must always offer you the `--state` option with
  the `foo` and `bar` arguments (to restart).

I managed to implement such a completion script "manually", with the
`words` and `CURRENT` variables, compset(), and _describe() to add
completions. It works, but I feel like I'm rewriting parts of
_arguments().

Is there a known way to achieve this mostly with _arguments()?

Thank you,

Phil


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: How to complete with _arguments() depending on an option and within a loop
  2021-05-10 17:30 How to complete with _arguments() depending on an option and within a loop Philippe Proulx
@ 2021-05-11 14:12 ` Daniel Shahaf
  2021-05-12 13:44   ` Philippe Proulx
  0 siblings, 1 reply; 7+ messages in thread
From: Daniel Shahaf @ 2021-05-11 14:12 UTC (permalink / raw)
  To: Philippe Proulx, zsh-users

Philippe Proulx wrote on Mon, 10 May 2021 17:30 +00:00:
>     $ prog --state=foo --meow --state=bar cola --mix --lol=34 \
>            --state=foo --meow --zoom
> 
> In a Zsh completion script, how would you complete the options above,
> knowing that:
> I managed to implement such a completion script "manually", with the
> `words` and `CURRENT` variables, compset(), and _describe() to add
> completions. It works, but I feel like I'm rewriting parts of
> _arguments().
> 
> Is there a known way to achieve this mostly with _arguments()?

Look at _beep.  It does basically what you're describing, and does use
_arguments for the core logic.

I'd go for something along the lines of:

_prog() {
  local -a args=( --state=': :(foo bar)' )
  if ((CURRENT > 1)); then
    case ${words[(Ib.CURRENT-1.)--state=*]} in
      (*=foo) args+=( -meow -zoom );;
      (*=bar) args+=( --mix --lol :cola );;
    esac
  fi
  (munge $words as _beep does)
  _arguments : "${args[@]}"
}

Cheers,

Daniel


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: How to complete with _arguments() depending on an option and within a loop
  2021-05-11 14:12 ` Daniel Shahaf
@ 2021-05-12 13:44   ` Philippe Proulx
  2021-05-12 15:11     ` Bart Schaefer
  0 siblings, 1 reply; 7+ messages in thread
From: Philippe Proulx @ 2021-05-12 13:44 UTC (permalink / raw)
  To: Daniel Shahaf; +Cc: zsh-users

On Tue, May 11, 2021 at 10:13 AM Daniel Shahaf <d.s@daniel.shahaf.name> wrote:
>
> Philippe Proulx wrote on Mon, 10 May 2021 17:30 +00:00:
> >     $ prog --state=foo --meow --state=bar cola --mix --lol=34 \
> >            --state=foo --meow --zoom
> >
> > In a Zsh completion script, how would you complete the options above,
> > knowing that:
> ⋮
> > I managed to implement such a completion script "manually", with the
> > `words` and `CURRENT` variables, compset(), and _describe() to add
> > completions. It works, but I feel like I'm rewriting parts of
> > _arguments().
> >
> > Is there a known way to achieve this mostly with _arguments()?
>
> Look at _beep.  It does basically what you're describing, and does use
> _arguments for the core logic.
>
> I'd go for something along the lines of:
>
> _prog() {
>   local -a args=( --state=': :(foo bar)' )
>   if ((CURRENT > 1)); then
>     case ${words[(Ib.CURRENT-1.)--state=*]} in
>       (*=foo) args+=( -meow -zoom );;
>       (*=bar) args+=( --mix --lol :cola );;
>     esac
>   fi
>   (munge $words as _beep does)
>   _arguments : "${args[@]}"
> }

This seems fragile.

For example (I know it's far-fetched here, but just to make my point),
what if your device file is literally named `--new` in the current
working directory, such that you would write:

    $ beep --device=--new

or

    $ beep --device --new

Now, completion doesn't work as expected:

    $ beep --device --new <tab>

Zsh offers `--device` again, because the completion script "saw" the
`--new` word, without taking any parsing into account.

My point being: I'll still need to handle command-line parsing manually,
including supporting both `--opt=arg` and `--opt arg` forms, etc. to
find where the current state (equivalent of the `--new` option of
beep(1)) really begins.

Phil

>
> Cheers,
>
> Daniel


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: How to complete with _arguments() depending on an option and within a loop
  2021-05-12 13:44   ` Philippe Proulx
@ 2021-05-12 15:11     ` Bart Schaefer
  2021-05-12 15:14       ` Philippe Proulx
  0 siblings, 1 reply; 7+ messages in thread
From: Bart Schaefer @ 2021-05-12 15:11 UTC (permalink / raw)
  To: Philippe Proulx; +Cc: Daniel Shahaf, Zsh Users

On Wed, May 12, 2021 at 6:44 AM Philippe Proulx <eeppeliteloop@gmail.com> wrote:
>
>     $ beep --device --new <tab>
>
> Zsh offers `--device` again, because the completion script "saw" the
> `--new` word, without taking any parsing into account.

What everybody seems to forget about completion is that it's supposed
to save the user typing time, not save the user from thinkos.  If the
user is uncomprehending enough to select --device twice just because
completion offered it, it's not our job to come to the rescue.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: How to complete with _arguments() depending on an option and within a loop
  2021-05-12 15:11     ` Bart Schaefer
@ 2021-05-12 15:14       ` Philippe Proulx
  2021-05-12 15:50         ` Bart Schaefer
  0 siblings, 1 reply; 7+ messages in thread
From: Philippe Proulx @ 2021-05-12 15:14 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Daniel Shahaf, Zsh Users

On Wed, May 12, 2021 at 11:11 AM Bart Schaefer
<schaefer@brasslantern.com> wrote:
>
> On Wed, May 12, 2021 at 6:44 AM Philippe Proulx <eeppeliteloop@gmail.com> wrote:
> >
> >     $ beep --device --new <tab>
> >
> > Zsh offers `--device` again, because the completion script "saw" the
> > `--new` word, without taking any parsing into account.
>
> What everybody seems to forget about completion is that it's supposed
> to save the user typing time, not save the user from thinkos.  If the
> user is uncomprehending enough to select --device twice just because
> completion offered it, it's not our job to come to the rescue.

You'd love Bash then!

I believe the complexity of Zsh completion can translate into better
command line UX.

Why would _argument() support not repeating an option (the default)
then (`--opt[my option]` vs `*--opt[my option]`)?

Phil


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: How to complete with _arguments() depending on an option and within a loop
  2021-05-12 15:14       ` Philippe Proulx
@ 2021-05-12 15:50         ` Bart Schaefer
  2021-05-12 16:14           ` Ray Andrews
  0 siblings, 1 reply; 7+ messages in thread
From: Bart Schaefer @ 2021-05-12 15:50 UTC (permalink / raw)
  To: Philippe Proulx; +Cc: Daniel Shahaf, Zsh Users

On Wed, May 12, 2021 at 8:15 AM Philippe Proulx <eeppeliteloop@gmail.com> wrote:
>
> I believe the complexity of Zsh completion can translate into better
> command line UX.

Certainly.

> Why would _argument() support not repeating an option (the default)
> then (`--opt[my option]` vs `*--opt[my option]`)?

It's a degrees-of-effort thing.

There's a (subjective) point at which the effort to limit the
completion results to exactly what "makes sense" in a given context,
exceeds the benefit of doing so.  I think that a lot of the time the
benefit is given so much weight that the effort becomes unreasonable.
Completion shouldn't offer nonsense (like the \"\"\" result in another
recent thread, that's clearly a bug) but it's rarely going to achieve
perfection.

Returning to your specific question, you might look at using
_regex_arguments instead.  If you can figure out the syntax, you can
put almost unlimited effort into making the result perfect.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: How to complete with _arguments() depending on an option and within a loop
  2021-05-12 15:50         ` Bart Schaefer
@ 2021-05-12 16:14           ` Ray Andrews
  0 siblings, 0 replies; 7+ messages in thread
From: Ray Andrews @ 2021-05-12 16:14 UTC (permalink / raw)
  To: zsh-users

On 2021-05-12 8:50 a.m., Bart Schaefer wrote:
> I think that a lot of the time the
> benefit is given so much weight that the effort becomes unreasonable.
And then there's the law of unintended consequences merged with Murphy's 
Law -- you end up with something very 'helpful' that you can't turn off 
in that situation where the 'help' isn't helpful *and* the complexity is 
such that the thing might break in ways that no one even anticipated.   
Think avionics like that 'helpful' stall sensor in the 737 that crashed 
two airplanes.  Not too long ago you were kind enough to help me turn 
off every bit of helpfulness in completion -- just local files please -- 
I don't have the experience to remember all the 'help' that's available 
so please don't help, it's easier to just type a few more characters.  
KISS.  Nice to have it there of course, but also nice to be able to turn 
it off.




^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2021-05-12 16:15 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-10 17:30 How to complete with _arguments() depending on an option and within a loop Philippe Proulx
2021-05-11 14:12 ` Daniel Shahaf
2021-05-12 13:44   ` Philippe Proulx
2021-05-12 15:11     ` Bart Schaefer
2021-05-12 15:14       ` Philippe Proulx
2021-05-12 15:50         ` Bart Schaefer
2021-05-12 16:14           ` Ray Andrews

zsh-users

This inbox may be cloned and mirrored by anyone:

	git clone --mirror http://inbox.vuxu.org/zsh-users

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V1 zsh-users zsh-users/ http://inbox.vuxu.org/zsh-users \
		zsh-users@zsh.org
	public-inbox-index zsh-users

Example config snippet for mirrors.
Newsgroup available over NNTP:
	nntp://inbox.vuxu.org/vuxu.archive.zsh.users


code repositories for the project(s) associated with this inbox:

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

AGPL code for this site: git clone https://public-inbox.org/public-inbox.git