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

Re: About the new long/short options changes



Bart Schaefer wrote:

> ...
>  
> } I have some ideas how we could achive this, part of the stuff we need is
> } already there.  Think of some combination of list-packed, list-rows-first
> } and `dummy' matches that get slots in the listing but show nothing and
> } can't be selected.
> 
> Yes, that is what I was thinking, though rather than dummy matches I
> was thinking about chopping up the display into groups with different
> columnations, as already happens when matches are explicitly added in
> different groups.

I first thought about that, too, but it would require some serious
changes to the listing code, so I decided to first try it with only
those dummy matches I mentioned.

The result is the patch below, which is already quite satisfying, I
think.  It took a bit longer and the patch is a bit larger, because of
the needed re-implementation of the guts of compdescribe.  And because I
wasn't too happy with the amount of screen space wasted due to
LIST_TYPES.  So I dug into the listing code to make it add that extra
space only for groups that contain at least one file [*] and I also made
it try a bit harder to find an optimal columnation for LIST_PACKED.

If you try it, you'll see that this now behaves slightly different when
completion options with and without groups in menu selection.  In the
first case, only the matches are highlighted, in the latter case the
whole lines are highlighted.  I'm torn in two here, because I like it
that the description is highlighted, too if there is a one-to-one
correspondence between matches and descriptions.  If I get complaints, I
can change it quite easily, though.  But then I'd prefer to find a
solution that makes that more easily usable from shell code (and I'm not
happy that the code that uses such line-oriented dummy matches currently
has to take care of things like the screen width itself), so that we
could use it for, e.g., process listings and the like, too.  I was
thinking about allowing display strings to be defined as `expandable',
meaning that we would like to see as much of the strings as the screen
width permits, but that they may be shortened to make them fit on the
current line of the completion listing.  But that, too, would require
some serious changes to the listing code.  Hm.
 

Bye
  Sven

[*] This does not change it to not add a space to normal files -- the
    thing we discussed some time ago, when comparing it to what GNU ls
    does.

Index: Completion/Base/Utility/_describe
===================================================================
RCS file: /cvsroot/zsh/zsh/Completion/Base/Utility/_describe,v
retrieving revision 1.3
diff -u -r1.3 _describe
--- Completion/Base/Utility/_describe	2001/07/19 08:40:37	1.3
+++ Completion/Base/Utility/_describe	2001/07/25 08:36:54
@@ -2,8 +2,9 @@
 
 # This can be used to add options or values with descriptions as matches.
 
-local _opt _expl _tmps _tmpd _tmph _tmpmd _tmpms _tmpmh
-local _type=values _descr _ret=1 _showd _nm _hide _args _grp
+local _opt _expl _tmpm _tmpd
+local _type=values _descr _ret=1 _showd _nm _hide _args _grp _sep
+local csl="$compstate[list]" csl2
 
 # Get the option.
 
@@ -27,6 +28,7 @@
 
   _argv=( "$@" )
   _grp=(-g)
+  _sep='-- '
   _new=( "$1" )
   shift
 
@@ -66,43 +68,33 @@
   set - "$_argv[@]"
 else
   _grp=()
+  _sep=' -- '
 fi
 
 _descr="$1"
 shift
 
 [[ "$_type" = options ]] &&
-    zstyle -t ":completion:${curcontext}:options" prefix-hidden && _hide=yes
+    zstyle -t ":completion:${curcontext}:options" prefix-hidden &&
+        _hide="${(M)PREFIX##(--|[-+])}"
 
 _tags "$_type"
 while _tags; do
   while _next_label "$_type" _expl "$_descr"; do
 
     if [[ -n "$_showd" ]]; then
-      compdescribe -I ' -- ' "$_grp[@]" "$@"
+      compdescribe -I "$_hide" "$_sep" _expl "$_grp[@]" "$@"
     else
-      compdescribe -i "$@"
+      compdescribe -i "$_hide" "$@"
     fi
 
-    while compdescribe -g _args _tmpd _tmpmd _tmph _tmpmh _tmps _tmpms; do
+    compstate[list]="$csl"
 
-      # See if we should remove the option prefix characters.
+    while compdescribe -g csl2 _args _tmpm _tmpd; do
 
-      if [[ -n "$_hide" ]]; then
-        if [[ "$PREFIX" = --* ]]; then
-          _tmpd=( "${(@)_tmpd#--}" )
-          _tmph=( "${(@)_tmph#--}" )
-          _tmps=( "${(@)_tmps#--}" )
-        elif [[ "$PREFIX" = [-+]* ]]; then
-          _tmpd=( "${(@)_tmpd#[-+]}" )
-          _tmph=( "${(@)_tmph#[-+]}" )
-          _tmps=( "${(@)_tmps#[-+]}" )
-        fi
-      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
+      compstate[list]="$csl $csl2"
+
+      compadd "$_args[@]" -d _tmpd -a _tmpm && _ret=0
     done
   done
   (( _ret )) || return 0
