zsh-workers
 help / color / mirror / code / Atom feed
* Advanced option parsing across zsh commands
@ 2016-01-26  9:20 Sebastian Gniazdowski
  2016-01-26 18:28 ` Bart Schaefer
  0 siblings, 1 reply; 6+ messages in thread
From: Sebastian Gniazdowski @ 2016-01-26  9:20 UTC (permalink / raw)
  To: Zsh hackers list

Hello,
This will bind to current keymap, not to "a":

% bindkey -N a main
% bindkey -s '^[t' 'echo test' -M a

I like zparseopts because of -E option, which allows to mix options
with strings and handles --. Is it expected that one day zsh will do
the same? It's a matter of providing one well written options parsing
function, isn't it.

That said, following zparseopts apparently fails:

% set -- a -b something -- -c
% typeset -A opts
% zparseopts -A opts -DE b: c
% echo "${(kv)opts}"

% # $1, $2, ... $5 are still the same

I once (12 years ago) used zparseopts this way and it worked great.
The call had to be different then.

Best regards,
Sebastian Gniazdowski


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

* Re: Advanced option parsing across zsh commands
  2016-01-26  9:20 Advanced option parsing across zsh commands Sebastian Gniazdowski
@ 2016-01-26 18:28 ` Bart Schaefer
  2016-01-26 18:59   ` Sebastian Gniazdowski
  0 siblings, 1 reply; 6+ messages in thread
From: Bart Schaefer @ 2016-01-26 18:28 UTC (permalink / raw)
  To: Zsh hackers list

On Jan 26, 10:20am, Sebastian Gniazdowski wrote:
} Subject: Advanced option parsing across zsh commands
}
} I like zparseopts because of -E option, which allows to mix options
} with strings and handles --. Is it expected that one day zsh will do
} the same?

No, this is not expected.

} % set -- a -b something -- -c
} % typeset -A opts
} % zparseopts -A opts -DE b: c
} % echo "${(kv)opts}"
} 
} % # $1, $2, ... $5 are still the same

You can't stack the options of zparseopts itself, i.e, you can't use -DE,
you have to use -D -E.

zparseopts also doesn't handle "negated options" in the +X format, only
those introduced with "-".  There's a fairly convoluted issue with making
"+" work for the associative array case because of the way zparseopts
gathers up the arguments of each option before assigning to the array.


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

* Re: Advanced option parsing across zsh commands
  2016-01-26 18:28 ` Bart Schaefer
@ 2016-01-26 18:59   ` Sebastian Gniazdowski
  2016-01-26 19:09     ` Sebastian Gniazdowski
  2016-01-27  6:56     ` Bart Schaefer
  0 siblings, 2 replies; 6+ messages in thread
From: Sebastian Gniazdowski @ 2016-01-26 18:59 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh hackers list

On 26 January 2016 at 19:28, Bart Schaefer <schaefer@brasslantern.com> wrote:
> } % set -- a -b something -- -c
> } % typeset -A opts
> } % zparseopts -A opts -DE b: c
> } % echo "${(kv)opts}"
> }
> } % # $1, $2, ... $5 are still the same
>
> You can't stack the options of zparseopts itself, i.e, you can't use -DE,
> you have to use -D -E.

Thanks, this works

> zparseopts also doesn't handle "negated options" in the +X format, only
> those introduced with "-".  There's a fairly convoluted issue with making
> "+" work for the associative array case because of the way zparseopts
> gathers up the arguments of each option before assigning to the array.

This sounded like if there would a workaround for +X. I tried the
following: define option "+", which takes argument. Then replace "+X"
with "-+X" in the command line. However:

% unset opts
% typeset -A opts
% set -- a -b something -+X -- -c
% zparseopts -A opts -D -E b: c +:
% echo "${(k)opts}"

% echo "${(v)opts}"
b+X

Weird, isn't it? With also a regular array:

% unset opts
% unset optsa
% typeset -A opts
% typeset -a optsa
% set -- a -b something -+X -- -c
% zparseopts -a optsa -A opts -D -E b: c +:
% echo ${(k)opts}

% echo ${(v)opts}
b+X
% echo $optsa
b - +X

With only regular array it's the same

Best regards,
Sebastian Gniazdowski


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

* Re: Advanced option parsing across zsh commands
  2016-01-26 18:59   ` Sebastian Gniazdowski
@ 2016-01-26 19:09     ` Sebastian Gniazdowski
  2016-01-27  7:07       ` Bart Schaefer
  2016-01-27  6:56     ` Bart Schaefer
  1 sibling, 1 reply; 6+ messages in thread
From: Sebastian Gniazdowski @ 2016-01-26 19:09 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh hackers list

Here is how it works if order of option specification is changed:

% unset opts
% unset optsa
% typeset -A opts
% typeset -a optsa
% set -- a -b something -+X -- -c
% zparseopts -a optsa -A opts -D -E +: b: c
% echo "${(k)opts}"
-b -
% echo "${(v)opts}"
something +X
% echo "${opts[-]}"
+X
% echo $optsa
-b something - +X

That's quite a work around, but I wonder what's going on internally?
Tested (the previous runs too) on 5.2

Best regards,
Sebastian Gniazdowski


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

* Re: Advanced option parsing across zsh commands
  2016-01-26 18:59   ` Sebastian Gniazdowski
  2016-01-26 19:09     ` Sebastian Gniazdowski
@ 2016-01-27  6:56     ` Bart Schaefer
  1 sibling, 0 replies; 6+ messages in thread
