about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTanaka Akira <akr@users.sourceforge.net>1999-12-02 14:05:59 +0000
committerTanaka Akira <akr@users.sourceforge.net>1999-12-02 14:05:59 +0000
commit158204bce06cc89519fe99dc38f76f2251bbaea3 (patch)
tree74ae714eeab01fa58e5895229f2ffc13bbb3bc02
parent7f7497c531841c7fa53bfa2618c7d5592abddfda (diff)
downloadzsh-158204bce06cc89519fe99dc38f76f2251bbaea3.tar.gz
zsh-158204bce06cc89519fe99dc38f76f2251bbaea3.tar.xz
zsh-158204bce06cc89519fe99dc38f76f2251bbaea3.zip
zsh-workers/8852
-rw-r--r--Doc/Zsh/mod_complist.yo15
-rw-r--r--Src/Zle/complist.c189
-rw-r--r--Src/pattern.c40
3 files changed, 218 insertions, 26 deletions
diff --git a/Doc/Zsh/mod_complist.yo b/Doc/Zsh/mod_complist.yo
index 54211674c..02ae210c5 100644
--- a/Doc/Zsh/mod_complist.yo
+++ b/Doc/Zsh/mod_complist.yo
@@ -78,11 +78,24 @@ Apart from these strings, the var(name) may also be an asterisk
 string will be used for all files whose name ends with the string.
 The var(name) may also be a equal sign (`tt(=)') followed by a
 pattern. The var(value) given for this pattern will be used for all
-matches (not only filenames) that whose display string are matched by
+matches (not only filenames) whose display string are matched by
 the pattern. Definitions for both of these take precedence over the
 values defined for file types and the form with the leading asterisk 
 takes precedence over the form with the leading equal sign.
 
+The last form also allows to color separate parts of the displayed
+strings using different colors. For this, the pattern has to use the
+`tt((#b))' globbing flag and pairs of parentheses surrounding the
+parts of the strings that are to be colored differently. In this case 
+the var(value) may consist of more than one color code separated by
+equal signs. The first code will be used for all parts for which no
+explicit code is specified and the following codes will be used for
+the parts matched by the sub-patterns in parentheses. For example,
+the specification `tt(=(#b)(?)*(?)=0=3=7)' will be used for all
+matches which are at least two characters long and will make the use
+the code `tt(3)' for the first character, `tt(7)' for the last
+character and `tt(0)' for the rest.
+
 All three forms of var(name) may be preceded by a pattern in
 parentheses. If such a pattern is given, the var(value) will be used
 only for matches in groups whose names are matched by the pattern
diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c
index 1f8cd0fa7..0d88cdc5c 100644
--- a/Src/Zle/complist.c
+++ b/Src/Zle/complist.c
@@ -60,6 +60,10 @@ static Keymap mskeymap;
 
 #define NUM_COLS 16
 
+/* Maximum number of in-string colours supported. */
+
+#define MAX_POS 11
+
 /* Names of the terminal strings. */
 
 static char *colnames[] = {
@@ -91,7 +95,7 @@ typedef struct patcol *Patcol;
 struct patcol {
     Patprog prog;
     Patprog pat;		/* pattern for match */
-    char *col;
+    char *cols[MAX_POS + 1];
     Patcol next;
 };
 
@@ -120,11 +124,11 @@ struct listcols {
  * The return value is a pointer to the character after it. */
 
 static char *
-getcolval(char *s)
+getcolval(char *s, int multi)
 {
     char *p;
 
-    for (p = s; *s && *s != ':'; p++, s++) {
+    for (p = s; *s && *s != ':' && (!multi || *s != '='); p++, s++) {
 	if (*s == '\\' && s[1]) {
 	    switch (*++s) {
 	    case 'a': *p = '\007'; break;
@@ -212,7 +216,7 @@ getcoldef(Listcols c, char *s)
 	if (!*s)
 	    return s;
 	*s++ = '\0';
-	p = getcolval(s);
+	p = getcolval(s, 0);
 	ec = (Extcol) zhalloc(sizeof(*ec));
 	ec->prog = gprog;
 	ec->ext = n;
@@ -228,7 +232,8 @@ getcoldef(Listcols c, char *s)
 	    *p++ = '\0';
 	return p;
     } else if (*s == '=') {
-	char *p = ++s, *t;
+	char *p = ++s, *t, *cols[MAX_POS];
+	int ncols = 0;
 	Patprog prog;
 
 	/* This is for a pattern. */
@@ -238,15 +243,26 @@ getcoldef(Listcols c, char *s)
 	if (!*s)
 	    return s;
 	*s++ = '\0';
-	t = getcolval(s);
+	while (1) {
+	    t = getcolval(s, 1);
+	    if (ncols < MAX_POS)
+		cols[ncols++] = s;
+	    s = t;
+	    if (*s != '=')
+		break;
+	    *s++ = '\0';
+	}
 	tokenize(p);
 	if ((prog = patcompile(p, 0, NULL))) {
 	    Patcol pc, po;
+	    int i;
 
 	    pc = (Patcol) zhalloc(sizeof(*pc));
 	    pc->prog = gprog;
 	    pc->pat = prog;
-	    pc->col = s;
+	    for (i = 0; i < ncols; i++)
+		pc->cols[i] = cols[i];
+	    pc->cols[i] = NULL;
 	    pc->next = NULL;
 	    if ((po = c->pats)) {
 		while (po->next)
@@ -272,7 +288,7 @@ getcoldef(Listcols c, char *s)
 	for (i = 0, nn = colnames; *nn; i++, nn++)
 	    if (!strcmp(n, *nn))
 		break;
-	p = getcolval(s);
+	p = getcolval(s, 0);
 	if (*nn) {
 	    Filecol fc, fo;
 
@@ -369,6 +385,14 @@ static Cmatch **mtab, **mmtabp;
 static Cmgroup *mgtab, *mgtabp;
 static struct listcols mcolors;
 
+/* Information for in-string colours. */
+
+static int nrefs;
+static int begpos[MAX_POS], curisbeg;
+static int endpos[MAX_POS], curisend;
+static char **patcols, *curiscols[MAX_POS];
+static int curiscol;
+
 /* The last color used. */
 
 static char *last_cap;
@@ -414,28 +438,131 @@ zcoff(void)
 	zcputs(&mcolors, NULL, COL_NO);
 }
 
-/* Get the terminal color string for the given match. */
 
 static void
+initiscol(Listcols c)
+{
+    int i;
+
+    zlrputs(c, patcols[0]);
+
+    curiscols[curiscol = 0] = *patcols++;
+
+    curisbeg = curisend = 0;
+
+    for (i = nrefs;  i < MAX_POS; i++)
+	begpos[i] = -1, endpos[i] = 0xfffffff;
+}
+
+static void
+doiscol(Listcols c, int pos)
+{
+    if (pos > endpos[curisend]) {
+	curisend++;
+	if (curiscol) {
+	    zcputs(c, NULL, COL_NO);
+	    zlrputs(c, curiscols[--curiscol]);
+	}
+    }
+    if (pos == begpos[curisbeg] && *patcols) {
+	curisbeg++;
+
+	zcputs(c, NULL, COL_NO);
+	zlrputs(c, *patcols);
+
+	curiscols[++curiscol] = *patcols++;
+    }
+}
+
+/* Stripped-down version of printfmt(). But can do in-string colouring. */
+
+static void
+clprintfmt(Listcols c, char *p)
+{
+    int cc = 0, i = 0;
+
+    initiscol(c);
+
+    for (; *p; p++) {
+	doiscol(c, i++);
+	cc++;
+	if (*p == '\n') {
+	    if (tccan(TCCLEAREOL))
+		tcout(TCCLEAREOL);
+	    else {
+		int s = columns - 1 - (cc % columns);
+
+		while (s-- > 0)
+		    putc(' ', shout);
+	    }
+	    cc = 0;
+	}
+	putc(*p, shout);
+    }
+    if (tccan(TCCLEAREOL))
+	tcout(TCCLEAREOL);
+    else {
+	int s = columns - 1 - (cc % columns);
+
+	while (s-- > 0)
+	    putc(' ', shout);
+    }
+}
+
+/* Local version of nicezputs() with in-string colouring. */
+
+static void
+clnicezputs(Listcols c, char *s)
+{
+    int cc, i = 0;
+
+    initiscol(c);
+
+    while ((cc = *s++)) {
+	doiscol(c, i++);
+	if (itok(cc)) {
+	    if (cc <= Comma)
+		cc = ztokens[cc - Pound];
+	    else 
+		continue;
+	}
+	if (cc == Meta)
+	    cc = *s++ ^ 32;
+	fputs(nicechar(cc), shout);
+    }
+}
+
+/* Get the terminal color string for the given match. */
+
+static int
 putmatchcol(Listcols c, char *group, char *n)
 {
     Patcol pc;
 
+    nrefs = MAX_POS - 1;
+
     for (pc = c->pats; pc; pc = pc->next)
 	if ((!pc->prog || !group || pattry(pc->prog, group)) &&
-	    pattry(pc->pat, n)) {
-	    zlrputs(c, pc->col);
+	    pattryrefs(pc->pat, n, &nrefs, begpos, endpos)) {
+	    if (pc->cols[1]) {
+		patcols = pc->cols;
 
-	    return;
+		return 1;
+	    }
+	    zlrputs(c, pc->cols[0]);
+
+	    return 0;
 	}
 
     zcputs(c, group, COL_NO);
+
+    return 0;
 }
 
 /* Get the terminal color string for the file with the given name and
  * file modes. */
 
-static void
+static int
 putfilecol(Listcols c, char *group, char *n, mode_t m)
 {
     int colour;
@@ -447,14 +574,22 @@ putfilecol(Listcols c, char *group, char *n, mode_t m)
 	    (!ec->prog || !group || pattry(ec->prog, group))) {
 	    zlrputs(c, ec->col);
 
-	    return;
+	    return 0;
 	}
+
+    nrefs = MAX_POS - 1;
+
     for (pc = c->pats; pc; pc = pc->next)
 	if ((!pc->prog || !group || pattry(pc->prog, group)) &&
-	    pattry(pc->pat, n)) {
-	    zlrputs(c, pc->col);
+	    pattryrefs(pc->pat, n, &nrefs, begpos, endpos)) {
+	    if (pc->cols[1]) {
+		patcols = pc->cols;
 
-	    return;
+		return 1;
+	    }
+	    zlrputs(c, pc->cols[0]);
+
+	    return 0;
 	}
 
     if (S_ISDIR(m))
@@ -475,6 +610,8 @@ putfilecol(Listcols c, char *group, char *n, mode_t m)
 	colour = COL_FI;
 
     zcputs(c, group, colour);
+
+    return 0;
 }
 
 static void
@@ -482,7 +619,7 @@ clprintm(Cmgroup g, Cmatch *mp, int mc, int ml, int lastc, int width,
 	 char *path, struct stat *buf)
 {
     Cmatch m;
-    int len;
+    int len, subcols = 0;
 
     if (!mp) {
 	zcputs(&mcolors, g->name, COL_MI);
@@ -511,8 +648,11 @@ clprintm(Cmgroup g, Cmatch *mp, int mc, int ml, int lastc, int width,
 	    mmlen = mcols;
 	    zcputs(&mcolors, g->name, COL_MA);
 	} else
-	    putmatchcol(&mcolors, g->name, m->disp);
-	printfmt(m->disp, 0, 1, 0);
+	    subcols = putmatchcol(&mcolors, g->name, m->disp);
+	if (subcols)
+	    clprintfmt(&mcolors, m->disp);
+	else
+	    printfmt(m->disp, 0, 1, 0);
 	zcoff();
     } else {
 	int mx;
@@ -543,11 +683,14 @@ clprintm(Cmgroup g, Cmatch *mp, int mc, int ml, int lastc, int width,
 	    mmlen = width;
 	    zcputs(&mcolors, g->name, COL_MA);
 	} else if (buf)
-	    putfilecol(&mcolors, g->name, path, buf->st_mode);
+	    subcols = putfilecol(&mcolors, g->name, path, buf->st_mode);
 	else
-	    putmatchcol(&mcolors, g->name, (m->disp ? m->disp : m->str));
+	    subcols = putmatchcol(&mcolors, g->name, (m->disp ? m->disp : m->str));
 
-	nicezputs((m->disp ? m->disp : m->str), shout);
+	if (subcols)
+	    clnicezputs(&mcolors, (m->disp ? m->disp : m->str));
+	else
+	    nicezputs((m->disp ? m->disp : m->str), shout);
 	len = niceztrlen(m->disp ? m->disp : m->str);
 
 	 if (isset(LISTTYPES) && buf) {
diff --git a/Src/pattern.c b/Src/pattern.c
index 35e11161b..7d77a94da 100644
--- a/Src/pattern.c
+++ b/Src/pattern.c
@@ -1283,10 +1283,25 @@ pattrystart(void)
 mod_export int
 pattry(Patprog prog, char *string)
 {
-    int i;
+    return pattryrefs(prog, string, NULL, NULL, NULL);
+}
+
+/* The last three arguments are used to report the positions for the
+ * backreferences. On entry, *nump should contain the maximum number
+ * positions to report. */
+
+/**/
+mod_export int
+pattryrefs(Patprog prog, char *string, int *nump, int *begp, int *endp)
+{
+    int i, maxnpos;
     char **sp, **ep;
     char *progstr = (char *)prog + prog->startoff;
 
+    if (nump) {
+	maxnpos = *nump;
+	*nump = 0;
+    }
     /* inherited from domatch, but why, exactly? */
     if (*string == Nularg)
 	string++;
@@ -1350,7 +1365,28 @@ pattry(Patprog prog, char *string)
 		setiparam("MEND",
 			  (zlong)(mlen + patoffset + !isset(KSHARRAYS) - 1));
 	    }
-	    if (prog->patnpar && !(patflags & PAT_FILE)) {
+	    if (prog->patnpar && nump) {
+		/*
+		 * b flag: for backreferences using parentheses. Reported
+		 * directly.
+		 */
+		*nump = prog->patnpar;
+
+		sp = patbeginp;
+		ep = patendp;
+
+		for (i = 0; i < prog->patnpar && i < maxnpos; i++) {
+		    DPUTS(!*sp || !*ep, "BUG: backrefs not set.");
+
+		    if (begp)
+			*begp++ = ztrsub(*sp, patinstart) + patoffset;
+		    if (endp)
+			*endp++ = ztrsub(*ep, patinstart) + patoffset - 1;
+
+		    sp++;
+		    ep++;
+		}
+	    } else if (prog->patnpar && !(patflags & PAT_FILE)) {
 		/*
 		 * b flag: for backreferences using parentheses.
 		 */