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

PATCH: groups in ZLS_COLOURS (and questions)



Step by step...


This allows to make specs in ZLS_COLO(|U)RS work only in certain
groups. For now I've taken the syntax `(group-pat)<spec>', i.e. a pattern 
for the group name(s) has to be given at the beginning in parentheses.

Another enhancement is that one can also give pattern-specs that will
be used for all matches (not only files, but also files). The syntax
for that is now `=<pat>=<color-code>'.

Of course, the syntax for both of them can easily be changed if you
don't like it.


What this patch doesn't do is make this configurable with styles.
That's because I'm not sure how to do that best. What I would like to
achieve is that one could do, e.g.:

  compstyle '*:jobs' list-colors <specs...>

which would make the completion code use these patterns only for
groups named `jobs'. Building appropriate specs for ZLS_* is
simple. But there are three problems I see:

1) Where to do it. I think I would put this in a helper function that
can would be called from _description (and from _files because that
has to mess around with the group names).

2) How to merge different definitions. Most of the things we could do
before affected only file names but there were already some specs that 
have to take affect everywhere (the lc, rc, ec capabilities, for
example). With the per-group specs above the user would either have to
include the definitions for these things (and other specs he wants to
have used everywhere) in every value for list-colors or we make the
completion code look up such default specs at some central place
(e.g. _main_complete) and the special specs are then appended to that
when then groups are added. The problem is that I don't know if that
nice enough, maybe if we use a tag `default' (or `global'?) for that:

  compstyle '*:default' list-colors lc=... rc=...
  compstyle '*:jobs' list-colors ...

Would that be ok? Btw, when we do this with styles we could also use
more descriptive names for the capabilities and a nicer syntax for the 
extension (`*.foo=<color>') and pattern (`=<pat>=<color>') specs. I
would then probably try to get some help from computil for this.

3) When and how to set ZLS_*. The completion system would have to
set/change the value of one of these. But what if a user has set it
already? Is it enough to document that one shouldn't set it directly
when using the new completion system? And document that one can use:

  compstyle '*(files|directories)' list-colors ${(s.:.)LS_COLORS}