Index: Doc/Zsh/compwid.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/compwid.yo,v
retrieving revision 1.30
diff -u -r1.30 compwid.yo
--- Doc/Zsh/compwid.yo	2001/04/01 16:19:17	1.30
+++ Doc/Zsh/compwid.yo	2001/07/25 08:36:57
@@ -441,6 +441,7 @@
 xitem([ tt(-J) var(name) ] [ tt(-V) var(name) ] [ tt(-X) var(explanation) ] [ tt(-x) var(message) ])
 xitem([ tt(-r) var(remove-chars) ] [ tt(-R) var(remove-func) ])
 xitem([ tt(-D) var(array) ] [ tt(-O) var(array) ] [ tt(-A) var(array) ])
+xitem([ tt(-E) var(number) ])
 item([ tt(-M) var(match-spec) ] [ tt(--) ] [ var(words) ... ])(
 
 This builtin command can be used to add matches directly and control
@@ -663,6 +664,17 @@
 match.  If no string is given, it will be shown as a string containing 
 the strings that would be inserted for the other matches, truncated to 
 the width of the screen.
+)
+item(tt(-E))(
+This option adds var(number) empty matches after the var(words) have
+been added.  An empty match takes up space in completion listings but
+will never be inserted in the line and can't be selected with menu
+completion or menu selection.  This makes empty matches only useful to
+format completion lists and to make explanatory string be shown in
+completion lists (since empty matches can be given display strings
+with the tt(-d) option).  And because all but one empty string would
+otherwise be removed, this option implies the tt(-V) and tt(-1)
+options (even if an explicit tt(-J) option is given).
 )
 xitem(tt(-))
 item(tt(-)tt(-))(
Index: Src/Zle/comp.h
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/comp.h,v
retrieving revision 1.10
diff -u -r1.10 comp.h
--- Src/Zle/comp.h	2001/01/11 10:06:50	1.10
+++ Src/Zle/comp.h	2001/07/25 08:36:58
@@ -85,6 +85,7 @@
 #define CGF_UNIQCON 16		/* remove consecutive duplicates */
 #define CGF_PACKED  32		/* LIST_PACKED for this group */
 #define CGF_ROWS    64		/* LIST_ROWS_FIRST for this group */
+#define CGF_FILES   128		/* contains file names */
 
 /* This is the struct used to hold matches. */
 
@@ -125,6 +126,7 @@
 #define CMF_MULT     (1<<11)	/* string appears more than once */
 #define CMF_FMULT    (1<<12)	/* first of multiple equal strings */
 #define CMF_ALL      (1<<13)	/* a match representing all other matches */
+#define CMF_DUMMY    (1<<14)	/* unselectable dummy match */
 
 /* Stuff for completion matcher control. */
 
@@ -264,6 +266,7 @@
     char *dpar;			/* array to delete non-matches in (-D) */
     char *disp;			/* array with display lists (-d) */
     char *mesg;			/* message to show unconditionally (-x) */
+    int dummies;               /* add that many dummy matches */
 };
 
 /* List data. */
Index: Src/Zle/compcore.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/compcore.c,v
retrieving revision 1.46
diff -u -r1.46 compcore.c
--- Src/Zle/compcore.c	2001/07/10 09:25:43	1.46
+++ Src/Zle/compcore.c	2001/07/25 08:37:12
@@ -1558,6 +1558,40 @@
     return ret;
 }
 
+static void
+addmatch(char *str, int flags, char ***dispp, int line)
+{
+    Cmatch cm = (Cmatch) zhalloc(sizeof(struct cmatch));
+    char **disp = *dispp;
+
+    memset(cm, 0, sizeof(struct cmatch));
+    cm->str = dupstring(str);
+    cm->flags = (flags |
+                 (complist ?
+                  ((strstr(complist, "packed") ? CMF_PACKED : 0) |
+                   (strstr(complist, "rows")   ? CMF_ROWS   : 0)) : 0));
+    if (disp) {
+        if (!*++disp)
+            disp = NULL;
+        if (disp)
+            cm->disp = dupstring(*disp);
+    } else if (line) {
+        cm->disp = dupstring("");
+        cm->flags |= CMF_DISPLINE;
+    }
+    mnum++;
+    ainfo->count++;
+    if (curexpl)
+        curexpl->count++;
+
+    addlinknode(matches, cm);
+
+    newmatches = 1;
+    mgroup->new = 1;
+
+    *dispp = disp;
+}
+
 /* This is used by compadd to add a couple of matches. The arguments are
  * the strings given via options. The last argument is the array with
  * the matches. */
@@ -1583,7 +1617,7 @@
     Brinfo bp, bpl = brbeg, obpl, bsl = brend, obsl;
     Heap oldheap;
 