From: Bart Schaefer @ 2016-01-27  6:56 UTC (permalink / raw)
  To: Zsh hackers list

On Jan 26,  7:59pm, Sebastian Gniazdowski wrote:
} Subject: Re: Advanced option parsing across zsh commands
}
} > zparseopts also doesn't handle "negated options" in the +X format
} 
} This sounded like if there would a workaround for +X. I tried the
} following: define option "+", which takes argument. Then replace "+X"
} with "-+X" in the command line. However:
} 
} % zparseopts -A opts -D -E b: c +:

That does not define an option "+" which takes an argument.  That in
fact defines an option (empty string) which may be repeated multiple
times and takes an argument, because the "+" invokes the NAME+ form
of option description.

There's not a lot of internal consistency checking in zparseopts.  Old
code that has not been reviewed since it was written.

To define an option named "+" instead of an option named "", you are
intended to use:

    zparseopts -A opts -D -E b: c '\+:'

However, because of a bug, you can't actually do that.  The backslash
causes everything after it to shift one character to the left, but
the NUL-terminator is not also shifted, so the above accidentally
defines the option "++" instead of the option "+".

torch% typeset -A opts
torch% set -- a -b something -++X -- -c
torch% zparseopts -A opts -D -E b: c \\+:
torch% print -lr -- $@
a
--
-c
torch% print -r -- ${(kv)opts}
-b something -++ X
torch% 

With the patch below, the very first character of the option spec is
always taken to be part of the option name (unless that first char is
is a backslash, in which case it is shifted off as usual).  So you
no longer need to escape a "+" (though it doesn't hurt to do so):

torch% typeset -A opts
torch% set -- a -b something -+X -- -c
torch% zparseopts -A opts -D -E b: c +:  
torch% print -r -- ${(kv)opts}         
-b something -+ X

And using "++" does the expected thing:

torch% typeset -A opts=()                     
torch% set -- a -b something -+X -+Y -+Z -- -c
torch% zparseopts -A opts -D -E b: c ++:      
torch% print -r -- ${(kv)opts}                
-b something -+ XYZ
torch% 

For pre-5.3 zsh I suggest you use a different character than "+" for
your proposed workaround, e.g.

    set -- a -b something -\*X -\*Y -\*Z -- -c
    zparseopts -A opts -D -E b: c '*+:'

should work.


diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c
index d98028a..12a4c03 100644
--- a/Src/Modules/zutil.c
+++ b/Src/Modules/zutil.c
@@ -1745,13 +1745,15 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
 	for (p = o; *p; p++) {
 	    if (*p == '\\' && p[1])
 		p++;
-	    else if (*p == '+') {
-		f |= ZOF_MULT;
-		*p = '\0';
-		p++;
-		break;
-	    } else if (*p == ':' || *p == '=')
-		break;
+	    else if (p > o) {	/* At least one character of option name */
+		if (*p == '+') {
+		    f |= ZOF_MULT;
+		    *p = '\0';
+		    p++;
+		    break;
+		} else if (*p == ':' || *p == '=')
+		    break;
+	    }
 	}
 	if (*p == ':') {
 	    f |= ZOF_ARG;
@@ -1789,6 +1791,7 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
 		p++;
 	    *n++ = *p;
 	}
+	*n = '\0';
 	if (get_opt_desc(o)) {
 	    zwarnnam(nam, "option defined more than once: %s", o);
 	    return 1;


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

* Re: Advanced option parsing across zsh commands
  2016-01-26 19:09     ` Sebastian Gniazdowski
@ 2016-01-27  7:07       ` Bart Schaefer
  0 siblings, 0 replies; 6+ messages in thread
From: Bart Schaefer @ 2016-01-27  7:07 UTC (permalink / raw)
  To: Zsh hackers list

On Jan 26,  8:09pm, Sebastian Gniazdowski wrote:
}
} Here is how it works if order of option specification is changed:
} 
} % zparseopts -a optsa -A opts -D -E +: b: c

All you've done there is manage to get the empty-string option to
be tested after any of the others (the specs are tested against
$argv in reverse of the order they appear as zparseopts arguments).
It's almost certainly coincidental that this created options that
seem to be named "-" and assigned "+X" as the value; this effect
no longer occurs with my patch from 37810, and is probably not
reliable with any zsh prior to that patch.


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

end of thread, other threads:[~2016-01-27  7:06 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-26  9:20 Advanced option parsing across zsh commands Sebastian Gniazdowski
2016-01-26 18:28 ` Bart Schaefer
2016-01-26 18:59   ` Sebastian Gniazdowski
2016-01-26 19:09     ` Sebastian Gniazdowski
2016-01-27  7:07       ` Bart Schaefer
2016-01-27  6:56     ` Bart Schaefer

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).