about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSven Wischnowsky <wischnow@users.sourceforge.net>2001-07-18 13:10:07 +0000
committerSven Wischnowsky <wischnow@users.sourceforge.net>2001-07-18 13:10:07 +0000
commit8c1b953b5a6c49d47f55d311d16852f94d2ebeed (patch)
treebbd14925f61c99b3aa89067b89e82abbae4f253e
parent40f651019666eba2c3c8a53055f16d28f6ed9385 (diff)
downloadzsh-8c1b953b5a6c49d47f55d311d16852f94d2ebeed.tar.gz
zsh-8c1b953b5a6c49d47f55d311d16852f94d2ebeed.tar.xz
zsh-8c1b953b5a6c49d47f55d311d16852f94d2ebeed.zip
add list-grouped option to make options and such be grouped together if they have the same description; matches with line-display strings can be hidden; hi and du capabalities in complist are only used if set by the user (15407)
-rw-r--r--ChangeLog8
-rw-r--r--Completion/Base/Utility/_describe14
-rw-r--r--Completion/Zsh/Command/_zstyle1
-rw-r--r--Doc/Zsh/compsys.yo14
-rw-r--r--Src/Zle/complist.c12
-rw-r--r--Src/Zle/compresult.c71
-rw-r--r--Src/Zle/computil.c323
7 files changed, 284 insertions, 159 deletions
diff --git a/ChangeLog b/ChangeLog
index 716f73120..68e6f8631 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 2001-07-18  Sven Wischnowsky  <wischnow@zsh.org>
 
+	* 15407: Completion/Base/Utility/_describe,
+	Completion/Zsh/Command/_zstyle, Doc/Zsh/compsys.yo,
+	Src/Zle/complist.c, Src/Zle/compresult.c, Src/Zle/computil.c:
+	add list-grouped option to make options and such be grouped
+	together if they have the same description; matches with
+	line-display strings can be hidden; hi and du capabalities in
+	complist are only used if set by the user
+
 	* 15402 (Akinora Musha): Completion/Unix/Command/_cvs: add
 	support for -R option on BSDs
 
diff --git a/Completion/Base/Utility/_describe b/Completion/Base/Utility/_describe
index a658d16df..a58954f47 100644
--- a/Completion/Base/Utility/_describe
+++ b/Completion/Base/Utility/_describe
@@ -2,8 +2,8 @@
 
 # This can be used to add options or values with descriptions as matches.
 
-local _opt _expl _tmps _tmpd _tmpmd _tmpms _ret=1 _showd _nm _hide _args
-local _type=values _descr
+local _opt _expl _tmps _tmpd _tmph _tmpmd _tmpms _tmpmh
+local _type=values _descr _ret=1 _showd _nm _hide _args _grp
 
 # Get the option.
 
@@ -21,6 +21,11 @@ fi
 # Do the tests. `showd' is set if the descriptions should be shown.
 
 zstyle -T ":completion:${curcontext}:$_type" verbose && _showd=yes
+if zstyle -T ":completion:${curcontext}:$_type" list-grouped; then
+  _grp=(-g)
+else
+  _grp=()
+fi
 
 _descr="$1"
 shift
@@ -33,12 +38,12 @@ while _tags; do
   while _next_label "$_type" _expl "$_descr"; do
 
     if [[ -n "$_showd" ]]; then
-      compdescribe -I ' -- ' "$@"
+      compdescribe -I ' -- ' "$_grp[@]" "$@"
     else
       compdescribe -i "$@"
     fi
 
-    while compdescribe -g _args _tmpd _tmpmd _tmps _tmpms; do
+    while compdescribe -g _args _tmpd _tmpmd _tmph _tmpmh _tmps _tmpms; do
 
       # See if we should remove the option prefix characters.
 
@@ -53,6 +58,7 @@ while _tags; do
       fi
 
       compadd "$_args[@]" "$_expl[@]" -ld _tmpd -a _tmpmd && _ret=0
+      compadd -n "$_args[@]" "$_expl[@]" -ld _tmph -a _tmpmh && _ret=0
       compadd "$_args[@]" "$_expl[@]" -d _tmps  -a _tmpms && _ret=0
     done
   done
