diff options
-rw-r--r-- | ChangeLog | 39 | ||||
-rw-r--r-- | Completion/Unix/Command/_ruby | 2 | ||||
-rw-r--r-- | Completion/Unix/Command/_ssh | 3 | ||||
-rw-r--r-- | Completion/Unix/Type/_ssh_hosts | 11 | ||||
-rw-r--r-- | Completion/Zsh/Command/_fc | 2 | ||||
-rw-r--r-- | Completion/Zsh/Command/_vared | 2 | ||||
-rw-r--r-- | Doc/Zsh/cond.yo | 6 | ||||
-rw-r--r-- | Doc/Zsh/expn.yo | 13 | ||||
-rw-r--r-- | Doc/Zsh/params.yo | 4 | ||||
-rw-r--r-- | Etc/FAQ.yo | 20 | ||||
-rw-r--r-- | Src/hashtable.c | 8 | ||||
-rw-r--r-- | Src/lex.c | 2 | ||||
-rw-r--r-- | Src/subst.c | 143 | ||||
-rw-r--r-- | Test/D10nofork.ztst | 52 | ||||
-rw-r--r-- | Test/V10private.ztst | 8 |
15 files changed, 232 insertions, 83 deletions
diff --git a/ChangeLog b/ChangeLog index 72e8efbe7..6a753e3f9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,42 @@ +2024-05-10 Peter Stephenson <p.stephenson@samsung.com> + + * 52924: Src/Modules/zftp.c: NULL zfsessions after free. + +2024-05-08 Peter Stephenson <p.stephenson@samsung.com> + + * 52915: Doc/Zsh/cond.yo: be explicit about behaviour of globbing + patterns within conditions. + +2024-04-07 Mikael Magnusson <mikachu@gmail.com> + + * 52878: Src/subst.c: Fix ${foo:^bar} where bar is an associative + array + +2024-04-01 Bart Schaefer <schaefer@zsh.org> + + * 52865: Doc/Zsh/expn.yo, Doc/Zsh/params.yo, Etc/FAQ.yo: + Documentation update for 52864 + + * 52864: Src/lex.c, Src/subst.c, Test/D10nofork.ztst, + Test/V10private.ztst: Change ${|var|...} to ${{var} ...}, + limit local REPLY behavior to ${|...}, update tests. + + * 52781 (and typo fix): Src/hashtable.c: HIST IGNORE_DUPS treats + whitespace as significant when HIST_REDUCE_BLANKS is also set. + +2024-04-01 Oliver Kiddle <opk@zsh.org> + + * github #115: OKURA Masafumi: Completion/Unix/Command/_ruby: + IRB now has `--regexp-completor` and `--type-completor` options + + * 52859: Completion/Zsh/Command/_fc, Completion/Zsh/Command/_vared: + use _date_formats for fc and complete -m/-M for vared + +2024-03-25 Oliver Kiddle <opk@zsh.org> + + * 52798: Completion/Unix/Command/_ssh, + Completion/Unix/Type/_ssh_hosts: handle comments in ssh config + 2024-03-23 Mikael Magnusson <mikachu@gmail.com> * 52768: Completion/compdump, Completion/compinit: Handle diff --git a/Completion/Unix/Command/_ruby b/Completion/Unix/Command/_ruby index b6b42637d..9955253b3 100644 --- a/Completion/Unix/Command/_ruby +++ b/Completion/Unix/Command/_ruby @@ -89,6 +89,8 @@ irb=( "(--colorize)--nocolorize[don't use color-highlighting]" '(--noautocomplete)--autocomplete[use auto-completion]' "(--autocomplete)--noautocomplete[don't use auto-completion]" + '(--regexp-completor)--type-completor[use regexp based completion]' + '(--type-completor)--regexp-completor[use type based completion]' '(--noscript)--script[script mode]' '(--script)--noscript[no script mode]' '--single-irb[share self with sub-irb]' diff --git a/Completion/Unix/Command/_ssh b/Completion/Unix/Command/_ssh index dc3979a58..5e6e60573 100644 --- a/Completion/Unix/Command/_ssh +++ b/Completion/Unix/Command/_ssh @@ -101,6 +101,7 @@ _ssh () { '--apple-use-keychain[update keychain when adding/removing identities]' ) _arguments -C -s : $args \ + '-C[process certificates only]' \ '-c[identity is subject to confirmation via SSH_ASKPASS]' \ '-D[delete all identities]' \ '-d[remove identity]' \ @@ -214,7 +215,7 @@ _ssh () { "(${${(@)cmds:#-p}} -v ${${(@)cms:#-[qt]}})-N+[provide new passphrase]:new passphrase" \ "(${${(@)cmds:#-c}} -v $cms)-C+[provide new comment]:new comment" \ "(-D -I -h -n -V -A)-f+[$file file]:$file file:_files" \ - "$p1(${${(@)cmds:#-[FE]}} ${${(@)cmn:#-v}} ${${(@)cms:#-E}})-l[show fingerprint of key file]" \ + "(${${(@)cmds:#-[FE]}} ${${(@)cmn:#-v}} ${${(@)cms:#-E}})-l[show fingerprint of key file]" \ "$p1(${${(@)cmds:#-[iep]}} $cms)-m+[specify conversion format]:format [RFC4716]:(PEM PKCS8 RFC4716)" \ "$p1*-O+[specify a key/value option]: : _values 'option' $options" \ "(${${(@)cmds:#-[lGT]}} ${${(@)cmn:#-[bv]}} -f)*-v[verbose mode]" \ diff --git a/Completion/Unix/Type/_ssh_hosts b/Completion/Unix/Type/_ssh_hosts index a4a08ad91..b50e1c16a 100644 --- a/Completion/Unix/Type/_ssh_hosts +++ b/Completion/Unix/Type/_ssh_hosts @@ -24,7 +24,7 @@ if [[ -r $config ]]; then while (( idx <= $#lines )); do IFS=$'=\t ' read -r key line <<<"${lines[idx]}" if [[ "$key" == ((#i)match) ]]; then - match_args=(${(z)line}) + match_args=( ${(Z.C.)line} ) while [[ $#match_args -ge 2 ]]; do if [[ "${match_args[1]}" == (#i)(canonical|final|(|original)host) ]]; then key="Host" @@ -36,13 +36,10 @@ if [[ -r $config ]]; then fi case "$key" in ((#i)include) - lines[idx]=("${(@f)$(cd $HOME/.ssh; cat ${(z)~line})}") 2>/dev/null;; + lines[idx]=( "${(@f)$(cd $HOME/.ssh; cat ${(Z.C.)~line} 2>/dev/null)}" ) ;; ((#i)host(|name)) - for host in ${(z)line}; do - case $host in - (*[*?]*) ;; - (*) config_hosts+=("$host") ;; - esac + for host in ${(Z.C.)line}; do + [[ $host != *[*?%]* ]] && config_hosts+=( $host ) done ;& (*) (( ++idx ));; esac diff --git a/Completion/Zsh/Command/_fc b/Completion/Zsh/Command/_fc index 80e570c5d..626d35956 100644 --- a/Completion/Zsh/Command/_fc +++ b/Completion/Zsh/Command/_fc @@ -40,7 +40,7 @@ fc_hist=( '(-A -R -W -e -d -E -i -t -a -p -P)-f[mm/dd/yyyy format time-stamps]' '(-A -R -W -e -d -f -i -t -a -p -P)-E[dd.mm.yyyy format time-stamps]' '(-A -R -W -e -d -f -E -t -a -p -P)-i[yyyy-mm-dd format time-stamps]' - '(-A -R -W -e -d -f -E -i -a -p -P)-t[print time-stamps in specified format]:date format' + '(-A -R -W -e -d -f -E -i -a -p -P)-t[print time-stamps in specified format]: : _date_formats zsh' '(-A -R -W -e -a -p -P)-D[print elapsed times]' '(-A -R -W -I -e -d -f -i -l -m -n -r -D -E -t -P)-a[with -p, automatically pop history on function return]' diff --git a/Completion/Zsh/Command/_vared b/Completion/Zsh/Command/_vared index aba64880a..e7072ca6d 100644 --- a/Completion/Zsh/Command/_vared +++ b/Completion/Zsh/Command/_vared @@ -10,5 +10,7 @@ _arguments -s -A "-*" \ '-f+[specify finish widget]:widget:_widgets' \ '-h[allow access to history]' \ '-e[exit on EOF (^D)]' \ + '-M+[specify keymap to link to main]:keymap:compadd -a keymaps' \ + '-m+[specify keymap to link to vicmd]:keymap:compadd -a keymaps' \ '1:parameter spec:_vars' diff --git a/Doc/Zsh/cond.yo b/Doc/Zsh/cond.yo index 000e576d0..db92cc766 100644 --- a/Doc/Zsh/cond.yo +++ b/Doc/Zsh/cond.yo @@ -241,7 +241,11 @@ ifnzman(\ noderef(Filename Generation)\ )\ , but there is no special behaviour -of `tt(/)' nor initial dots, and no glob qualifiers are allowed. +of `tt(/)' nor initial dot, and the patterns `tt(**/)' and `tt(***/)' behave +the same as `tt(*/)', in which the `tt(*)' has its standard behaviour +but may also match further `tt(/)' characters. Also, no bare glob +qualifiers are allowed, though the form `((#q)var(...))' is allowed as +shown above. In each of the above expressions, if var(file) is of the form `tt(/dev/fd/)var(n)', diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo index 0e121e784..7eade4a11 100644 --- a/Doc/Zsh/expn.yo +++ b/Doc/Zsh/expn.yo @@ -1937,13 +1937,14 @@ split on tt(IFS) unless the tt(SH_WORD_SPLIT) option is set. cindex(substitution, command, current shell) cindex(substitution, command, non forking) cindex(substitution, nofork) -Substitutions of the form `tt(${|)var(param)tt(|)...tt(})' are similar, +Substitutions of the form `tt(${{)var(param)tt(}) ...tt(})' are similar, except that the substitution is replaced by the value of the parameter named by var(param). No implicit save or restore applies to var(param) -except as noted for tt(REPLY), and var(param) should em(not) be declared -within the command. If, after evaluating the expression, var(param) -names an array, array expansion rules apply. However, tt(REPLY) is -always expanded in scalar context, even if assigned an array. +and var(param) should em(not) be declared within the command. No space +is allowed within `tt(${{)' and space or newline is required after +`tt({)var(param)tt(})'. The var(param) may include a subscript, and if, +after evaluating the expression, var(param) names an array, then array +expansion rules apply to the final substitution. A command enclosed in braces preceded by a dollar sign, and set off from the braces by whitespace, like `tt(${ )...tt( })', is replaced by its @@ -1954,7 +1955,7 @@ Word splitting does not apply unless tt(SH_WORD_SPLIT) is set, but a single trailing newline is stripped unless the substitution is enclosed in double quotes. -Note that because the `tt(${|)...tt(})' and `tt(${ )...tt( })' forms +Note that because `tt(${|)...tt(})' and the two related substitutions must be parsed at once as both string tokens and commands, all other braces (`tt({)' or `tt(})') within the command either must be quoted, or must appear in syntactically valid pairs, such as around complex diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo index 9516c84de..02ce796a9 100644 --- a/Doc/Zsh/params.yo +++ b/Doc/Zsh/params.yo @@ -1032,8 +1032,8 @@ the shell. ) item(tt(cmdsubst))( Command substitution using of the tt(`)var(...)tt(`), -tt($+LPAR())var(...)tt(RPAR()), tt(${ )var(...)tt( }) or -tt(${|)var(...)tt(}) constructs. +tt($+LPAR())var(...)tt(RPAR()),tt(${{)var(name)tt(}) var(...)tt(}), +tt(${|)var(...)tt(}), or tt(${ )var(...)tt( }) constructs. ) item(tt(equalsubst))( The tt(=+LPAR())var(...)tt(RPAR()) form of process substitution. diff --git a/Etc/FAQ.yo b/Etc/FAQ.yo index 4d71c8f30..4e11637ea 100644 --- a/Etc/FAQ.yo +++ b/Etc/FAQ.yo @@ -1047,15 +1047,18 @@ label(211) ) Runs code in the current shell context and then substitutes mytt(${REPLY}). The result is not split into words unless the tt(SH_WORD_SPLIT) option - is set, for example by mytt(${=${| code }}). + is set, for example by mytt(${=${| code }}). mytt($REPLY) is a local + parameter within the substitution so its value in the surrounding scope + is not changed. eit() An extension to #1 verb( - ${|var| code } + ${{var} code } ) Runs code in the current shell and then substitutes mytt(${var}). If mytt(${var}) names an array, the result is an array of those elements, - but no further splitting is done without tt(SH_WORD_SPLIT). + but no further splitting is done without tt(SH_WORD_SPLIT). mytt(${var}) + is myem(not) local to the substitution. eit() The traditional ksh form, except that the closing mytt(;) may usually be omitted: @@ -1071,12 +1074,11 @@ label(211) In all three forms mytt(code) behaves myem(similarly) to an anonymous function invoked like: verb( - () { local REPLY; code } "$@" + () { code } "$@" ) - Thus, mytt($REPLY) is implicitly local and returns to its previous - value after the substitution ends, all other parameters declared from - inside the substitution are also local by default, and positional - parameters mytt($1), mytt($2), etc. are those of the calling context. + Thus, all parameters declared inside the substitution are local by + default, and positional parameters mytt($1), mytt($2), etc. are those + of the calling context. The most significant limitation is that braces (mytt({) and mytt(})) within the substitutions must either be in balanced pairs, or must be @@ -1096,7 +1098,7 @@ sect(Comparisons of forking and non-forking command substitution) bash and ksh, unquoted non-forking substitutions behave like parameter expansions with respect to the tt(SH_WORD_SPLIT) option. - Both of the mytt(${|...}) formats retain any trailing newlines, + Both mytt(${|...}) and mytt(${{var} ...}) retain any trailing newlines, except as handled by the tt(SH_WORD_SPLIT) option, consistent with mytt(${|...}) from mksh. mytt(${ command }) removes a single final newline, but mytt("${ command }") retains it. This differs from diff --git a/Src/hashtable.c b/Src/hashtable.c index 75b06c4ad..96675a393 100644 --- a/Src/hashtable.c +++ b/Src/hashtable.c @@ -1397,6 +1397,14 @@ histstrcmp(const char *str1, const char *str2) { while (inblank(*str1)) str1++; while (inblank(*str2)) str2++; + + /* If insignificant whitespace has already been eliminated, + * there is no reason to expend similar effort here. Also, + * this is more accurate in cases of quoted whitespace. + */ + if (isset(HISTREDUCEBLANKS)) + return strcmp(str1, str2); + while (*str1 && *str2) { if (inblank(*str1)) { if (!inblank(*str2)) diff --git a/Src/lex.c b/Src/lex.c index 31b130b07..700af2da1 100644 --- a/Src/lex.c +++ b/Src/lex.c @@ -1423,7 +1423,7 @@ gettokstr(int c, int sub) if (lexstop) break; if (!cmdsubst && in_brace_param && act == LX2_STRING && - (c == '|' || c == Bar || inblank(c))) { + (c == '|' || c == Bar || c == '{' || c == Inbrace || inblank(c))) { cmdsubst = in_brace_param; cmdpush(CS_CURSH); } else if (in_pattern == 2 && c != '/') diff --git a/Src/subst.c b/Src/subst.c index 9d20a2d0e..a079672df 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -1866,10 +1866,11 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, * joining the array into a string (for compatibility with ksh/bash). */ int quoted_array_with_offset = 0; - /* Indicates ${|...;} */ - char *rplyvar = NULL; - /* Indicates ${ ... ;} */ - char *rplytmp = NULL; + /* + * Nofork substitution controls + */ + char *rplyvar = NULL; /* Indicates ${|...;} or ${{var} ...;} */ + char *rplytmp = NULL; /* Indicates ${ ... ;} */ *s++ = '\0'; /* @@ -1897,14 +1898,16 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, * flags in parentheses, but also one ksh hack. */ if (c == Inbrace) { - /* The command string to be run by ${|...;} */ - char *cmdarg = NULL; + /* For processing nofork command substitution string */ + char *cmdarg = NULL, *endvar = NULL, inchar = *++s; + char *outbracep = s, sav = *s; + Param rplypm = NULL; size_t slen = 0; int trim = (!EMULATION(EMULATE_ZSH)) ? 2 : !qt; - inbrace = 1; - s++; - /* Short-path for the nofork command substitution ${|cmd;} + inbrace = 1; /* Outer scope boolean, see above */ + + /* Handling for nofork command substitution e.g. ${|cmd;} * See other comments about kludges for why this is here. * * The command string is extracted and executed, and the @@ -1913,48 +1916,77 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, * should not be part of command substitution in any case. * Use ${(U)${|cmd;}} as you would for ${(U)$(cmd;)}. */ - if (*s == '|' || *s == Bar || inblank(*s)) { - char *outbracep = s; - char sav = *s; + if (inchar == '|' || inchar == Bar || inblank(inchar)) { *s = Inbrace; - if (skipparens(Inbrace, Outbrace, &outbracep) == 0) { + if (skipparens(Inbrace, Outbrace, &outbracep) == 0) slen = outbracep - s - 1; - if ((*s = sav) != Bar) { - sav = *outbracep; - *outbracep = '\0'; - tokenize(s); - *outbracep = sav; + *s = sav; + if (inchar == '|') + inchar = Bar; /* Simplify later compares */ + } else if (inchar == '{' || inchar == Inbrace) { + *s = Inbrace; + if ((outbracep = itype_end(s+1, INAMESPC, 0))) { + if (*outbracep == Inbrack && + (outbracep = parse_subscript(++outbracep, 1, ']'))) + ++outbracep; + } + + /* If we reached the first close brace, find the last */ + if (outbracep && *outbracep == Outbrace) { + char outchar = inchar == Inbrace ? Outbrace : '}'; + endvar = outbracep++; + + /* Require space to avoid ${{var}} typo for ${${var}} */ + if (!inblank(*outbracep)) { + zerr("bad substitution"); + return NULL; } + + *endvar = '|'; /* Almost anything but braces/brackets */ + outbracep = s; + if (skipparens(Inbrace, outchar, &outbracep) == 0) + *endvar = Outbrace; + else { /* Never happens? */ + *endvar = outchar; + outbracep = endvar + 1; + } + slen = outbracep - s - 1; + if (inchar != Inbrace) + outbracep[-1] = Outbrace; + *s = sav; + inchar = Inbrace; /* Simplify later compares */ + } else { + zerr("bad substitution"); + return NULL; } } if (slen > 1) { char *outbracep = s + slen; + if (!itok(*s) || inblank(inchar)) { + /* This tokenize() is important */ + char sav = *outbracep; + *outbracep = '\0'; + tokenize(s); + *outbracep = sav; + } if (*outbracep == Outbrace) { - if ((rplyvar = itype_end(s+1, INAMESPC, 0))) { - if (*rplyvar == Inbrack && - (rplyvar = parse_subscript(++rplyvar, 1, ']'))) - ++rplyvar; - } - if (rplyvar == s+1 && *rplyvar == Bar) { - /* Is ${||...} a subtitution error or a syntax error? - zerr("bad substitution"); - return NULL; - */ + if (endvar == s+1) { + /* For consistency with ${} we allow ${{}...} */ rplyvar = NULL; } - if (rplyvar && *rplyvar == Bar) { - cmdarg = dupstrpfx(rplyvar+1, outbracep-rplyvar-1); - rplyvar = dupstrpfx(s+1,rplyvar-s-1); + if (endvar && *endvar == Outbrace) { + cmdarg = dupstrpfx(endvar+1, outbracep-endvar-1); + rplyvar = dupstrpfx(s+1,endvar-s-1); } else { cmdarg = dupstrpfx(s+1, outbracep-s-1); rplyvar = "REPLY"; } - if (inblank(*s)) { + if (inblank(inchar)) { /* - * Admittedly a hack. Take advantage of the enforced - * locality of REPLY and the semantics of $(<file) to + * Admittedly a hack. Take advantage of the added + * parameter scope and the semantics of $(<file) to * construct a command to write/read a temporary file. - * Then fall through to the regular handling of $REPLY + * Then fall through to the regular parameter handling * to manage word splitting, expansion flags, etc. */ char *outfmt = ">| %s {\n%s\n;}"; /* 13 */ @@ -1977,22 +2009,39 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, } if (rplyvar) { - Param pm; - /* char *rplyval = getsparam("REPLY"); */ + /* char *rplyval = getsparam("REPLY"); cf. Future? below */ startparamscope(); /* "local" behaves as if in a function */ - pm = createparam("REPLY", PM_LOCAL|PM_UNSET); - if (pm) /* Shouldn't createparam() do this? */ - pm->level = locallevel; - /* if (rplyval) setsparam("REPLY", ztrdup(rplyval)); */ + if (inchar == Bar) { + /* rplyvar should be REPLY at this point, but create + * hardwired name anyway to expose any bugs elsewhere + */ + rplypm = createparam("REPLY", PM_LOCAL|PM_UNSET|PM_HIDE); + if (rplypm) /* Shouldn't createparam() do this? */ + rplypm->level = locallevel; + /* Future? Expose global value of $REPLY if any? */ + /* if (rplyval) setsparam("REPLY", ztrdup(rplyval)); */ + } else if (inblank(inchar)) { + rplypm = createparam(".zsh.cmdsubst", + PM_LOCAL|PM_UNSET|PM_HIDE| + PM_READONLY_SPECIAL); + if (rplypm) + rplypm->level = locallevel; + } + if (inchar != Inbrace && !rplypm) { + zerr("failed to create scope for command substitution"); + return NULL; + } } if (rplyvar && cmdarg && *cmdarg) { int obreaks = breaks; Eprog cmdprog; /* Execute the shell command */ + queue_signals(); untokenize(cmdarg); cmdprog = parse_string(cmdarg, 0); if (cmdprog) { + /* exec.c handles dont_queue_signals() */ execode(cmdprog, 1, 0, "cmdsubst"); cmdoutval = lastval; /* "return" behaves as if in a function */ @@ -2002,6 +2051,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, } } else /* parse error */ errflag |= ERRFLAG_ERROR; + if (rplypm) + rplypm->node.flags &= ~PM_READONLY_SPECIAL; if (rplytmp && !errflag) { int onoerrs = noerrs, rplylen; noerrs = 2; @@ -2017,15 +2068,16 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, } noerrs = onoerrs; if (rplylen >= 0) - setsparam("REPLY", metafy(cmdarg, rplylen, META_REALLOC)); + setsparam(rplyvar, metafy(cmdarg, rplylen, META_REALLOC)); } + unqueue_signals(); } if (rplytmp) unlink(rplytmp); if (rplyvar) { - if (strcmp(rplyvar, "REPLY") == 0) { - if ((val = dupstring(getsparam("REPLY")))) + if (inchar != Inbrace) { + if ((val = dupstring(getsparam(rplyvar)))) vunset = 0; else { vunset = 1; @@ -3423,6 +3475,9 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, char *sval; zip = getaparam(s); if (!zip) { + zip = gethparam(s); + } + if (!zip) { sval = getsparam(s); if (sval) zip = hmkarray(sval); diff --git a/Test/D10nofork.ztst b/Test/D10nofork.ztst index fc6b84613..5bb10266f 100644 --- a/Test/D10nofork.ztst +++ b/Test/D10nofork.ztst @@ -14,6 +14,28 @@ 0:Basic substitution and REPLY scoping >INNER OUTER + reply=(x OUTER x) + purl ${{reply} reply=(\{ INNER \})} $reply +0:Basic substitution, brace quoting, and array result +>{ +>INNER +>} +>{ +>INNER +>} + + () { + setopt localoptions ignorebraces + purl ${{reply} reply=({ INNER })} $reply + } +0:Basic substitution, ignorebraces, and array result +>{ +>INNER +>} +>{ +>INNER +>} + purr ${| REPLY=first}:${| REPLY=second}:$REPLY 0:re-scoping of REPLY in one statement >first:second:OUTER @@ -229,7 +251,7 @@ F:Why not use this error in the previous case as well? >26 unset reply - purl ${|reply| reply=(1 2 ${| REPLY=3 } 4) } + purl ${{reply} reply=(1 2 ${| REPLY=3 } 4) } typeset -p reply 0:array behavior with global assignment >1 @@ -315,7 +337,7 @@ F:status of "print" should hide return unset zz outer=GLOBAL - purr "${|zz| + purr "${{zz} local outer=LOCAL zz=NONLOCAL } $outer $?" @@ -440,7 +462,8 @@ F:must do this before evaluating the next test block 0:ignored braces, part 1 >buried} - purr "${ purr ${REPLY:-buried}}}" + # Global $REPLY still set from earlier test + purr "${ purr ${REPLY:+buried}}}" 0:ignored braces, part 2 >buried >} @@ -453,6 +476,7 @@ F:must do this before evaluating the next test block 1:ignored braces, part 4 ?(eval):3: parse error near `}' + unsetopt ignorebraces # "break" blocks function calls in outer loop # Could use print, but that might get fixed repeat 3 do purr ${ @@ -467,11 +491,25 @@ F:must do this before evaluating the next test block ?1 ?2 - print -u $ZTST_fd ${ZTST_testname}: TEST COMPLETE -0:make sure we got to the end -F:some tests might silently break the test harness + # Cannot "purr": break skips pending function calls + # Use "repeat" to avoid infinite loop on failure + repeat 3 do; echo ${|REPLY=x; break }; done + repeat 3 do; echo ${{x} x=y; break }; done + repeat 3 do; echo ${ echo z; break }; done +0:break after assignment completes the assignment +>x +>y +>z + + # Subshell because error exits + ( purr ${ echo ${unset?oops} } ) +1:error handling (without crashing) +*?*unset: oops + + purr ${ .zsh.cmdsubst=error } +1:reserved parameter name (without crashing) +*?*.zsh.cmdsubst: can't modify read-only parameter %clean unfunction purr purl - unsetopt ignorebraces diff --git a/Test/V10private.ztst b/Test/V10private.ztst index ed51316f3..26004a2dc 100644 --- a/Test/V10private.ztst +++ b/Test/V10private.ztst @@ -497,7 +497,7 @@ F:Better if caught in checkclobberparam() but exec.c doesn't know scope () { private z=outer print ${(t)z} $z - print ${| REPLY=${|z| z=nofork} } + print ${| REPLY=${{z} z=nofork} } print ${(t)z} $z } 0:nofork may write to private in calling function @@ -518,9 +518,9 @@ F:Better if caught in checkclobberparam() but exec.c doesn't know scope () { private z=outer print ${(t)z} $z - print ${|z| + print ${{z} private q - z=${|q| q=nofork} + z=${{q} q=nofork} } print ${(t)z} $z } @@ -533,7 +533,7 @@ F:Better if caught in checkclobberparam() but exec.c doesn't know scope print ${| () { REPLY="{$q}" } } - print ${|q| + print ${{q} () { q=nofork } } } |