Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

[PATCH] comparguments: search more thoroughly for foreign-set options



when searching for options in other sets we only look at whole words, so
stacked options etc don't match right:

  compdef _foo foo
  _foo() { _arguments -s : - set1 -a -b -c - set2 -d -e -f }
  foo -ab <TAB> # still offers set2

this makes it match more thoroughly

there's a cost to this but i'm not sure how to measure it. i tried
timing `comparguments -i` with a large number of specs, but i didn't see
much of a difference. i'm not sure if that's because the test was bad or
because the poor set performance i've been warned about just isn't an
issue on modern pcs

dana


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




Messages sorted by: Reverse Date, Date, Thread, Author