diff --git a/Completion/Zsh/Command/_zstyle b/Completion/Zsh/Command/_zstyle
index 37590f0d9..c72109433 100644
--- a/Completion/Zsh/Command/_zstyle
+++ b/Completion/Zsh/Command/_zstyle
@@ -55,6 +55,7 @@ styles=(
   last-prompt		 c:bool
   list			 c:listwhen
   list-colors		 c:
+  list-grouped		 c:bool
   list-packed		 c:bool
   list-prompt            c:
   list-rows-first	 c:bool
diff --git a/Doc/Zsh/compsys.yo b/Doc/Zsh/compsys.yo
index c5260245a..22352b550 100644
--- a/Doc/Zsh/compsys.yo
+++ b/Doc/Zsh/compsys.yo
@@ -1508,6 +1508,17 @@ example(zstyle ':completion:*:default' list-colors ${(s.:.)LS_COLORS})
 The default colors are the same as for the GNU tt(ls) command and can be
 obtained by setting the style to an empty string (i.e. tt('')).
 )
+kindex(list-grouped, completion style)
+item(tt(list-grouped))(
+If this style is `true' (the default), the completion system will try to
+make some completion listings more compact by grouping matches together.
+For example, options for commands that have the same description (which
+are shown because the tt(verbose) style is set to `true') will have only
+one entry in the list, showing all options that can be used to select
+the specific behaviour.  When menu selection is done on such a list, the
+matches will appear as separate entries in the list to be able to select
+each of them.
+)
 kindex(list-packed, completion style)
 item(tt(list-packed))(
 Like the tt(list-colors) style, this is tested with the tt(default)
@@ -3463,6 +3474,9 @@ the tt(prefix-hidden), tt(prefix-needed) and tt(verbose) styles to find out
 if the strings should be added at all and if the descriptions should be
 shown.  Without the `tt(-o)' option, only the tt(verbose) style is used.
 
+If selected by the tt(list-grouped) style, strings with the same
+description will be added in a way that they appear together in the list.
+
 tt(_describe) uses the tt(_all_labels) function to generate the matches, so
 it does not need to appear inside a loop over tag labels.
 )
diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c
index f76e54116..94fd2cc56 100644
--- a/Src/Zle/complist.c
+++ b/Src/Zle/complist.c
@@ -77,7 +77,7 @@ static char *colnames[] = {
 
 static char *defcols[] = {
     "0", "0", "1;31", "1;36", "33", "1;35", "1;33", "1;33", "1;32", NULL,
-    "\033[", "m", NULL, "0", "0", "7", "0", "0"
+    "\033[", "m", NULL, "0", "0", "7", NULL, NULL
 };
 
 /* This describes a terminal string for a file type. */
@@ -444,6 +444,7 @@ zcputs(Listcols c, char *group, int colour)
 
 	    return;
 	}
+    zlrputs(c, "0");
 }
 
 /* Turn off colouring. */
@@ -1170,7 +1171,8 @@ compprintlist(int showall)
 		    p = g->matches;
 
 		for (; (m = *p); p++) {
-		    if (m->disp && (m->flags & CMF_DISPLINE)) {
+		    if (m->disp && (m->flags & CMF_DISPLINE) &&
+                        (showall || !(m->flags & (CMF_HIDE|CMF_NOLIST)))) {
 			if (pnl) {
 			    if (dolistnl(ml) && compprintnl(ml))
 				goto end;
@@ -1412,9 +1414,11 @@ clprintm(Cmgroup g, Cmatch *mp, int mc, int ml, int lastc, int width,
 	    mgtabp = mgtab + mm;
 	    mmlen = mcols;
 	    zcputs(&mcolors, g->name, COL_MA);
-	} else if (m->flags & CMF_NOLIST)
+	} else if ((m->flags & CMF_NOLIST) &&
+                   mcolors.files[COL_HI] && mcolors.files[COL_HI]->col)
 	    zcputs(&mcolors, g->name, COL_HI);
-	else if (mselect >= 0 && (m->flags & (CMF_MULT | CMF_FMULT)))
+	else if (mselect >= 0 && (m->flags & (CMF_MULT | CMF_FMULT)) &&
+                 mcolors.files[COL_DU] && mcolors.files[COL_DU]->col)
 	    zcputs(&mcolors, g->name, COL_DU);
 	else
 	    subcols = putmatchcol(&mcolors, g->name, m->disp);
diff --git a/Src/Zle/compresult.c b/Src/Zle/compresult.c
index c1da0fbff..0e7bbedba 100644
--- a/Src/Zle/compresult.c
+++ b/Src/Zle/compresult.c
@@ -1443,44 +1443,46 @@ calclist(int showall)
 		}
 		m->flags &= ~CMF_HIDE;
 
-		if (m->disp) {
-		    if (m->flags & CMF_DISPLINE) {
-			nlines += 1 + printfmt(m->disp, 0, 0, 0);
-			g->flags |= CGF_HASDL;
-		    } else {
-			l = niceztrlen(m->disp);
-			ndisp++;
-			if (l > glong)
-			    glong = l;
-			if (l < gshort)
-			    gshort = l;
-			totl += l;
-			mlens[m->gnum] = l;
-		    }
-		    nlist++;
-		    if (!(m->flags & CMF_PACKED))
-			g->flags &= ~CGF_PACKED;
-		    if (!(m->flags & CMF_ROWS))
-			g->flags &= ~CGF_ROWS;
-		} else if (showall || !(m->flags & (CMF_NOLIST | CMF_MULT))) {
+                if (showall || !(m->flags & (CMF_NOLIST | CMF_MULT))) {
 		    if ((m->flags & (CMF_NOLIST | CMF_MULT)) &&
 			(!m->str || !*m->str)) {
 			m->flags |= CMF_HIDE;
 			continue;
 		    }
-		    l = niceztrlen(m->str);
-		    ndisp++;
-		    if (l > glong)
-			glong = l;
-		    if (l < gshort)
-			gshort = l;
-		    totl += l;
-		    mlens[m->gnum] = l;
-		    nlist++;
-		    if (!(m->flags & CMF_PACKED))
-			g->flags &= ~CGF_PACKED;
-		    if (!(m->flags & CMF_ROWS))
-			g->flags &= ~CGF_ROWS;
+                    if (m->disp) {
+                        if (m->flags & CMF_DISPLINE) {
+                            nlines += 1 + printfmt(m->disp, 0, 0, 0);
+                            g->flags |= CGF_HASDL;
+                        } else {
+                            l = niceztrlen(m->disp);
+                            ndisp++;
+                            if (l > glong)
+                                glong = l;
+                            if (l < gshort)
+                                gshort = l;
+                            totl += l;
+                            mlens[m->gnum] = l;
+                        }
+                        nlist++;
+                        if (!(m->flags & CMF_PACKED))
+                            g->flags &= ~CGF_PACKED;
+                        if (!(m->flags & CMF_ROWS))
+                            g->flags &= ~CGF_ROWS;
+                    } else {
+                        l = niceztrlen(m->str);
+                        ndisp++;
+                        if (l > glong)
+                            glong = l;
+                        if (l < gshort)
+                            gshort = l;
+                        totl += l;
+                        mlens[m->gnum] = l;
+                        nlist++;
+                        if (!(m->flags & CMF_PACKED))
+                            g->flags &= ~CGF_PACKED;
+                        if (!(m->flags & CMF_ROWS))
+                            g->flags &= ~CGF_ROWS;
+                    }
 		} else
 		    hidden = 1;
 	    }
@@ -1972,7 +1974,8 @@ printlist(int over, CLPrintFunc printm, int showall)
 
 	    if (g->flags & CGF_HASDL) {
 		for (p = g->matches; (m = *p); p++)
-		    if (m->disp && (m->flags & CMF_DISPLINE)) {
+		    if (m->disp && (m->flags & CMF_DISPLINE) &&
+                        (showall || !(m->flags & (CMF_HIDE|CMF_NOLIST)))) {
 			if (pnl) {
 			    putc('\n', shout);
 			    pnl = 0;
diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c
index 870bbcce8..522c6356d 100644
--- a/Src/Zle/computil.c
+++ b/Src/Zle/computil.c
@@ -31,59 +31,42 @@
 #include "computil.pro"
 
 
-/* Help for `_display'. */
-
-/* Calculation state. */
-
-typedef struct cdisp *Cdisp;
-
-struct cdisp {
-    int pre;			/* prefix length */
-    int suf;			/* suffix length */
-    int colon;			/* number of strings with descriptions */
-};
-
-/* Calculate longest prefix and suffix and count the strings with
- * descriptions. */
-
-static void
-cdisp_calc(Cdisp disp, char **args)
-{
-    char *cp;
-    int i, nbc;
-
-    for (; *args; args++) {
-	for (nbc = 0, cp = *args; *cp && *cp != ':'; cp++)
-	    if (*cp == '\\' && cp[1])
-		cp++, nbc++;
-	if (*cp == ':' && cp[1]) {
-	    disp->colon++;
-	    if ((i = cp - *args - nbc) > disp->pre)
-		disp->pre = i;
-	    if ((i = strlen(cp + 1)) > disp->suf)
-		disp->suf = i;
-	}
-    }
-}
-
-/* Help fuer `_describe'. */
+/* Help for `_describe'. */
 
 typedef struct cdset *Cdset;
+typedef struct cdstr *Cdstr;
 
 struct cdstate {
     int showd;			/* != 0 if descriptions should be shown */
     char *sep;			/* the separator string */
+    int slen;			/* its length */
     Cdset sets;			/* the sets of matches */
-    struct cdisp disp;		/* used to calculate the alignment */
+    int pre;                    /* longest prefix (before description) */
+    int suf;                    /* longest suffix (description) */
+};
+
+struct cdstr {
+    Cdstr next;                 /* the next one in this set */
+    char *str;                  /* the string to display */
+    char *desc;                 /* the description or NULL */
+    char *match;                /* the match to add */
+    Cdstr other;                /* next string with the same description */
+    int kind;                   /* 0: not in a group, 1: the first, 2: other */
 };
 
 struct cdset {
     Cdset next;			/* guess what */
     char **opts;		/* the compadd-options */
-    char **strs;		/* the display-strings */
-    char **matches;		/* the matches (or NULL) */
+    Cdstr strs;                 /* the strings/matches */
+    int count;                  /* number of matches in this set */
+    int desc;                   /* number of matches with description */
 };
 
+/* Maximum string length when used with descriptions. */
+
+#define CD_MAXLEN 20
+
+
 static struct cdstate cd_state;
 static int cd_parsed = 0;
 
@@ -91,26 +74,116 @@ static void
 freecdsets(Cdset p)
 {
     Cdset n;
+    Cdstr s, sn;
 
     for (; p; p = n) {
 	n = p->next;
 	if (p->opts)
 	    freearray(p->opts);
-	if (p->strs)
-	    freearray(p->strs);
-	if (p->matches)
-	    freearray(p->matches);
+        for (s = p->strs; s; s = sn) {
+            sn = s->next;
+            zsfree(s->str);
+            zsfree(s->desc);
+            if (s->match != s->str)
+                zsfree(s->match);
+            zfree(s, sizeof(*s));
+        }
 	zfree(p, sizeof(*p));
     }
 }
 
+/* Find matches with same descriptions and group them. */
+
+static void
+cd_group()
+{
+    Cdset set1, set2;
+    Cdstr str1, str2, *strp;
+    int yep = 0;
+    char *buf;
+
+    for (set1 = cd_state.sets; set1; set1 = set1->next) {
+        for (str1 = set1->strs; str1; str1 = str1->next) {
+            if (!str1->desc || str1->kind != 0)
+                continue;
+
+            strp = &(str1->other);
+
+            for (set2 = set1; set2; set2 = set2->next)
+                for (str2 = (set2 == set1 ? str1->next : set2->strs);
+                     str2; str2 = str2->next)
+                    if (str2->desc && !strcmp(str1->desc, str2->desc)) {
+                        str1->kind = 1;
+                        str2->kind = 2;
+                        zsfree(str2->desc);
+                        str2->desc = ztrdup("|");
+                        *strp = str2;
+                        strp = &(str2->other);
+                        yep = 1;
+                    }
+            *strp = NULL;
+        }
+    }
+    if (!yep)
+        return;
+
+    for (set1 = cd_state.sets; set1; set1 = set1->next) {
+        for (str1 = set1->strs; str1; str1 = str1->next) {
+            if (str1->kind != 1)
+                continue;
+
+            buf = str1->str;
+            for (str2 = str1->other; str2; str2 = str2->other)
+                buf = zhtricat(buf, ", ", str2->str);
+
+            for (str2 = str1; str2; str2 = str2->other) {
+                if (str2->str == str2->match)
+                    str2->match = ztrdup(str2->match);
+                zsfree(str2->str);
+                str2->str = ztrdup(buf);
+            }
+        }
+    }
+}
+
+/* Calculate longest prefix and suffix and count the strings with
+ * descriptions. */
+
+static void
+cd_calc()
+{
+    Cdset set;
+    Cdstr str;
+    int l;
+
+    cd_state.pre = cd_state.suf = 0;
+
+    for (set = cd_state.sets; set; set = set->next) {
+        set->count = set->desc = 0;
+        for (str = set->strs; str; str = str->next) {
+            set->count++;
+            if ((l = strlen(str->str)) > cd_state.pre)
+                cd_state.pre = l;
+            if (str->desc) {
+                set->desc++;
+                if ((l = strlen(str->desc)) > cd_state.suf)
+                    cd_state.suf = l;
+            }
+        }
+    }
+    if (cd_state.pre > 20)
+        cd_state.pre = 20;
+}
+
 /* Initialisation. Store and calculate the string and matches and so on. */
 
 static int
 cd_init(char *nam, char *sep, char **args, int disp)
 {
     Cdset *setp, set;
+    Cdstr *strp, str;
     char **ap, *tmp;
+    int grp = 0;
 
     if (cd_parsed) {
 	zsfree(cd_state.sep);
@@ -119,29 +192,57 @@ cd_init(char *nam, char *sep, char **args, int disp)
     }
     setp = &(cd_state.sets);
     cd_state.sep = ztrdup(sep);
+    cd_state.slen = ztrlen(sep);
     cd_state.sets = NULL;
-    cd_state.disp.pre = cd_state.disp.suf = cd_state.disp.colon = 0;
     cd_state.showd = disp;
 
+    if (*args && !strcmp(*args, "-g")) {
+        args++;
+        grp = 1;
+    }
     while (*args) {
 	*setp = set = (Cdset) zcalloc(sizeof(*set));
 	setp = &(set->next);
+        *setp = NULL;
+        set->opts = NULL;
+        set->strs = NULL;
 
 	if (!(ap = get_user_var(*args))) {
 	    zwarnnam(nam, "invalid argument: %s", *args, 0);
+            zsfree(cd_state.sep);
+            freecdsets(cd_state.sets);
 	    return 1;
 	}
-	set->strs = zarrdup(ap);
+        for (strp = &(set->strs); *ap; ap++) {
+            *strp = str = (Cdstr) zalloc(sizeof(*str));
+            strp = &(str->next);
 
-	if (disp)
-	    cdisp_calc(&(cd_state.disp), set->strs);
+            str->kind = 0;
+            str->other = NULL;
+
+            for (tmp = *ap; *tmp && *tmp != ':'; tmp++)
+                if (*tmp == '\\' && tmp[1])
+                    tmp++;
+
+            if (*tmp)
+                str->desc = ztrdup(rembslash(tmp + 1));
+            else
+                str->desc = NULL;
+            *tmp = '\0';
+            str->str = str->match = ztrdup(rembslash(*ap));
+        }
+        str->next = NULL;
 
 	if (*++args && **args != '-') {
 	    if (!(ap = get_user_var(*args))) {
 		zwarnnam(nam, "invalid argument: %s", *args, 0);
+                zsfree(cd_state.sep);
+                freecdsets(cd_state.sets);
 		return 1;
 	    }
-	    set->matches = zarrdup(ap);
+            for (str = set->strs; str && *ap; str = str->next, ap++)
+                str->match = ztrdup(*ap);
+
 	    args++;
 	}
 	for (ap = args; *args &&
@@ -154,6 +255,11 @@ cd_init(char *nam, char *sep, char **args, int disp)
 	if ((*args = tmp))
 	    args++;
     }
+    if (disp && grp)
+        cd_group();
+
+    cd_calc();
+
     cd_parsed = 1;
     return 0;
 }
@@ -166,77 +272,60 @@ cd_get(char **params)
     Cdset set;
 
     if ((set = cd_state.sets)) {
-	char **sd, **sdp, **md, **mdp, **ss, **ssp, **ms, **msp;
-	char **p, **mp, *cp, *copy, *cpp, oldc;
-	int dl = 1, sl = 1, sepl = strlen(cd_state.sep);
-	int pre = cd_state.disp.pre, suf = cd_state.disp.suf;
-	VARARR(char, buf, pre + suf + sepl + 1);
-
-	for (p = set->strs; *p; p++)
-	    if (cd_state.showd) {
-		for (cp = *p; *cp && *cp != ':'; cp++)
-		    if (*cp == '\\' && cp[1])
-			cp++;
-		if (*cp == ':' && cp[1])
-		    dl++;
-		else
-		    sl++;
-	    } else
-		sl++;
-
-	sd = (char **) zalloc(dl * sizeof(char *));
-	ss = (char **) zalloc(sl * sizeof(char *));
-	md = (char **) zalloc(dl * sizeof(char *));
-	ms = (char **) zalloc(sl * sizeof(char *));
-
-	if (cd_state.showd) {
-	    memcpy(buf + pre, cd_state.sep, sepl);
-	    suf = pre + sepl;
-	}
-
-	/* Build the aligned display strings. */
-
-	for (sdp = sd, ssp = ss, mdp = md, msp = ms,
-		 p = set->strs, mp = set->matches; *p; p++) {
-	    copy = dupstring(*p);
-	    for (cp = cpp = copy; *cp && *cp != ':'; cp++) {
-		if (*cp == '\\' && cp[1])
-		    cp++;
-		*cpp++ = *cp;
-	    }
-	    oldc = *cpp;
-	    *cpp = '\0';
-	    if (((cpp == cp && oldc == ':') || *cp == ':') && cp[1] &&
-		cd_state.showd) {
-		memset(buf, ' ', pre);
-		memcpy(buf, copy, (cpp - copy));
-		strcpy(buf + suf, cp + 1);
-		*sdp++ = ztrdup(buf);
-		if (mp) {
-		    *mdp++ = ztrdup(*mp);
-		    if (*mp)
-			mp++;
-		} else
-		    *mdp++ = ztrdup(copy);
-	    } else {
-		*ssp++ = ztrdup(copy);
-		if (mp) {
-		    *msp++ = ztrdup(*mp);
-		    if (*mp)
-			mp++;
-		} else
-		    *msp++ = ztrdup(copy);
-	    }
-	}
-	*sdp = *ssp = *mdp = *msp = NULL;
+	char **sd, **sdp, **md, **mdp, **sh, **shp, **mh, **mhp;
+        char **ss, **ssp, **ms, **msp;
+        Cdstr str;
+        VARARR(char, buf, cd_state.pre + cd_state.suf + cd_state.slen + 1);
+        char *sufp = NULL, *disp;
+
+        if (cd_state.showd) {
+            memcpy(buf + cd_state.pre, cd_state.sep, cd_state.slen);
+            sufp = buf + cd_state.pre + cd_state.slen;
+        }
+	sd = (char **) zalloc((set->desc + 1) * sizeof(char *));
+	md = (char **) zalloc((set->desc + 1) * sizeof(char *));
+	sh = (char **) zalloc((set->desc + 1) * sizeof(char *));
+	mh = (char **) zalloc((set->desc + 1) * sizeof(char *));
+	ss = (char **) zalloc((set->count + 1) * sizeof(char *));
+	ms = (char **) zalloc((set->count + 1) * sizeof(char *));
+
+        for (sdp = sd, mdp = md, shp = sh, mhp = mh,
+             ssp = ss, msp = ms, str = set->strs;
+             str;
+             str = str->next) {
+            if (cd_state.showd && str->desc) {
+                if (strlen(str->str) > CD_MAXLEN)
+                    disp = tricat(str->str, cd_state.sep, str->desc);
+                else {
+                    strcpy(sufp, str->desc);
+                    memset(buf, ' ', cd_state.pre);
+                    memcpy(buf, str->str, strlen(str->str));
+                    disp = ztrdup(buf);
+                }
+                if (strlen(disp) >= columns)
+                    disp[columns - 1] = '\0';
 
-	p = zarrdup(set->opts);
+                if (str->kind == 2) {
+                    *shp++ = disp;
+                    *mhp++ = ztrdup(str->match);
+                } else {
+                    *sdp++ = disp;
+                    *mdp++ = ztrdup(str->match);
+                }
+            } else {
+                *ssp++ = ztrdup(str->str);
+                *msp++ = ztrdup(str->match);
+            }
+        }
+        *sdp = *mdp = *shp = *mhp = *ssp = *msp = NULL;
 
-	setaparam(params[0], p);
+	setaparam(params[0], zarrdup(set->opts));
 	setaparam(params[1], sd);
 	setaparam(params[2], md);
-	setaparam(params[3], ss);
-	setaparam(params[4], ms);
+	setaparam(params[3], sh);
+	setaparam(params[4], mh);
+	setaparam(params[5], ss);
+	setaparam(params[6], ms);
 
 	cd_state.sets = set->next;
 	set->next = NULL;
@@ -268,8 +357,8 @@ bin_compdescribe(char *nam, char **args, char *ops, int func)
 	if (cd_parsed) {
 	    int n = arrlen(args);
 
-	    if (n != 6) {
-		zwarnnam(nam, (n < 6 ? "not enough arguments" :
+	    if (n != 8) {
+		zwarnnam(nam, (n < 8 ? "not enough arguments" :
 			      "too many arguments"), NULL, 0);
 		return 1;
 	    }