summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordana <dana@dana.is>2026-06-29 23:35:41 -0500
committerdana <dana@dana.is>2026-07-03 06:59:40 -0500
commite9d0e6a8ad252c6eaceaca4301bd2b4d44570574 (patch)
treec48e7fe3f912252ad38c4c553f4ab88a15738392
parentunposted: _ping: revert previous _arguments fix (diff)
downloadzsh-e9d0e6a8ad252c6eaceaca4301bd2b4d44570574.tar
zsh-e9d0e6a8ad252c6eaceaca4301bd2b4d44570574.tar.gz
zsh-e9d0e6a8ad252c6eaceaca4301bd2b4d44570574.tar.bz2
zsh-e9d0e6a8ad252c6eaceaca4301bd2b4d44570574.tar.lz
zsh-e9d0e6a8ad252c6eaceaca4301bd2b4d44570574.tar.xz
zsh-e9d0e6a8ad252c6eaceaca4301bd2b4d44570574.tar.zst
zsh-e9d0e6a8ad252c6eaceaca4301bd2b4d44570574.zip
54876: comparguments: search more thoroughly for foreign-set options
-rw-r--r--ChangeLog3
-rw-r--r--Src/Zle/computil.c38
-rw-r--r--Test/Y03arguments.ztst29
3 files changed, 52 insertions, 18 deletions
diff --git a/ChangeLog b/ChangeLog
index 2f9931e30..7fe8c47e3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,8 @@
2026-07-03 dana <dana@dana.is>
+ * 54876: Src/Zle/computil.c, Test/Y03arguments.ztst:
+ comparguments: search more thoroughly for foreign-set options
+
* unposted: Completion/Unix/Command/_ping: revert previous
_arguments fix
diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c
index 75f01521e..3e7755156 100644
--- a/Src/Zle/computil.c
+++ b/Src/Zle/computil.c
@@ -1722,6 +1722,8 @@ get_cadef(char *nam, char **args)
*
* "d" is a complete set of argument/option definitions to scan.
* "line" is the word we are scanning.
+ * "ign_active" indicates that whether an option def is active or not
+ * should be ignored when matching
* "full" indicates that the option must match a full word; otherwise
* we look for "=" arguments or prefixes.
* *"end" is set to point to the end of the option, in some cases
@@ -1729,24 +1731,25 @@ get_cadef(char *nam, char **args)
*/
static Caopt
-ca_get_opt(Cadef d, char *line, int full, char **end)
+ca_get_opt(Cadef d, char *line, int ign_active, int full, char **end)
{
Caopt p;
/* The full string may be an option. */
- for (p = d->opts; p; p = p->next)
- if (p->active && !strcmp(p->name, line)) {
+ for (p = d->opts; p; p = p->next) {
+ if ((ign_active || p->active) && !strcmp(p->name, line)) {
if (end)
*end = line + strlen(line);
return p;
}
+ }
if (!full) {
/* The string from the line probably only begins with an option. */
for (p = d->opts; p; p = p->next)
- if (p->active && ((!p->args || p->type == CAO_NEXT) ?
+ if ((ign_active || p->active) && ((!p->args || p->type == CAO_NEXT) ?
!strcmp(p->name, line) : strpfx(p->name, line))) {
int l = strlen(p->name);
if ((p->type == CAO_OEQUAL || p->type == CAO_EQUAL) &&
@@ -1770,7 +1773,7 @@ ca_get_opt(Cadef d, char *line, int full, char **end)
/* Same as above, only for single-letter-style. */
static Caopt
-ca_get_sopt(Cadef d, char *line, char **end, LinkList *lp)
+ca_get_sopt(Cadef d, char *line, int ign_active, char **end, LinkList *lp)
{
Caopt p, pp = NULL;
char pre = *line++;
@@ -1779,8 +1782,8 @@ ca_get_sopt(Cadef d, char *line, char **end, LinkList *lp)
*lp = NULL;
for (p = NULL; *line; line++) {
- if ((sidx = single_index(pre, *line)) != -1 &&
- (p = d->single[sidx]) && p->active && p->args) {
+ if (d->single && (sidx = single_index(pre, *line)) != -1 &&
+ (p = d->single[sidx]) && (ign_active || p->active) && p->args) {
if (p->type == CAO_NEXT) {
if (!l)
*lp = l = newlinklist();
@@ -1796,7 +1799,7 @@ ca_get_sopt(Cadef d, char *line, char **end, LinkList *lp)
pp = p;
break;
}
- } else if (!p || (p && !p->active))
+ } else if (!p || (p && !(ign_active || p->active)))
return NULL;
pp = (p->name[0] == pre ? p : NULL);
p = NULL;
@@ -1813,16 +1816,15 @@ static int
ca_foreign_opt(Cadef curset, Cadef all, char *option)
{
Cadef d;
- Caopt p;
+ LinkList l;
for (d = all; d; d = d->snext) {
if (d == curset)
continue;
-
- for (p = d->opts; p; p = p->next) {
- if (!strcmp(p->name, option))
- return 1;
- }
+ if (ca_get_opt(d, option, 1, 0, NULL))
+ return 1;
+ if (ca_get_sopt(d, option, 1, NULL, &l))
+ return 1;
}
return 0;
}
@@ -1932,7 +1934,7 @@ ca_inactive(Cadef d, char **xor, int cur, int opts)
if (a && a->num == n && (!grp || (a->gsname &&
!strncmp(a->gsname, grp, grplen))))
a->active = 0;
- } else if ((opt = ca_get_opt(d, x, 1, NULL)) &&
+ } else if ((opt = ca_get_opt(d, x, 0, 1, NULL)) &&
(!grp || (opt->gsname && !strncmp(opt->gsname, grp, grplen))) &&
!(single && *opt->name && opt->name[1] && opt->name[2]))
opt->active = 0;
@@ -2181,7 +2183,7 @@ ca_parse_line(Cadef d, Cadef all, int multi, int first)
/* See if it's an option. */
if (state.opt == 2 && (*line == '-' || *line == '+') &&
- (state.curopt = ca_get_opt(d, line, 0, &pe)) &&
+ (state.curopt = ca_get_opt(d, line, 0, 0, &pe)) &&
(state.curopt->type == CAO_OEQUAL ?
(compwords[cur] || pe[-1] == '=') :
(state.curopt->type == CAO_EQUAL ?
@@ -2230,7 +2232,7 @@ ca_parse_line(Cadef d, Cadef all, int multi, int first)
}
} else if (state.opt == 2 && d->single &&
(*line == '-' || *line == '+') &&
- ((state.curopt = ca_get_sopt(d, line, &pe, &sopts)) ||
+ ((state.curopt = ca_get_sopt(d, line, 0, &pe, &sopts)) ||
(cur != compcurrent && sopts && nonempty(sopts)))) {
/* Or maybe it's a single-letter option? */
@@ -2812,7 +2814,7 @@ bin_comparguments(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
subc = newlinklist();
while (lstate) {
- opt = ca_get_opt(lstate->d, args[1], 1, NULL);
+ opt = ca_get_opt(lstate->d, args[1], 0, 1, NULL);
if (opt && opt->args) {
ret = 0;
diff --git a/Test/Y03arguments.ztst b/Test/Y03arguments.ztst
index b118f2626..14a786709 100644
--- a/Test/Y03arguments.ztst
+++ b/Test/Y03arguments.ztst
@@ -728,6 +728,35 @@ F:should offer both sets of arguments in first case
>NO:{-d}
F:shouldn't offer -t in the first case (with stacked options)
+ tst_arguments -s : - set1 -a -b -c+: --d=: - set2 -e -f
+ comptest $'tst -ab -\t' # stack with known options
+ comptest $'tst -ax -\t' # stack with unknown option
+ comptest $'tst -cx -\t' # short option with same-word optarg
+ comptest $'tst --d=x -\t' # long option with same-word optarg
+0:detection of foreign-set option in stack or with same-word optarg
+>line: {tst -ab -}{}
+>DESCRIPTION:{option}
+>NO:{--d}
+>NO:{-c}
+>line: {tst -ax -}{}
+>DESCRIPTION:{option}
+>NO:{--d}
+>NO:{-a}
+>NO:{-b}
+>NO:{-c}
+>NO:{-e}
+>NO:{-f}
+>line: {tst -cx -}{}
+>DESCRIPTION:{option}
+>NO:{--d}
+>NO:{-a}
+>NO:{-b}
+>line: {tst --d=x -}{}
+>DESCRIPTION:{option}
+>NO:{-a}
+>NO:{-b}
+>NO:{-c}
+
tst_arguments -s '(set-a set--b grp-a grp--b grp-)-a' - set-a -s - set--b -t + grp-a -g + grp--b -h + grp- -i
comptest $'tst -a\t'
0:sets and groups with - in their name