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

_arguments



Some changes that had been discussed:

- A way to specify in the auto-long-options specifications that it
  should use `=-', i.e. that the strings should only be completed
  directly after the `='. I couldn't find a better way than to use the 
  syntax `pat(-):descr:action'.
  I have not changed any of the functions that use auto-long-options
  and has optional arguments. Should this be the default for optional
  arguments? At least they are automatically detected?

- I've merged _argument_sets and _arguments, i.e. one can now use
  _arguments with multiple sets, with the same argument-syntax as was
  used for _argument_sets. This allowed to clean up _arguments and
  most of the new code is in C, so it should be faster. It shouldn't
  have problems with `->state' actions anymore either.


Then there is a change in _arguments for what Chmouel Boudjnah wrote:

> Maybe i missed something but _arguments don't do his job, thing like :
> 
> rpm -ba --[tab]
> 
> should complete something like :
> 
> ...
> 
> but zsh do nothing (like didn't see any --). Testing with last cvs
> version and a minmal .zshrc to load compinit.

this was caused by the change that options weren't tried when normal
arguments had beed tried. Damn. For now I've only slightly changed the 
test that leaves the loop when normal arguments have been tried, but
maybe someone sees a better way to decide when options should (not) be 
completed.


Bye
 Sven

Index: Completion/Base/_arguments
===================================================================
RCS file: /cvsroot/zsh/zsh/Completion/Base/_arguments,v
retrieving revision 1.19
diff -u -r1.19 _arguments
--- Completion/Base/_arguments	2000/05/19 08:26:34	1.19
+++ Completion/Base/_arguments	2000/05/22 09:13:57
@@ -4,7 +4,7 @@
 # descriptions given as arguments to this function.
 
 local long cmd="$words[1]" descr mesg subopts opt usecc autod
-local oldcontext="$curcontext" hasopts multi ismulti
+local oldcontext="$curcontext" hasopts
 
 long=$argv[(I)--]
 if (( long )); then
@@ -23,7 +23,7 @@
   name="${name//[^a-zA-Z0-9_]/_}"
 
   if (( ! ${(P)+name} )); then
-    local iopts sopts pattern tmpo cur cache
+    local iopts sopts pattern tmpo dir cur cache
     typeset -U lopts
 
     cache=()
@@ -98,6 +98,12 @@
 
       pattern="${${${(M)1#*[^\\]:}[1,-2]}//\\\\:/:}"
       descr="${1#${pattern}}"
+      if [[ "$pattern" = *\(-\) ]]; then
+        pattern="$pattern[1,-4]"
+	dir=-
+      else
+        dir=
+      fi
       shift
 
       # We get all options matching the pattern and take them from the
@@ -111,7 +117,7 @@
 
       opt=''
 
-      # If there are option strings with a `[=', we take these get an
+      # If there are option strings with a `[=', we take these to get an
       # optional argument.
 
       tmpo=("${(@M)tmp:#*\[\=*}")
@@ -120,9 +126,9 @@
         tmpo=("${(@)${(@)tmpo%%\=*}//[^a-z0-9-]}")
 
         if [[ "$descr" = ::* ]]; then
-	  cache=( "$cache[@]" "${(@)^tmpo}=${descr}" )
+	  cache=( "$cache[@]" "${(@)^tmpo}=${dir}${descr}" )
         else
-	  cache=( "$cache[@]" "${(@)^tmpo}=:${descr}" )
+	  cache=( "$cache[@]" "${(@)^tmpo}=${dir}:${descr}" )
         fi
       fi
 
@@ -133,10 +139,10 @@
         tmp=("${(@)tmp:#*\=*}")
         tmpo=("${(@)${(@)tmpo%%\=*}//[^a-z0-9-]}")
 
-	cache=( "$cache[@]" "${(@)^tmpo}=${descr}" )
+	cache=( "$cache[@]" "${(@)^tmpo}=${dir}${descr}" )
       fi
 
-      # Everything else is just added as a option without arguments.
+      # Everything else is just added as an option without arguments.
 
       if (( $#tmp )); then
         tmp=("${(@)tmp//[^a-zA-Z0-9-]}")
@@ -148,27 +154,22 @@
   set -- "$tmpargv[@]" "${(@P)name}"
 fi
 
-multi=(-i)
 subopts=()
 while [[ "$1" = -(O*|C|m*) ]]; do
   case "$1" in
   -C) usecc=yes; shift ;;
   -O) subopts=( "${(@P)2}" ); shift 2 ;;
   -O*)  subopts=( "${(@P)1[3,-1]}" ); shift ;;
-  -m) ismulti=yes multi=(-I "$2" "$3"); shift 3 ;;
-  -m*) ismulti=yes multi=(-I "${1[3,-1]}" "$2"); shift 2 ;;
   esac
 done
 
 zstyle -s ":completion:${curcontext}:options" auto-description autod
 