-    if (!*argv && !(dat->aflags & CAF_ALL)) {
+    if (!*argv && !dat->dummies && !(dat->aflags & CAF_ALL)) {
 	SWITCHHEAPS(oldheap, compheap) {
 	    /* Select the group in which to store the matches. */
 	    gflags = (((dat->aflags & CAF_NOSORT ) ? CGF_NOSORT  : 0) |
@@ -1602,6 +1636,8 @@
 
 	return 1;
     }
+    if (dat->dummies)
+        dat->aflags = dat->aflags | CAF_NOSORT | CAF_UNIQALL;
     for (bp = brbeg; bp; bp = bp->next)
 	bp->curpos = ((dat->aflags & CAF_QUOTE) ? bp->pos : bp->qpos);
     for (bp = brend; bp; bp = bp->next)
@@ -2022,35 +2058,12 @@
 	if (dat->exp)
 	    addexpl();
 	if (!hasallmatch && (dat->aflags & CAF_ALL)) {
-	    Cmatch cm = (Cmatch) zhalloc(sizeof(struct cmatch));
-
-	    memset(cm, 0, sizeof(struct cmatch));
-	    cm->str = dupstring("<all>");
-	    cm->flags = (dat->flags | CMF_ALL |
-			 (complist ?
-			  ((strstr(complist, "packed") ? CMF_PACKED : 0) |
-			   (strstr(complist, "rows")   ? CMF_ROWS   : 0)) : 0));
-	    if (disp) {
-		if (!*++disp)
-		    disp = NULL;
-		if (disp)
-		    cm->disp = dupstring(*disp);
-	    } else {
-		cm->disp = dupstring("");
-		cm->flags |= CMF_DISPLINE;
-	    }
-	    mnum++;
-	    ainfo->count++;
-	    if (curexpl)
-		curexpl->count++;
-
-	    addlinknode(matches, cm);
-
-	    newmatches = 1;
-	    mgroup->new = 1;
-
+            addmatch("<all>", dat->flags | CMF_ALL, &disp, 1);
 	    hasallmatch = 1;
 	}
+        while (dat->dummies--)
+            addmatch("", dat->flags | CMF_DUMMY, &disp, 0);
+
     } SWITCHBACKHEAPS(oldheap);
 
     /* We switched back to the current heap, now restore the stack of
Index: Src/Zle/complete.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/complete.c,v
retrieving revision 1.16
diff -u -r1.16 complete.c
--- Src/Zle/complete.c	2001/05/31 09:44:00	1.16
+++ Src/Zle/complete.c	2001/07/25 08:37:16
@@ -435,6 +435,7 @@
     dat.match = NULL;
     dat.flags = 0;
     dat.aflags = CAF_MATCH;
+    dat.dummies = 0;
 
     for (; *argv && **argv ==  '-'; argv++) {
 	if (!(*argv)[1]) {
@@ -564,6 +565,23 @@
 		break;
 	    case 'l':
 		dat.flags |= CMF_DISPLINE;
+		break;
+	    case 'E':
+                if (p[1]) {
+                    dat.dummies = atoi(p + 1);
+                    p = "" - 1;
+                } else if (argv[1]) {
+                    argv++;
+                    dat.dummies = atoi(*argv);
+                    p = "" - 1;
+                } else {
+                    zwarnnam(name, "number expected after -%c", NULL, *p);
+                    return 1;
+                }
+                if (dat.dummies < 0) {
+                    zwarnnam(name, "invalid number: %d", NULL, dat.dummies);
+                    return 1;
+                }
 		break;
 	    case '-':
 		argv++;
Index: Src/Zle/complist.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/complist.c,v
retrieving revision 1.43
diff -u -r1.43 complist.c
--- Src/Zle/complist.c	2001/07/18 13:10:10	1.43
+++ Src/Zle/complist.c	2001/07/25 08:37:22
@@ -1394,7 +1394,7 @@
 
     mlastm = m->gnum;
     if (m->disp && (m->flags & CMF_DISPLINE)) {
-	if (mselect >= 0) {
+	if (mselect >= 0 && !(m->flags & CMF_DUMMY)) {
 	    int mm = (mcols * ml), i;
 
 	    for (i = mcols; i--; ) {
@@ -1441,7 +1441,7 @@
 	} else
 	    mx = mc * g->width;
 
-	if (mselect >= 0) {
+	if (mselect >= 0 && !(m->flags & CMF_DUMMY)) {
 	    int mm = mcols * ml, i;
 
 	    for (i = (width ? width : mcols); i--; ) {
@@ -1482,7 +1482,7 @@
 	len = niceztrlen(m->disp ? m->disp : m->str);
 	mlprinted = len / columns;
 
-	if (isset(LISTTYPES) && buf) {
+	if ((g->flags & CGF_FILES) && buf) {
 	    if (m->gnum != mselect) {
 		zcoff();
 		zcputs(&mcolors, g->name, COL_TC);
@@ -1684,6 +1684,7 @@
     noselect = 1;
     while ((menuacc &&
 	    !hasbrpsfx(*(minfo.cur), minfo.prebr, minfo.postbr)) ||
+	   ((*minfo.cur)->flags & CMF_DUMMY) ||
 	   (((*minfo.cur)->flags & (CMF_NOLIST | CMF_MULT)) &&
 	    (!(*minfo.cur)->str || !*(*minfo.cur)->str)))
 	do_menucmp(0);
Index: Src/Zle/compresult.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/compresult.c,v
retrieving revision 1.38
diff -u -r1.38 compresult.c
--- Src/Zle/compresult.c	2001/07/18 13:10:10	1.38
+++ Src/Zle/compresult.c	2001/07/25 08:37:30
@@ -1160,6 +1160,7 @@
 	}
     } while ((menuacc &&
 	      !hasbrpsfx(*(minfo.cur), minfo.prebr, minfo.postbr)) ||
+             ((*minfo.cur)->flags & CMF_DUMMY) ||
 	     (((*minfo.cur)->flags & (CMF_NOLIST | CMF_MULT)) &&
 	      (!(*minfo.cur)->str || !*(*minfo.cur)->str)));
     /* ... and insert it into the command line. */
@@ -1183,6 +1184,7 @@
 	    minfo.cur--;
     } while ((menuacc &&
 	      !hasbrpsfx(*(minfo.cur), minfo.prebr, minfo.postbr)) ||
+	     ((*minfo.cur)->flags & CMF_DUMMY) ||
 	     (((*minfo.cur)->flags & (CMF_NOLIST | CMF_MULT)) &&
 	      (!(*minfo.cur)->str || !*(*minfo.cur)->str)));
     metafy_line();
@@ -1378,7 +1380,7 @@
     Cmgroup g;
     Cmatch *p, m;
     Cexpl *e;
-    int hidden = 0, nlist = 0, nlines = 0, add = 2 + isset(LISTTYPES);
+    int hidden = 0, nlist = 0, nlines = 0, add;
     int max = 0, i;
     VARARR(int, mlens, nmatches + 1);
 
@@ -1392,6 +1394,7 @@
     for (g = amatches; g; g = g->next) {
 	char **pp = g->ylist;
 	int nl = 0, l, glong = 1, gshort = columns, ndisp = 0, totl = 0;
+        int hasf = 0;
 
 	g->flags |= CGF_PACKED | CGF_ROWS;
 
@@ -1437,6 +1440,8 @@
 	    }
 	} else if (!onlyexpl) {
 	    for (p = g->matches; (m = *p); p++) {
+                if (m->flags & CMF_FILE)
+                    hasf = 1;
 		if (menuacc && !hasbrpsfx(m, minfo.prebr, minfo.postbr)) {
 		    m->flags |= CMF_HIDE;
 		    continue;
@@ -1496,6 +1501,11 @@
 		e++;
 	    }
 	}
+        if (isset(LISTTYPES) && hasf) {
+            g->flags |= CGF_FILES;
+            add = 3;
+        } else
+            add = 2;
 	g->totl = totl + (ndisp * add);
 	g->dcount = ndisp;
 	g->width = glong + add;
@@ -1513,6 +1523,7 @@
 	int *ws, tlines, tline, tcols, maxlen, nth, width, glines;
 
 	for (g = amatches; g; g = g->next) {
+            add = 2 + !!(g->flags & CGF_FILES);
 	    glines = 0;
 
 	    zfree(g->widths, 0);
@@ -1523,7 +1534,8 @@
 		    if (g->cols) {
 			glines += (arrlen(pp) + g->cols - 1) / g->cols;
 			if (g->cols > 1)
-			    g->width += (max - (g->width * g->cols - add)) / g->cols;
+			    g->width += ((max - (g->width * g->cols - add)) /
+                                         g->cols);
 		    } else {
 			g->cols = 1;
 			g->width = 1;
@@ -1559,6 +1571,8 @@
 	    if (!(g->flags & CGF_PACKED))
 		continue;
 
+            add = 2 + !!(g->flags & CGF_FILES);
+
 	    ws = g->widths = (int *) zalloc(columns * sizeof(int));
 	    memset(ws, 0, columns * sizeof(int));
 	    tlines = g->lins;
@@ -1666,7 +1680,7 @@
 	    } else if (g->width) {
 		if (g->flags & CGF_ROWS) {
 		    int addlen, count, tcol, maxlines = 0, llines, i;
-		    int beg = columns / g->shortest, end = g->cols;
+		    int beg = columns / g->shortest, end = g->cols, fe = 1;
 		    Cmatch *first;
 
 		    while (1) {
@@ -1677,7 +1691,8 @@
 				 count = g->dcount;
 			     count > 0; count--) {
 			    m = *p;
-			    addlen = mlens[m->gnum] + add;
+			    addlen = (mlens[m->gnum] +
+                                      (tcol == tcols - 1 ? 0 : add));
 			    if (addlen > maxlen)
 				maxlen = addlen;
 			    for (i = tcols; i && *p; i--)
@@ -1706,15 +1721,21 @@
 			    break;
 
 			if (beg == end) {
-			    beg--;
-			    end--;
+                            if (fe) {
+                                beg += 2;
+                                end += 2;
+                                fe = 0;
+                            } else {
+                                beg--;
+                                end--;
+                            }
 			} else if (width < columns) {
 			    if ((end = tcols) == beg - 1)
 				end++;
 			} else {
 			    if ((beg = tcols) - 1 == end)
 				end++;
-			}
+                        }
 		    }
 		    if (tcols > g->cols)
 			tlines = maxlines;
@@ -1723,7 +1744,7 @@
 		    int smask = ((showall ? 0 : (CMF_NOLIST | CMF_MULT)) |
 				 CMF_HIDE);
 		    int beg = ((g->totl + columns) / columns);
-		    int end = g->lins;
+		    int end = g->lins, fe = 1;
 
 		    while (1) {
 			tlines = (beg + end) >> 1;
@@ -1755,8 +1776,14 @@
 			    break;
 
 			if (beg == end) {
-			    beg++;
-			    end++;
+                            if (fe) {
+                                beg -= 2;
+                                end -= 2;
+                                fe = 0;
+                            } else {
+                                beg++;
+                                end++;
+                            }
 			} else if (width < columns) {
 			    if ((end = tlines) == beg + 1)
 				end--;
@@ -1783,6 +1810,7 @@
 	    }
 	}
 	for (g = amatches; g; g = g->next) {
+            add = 2 + !!(g->flags & CGF_FILES);
 	    if (g->widths) {
 		int *p, a = (max - g->totl + add) / g->cols;
 
@@ -2152,7 +2180,7 @@
 	nicezputs(m->str, shout);
 	len = niceztrlen(m->str);
 
-	if (isset(LISTTYPES) && buf) {
+	if ((g->flags & CGF_FILES) && buf) {
 	    putc(file_type(buf->st_mode), shout);
 	    len++;
 	}
Index: Src/Zle/computil.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/computil.c,v
retrieving revision 1.66
diff -u -r1.66 computil.c
--- Src/Zle/computil.c	2001/07/20 10:54:38	1.66
+++ Src/Zle/computil.c	2001/07/25 08:37:34
@@ -35,6 +35,7 @@
 
 typedef struct cdset *Cdset;
 typedef struct cdstr *Cdstr;
+typedef struct cdrun *Cdrun;
 
 struct cdstate {
     int showd;			/* != 0 if descriptions should be shown */
@@ -43,6 +44,11 @@
     Cdset sets;			/* the sets of matches */
     int pre;                    /* longest prefix (before description) */
     int suf;                    /* longest suffix (description) */
+    int maxg;                   /* size of largest group */
+    int groups;                 /* number of groups */
+    int descs;                  /* number of non-group matches with desc */
+    int gpre;                   /* prefix length for group display */
+    Cdrun runs;                 /* runs to report to shell code */
 };
 
 struct cdstr {
@@ -50,10 +56,25 @@
     char *str;                  /* the string to display */
     char *desc;                 /* the description or NULL */
     char *match;                /* the match to add */
+    int len;                    /* length of str or match */
     Cdstr other;                /* next string with the same description */
     int kind;                   /* 0: not in a group, 1: the first, 2: other */
+    Cdset set;                  /* the set this string is in */
+    Cdstr run;                  /* next in this run */
 };
 
+struct cdrun {
+    Cdrun next;                 /* ... */
+    int type;                   /* see CRT_* below */
+    Cdstr strs;                 /* strings in this run */
+    int count;                  /* number of strings in this run */
+};
+
+#define CRT_SIMPLE 0
+#define CRT_DESC   1
+#define CRT_SPEC   2
+#define CRT_DUMMY  3
+
 struct cdset {
     Cdset next;			/* guess what */
     char **opts;		/* the compadd-options */
@@ -62,11 +83,6 @@
     int desc;                   /* number of matches with description */
 };
 
-/* Maximum string length when used with descriptions. */
-
-#define CD_MAXLEN 30
-
-
 static struct cdstate cd_state;
 static int cd_parsed = 0;
 
@@ -75,6 +91,7 @@
 {
     Cdset n;
     Cdstr s, sn;
+    Cdrun r, rn;
 
     for (; p; p = n) {
 	n = p->next;
@@ -88,6 +105,10 @@
                 zsfree(s->match);
             zfree(s, sizeof(*s));
         }
+        for (r = cd_state.runs; r; r = rn) {
+            rn = r->next;
+            zfree(r, sizeof(*r));
+        }
 	zfree(p, sizeof(*p));
     }
 }
@@ -99,14 +120,14 @@
 {
     Cdset set1, set2;
     Cdstr str1, str2, *strp;
-    int yep = 0;
-    char *buf;
+    int num;
 
     for (set1 = cd_state.sets; set1; set1 = set1->next) {
         for (str1 = set1->strs; str1; str1 = str1->next) {
             if (!str1->desc || str1->kind != 0)
                 continue;
 
+            num = 1;
             strp = &(str1->other);
 
             for (set2 = set1; set2; set2 = set2->next)
@@ -115,33 +136,18 @@
                     if (str2->desc && !strcmp(str1->desc, str2->desc)) {
                         str1->kind = 1;
                         str2->kind = 2;
-                        zsfree(str2->desc);
-                        str2->desc = ztrdup("|");
+                        num++;
                         *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;
+            if (num > 1)
+                cd_state.groups++;
+            else
+                cd_state.descs++;
 
-            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);
-            }
+            if (num > cd_state.maxg)
+                cd_state.maxg = num;
         }
     }
 }
@@ -170,15 +176,173 @@
                     cd_state.suf = l;
             }
         }
+    }
+}
+
+static int
+cd_sort(const void *a, const void *b)
+{
+    return strcmp((*((Cdstr *) a))->str, (*((Cdstr *) b))->str);
+}
+
+static void
+cd_prep()
+{
+    Cdrun run, *runp;
+    Cdset set;
+    Cdstr str, *strp;
+
+    runp = &(cd_state.runs);
+
+    if (cd_state.groups) {
+        int lines = cd_state.groups + cd_state.descs;
+        VARARR(Cdstr, grps, lines);
+        VARARR(int, wids, cd_state.maxg);
+        Cdstr gs, gp, gn, *gpp;
+        int i, j;
+
+        memset(wids, 0, cd_state.maxg * sizeof(int));
+        strp = grps;
+
+        for (set = cd_state.sets; set; set = set->next)
+            for (str = set->strs; str; str = str->next) {
+                if (str->kind != 1) {
+                    if (!str->kind && str->desc) {
+                        str->other = NULL;
+                        *strp++ = str;
+                    }
+                    continue;
+                }
+                gs = str;
+                gs->kind = 2;
+                gp = str->other;
+                gs->other = NULL;
+                for (; gp; gp = gn) {
+                    gn = gp->other;
+                    gp->other = NULL;
+                    for (gpp = &gs; *gpp && (*gpp)->len > gp->len;
+                         gpp = &((*gpp)->other));
+                    gp->other = *gpp;
+                    *gpp = gp;
+                }
+                for (gp = gs, i = 0; gp; gp = gp->other, i++)
+                    if (gp->len > wids[i])
+                        wids[i] = gp->len;
+
+                *strp++ = gs;
+            }
+
+        qsort(grps, lines, sizeof(Cdstr), cd_sort);
+
+        for (i = lines, strp = grps; i; i--, strp++) {
+            for (j = 0, gs = *strp; gs->other; gs = gs->other, j++) {
+                *runp = run = (Cdrun) zalloc(sizeof(*run));
+                runp = &(run->next);
+                run->type = CRT_SPEC;
+                run->strs = gs;
+                gs->run = NULL;
+                run->count = 1;
+            }
+            *runp = run = (Cdrun) zalloc(sizeof(*run));
+            runp = &(run->next);
+            run->type = CRT_DUMMY + cd_state.maxg - j - 1;
+            run->strs = gs;
+            gs->run = NULL;
+            run->count = 1;
+        }
+        for (set = cd_state.sets; set; set = set->next) {
+            for (i = 0, gs = NULL, gpp = &gs, str = set->strs;
+                 str; str = str->next) {
+                if (str->kind || str->desc)
+                    continue;
+
+                i++;
+                *gpp = str;
+                gpp = &(str->run);
+            }
+            *gpp = NULL;
+            if (i) {
+                *runp = run = (Cdrun) zalloc(sizeof(*run));
+                runp = &(run->next);
+                run->type = CRT_SIMPLE;
+                run->strs = gs;
+                run->count = i;
+            }
+        }
+        cd_state.gpre = 0;
+        for (i = 0; i < cd_state.maxg; i++)
+            cd_state.gpre += wids[i] + 2;
+    } else if (cd_state.showd) {
+        for (set = cd_state.sets; set; set = set->next) {
+            if (set->desc) {
+                *runp = run = (Cdrun) zalloc(sizeof(*run));
+                runp = &(run->next);
+                run->type = CRT_DESC;
+                strp = &(run->strs);
+                for (str = set->strs; str; str = str->next)
+                    if (str->desc) {
+                        *strp = str;
+                        strp = &(str->run);
+                    }
+                *strp = NULL;
+                run->count = set->desc;
+            }
+            if (set->desc != set->count) {
+                *runp = run = (Cdrun) zalloc(sizeof(*run));
+                runp = &(run->next);
+                run->type = CRT_SIMPLE;
+                strp = &(run->strs);
+                for (str = set->strs; str; str = str->next)
+                    if (!str->desc) {
+                        *strp = str;
+                        strp = &(str->run);
+                    }
+                *strp = NULL;
+                run->count = set->count - set->desc;
+            }
+        }
+    } else {
+        for (set = cd_state.sets; set; set = set->next)
+            if (set->count) {
+                *runp = run = (Cdrun) zalloc(sizeof(*run));
+                runp = &(run->next);
+                run->type = CRT_SIMPLE;
+                run->strs = set->strs;
+                for (str = set->strs; str; str = str->next)
+                    str->run = str->next;
+                run->count = set->count;
+            }
     }
-    if (cd_state.pre > CD_MAXLEN)
-        cd_state.pre = CD_MAXLEN;
+    *runp = NULL;
 }
 