(or put it into the `default' list-colors style) to include the stuff
one uses for GNU ls?

The same question is important when we try to support things like
menu-selection via styles, btw, so I'd really like to hear your
opinions and suggestions here.


One last comment about this colouring: I guess with this per-group and 
pattern matching stuff going on somebody will ask if it wouldn't be
possible to highlight different line-parts of, say, a process listing
differently (e.g. pids in red cmd-line in blue or whatever).
This is something even I may like so I'm thinking about it. One step
would be to enhance the pattern matching code to directly report
backreferences in integer arrays (so that we don't have to set/use the 
match arrays). Doesn't look to hairy. Being able to print different
parts of a string in different colours is more difficult. complist
would have to implement its own versions of printfmt() and
nicezputs(). Hm. But still, looks like something I could like to play
with...


Bye
 Sven

diff -u oldsrc/Zle/compcore.c Src/Zle/compcore.c
--- oldsrc/Zle/compcore.c	Thu Dec  2 10:16:19 1999
+++ Src/Zle/compcore.c	Thu Dec  2 09:30:23 1999
@@ -445,9 +445,8 @@
     /* We may have to reset the cursor to its position after the   *
      * string inserted by the last completion. */
 
-    if (fromcomp & FC_INWORD)
-	if ((cs = lastend) > ll)
-	    cs = ll;
+    if ((fromcomp & FC_INWORD) && (cs = lastend) > ll)
+	cs = ll;
 
     /* Check if we have to start a menu-completion (via automenu). */
 
@@ -2512,6 +2511,7 @@
 	n->mcount = g->mcount;
 	n->matches = p = (Cmatch *) ncalloc((n->mcount + 1) *
 					    sizeof(Cmatch));
+	n->name = ztrdup(g->name);
 	for (q = g->matches; *q; q++, p++)
 	    *p = dupmatch(*q, nbrbeg, nbrend);
 	*p = NULL;
@@ -2609,6 +2609,7 @@
 	    }
 	    free(g->expls);
 	}
+	zsfree(g->name);
 	free(g);
 
 	g = n;
diff -u oldsrc/Zle/complist.c Src/Zle/complist.c
--- oldsrc/Zle/complist.c	Thu Dec  2 10:16:19 1999
+++ Src/Zle/complist.c	Thu Dec  2 11:05:27 1999
@@ -74,11 +74,33 @@
     "\033[", "m", NULL, "0", "0", "7"
 };
 
+/* This describes a terminal string for a file type. */
+
+typedef struct filecol *Filecol;
+
+struct filecol {
+    Patprog prog;		/* group pattern */
+    char *col;			/* color string */
+    Filecol next;		/* next one */
+};
+
+/* This describes a terminal string for a pattern. */
+
+typedef struct patcol *Patcol;
+
+struct patcol {
+    Patprog prog;
+    Patprog pat;		/* pattern for match */
+    char *col;
+    Patcol next;
+};
+
 /* This describes a terminal string for a filename extension. */
 
 typedef struct extcol *Extcol;
 
 struct extcol {
+    Patprog prog;		/* group pattern or NULL */
     char *ext;			/* the extension */
     char *col;			/* the terminal color string */
     Extcol next;		/* the next one in the list */
@@ -89,7 +111,8 @@
 typedef struct listcols *Listcols;
 
 struct listcols {
-    char *cols[NUM_COLS];	/* strings for file types */
+    Filecol files[NUM_COLS];	/* strings for file types */
+    Patcol pats;		/* strings for patterns */
     Extcol exts;		/* strings for extensions */
 };
 
@@ -152,8 +175,33 @@
 static char *
 getcoldef(Listcols c, char *s)
 {
+    Patprog gprog = NULL;
+
+    if (*s == '(') {
+	char *p;
+	int l = 0;
+
+	for (p = s + 1, l = 0; *p && (*p != ')' || l); p++)
+	    if (*p == '\\' && p[1])
+		p++;
+	    else if (*p == '(')
+		l++;
+	    else if (*p == ')')
+		l--;
+
+	if (*p == ')') {
+	    char sav = p[1];
+
+	    p[1] = '\0';
+	    tokenize(s);
+	    gprog = patcompile(s, 0, NULL);
+	    p[1]  =sav;
+
+	    s = p + 1;
+	}
+    }
     if (*s == '*') {
-	Extcol ec;
+	Extcol ec, eo;
 	char *n, *p;
 
 	/* This is for an extension. */
@@ -166,13 +214,50 @@
 	*s++ = '\0';
 	p = getcolval(s);
 	ec = (Extcol) zhalloc(sizeof(*ec));
+	ec->prog = gprog;
 	ec->ext = n;
 	ec->col = s;
-	ec->next = c->exts;
-	c->exts = ec;
+	ec->next = NULL;
+	if ((eo = c->exts)) {
+	    while (eo->next)
+		eo = eo->next;
+	    eo->next = ec;
+	} else
+	    c->exts = ec;
 	if (*p)
 	    *p++ = '\0';
 	return p;
+    } else if (*s == '=') {
+	char *p = ++s, *t;
+	Patprog prog;
+
+	/* This is for a pattern. */
+
+	while (*s && *s != '=')
+	    s++;
+	if (!*s)
+	    return s;
+	*s++ = '\0';
+	t = getcolval(s);
+	tokenize(p);
+	if ((prog = patcompile(p, 0, NULL))) {
+	    Patcol pc, po;
+
+	    pc = (Patcol) zhalloc(sizeof(*pc));
+	    pc->prog = gprog;
+	    pc->pat = prog;
+	    pc->col = s;
+	    pc->next = NULL;
+	    if ((po = c->pats)) {
+		while (po->next)
+		    po = po->next;
+		po->next = pc;
+	    } else
+		c->pats = pc;
+	}
+	if (*t)
+	    *t++ = '\0';
+	return t;
     } else {
 	char *n = s, *p, **nn;
 	int i;
@@ -185,17 +270,43 @@
 	    return s;
 	*s++ = '\0';
 	for (i = 0, nn = colnames; *nn; i++, nn++)
-	    if (!strcmp(n ,*nn))
+	    if (!strcmp(n, *nn))
 		break;
 	p = getcolval(s);
-	if (*nn)
-	    c->cols[i] = s;
+	if (*nn) {
+	    Filecol fc, fo;
+
+	    fc = (Filecol) zhalloc(sizeof(*fc));
+	    fc->prog = (i == COL_EC || i == COL_LC || i == COL_RC ?
+			NULL : gprog);
+	    fc->col = s;
+	    fc->next = NULL;
+	    if ((fo = c->files[i])) {
+		while (fo->next)
+		    fo = fo->next;
+		fo->next = fc;
+	    } else
+		c->files[i] = fc;
+	}
 	if (*p)
 	    *p++ = '\0';
 	return p;
     }
 }
 
+static Filecol
+filecol(char *col)
+{
+    Filecol fc;
+
+    fc = (Filecol) zhalloc(sizeof(*fc));
+    fc->prog = NULL;
+    fc->col = col;
+    fc->next = NULL;
+
+    return fc;
+}
+
 /* Combined length of LC and RC, maximum length of capability strings. */
 
 static int lr_caplen, max_caplen;
@@ -211,17 +322,18 @@
     if (!(s = getsparam("ZLS_COLORS")) &&
 	!(s = getsparam("ZLS_COLOURS"))) {
 	for (i = 0; i < NUM_COLS; i++)
-	    c->cols[i] = "";
+	    c->files[i] = filecol("");
+	c->pats = NULL;
 	c->exts = NULL;
 	
-	if (!(c->cols[COL_MA] = tcstr[TCSTANDOUTBEG]) ||
-	    !c->cols[COL_MA][0])
-	    c->cols[COL_MA] = "";
-	else
-	    c->cols[COL_EC] = tcstr[TCSTANDOUTEND];
+	if ((s = tcstr[TCSTANDOUTBEG]) && s[0]) {
+	    c->files[COL_MA] = filecol(s);
+	    c->files[COL_EC] = filecol(tcstr[TCSTANDOUTEND]);
+	} else
+	    c->files[COL_MA] = filecol("");
 	lr_caplen = 0;
-	if ((max_caplen = strlen(c->cols[COL_MA])) <
-	    (l = strlen(c->cols[COL_EC])))
+	if ((max_caplen = strlen(c->files[COL_MA]->col)) <
+	    (l = strlen(c->files[COL_EC]->col)))
 	    max_caplen = l;
 	return;
     }
@@ -234,16 +346,17 @@
     /* Use default values for those that aren't set explicitly. */
     max_caplen = lr_caplen = 0;
     for (i = 0; i < NUM_COLS; i++) {
-	if (!c->cols[i])
-	    c->cols[i] = defcols[i];
-	if (c->cols[i] && (l = strlen(c->cols[i])) > max_caplen)
+	if (!c->files[i] || !c->files[i]->col)
+	    c->files[i] = filecol(defcols[i]);
+	if (c->files[i] && c->files[i]->col &&
+	    (l = strlen(c->files[i]->col)) > max_caplen)
 	    max_caplen = l;
     }
-    lr_caplen = strlen(c->cols[COL_LC]) + strlen(c->cols[COL_RC]);
+    lr_caplen = strlen(c->files[COL_LC]->col) + strlen(c->files[COL_RC]->col);
 
     /* Default for missing files. */
-    if (!c->cols[COL_MI])
-	c->cols[COL_MI] = c->cols[COL_FI];
+    if (!c->files[COL_MI] || !c->files[COL_MI]->col)
+	c->files[COL_MI] = c->files[COL_FI];
 
     return;
 }
@@ -258,30 +371,36 @@
 
 /* The last color used. */
 
-static int last_col = COL_NO;
+static char *last_cap;
 
 static void
 zlrputs(Listcols c, char *cap)
 {
-    VARARR(char, buf, lr_caplen + max_caplen + 1);
+    if (strcmp(last_cap, cap)) {
+	VARARR(char, buf, lr_caplen + max_caplen + 1);
 
-    strcpy(buf, c->cols[COL_LC]);
-    strcat(buf, cap);
-    strcat(buf, c->cols[COL_RC]);
+	strcpy(buf, c->files[COL_LC]->col);
+	strcat(buf, cap);
+	strcat(buf, c->files[COL_RC]->col);
 
-    tputs(buf, 1, putshout);
+	tputs(buf, 1, putshout);
+
+	strcpy(last_cap, cap);
+    }
 }
 
 static void
-zcputs(Listcols c, int colour)
+zcputs(Listcols c, char *group, int colour)
 {
-    if (colour != last_col
-	&& (last_col < COL_NO
-	    || strcmp(c->cols[last_col], c->cols[colour]))) {
-	zlrputs(c, c->cols[colour]);
-	last_col = colour;
-    }
-    return;
+    Filecol fc;
+
+    for (fc = c->files[colour]; fc; fc = fc->next)
+	if (fc->col &&
+	    (!fc->prog || !group || pattry(fc->prog, group))) {
+	    zlrputs(c, fc->col);
+
+	    return;
+	}
 }
 
 /* Turn off colouring. */
@@ -289,28 +408,52 @@
 static void
 zcoff(void)
 {
-    if (mcolors.cols[COL_EC])
-	tputs(mcolors.cols[COL_EC], 1, putshout);
+    if (mcolors.files[COL_EC] && mcolors.files[COL_EC]->col)
+	tputs(mcolors.files[COL_EC]->col, 1, putshout);
     else
-	zcputs(&mcolors, COL_NO);
+	zcputs(&mcolors, NULL, COL_NO);
+}
+
+/* Get the terminal color string for the given match. */
+
+static void
+putmatchcol(Listcols c, char *group, char *n)
+{
+    Patcol pc;
+
+    for (pc = c->pats; pc; pc = pc->next)
+	if ((!pc->prog || !group || pattry(pc->prog, group)) &&
+	    pattry(pc->pat, n)) {
+	    zlrputs(c, pc->col);
+
+	    return;
+	}
+
+    zcputs(c, group, COL_NO);
 }
 
 /* Get the terminal color string for the file with the given name and
  * file modes. */
 
 static void
-putcolstr(Listcols c, char *n, mode_t m)
+putfilecol(Listcols c, char *group, char *n, mode_t m)
 {
     int colour;
-    Extcol e;
+    Extcol ec;
+    Patcol pc;
+
+    for (ec = c->exts; ec; ec = ec->next)
+	if (strsfx(ec->ext, n) &&
+	    (!ec->prog || !group || pattry(ec->prog, group))) {
+	    zlrputs(c, ec->col);
 
-    for (e = c->exts; e; e = e->next)
-	if (strsfx(e->ext, n)) {	/* XXX: unoptimised if used */
-	    if (last_col < COL_NO
-		|| strcmp(c->cols[last_col], e->col))
-		zlrputs(c, e->col);
+	    return;
+	}
+    for (pc = c->pats; pc; pc = pc->next)
+	if ((!pc->prog || !group || pattry(pc->prog, group)) &&
+	    pattry(pc->pat, n)) {
+	    zlrputs(c, pc->col);
 
-	    last_col = COL_NO - 1;
 	    return;
 	}
 
@@ -331,8 +474,7 @@
     else
 	colour = COL_FI;
 
-    zcputs(c, colour);
-    return;
+    zcputs(c, group, colour);
 }
 
 static void
@@ -340,10 +482,10 @@
 	 char *path, struct stat *buf)
 {
     Cmatch m;
-    int len, cc;
+    int len;
 
     if (!mp) {
-	zcputs(&mcolors, COL_MI);
+	zcputs(&mcolors, g->name, COL_MI);
 	len = width - 2;
 	while (len-- > 0)
 	    putc(' ', shout);
@@ -367,10 +509,9 @@
 	    mmtabp = mtab + mm;
 	    mgtabp = mgtab + mm;
 	    mmlen = mcols;
-	    cc = COL_MA;
+	    zcputs(&mcolors, g->name, COL_MA);
 	} else
-	    cc = COL_NO;
-	zcputs(&mcolors, cc);
+	    putmatchcol(&mcolors, g->name, m->disp);
 	printfmt(m->disp, 0, 1, 0);
 	zcoff();
     } else {
@@ -400,11 +541,11 @@
 	    mmtabp = mtab + mx + mm;
 	    mgtabp = mgtab + mx + mm;
 	    mmlen = width;
-	    zcputs(&mcolors, COL_MA);
+	    zcputs(&mcolors, g->name, COL_MA);
 	} else if (buf)
-	    putcolstr(&mcolors, path, buf->st_mode);
+	    putfilecol(&mcolors, g->name, path, buf->st_mode);
 	else
-	    zcputs(&mcolors, COL_NO);
+	    putmatchcol(&mcolors, g->name, (m->disp ? m->disp : m->str));
 
 	nicezputs((m->disp ? m->disp : m->str), shout);
 	len = niceztrlen(m->disp ? m->disp : m->str);
@@ -412,7 +553,7 @@
 	 if (isset(LISTTYPES) && buf) {
 	    if (m->gnum != mselect) {
 		zcoff();
-		zcputs(&mcolors, COL_TC);
+		zcputs(&mcolors, g->name, COL_TC);
 	    }
 	    putc(file_type(buf->st_mode), shout);
 	    len++;
@@ -420,14 +561,14 @@
 	if ((len = width - len - 2) > 0) {
 	    if (m->gnum != mselect) {
 		zcoff();
-		zcputs(&mcolors, COL_SP);
+		zcputs(&mcolors, g->name, COL_SP);
 	    }
 	    while (len-- > 0)
 		putc(' ', shout);
 	}
 	zcoff();
 	if (!lastc) {
-	    zcputs(&mcolors, COL_NO);
+	    zcputs(&mcolors, g->name, COL_NO);
 	    fputs("  ", shout);
 	    zcoff();
 	}
@@ -483,7 +624,8 @@
 	mcols = columns;
 	mlines = listdat.nlines;
     }
-    last_col = COL_NO - 1;
+    last_cap = (char *) zhalloc(max_caplen + 1);
+    *last_cap = '\0';
 
     if (!printlist(1, clprintm) || listdat.nlines >= lines)
 	noselect = 1;
diff -u olddoc/Zsh/mod_complist.yo Doc/Zsh/mod_complist.yo
--- olddoc/Zsh/mod_complist.yo	Wed Dec  1 16:02:57 1999
+++ Doc/Zsh/mod_complist.yo	Thu Dec  2 09:48:43 1999
@@ -76,6 +76,24 @@
 Apart from these strings, the var(name) may also be an asterisk
 (`tt(*)') followed by any string. The var(value) given for such a
 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
+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.
+
+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
+given in the parentheses. E.g. `tt((g*)~m*=43)' says to highlight all
+matches beginning with `tt(m)' in groups whose names  begin with
+`tt(g)' using the color code `tt(43)'. In case of the `tt(lc)',
+`tt(rc)', and `tt(ec)' codes, the group pattern is ignored.
+
+Note also that all patterns are tried in the order in which they
+appear in the parameter value until the first one matches which is
+then used.
 
 When printing a match, the code prints the value of tt(lc), the value
 for the file-type or the last matching specification with a `tt(*)',

--
Sven Wischnowsky                         wischnow@xxxxxxxxxxxxxxxxxxxxxxx



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