about summary refs log tree commit diff
path: root/Src/Zle/computil.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Zle/computil.c')
-rw-r--r--Src/Zle/computil.c323
1 files changed, 206 insertions, 117 deletions
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;
 	    }