+/* Duplicate and concatenate two arrays.  Return the result. */
+
+static char **
+cd_arrcat(char **a, char **b)
+{
+    if (!b)
+        return zarrdup(a);
+    else {
+        char **r = (char **) zalloc((arrlen(a) + arrlen(b) + 1) *
+                                    sizeof(char *));
+        char **p = r;
+
+        for (; *a; a++)
+            *p++ = ztrdup(*a);
+        for (; *b; b++)
+            *p++ = ztrdup(*b);
+
+        *p = NULL;
+
+        return r;
+    }
+}
+
 /* Initialisation. Store and calculate the string and matches and so on. */
 
 static int
-cd_init(char *nam, char *sep, char **args, int disp)
+cd_init(char *nam, char *hide, char *sep, char **opts, char **args, int disp)
 {
     Cdset *setp, set;
     Cdstr *strp, str;
@@ -195,6 +359,7 @@
     cd_state.slen = ztrlen(sep);
     cd_state.sets = NULL;
     cd_state.showd = disp;
+    cd_state.maxg = cd_state.groups = cd_state.descs = 0;
 
     if (*args && !strcmp(*args, "-g")) {
         args++;
@@ -219,6 +384,7 @@
 
             str->kind = 0;
             str->other = NULL;
+            str->set = set;
 
             for (tmp = *ap; *tmp && *tmp != ':'; tmp++)
                 if (*tmp == '\\' && tmp[1])
@@ -230,6 +396,7 @@
                 str->desc = NULL;
             *tmp = '\0';
             str->str = str->match = ztrdup(rembslash(*ap));
+            str->len = strlen(str->str);
         }
         if (str)
             str->next = NULL;
@@ -246,13 +413,23 @@
 
 	    args++;
 	}