-if (( $# )) && comparguments "$multi[@]" "$autod" "$@"; then
+if (( $# )) && comparguments -i "$autod" "$@"; then
   local action noargs aret expl local tried
   local next direct odirect equal single matcher matched ws tmp1 tmp2 tmp3
   local opts subc tc prefix suffix descrs actions subcs
-  local origpre="$PREFIX" origipre="$IPREFIX"
-
-  [[ -z "$ismulti" ]] && local nm="$compstate[nmatches]"
+  local origpre="$PREFIX" origipre="$IPREFIX" nm="$compstate[nmatches]"
 
   if comparguments -D descrs actions subcs; then
     if comparguments -O next direct odirect equal; then
@@ -180,7 +181,6 @@
   else
     if comparguments -a; then
       noargs='no more arguments'
-      had_args=yes
     else
       noargs='no arguments'
     fi
@@ -299,8 +299,7 @@
       done
 
       if [[ -z "$matched$hasopts" ]] && _requested options &&
-          { [[ -n "$ismulti" ]] ||
-            ! zstyle -T ":completion:${curcontext}:options" prefix-needed ||
+          { ! zstyle -T ":completion:${curcontext}:options" prefix-needed ||
             [[ "$origpre" = [-+]* || -z "$aret$mesg$tried" ]] } ; then
 	local prevpre="$PREFIX" previpre="$IPREFIX"
 
@@ -326,37 +325,22 @@
 	    tmp1=( "${(M@)tmp1:#[-+]?(|:*)}" )
 	    tmp2=( "${PREFIX}${(@M)^${(@)${(@)tmp1%%:*}#[-+]}:#?}" )
 
-	    if [[ -n "$ismulti" ]]; then
-	      _ms_opt=yes
-	      _ms_soptmid=( "$_ms_soptmid[@]" "$tmp1[@]" )
-	      _ms_soptmidadd=( "$_ms_soptmidadd[@]" "$tmp2[@]" )
-	      _ms_soptend=( "$_ms_soptend[@]" "$tmp3[@]" )
-	    else
-              _describe -o option \
-                        tmp1 tmp2 -Q -S '' -- \
-		        tmp3 -Q
-            fi
+            _describe -o option \
+                      tmp1 tmp2 -Q -S '' -- \
+		      tmp3 -Q
           fi
           single=yes
         else
           next=( "$next[@]" "$odirect[@]" )
-	  if [[ -n "$ismulti" ]]; then
-	    _ms_opt=yes
-	    _ms_match="$_ms_match $matcher"
-	    _ms_optnext=( "$_ms_optnext[@]" "$next[@]" )
-	    _ms_optdirect=( "$_ms_optdirect[@]" "$direct[@]" )
-	    _ms_optequal=( "$_ms_optequal[@]" "$equal[@]" )
-	  else
-            _describe -o option \
-                      next -Q -M "$matcher" -- \
-                      direct -QS '' -M "$matcher" -- \
-                      equal -QqS= -M "$matcher"
-          fi
+          _describe -o option \
+                    next -Q -M "$matcher" -- \
+                    direct -QS '' -M "$matcher" -- \
+                    equal -QqS= -M "$matcher"
         fi
 	PREFIX="$prevpre"
 	IPREFIX="$previpre"
       fi
-      [[ -n "$tried" ]] && break
+      [[ -n "$tried" && "$PREFIX" != [-+]* ]] && break
     done
     if [[ -n "$opts" && -z "$aret$matched$mesg" &&
           nm -eq compstate[nmatches] ]]; then
@@ -391,11 +375,7 @@
 
   [[ -n "$aret" ]] && return 300
 
-  if [[ -n "$noargs" ]]; then
-    [[ -z "$ismulti" && nm -eq "$compstate[nmatches]" ]] && _message "$noargs"
-  else
-    has_args=yes
-  fi
+  [[ -n "$noargs" && nm -eq "$compstate[nmatches]" ]] && _message "$noargs"
 
   # Set the return value.
 
Index: Doc/Zsh/compsys.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/compsys.yo,v
retrieving revision 1.52
diff -u -r1.52 compsys.yo
--- Doc/Zsh/compsys.yo	2000/05/20 18:21:22	1.52
+++ Doc/Zsh/compsys.yo	2000/05/22 09:13:59
@@ -2756,6 +2756,45 @@
 the tt(curcontext) parameter will be changed by appending the same
 string that is stored in the tt(context) parameter.
 
+The aruments also allows to specify multiple sets of options and
+arguments separated by single hyphens. The specifications before
+the first hyphen are shared by all sets given after the first
+hyphen. The first word in every other set gives the name of the
+set. This name may appear in exclusion lists in the specifications,
+either alone or before one of the possible values described above
+(with a `tt(-)' between the name and the rest).
+
+For example:
+
+example(_argument_sets \ 
+    -a \ 
+  - set1 \ 
+    -c \ 
+  - set2 \ 
+    -d \ 
+    ':arg:(x2 y2)')
+
+This defines two sets. When the command line contains the option
+`tt(-c)', the `tt(-d)' option and the argument will not be considered
+possible completions. When it contains `tt(-d)' or an argument, the
+option `tt(-c)' will not be completed any more, but if `tt(-a)' is
+given, both sets will still be considered valid, because it appears
+before the first hyphen, so both sets contain this option.
+
+If the name-string is of the form `tt(LPAR())var(name)tt(RPAR())' then 
+all specifications in the set have an implicit exclusion list
+containing the name of the set, i.e. all specifications are mutual
+exclusive with all other specifications in the same set. This is
+useful for defining multiple sets of options which are mutually
+exclusive and in which the options are aliases for each other. E.g.:
+
+example(_argument_sets \ 
+    -a -b \ 
+  - '(compress)' \ 
+    {-c,--compress}'[compress]' \ 
+  - '(uncompress)' \ 
+    {-d,--decompress}'[decompress]')
+
 Normally the option names are taken as multi-character names and a
 word from the line is considered to contain only one option (or
 none). By giving the tt(-s) option to this function (before the first
@@ -2834,6 +2873,11 @@
 detect this, the colon before the var(message) can be doubled to tell
 it about this as described for the normal option descriptions above.
 
+If the var(pattern) ends in `tt((-))', this will removed from the
+pattern and the var(action) will be used only directly after the
+`tt(=)', not in the next word. I.e., this is like a normal
+specification as descrobed above using `tt(=-)'.
+
 The option `tt(-i) var(patterns)' (which must be given after the
 `tt(-)tt(-)') can be used to give patterns for options which should not be
 completed. The patterns can be given as the name of an array parameter
@@ -2874,55 +2918,6 @@
 `var(postscript file)' and makes files ending in `tt(ps)' or `tt(eps)' 
 be completed. The last description says that all other arguments are
 `var(page numbers)' but does not give possible completions.
-)
-findex(_argument_sets)
-item(tt(_argument_sets) var(sets) ...)(
-This is like tt(_arguments) but allows to specify multiple sets of
-options and arguments. The arguments are sets of specifications for
-tt(_arguments) separated by single hyphens. The specifications before
-the first hyphen are shared by all sets given after the first
-hyphen. The first word in every other set gives the name of the
-set. This name may appear in exclusion lists in the specifications,
-either alone or before one of the possible values described for
-tt(_arguments) above (with a `tt(-)' between the name and the rest).
-
-For example:
-
-example(_argument_sets \ 
-    -a \ 
-  - set1 \ 
-    -c \ 
-  - set2 \ 
-    -d \ 
-    ':arg:(x2 y2)')
-
-This defines two sets. When the command line contains the option
-`tt(-c)', the `tt(-d)' option and the argument will not be considered
-possible completions. When it contains `tt(-d)' or an argument, the
-option `tt(-c)' will not be completed any more, but if `tt(-a)' is
-given, both sets will still be considered valid, because it appears
-before the first hyphen, so both sets contain this option.
-
-If the name-string is of the form `tt(LPAR())var(name)tt(RPAR())' then 
-all specifications in the set have an implicit exclusion list
-containing the name of the set, i.e. all specifications are mutual
-exclusive with all other specifications in the same set. This is
-useful for defining multiple sets of options which are mutual
-exclusive and in which the options are aliases for each other. E.g.:
-
-example(_argument_sets \ 
-    -a -b \ 
-  - '(compress)' \
-    {-c,--compress}'[compress]' \ 
-  - '(uncompress)' \ 
-    {-d,--decompress}'[decompress]')
-
-Don't expect too much with complicated options that get their
-arguments in the same string and `tt(->)var(state)' actions or with
-the tt(-C) option that is given to tt(_arguments), otherwise most
-things should work. Note that the contexts reported in the tt(context) 
-array and the options in the tt(opt_args) association are prefixed
-with the set names and a hyphen.
 )
 findex(_call)
 item(tt(_call) var(tag) var(string) ...)(
Index: Src/Zle/computil.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/computil.c,v
retrieving revision 1.21
diff -u -r1.21 computil.c
--- Src/Zle/computil.c	2000/05/12 14:36:46	1.21
+++ Src/Zle/computil.c	2000/05/22 09:14:00
@@ -293,6 +293,7 @@
 
 struct cadef {
     Cadef next;			/* next in cache */
+    Cadef snext;		/* next set */
     Caopt opts;			/* the options */
     int nopts, ndopts, nodopts;	/* number of options/direct/optional direct */
     Caarg args;			/* the normal arguments */
@@ -304,7 +305,8 @@
     char *match;		/* -M spec to use */
     int argsactive;		/* if arguments are still allowed */
 				/* used while parsing a command line */
-    char *set;			/* set name, shared */
+    char *set;			/* set name prefix (<name>-), shared */
+    char *sname;		/* set name */
     int flags;			/* see CDF_* below */
 };
 
@@ -399,11 +401,14 @@
 static void
 freecadef(Cadef d)
 {
-    if (d) {
-	Caopt p, n;
+    Cadef s;
+    Caopt p, n;
 
+    while (d) {
+	s = d->snext;
 	zsfree(d->match);
 	zsfree(d->set);
+	zsfree(d->sname);
 	if (d->defs)
 	    freearray(d->defs);
 
@@ -421,6 +426,7 @@
 	if (d->single)
 	    zfree(d->single, 256 * sizeof(Caopt));
 	zfree(d, sizeof(*d));
+	d = s;
     }
 }
 
@@ -510,25 +516,63 @@
     return ret;
 }
 
+static Cadef
+alloc_cadef(char **args, int single, char *match, int flags)
+{
+    Cadef ret;
+
+    ret = (Cadef) zalloc(sizeof(*ret));
+    ret->next = ret->snext = NULL;
+    ret->opts = NULL;
+    ret->args = ret->rest = NULL;
+    if (args) {
+	ret->defs = zarrdup(args);
+	ret->ndefs = arrlen(args);
+    } else {
+	ret->defs = NULL;
+	ret->ndefs = 0;
+    }
+    ret->lastt = time(0);
+    ret->set = ret->sname = NULL;
+    if (single) {
+	ret->single = (Caopt *) zalloc(256 * sizeof(Caopt));
+	memset(ret->single, 0, 256 * sizeof(Caopt));
+    } else
+	ret->single = NULL;
+    ret->match = ztrdup(match);
+    ret->flags = flags;
+
+    return ret;
+}
+
+static void
+set_cadef_opts(Cadef def)
+{
+    Caarg argp;
+    int xnum;
+
+    for (argp = def->args, xnum = 0; argp; argp = argp->next) {
+	if (!argp->direct)
+	    argp->min = argp->num - xnum;
+	if (argp->type == CAA_OPT)
+	    xnum++;
+    }
+}
+
 /* Parse an array of definitions. */
 
 static Cadef
-parse_cadef(char *nam, char **args, int multi)
+parse_cadef(char *nam, char **args)
 {
-    Cadef ret;
+    Cadef all, ret;
     Caopt *optp;
-    Caarg argp;
-    char **oargs = args, *p, *q, *match = "r:|[_-]=* r:|=*", **xor;
-    char *adpre, *adsuf, *set = NULL, *doset = NULL;
+    char **oargs = args, *p, *q, *match = "r:|[_-]=* r:|=*", **xor, **sargs;
+    char *adpre, *adsuf, *axor = NULL, *doset = NULL, **setp = NULL;
     int single = 0, anum = 1, xnum, nopts, ndopts, nodopts, flags = 0;
+    int state = 0;
 
     nopts = ndopts = nodopts = 0;
 
-    if (multi) {
-	if (!args[1])
-	    return NULL;
-	set = tricat(*args++, "-", "");
-    }
     /* First string is the auto-description definition. */
 
     for (p = args[0]; *p && (p[0] != '%' || p[1] != 'd'); p++);
@@ -582,27 +626,47 @@
 
     /* Looks good. Optimistically allocate the cadef structure. */
 
-    ret = (Cadef) zalloc(sizeof(*ret));
-    ret->next = NULL;
-    ret->opts = NULL;
-    ret->args = ret->rest = NULL;
-    ret->defs = zarrdup(oargs);
-    ret->ndefs = arrlen(oargs);
-    ret->lastt = time(0);
-    ret->set = set;
-    if (single) {
-	ret->single = (Caopt *) zalloc(256 * sizeof(Caopt));
-	memset(ret->single, 0, 256 * sizeof(Caopt));
-    } else
-	ret->single = NULL;
-    ret->match = ztrdup(match);
-    ret->flags = flags;
+    all = ret = alloc_cadef(oargs, single, match, flags);
+    optp = &(ret->opts);
+    single = flags = 0;
+    anum = 1;
 
+    sargs = args;
+
     /* Get the definitions. */
 
-    for (optp = &(ret->opts); *args; args++) {
-        if (args[0][0] == '-' && !args[0][1]) {
-	    doset = set;
+    for (; *args; args++) {
+        if (args[0][0] == '-' && !args[0][1] && args[1]) {
+	    if (!state) {
+		char *p;
+		int l;
+
+		if (setp)
+		    args = setp;
+		p = *++args;
+		l = strlen(p) - 1;
+		if (*p == '(' && p[l] == ')') {
+		    axor = p = dupstring(p + 1);
+		    p[l - 1] = '\0';
+		} else
+		    axor = NULL;
+		ret->set = doset = tricat(p, "-", "");
+		ret->sname = ztrdup(p);
+		state = 1;
+	    } else {
+		setp = args;
+		state = 0;
+		args = sargs - 1;
+		doset = NULL;
+		ret->nopts = nopts;
+		ret->ndopts = ndopts;
+		ret->nodopts = nodopts;
+		set_cadef_opts(ret);
+		ret = ret->snext = alloc_cadef(NULL, single, NULL, flags);
+		optp = &(ret->opts);
+		single = flags = nopts = ndopts = nodopts = 0;
+		anum = 1;
+	    }
 	    continue;
 	}
 	p = dupstring(*args);
@@ -632,16 +696,25 @@
 	    }
 	    /* Oops, end-of-string. */
 	    if (*p != ')') {
-		freecadef(ret);
+		freecadef(all);
 		zwarnnam(nam, "invalid argument: %s", *args, 0);
 		return NULL;
 	    }
+	    if (doset && axor)
+		xnum++;
 	    xor = (char **) zalloc((xnum + 2) * sizeof(char *));
 	    for (node = firstnode(list), xp = xor; node; incnode(node), xp++)
 		*xp = ztrdup((char *) getdata(node));
+	    if (doset && axor)
+		*xp++ = ztrdup(axor);
 	    xp[0] = xp[1] = NULL;
 
 	    p++;
+	} else if (doset && axor) {
+	    xnum = 1;
+	    xor = (char **) zalloc(3 * sizeof(char *));
+	    xor[0] = ztrdup(axor);
+	    xor[1] = xor[2] = NULL;
 	} else
 	    xor = NULL;
 
@@ -676,7 +749,7 @@
 		    p++;
 	    }
 	    if (!p[1]) {
-		freecadef(ret);
+		freecadef(all);
 		zwarnnam(nam, "invalid argument: %s", *args, 0);
 		return NULL;
 	    }
@@ -713,7 +786,7 @@
 			p++;
 
 		if (!*p) {
-		    freecadef(ret);
+		    freecadef(all);
 		    zwarnnam(nam, "invalid option definition: %s", *args, 0);
 		    return NULL;
 		}
@@ -723,7 +796,7 @@
 		descr = NULL;
 
 	    if (c && c != ':') {
-		freecadef(ret);
+		freecadef(all);
 		zwarnnam(nam, "invalid option definition: %s", *args, 0);
 		return NULL;
 	    }
@@ -766,7 +839,7 @@
 			    *p = sav;
 			}
 			if (*p != ':') {
-			    freecadef(ret);
+			    freecadef(all);
 			    freecaargs(oargs);
 			    zwarnnam(nam, "invalid option definition: %s",
 				    *args, 0);
@@ -848,12 +921,12 @@
 	    int type = CAA_REST;
 
 	    if (*++p != ':') {
-		freecadef(ret);
+		freecadef(all);
 		zwarnnam(nam, "invalid rest argument definition: %s", *args, 0);
 		return NULL;
 	    }
 	    if (ret->rest) {
-		freecadef(ret);
+		freecadef(all);
 		zwarnnam(nam, "doubled rest argument definition: %s", *args, 0);
 		return NULL;
 	    }
@@ -885,7 +958,7 @@
 		anum++;
 
 	    if (*p != ':') {
-		freecadef(ret);
+		freecadef(all);
 		zwarnnam(nam, "invalid argument: %s", *args, 0);
 		return NULL;
 	    }
@@ -905,7 +978,7 @@
 		 pre = tmp, tmp = tmp->next);
 
 	    if (tmp && tmp->num == anum - 1) {
-		freecadef(ret);
+		freecadef(all);
 		freecaargs(arg);
 		zwarnnam(nam, "doubled argument definition: %s", *args, 0);
 		return NULL;
@@ -920,21 +993,16 @@
     ret->nopts = nopts;
     ret->ndopts = ndopts;
     ret->nodopts = nodopts;
+    set_cadef_opts(ret);
 
-    for (argp = ret->args, xnum = 0; argp; argp = argp->next) {
-	if (!argp->direct)
-	    argp->min = argp->num - xnum;
-	if (argp->type == CAA_OPT)
-	    xnum++;
-    }
-    return ret;
+    return all;
 }
 
 /* Given an array of definitions, return the cadef for it. From the cache
  * are newly built. */
 
 static Cadef
-get_cadef(char *nam, char **args, int multi)
+get_cadef(char *nam, char **args)
 {
     Cadef *p, *min, new;
     int i, na = arrlen(args);
@@ -948,7 +1016,7 @@
 	    min = p;
     if (i)
 	min = p;
-    if ((new = parse_cadef(nam, args, multi))) {
+    if ((new = parse_cadef(nam, args))) {
 	freecadef(*min);
 	*min = new;
     }
@@ -1120,7 +1188,10 @@
 
 /* State when parsing a command line. */
 
+typedef struct castate *Castate;
+
 struct castate {
+    Castate snext;
     Cadef d;
     int nopts;
     Caarg def, ddef;
@@ -1134,10 +1205,23 @@
 static struct castate ca_laststate;
 static int ca_parsed = 0, ca_alloced = 0;
 
+static void
+freecastate(Castate s)
+{
+    int i;
+    LinkList *p;
+
+    freelinklist(s->args, freestr);
+    for (i = s->nopts, p = s->oargs; i--; p++)
+	if (*p)
+	    freelinklist(*p, freestr);
+    zfree(s->oargs, s->d->nopts * sizeof(LinkList));
+}
+
 /* Parse a command line. */
 
 static int
-ca_parse_line(Cadef d, int multi)
+ca_parse_line(Cadef d, int multi, int first)
 {
     Caarg adef, ddef;
     Caopt ptr, wasopt, dopt;
@@ -1147,17 +1231,18 @@
     Patprog endpat = NULL;
 
     /* Free old state. */
-
-    if (ca_alloced) {
-	int i = ca_laststate.nopts;
-	LinkList *p = ca_laststate.oargs;
-
-	freelinklist(ca_laststate.args, freestr);
-	while (i--)
-	    if (*p++)
-		freelinklist(p[-1], freestr);
 
-	zfree(ca_laststate.oargs, ca_laststate.d->nopts * sizeof(LinkList));
+    if (first && ca_alloced) {
+	Castate s = &ca_laststate, ss;
+	int f = 1;
+
+	while (s) {
+	    ss = s->snext;
+	    freecastate(s);
+	    if (!f)
+		zfree(s, sizeof(*s));
+	    s = ss;
+	}
     }
     /* Mark everything as active. */
 
@@ -1171,6 +1256,7 @@
 
     /* Default values for the state. */
 
+    state.snext = NULL;
     state.d = d;
     state.nopts = d->nopts;
     state.def = state.ddef = NULL;
@@ -1482,16 +1568,13 @@
 }
 
 static void
-ca_set_data(char *opt, Caarg arg, char **args, int single)
+ca_set_data(LinkList descr, LinkList act, LinkList subc,
+	    char *opt, Caarg arg, int single)
 {
-    LinkList descr, act, subc;
+    LinkNode dnode, anode;
     char nbuf[40], *buf;
     int restr = 0, onum, miss = 0, rest, oopt = 1, lopt = 0, addopt;
 
-    descr = newlinklist();
-    act = newlinklist();
-    subc = newlinklist();
-
  rec:
 
     addopt = (opt ? 0 : ca_laststate.oopt);
@@ -1503,33 +1586,40 @@
 	if (!opt && !lopt && oopt > 0)
 	    oopt = 0;
 
-	addlinknode(descr, arg->descr);
-	addlinknode(act, arg->action);
-
-	if (!restr) {
-	    if ((restr = (arg->type == CAA_RARGS)))
-		restrict_range(ca_laststate.optbeg, ca_laststate.argend);
-	    else if ((restr = (arg->type == CAA_RREST)))
-		restrict_range(ca_laststate.argbeg, ca_laststate.argend);
-	}
-	if (arg->opt) {
-	    buf = (char *) zhalloc((arg->set ? strlen(arg->set) : 0) +
-				   strlen(arg->opt) + 40);
-	    if (arg->num > 0 && arg->type < CAA_REST)
-		sprintf(buf, "%soption%s-%d",
-			(arg->set ? arg->set : ""), arg->opt, arg->num);
-	    else
-		sprintf(buf, "%soption%s-rest",
-			(arg->set ? arg->set : ""), arg->opt);
-	} else if (arg->num > 0) {
-	    sprintf(nbuf, "argument-%d", arg->num);
-	    buf = (arg->set ? dyncat(arg->set, nbuf) : dupstring(nbuf));
-	} else
-	    buf = (arg->set ? dyncat(arg->set, "argument-rest") :
-		   dupstring("argument-rest"));
+	for (dnode = firstnode(descr), anode = firstnode(act);
+	     dnode; incnode(dnode), incnode(anode))
+	    if (!strcmp((char *) getdata(dnode), arg->descr) &&
+		!strcmp((char *) getdata(anode), arg->action))
+		break;
 
-	addlinknode(subc, buf);
+	if (!dnode) {
+	    addlinknode(descr, arg->descr);
+	    addlinknode(act, arg->action);
+
+	    if (!restr) {
+		if ((restr = (arg->type == CAA_RARGS)))
+		    restrict_range(ca_laststate.optbeg, ca_laststate.argend);
+		else if ((restr = (arg->type == CAA_RREST)))
+		    restrict_range(ca_laststate.argbeg, ca_laststate.argend);
+	    }
+	    if (arg->opt) {
+		buf = (char *) zhalloc((arg->set ? strlen(arg->set) : 0) +
+				       strlen(arg->opt) + 40);
+		if (arg->num > 0 && arg->type < CAA_REST)
+		    sprintf(buf, "%soption%s-%d",
+			    (arg->set ? arg->set : ""), arg->opt, arg->num);
+		else
+		    sprintf(buf, "%soption%s-rest",
+			    (arg->set ? arg->set : ""), arg->opt);
+	    } else if (arg->num > 0) {
+		sprintf(nbuf, "argument-%d", arg->num);
+		buf = (arg->set ? dyncat(arg->set, nbuf) : dupstring(nbuf));
+	    } else
+		buf = (arg->set ? dyncat(arg->set, "argument-rest") :
+		       dupstring("argument-rest"));
 
+	    addlinknode(subc, buf);
+	}
 	if (single)
 	    break;
 
@@ -1565,15 +1655,13 @@
 
 	goto rec;
     }
-    set_list_array(args[0], descr);
-    set_list_array(args[1], act);
-    set_list_array(args[2], subc);
 }
 
 static int
 bin_comparguments(char *nam, char **args, char *ops, int func)
 {
     int min, max, n;
+    Castate lstate = &ca_laststate;
 
     if (incompfunc != 1) {
 	zwarnnam(nam, "can only be called from completion function", NULL, 0);
@@ -1588,8 +1676,7 @@
 	return 1;
     }
     switch (args[0][1]) {
-    case 'i':
-    case 'I': min = 2; max = -1; break;
+    case 'i': min = 2; max = -1; break;
     case 'D': min = 3; max =  3; break;
     case 'O': min = 4; max =  4; break;
     case 'L': min = 3; max =  4; break;
@@ -1611,171 +1698,235 @@
     }
     switch (args[0][1]) {
     case 'i':
-    case 'I':
 	if (compcurrent > 1 && compwords[0]) {
 	    Cadef def;
-	    int cap = ca_parsed;
-	    LinkList cax = ca_xor;
+	    int cap = ca_parsed, multi, first = 1, use, ret = 0;
+	    LinkList cax = ca_xor, nx;
+	    LinkNode node;
+	    Castate states = NULL, sp;
+	    char *xor[2];
 
 	    ca_parsed = 0;
-
-	    if (args[0][1] == 'I') {
-		char **xor;
+	    xor[1] = NULL;
 
-		if (!(def = get_cadef(nam, args + 2, 1)))
-		    return 1;
+	    if (!(def = get_cadef(nam, args + 1)))
+		return 1;
 
-		ca_parsed = cap;
-		ca_xor = newlinklist();
-		if ((xor = getaparam(args[1]))) {
-		    if (arrcontains(xor, args[2], 0) ||
-			ca_inactive(def, xor, compcurrent, 0)) {
-			ca_xor = cax;
-			return 1;
+	    multi = !!def->snext;
+	    ca_parsed = cap;
+	    ca_xor = (multi ? newlinklist() : NULL);
+
+	    while (def) {
+		use = !ca_parse_line(def, multi, first);
+		nx = ca_xor;
+		ca_xor = NULL;
+		while ((def = def->snext)) {
+		    if (nx) {
+			for (node = firstnode(nx); node; incnode(node)) {
+			    xor[0] = (char *) getdata(node);
+			    if (!strcmp(xor[0], def->sname) ||
+				ca_inactive(def, xor, compcurrent, 0))
+				break;
+			}
+			if (!node)
+			    break;
 		    }
 		}
-		if (ca_parse_line(def, 1)) {
-		    ca_xor = cax;
-		    return 1;
+		ca_xor = nx;
+		if (use && def) {
+		    sp = (Castate) zalloc(sizeof(*sp));
+		    memcpy(sp, &ca_laststate, sizeof(*sp));
+		    sp->snext = states;
+		    states = sp;
+		} else if (!use && !def) {
+		    if (states) {
+			freecastate(&ca_laststate);
+			memcpy(&ca_laststate, states, sizeof(*sp));
+			sp = states->snext;
+			zfree(states, sizeof(*states));
+			states = sp;
+		    } else
+			ret = 1;
 		}
-		set_list_array(args[1], ca_xor);
-	    } else {
-		if (!(def = get_cadef(nam, args + 1, 0)))
-		    return 1;
-
-		ca_parsed = cap;
-		ca_xor = NULL;
-		ca_parse_line(def, 0);
+		first = 0;
 	    }
 	    ca_xor = cax;
 	    ca_parsed = 1;
+	    ca_laststate.snext = states;
 
-	    return 0;
+	    return ret;
 	}
 	return 1;
 
     case 'D':
 	{
-	    Caarg arg = ca_laststate.def;
-
-	    if (arg) {
-		if (ca_laststate.doff > 0)
-		    ignore_prefix(ca_laststate.doff);
-
-		ca_set_data(arg->opt, arg, args + 1, (ca_laststate.doff > 0));
-
-		return 0;
+	    LinkList descr, act, subc;
+	    Caarg arg;
+	    int ign = 0, ret = 1;
+
+	    descr = newlinklist();
+	    act = newlinklist();
+	    subc = newlinklist();
+
+	    while (lstate) {
+		arg = lstate->def;
+
+		if (arg) {
+		    ret = 0;
+		    if (!ign && lstate->doff > 0) {
+			ign = 1;
+			ignore_prefix(lstate->doff);
+		    }
+		    ca_set_data(descr, act, subc, arg->opt, arg,
+				(lstate->doff > 0));
+		}
+		lstate = lstate->snext;
 	    }
-	    return 1;
+	    if (!ret) {
+		set_list_array(args[1], descr);
+		set_list_array(args[2], act);
+		set_list_array(args[3], subc);
+	    }
+	    return ret;
 	}
     case 'O':
-	if (ca_laststate.actopts &&
-	    (ca_laststate.opt || (ca_laststate.doff && ca_laststate.def) ||
-	     (ca_laststate.def &&
-	      (ca_laststate.def->type == CAA_OPT ||
-	       (ca_laststate.def->type >= CAA_RARGS &&
-		ca_laststate.def->num < 0)))) &&
-	    (!ca_laststate.def || ca_laststate.def->type < CAA_RARGS ||
-	     (ca_laststate.def->type == CAA_RARGS ?
-	      (ca_laststate.curpos == ca_laststate.argbeg + 1) :
-	      (compcurrent == 1)))) {
+	{
 	    LinkList next = newlinklist();
 	    LinkList direct = newlinklist();
 	    LinkList odirect = newlinklist();
 	    LinkList equal = newlinklist(), l;
 	    Caopt p;
 	    char *str;
+	    int ret = 1;
 
-	    for (p = ca_laststate.d->opts; p; p = p->next) {
-		if (p->active) {
-		    switch (p->type) {
-		    case CAO_NEXT:    l = next;    break;
-		    case CAO_DIRECT:  l = direct;  break;
-		    case CAO_ODIRECT: l = odirect; break;
-		    default:          l = equal;   break;
+	    for (; lstate; lstate = lstate->snext) {
+		if (lstate->actopts &&
+		    (lstate->opt || (lstate->doff && lstate->def) ||
+		     (lstate->def &&
+		      (lstate->def->type == CAA_OPT ||
+		       (lstate->def->type >= CAA_RARGS &&
+			lstate->def->num < 0)))) &&
+		    (!lstate->def || lstate->def->type < CAA_RARGS ||
+		     (lstate->def->type == CAA_RARGS ?
+		      (lstate->curpos == lstate->argbeg + 1) :
+		      (compcurrent == 1)))) {
+		    ret = 0;
+		    for (p = lstate->d->opts; p; p = p->next) {
+			if (p->active) {
+			    switch (p->type) {
+			    case CAO_NEXT:    l = next;    break;
+			    case CAO_DIRECT:  l = direct;  break;
+			    case CAO_ODIRECT: l = odirect; break;
+			    default:          l = equal;   break;
+			    }
+			    if (p->descr) {
+				char *n = bslashcolon(p->name);
+				int len = strlen(n) + strlen(p->descr) + 2;
+
+				str = (char *) zhalloc(len);
+				strcpy(str, n);
+				strcat(str, ":");
+				strcat(str, p->descr);
+			    } else
+				str = bslashcolon(p->name);
+			    addlinknode(l, str);
+			}
 		    }
-		    if (p->descr) {
-			char *n = bslashcolon(p->name);
-			int len = strlen(n) + strlen(p->descr) + 2;
-
-			str = (char *) zhalloc(len);
-			strcpy(str, n);
-			strcat(str, ":");
-			strcat(str, p->descr);
-		    } else
-			str = bslashcolon(p->name);
-		    addlinknode(l, str);
 		}
 	    }
-	    set_list_array(args[1], next);
-	    set_list_array(args[2], direct);
-	    set_list_array(args[3], odirect);
-	    set_list_array(args[4], equal);
+	    if (!ret) {
+		set_list_array(args[1], next);
+		set_list_array(args[2], direct);
+		set_list_array(args[3], odirect);
+		set_list_array(args[4], equal);
 
-	    return 0;
+		return 0;
+	    }
+	    return (ca_laststate.singles ? 2 : 1);
 	}
-	return (ca_laststate.singles ? 2 : 1);
     case 'L':
 	{
-	    Caopt opt = ca_get_opt(ca_laststate.d, args[1], 1, NULL);
-
-	    if (opt && opt->args) {
-		ca_set_data(opt->name, opt->args, args + 2, 1);
+	    LinkList descr, act, subc;
+	    Caopt opt;
+	    int ret = 1;
 
-		return 0;
+	    descr = newlinklist();
+	    act = newlinklist();
+	    subc = newlinklist();
+
+	    while (lstate) {
+		opt = ca_get_opt(lstate->d, args[1], 1, NULL);
+
+		if (opt && opt->args) {
+		    ret = 0;
+		    ca_set_data(descr, act, subc, opt->name, opt->args, 1);
+		}
+		lstate = lstate->snext;
 	    }
-	    return 1;
+	    if (!ret) {
+		set_list_array(args[2], descr);
+		set_list_array(args[3], act);
+		set_list_array(args[4], subc);
+	    }
+	    return ret;
 	}
     case 's':
-	if (ca_laststate.d->single && ca_laststate.singles &&
-	    ca_laststate.actopts && ca_laststate.opt) {
-	    setsparam(args[1],
-		      ztrdup((ca_laststate.ddef && ca_laststate.dopt) ?
-			     (ca_laststate.dopt->type == CAO_DIRECT ?
-			      "direct" :
-			      ((ca_laststate.dopt->type == CAO_OEQUAL ||
-				ca_laststate.dopt->type == CAO_EQUAL) ?
-			       "equal" : "next")) : ""));
-	    return 0;
-	}
+	for (; lstate; lstate = lstate->snext)
+	    if (lstate->d->single && lstate->singles &&
+		lstate->actopts && lstate->opt) {
+		setsparam(args[1],
+			  ztrdup((lstate->ddef && lstate->dopt) ?
+				 (lstate->dopt->type == CAO_DIRECT ?
+				  "direct" :
+				  ((lstate->dopt->type == CAO_OEQUAL ||
+				    lstate->dopt->type == CAO_EQUAL) ?
+				   "equal" : "next")) : ""));
+		return 0;
+	    }
 	return 1;
     case 'M':
 	setsparam(args[1], ztrdup(ca_laststate.d->match));
 	return 0;
     case 'a':
-	return !(ca_laststate.d->args || ca_laststate.d->rest);
+	for (; lstate; lstate = lstate->snext)
+	    if (lstate->d->args || lstate->d->rest)
+		return 0;
+	return 1;
     case 'W':
 	{
+	    Castate s;
 	    char **ret, **p;
 	    LinkNode n;
 	    LinkList *a;
 	    Caopt o;
 	    int num;
 
-	    ret = p = zalloc((countlinknodes(ca_laststate.args) + 1) *
-			     sizeof(char *));
+	    for (num = 0, s = lstate; s; s = s->snext)
+		num += countlinknodes(s->args);
+
+	    ret = p = zalloc((num + 1) * sizeof(char *));
 
-	    for (n = firstnode(ca_laststate.args); n; incnode(n))
-		*p++ = ztrdup((char *) getdata(n));
+	    for (s = lstate; s; s = s->snext)
+		for (n = firstnode(s->args); n; incnode(n))
+		    *p++ = ztrdup((char *) getdata(n));
 	    *p = NULL;
 
 	    setaparam(args[1], ret);
 
-	    for (num = 0, o = ca_laststate.d->opts, a = ca_laststate.oargs; o;
-		 o = o->next, a++)
-		if (*a)
-		    num += 2;
+	    for (num = 0, s = lstate; s; s = s->snext)
+		for (o = s->d->opts, a = s->oargs; o; o = o->next, a++)
+		    if (*a)
+			num += 2;
 
 	    ret = p = zalloc((num + 1) * sizeof(char *));
 
-	    for (o = ca_laststate.d->opts, a = ca_laststate.oargs; o;
-		 o = o->next, a++) {
-		if (*a) {
-		    *p++ = (o->set ? tricat(o->set, o->name, "") :
-			    ztrdup(o->name));
-		    *p++ = ca_colonlist(*a);
-		}
-	    }
+	    for (s = lstate; s; s = s->snext)
+		for (o = s->d->opts, a = s->oargs; o; o = o->next, a++)
+		    if (*a) {
+			*p++ = (o->set ? tricat(o->set, o->name, "") :
+				ztrdup(o->name));
+			*p++ = ca_colonlist(*a);
+		    }
 	    *p = NULL;
 
 	    sethparam(args[2], ret);

--
Sven Wischnowsky                         wischnow@xxxxxxxxxxxxxxxxxxxxxxx



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