+        if (hide && *hide) {
+            for (str = set->strs; str; str = str->next) {
+                if (str->str == str->match)
+                    str->str = ztrdup(str->str);
+                if (hide[1] && str->str[0] == '-' && str->str[1] == '-')
+                    strcpy(str->str, str->str + 2);
+                else if (str->str[0] == '-' || str->str[0] == '+')
+                    strcpy(str->str, str->str + 1);
+            }
+        }
 	for (ap = args; *args &&
 		 (args[0][0] != '-' || args[0][1] != '-' || args[0][2]);
 	     args++);
 
 	tmp = *args;
 	*args = NULL;
-	set->opts = zarrdup(ap);
+	set->opts = cd_arrcat(ap, opts);
 	if ((*args = tmp))
 	    args++;
     }
@@ -260,79 +437,157 @@
         cd_group();
 
     cd_calc();
+    cd_prep();
 
     cd_parsed = 1;
     return 0;
 }
 
+/* Copy an array with one element in reserve (at the beginning). */
+
+static char **
+cd_arrdup(char **a)
+{
+    char **r = (char **) zalloc((arrlen(a) + 2) * sizeof(char *));
+    char **p = r + 1;
+
+    while (*a)
+        *p++ = ztrdup(*a++);
+    *p = NULL;
+
+    return r;
+}
+
 /* Get the next set. */
 
 static int
 cd_get(char **params)
 {
-    Cdset set;
+    Cdrun run;
 
-    if ((set = cd_state.sets)) {
-	char **sd, **sdp, **md, **mdp, **sh, **shp, **mh, **mhp;
-        char **ss, **ssp, **ms, **msp;
+    if ((run = cd_state.runs)) {
         Cdstr str;
-        VARARR(char, buf, cd_state.pre + cd_state.suf + cd_state.slen + 1);
-        char *sufp = NULL, *disp;
+        char **mats, **mp, **dpys, **dp, **opts, *csl = "";
 
-        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);
+        cd_state.runs = run->next;
+
+        switch (run->type) {
+        case CRT_SIMPLE:
+            mats = mp = (char **) zalloc((run->count + 1) * sizeof(char *));
+            dpys = dp = (char **) zalloc((run->count + 1) * sizeof(char *));
+
+            for (str = run->strs; str; str = str->run) {
+                *mp++ = ztrdup(str->match);
+                *dp++ = ztrdup(str->str ? str->str : str->match);
+            }
+            *mp = *dp = NULL;
+            opts = zarrdup(run->strs->set->opts);
+            if (cd_state.groups) {
+                /* We are building a columnised list with dummy matches
+                 * but there are also matches without descriptions.
+                 * Those end up in a different group, so make sure that
+                 * groupd doesn't have an explanation. */
+
+                for (mp = dp = opts; *mp; mp++) {
+                    if (dp[0][0] == '-' && dp[0][1] == 'X') {
+                        if (!dp[0][2] && dp[1])
+                            mp++;
+                    } else
+                        *dp++ = *mp;
                 }
-                if (strlen(disp) >= columns)
-                    disp[columns - 1] = '\0';
+                *dp = NULL;
+            }
+            break;
+
+        case CRT_DESC:
+            {
+                VARARR(char, buf,
+                       cd_state.pre + cd_state.suf + cd_state.slen + 1);
+                char *sufp = NULL;
+
+                memcpy(buf + cd_state.pre, cd_state.sep, cd_state.slen);
+                sufp = buf + cd_state.pre + cd_state.slen;
 
-                if (str->kind == 2) {
-                    *shp++ = disp;
-                    *mhp++ = ztrdup(str->match);
-                } else {
-                    *sdp++ = disp;
-                    *mdp++ = ztrdup(str->match);
+                mats = mp = (char **) zalloc((run->count + 1) * sizeof(char *));
+                dpys = dp = (char **) zalloc((run->count + 1) * sizeof(char *));
+
+                for (str = run->strs; str; str = str->run) {
+                    *mp++ = ztrdup(str->match);
+                    memset(buf, ' ', cd_state.pre);
+                    memcpy(buf, str->str, str->len);
+                    strcpy(sufp, str->desc);
+                    if (strlen(buf) >= columns)
+                        buf[columns] = '\0';
+                    *dp++ = ztrdup(buf);
                 }
-            } else {
-                *ssp++ = ztrdup(str->str);
-                *msp++ = ztrdup(str->match);
-            }
-        }
-        *sdp = *mdp = *shp = *mhp = *ssp = *msp = NULL;
-
-	setaparam(params[0], zarrdup(set->opts));
-	setaparam(params[1], sd);
-	setaparam(params[2], md);
-	setaparam(params[3], sh);
-	setaparam(params[4], mh);
-	setaparam(params[5], ss);
-	setaparam(params[6], ms);
-
-	cd_state.sets = set->next;
-	set->next = NULL;
-	freecdsets(set);
+                *mp = *dp = NULL;
+                opts = cd_arrdup(run->strs->set->opts);
+                opts[0] = ztrdup("-l");
+                break;
+            }
+        case CRT_SPEC:
+            mats = (char **) zalloc(2 * sizeof(char *));
+            dpys = (char **) zalloc(2 * sizeof(char *));
+            mats[0] = ztrdup(run->strs->match);
+            dpys[0] = ztrdup(run->strs->str);
+            mats[1] = dpys[1] = NULL;
+            opts = cd_arrdup(run->strs->set->opts);
+            for (dp = opts + 1; *dp; dp++)
+                if (dp[0][0] == '-' && dp[0][1] == 'J')
+                    break;
+            if (*dp) {
+                char *s = tricat("-1V", "", dp[0] + 2);
+
+                zsfree(*dp);
+                *dp = s;
+
+                memmove(opts, opts + 1,
+                        (arrlen(opts + 1) + 1) * sizeof(char *));
+                
+            } else
+                opts[0] = ztrdup("-1V-default-");
+            csl = "packed rows";
+            break;
+
+        default:
+            {
+                int dlen = columns - cd_state.gpre - cd_state.slen;
+                VARARR(char, dbuf, dlen + cd_state.slen);
+                char buf[20];
+                int i = run->type - CRT_DUMMY;
+
+                sprintf(buf, "-E%d", i + 1);
+
+                mats = (char **) zalloc(2 * sizeof(char *));
+                dpys = (char **) zalloc((3 + i) * sizeof(char *));
+                mats[0] = ztrdup(run->strs->match);
+                dpys[0] = ztrdup(run->strs->str);
+                for (dp = dpys + 1; i; i--, dp++)
+                    *dp = ztrdup("");
+                memset(dbuf + cd_state.slen, ' ', dlen - 1);
+                dbuf[dlen + cd_state.slen - 1] = '\0';
+                strcpy(dbuf, cd_state.sep);
+                memcpy(dbuf + cd_state.slen,
+                       run->strs->desc,
+                       (strlen(run->strs->desc) >= dlen ? dlen - 1 :
+                        strlen(run->strs->desc)));
+                *dp++ = ztrdup(dbuf);
+                mats[1] = *dp = NULL;
+
+                opts = cd_arrdup(run->strs->set->opts);
+                opts[0] = ztrdup(buf);
+
+                csl = "packed rows";
+            }
+        }
+        setsparam(params[0], ztrdup(csl));
+        setaparam(params[1], opts);
+        setaparam(params[2], mats);
+        setaparam(params[3], dpys);
 
-	return 0;
+        zfree(run, sizeof(*run));
+
+        return 0;
     }
     return 1;
 }
@@ -341,6 +596,8 @@
 static int
 bin_compdescribe(char *nam, char **args, char *ops, int func)
 {
+    int n = arrlen(args);
+
     if (incompfunc != 1) {
 	zwarnnam(nam, "can only be called from completion function", NULL, 0);
 	return 1;
@@ -351,15 +608,30 @@
     }
     switch (args[0][1]) {
     case 'i':
-	return cd_init(nam, "", args + 1, 0);
+        if (n < 2) {
+            zwarnnam(nam, "not enough arguments", NULL, 0);
+
+            return 1;
+        }
+	return cd_init(nam, args[1], "", NULL, args + 2, 0);
     case 'I':
-	return cd_init(nam, args[1], args + 2, 1);
+        if (n < 5) {
+            zwarnnam(nam, "not enough arguments", NULL, 0);
+
+            return 1;
+        } else {
+            char **opts;
+
+            if (!(opts = getaparam(args[3]))) {
+		zwarnnam(nam, "unknown parameter: %s", args[2], 0);
+		return 1;
+            }
+            return cd_init(nam, args[1], args[2], opts, args + 4, 1);
+        }
     case 'g':
 	if (cd_parsed) {
-	    int n = arrlen(args);
-
-	    if (n != 8) {
-		zwarnnam(nam, (n < 8 ? "not enough arguments" :
+	    if (n != 5) {
+		zwarnnam(nam, (n < 5 ? "not enough arguments" :
 			      "too many arguments"), NULL, 0);
 		return 1;
 	    }

-- 
Sven Wischnowsky                         wischnow@xxxxxxxxxxxxxxxxxxxxxxx



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