zsh-workers
 help / color / mirror / code / Atom feed
From: Peter Stephenson <pws@csr.com>
To: zsh-workers@sunsite.dk (Zsh hackers list)
Subject: Re: PATCH: random attribute stuff
Date: Tue, 6 May 2008 19:16:11 +0100	[thread overview]
Message-ID: <20080506191611.79fdf69a@news01> (raw)
In-Reply-To: <200805061548.m46Fmq2X013524@news01.csr.com>

On Tue, 06 May 2008 16:48:52 +0100
Peter Stephenson <pws@csr.com> wrote:
> Bart Schaefer wrote:
> > } It ought to be (but might turn out not to be) fairly easy to add a
> > } "default" element to zle_highlight that causes the given attributes to
> > } be used as the default set for the command line, which would probably
> > } work a lot better, and then deprecate any reliance on what the prompt
> > } happened to produce.
> > 
> > Sounds reasonable to me, but could get ugly if a widget were to change
> > it on the fly -- do you trap that and reprint the entire buffer, or do
> > you allow blotches of different attributes as areas are selectively
> > repainted, or do you make that setting read-only in widgets?
> 
> It's likely to be implement in zle_refresh.c, so the answer is probably
> that it changes at the next refresh, which I think ought to work OK.

I'm sending it in quite a hurry since I discovered there's a nasty
allocation problem: moveto() can be called by trashzle() outside
zrefresh(), in which case the buffer for colour sequences isn't allocated.
So if you have turn an attribute off to output raw newlines, say, then
you're in trouble.  Showed up with the patch because you're still
highlighting at the end of the text (which means I haven't tried hard
enough to find the point at which it needs to turn attributes off) but was
there since I added the configuration for colour sequences.

Most likely remaining problem is that I haven't tracked down some
optimisation which is likely to leave you with a blotchy display with the
default highlighting.

Index: Doc/Zsh/zle.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/zle.yo,v
retrieving revision 1.68
diff -u -r1.68 zle.yo
--- Doc/Zsh/zle.yo	1 May 2008 11:33:03 -0000	1.68
+++ Doc/Zsh/zle.yo	6 May 2008 18:11:56 -0000
@@ -2097,6 +2097,10 @@
 startitem()
 cindex(region, highlighting)
 cindex(highlighting, region)
+item(tt(default))(
+Any text within the command line not affected by any other highlighting.
+Text outside the editable area of the command line is not affected.
+)
 item(tt(isearch))(
 When one of the incremental history search widgets is active, the
 area of the command line matched by the search string or pattern.
Index: Src/Zle/zle_refresh.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/zle_refresh.c,v
retrieving revision 1.66
diff -u -r1.66 zle_refresh.c
--- Src/Zle/zle_refresh.c	6 May 2008 09:23:08 -0000	1.66
+++ Src/Zle/zle_refresh.c	6 May 2008 18:11:57 -0000
@@ -203,11 +203,12 @@
 
 
 /*
- * Attributes used for highlighting special (unprintable) characters
+ * Attributes used by default on the command line, and
+ * attributes for highlighting special (unprintable) characters
  * displayed on screen.
  */
 
-static int special_atr_on;
+static int default_atr_on, special_atr_on;
 
 /* Flags for the region_highlight structure */
 enum {
@@ -503,6 +504,31 @@
 }
 
 
+/* Allocate buffer for colour code composition */
+
+static void
+set_colseq_buf(void)
+{
+    int lenfg, lenbg, len;
+
+    lenfg = strlen(fg_bg_sequences[COL_SEQ_FG].def);
+    /* always need 1 character for non-default code */
+    if (lenfg < 1)
+	lenfg = 1;
+    lenfg += strlen(fg_bg_sequences[COL_SEQ_FG].start) +
+	strlen(fg_bg_sequences[COL_SEQ_FG].end);
+
+    lenbg = strlen(fg_bg_sequences[COL_SEQ_BG].def);
+    /* always need 1 character for non-default code */
+    if (lenbg < 1)
+	lenbg = 1;
+    lenbg += strlen(fg_bg_sequences[COL_SEQ_BG].start) +
+	strlen(fg_bg_sequences[COL_SEQ_BG].end);
+
+    len = lenfg > lenbg ? lenfg : lenbg;
+    colseq_buf = (char *)zalloc(len+1);
+}
+
 /*
  * Parse the variable zle_highlight to decide how to highlight characters
  * and regions.  Set defaults for anything not explicitly covered.
@@ -516,30 +542,30 @@
     int special_atr_on_set = 0;
     int region_atr_on_set = 0;
     int isearch_atr_on_set = 0;
-    int lenfg, lenbg, len;
     struct region_highlight *rhp;
 
-    special_atr_on = 0;
+    special_atr_on = default_atr_on = 0;
     if (!region_highlights) {
 	region_highlights = (struct region_highlight *)
 	    zshcalloc(N_SPECIAL_HIGHLIGHTS*sizeof(struct region_highlight));
 	n_region_highlights = N_SPECIAL_HIGHLIGHTS;
     } else {
-	region_highlights->atr = 0;
+	for (rhp = region_highlights;
+	     rhp < region_highlights + N_SPECIAL_HIGHLIGHTS;
+	     rhp++) {
+	    rhp->atr = 0;
+	}
     }
 
     if (atrs) {
 	for (; *atrs; atrs++) {
 	    if (!strcmp(*atrs, "none")) {
 		/* reset attributes for consistency... usually unnecessary */
-		special_atr_on = 0;
+		special_atr_on = default_atr_on = 0;
 		special_atr_on_set = region_atr_on_set =
 		    isearch_atr_on_set = 1;
-		for (rhp = region_highlights;
-		     rhp < region_highlights + N_SPECIAL_HIGHLIGHTS;
-		     rhp++) {
-		    rhp->atr = 0;
-		}
+	    } else if (strpfx("default:", *atrs)) {
+		match_highlight(*atrs + 8, &default_atr_on);
 	    } else if (strpfx("special:", *atrs)) {
 		match_highlight(*atrs + 8, &special_atr_on);
 		special_atr_on_set = 1;
@@ -573,23 +599,7 @@
     if (!isearch_atr_on_set)
 	region_highlights[1].atr = TXTUNDERLINE;
 
-    /* Allocate buffer for colour code composition */
-    lenfg = strlen(fg_bg_sequences[COL_SEQ_FG].def);
-    /* always need 1 character for non-default code */
-    if (lenfg < 1)
-	lenfg = 1;
-    lenfg += strlen(fg_bg_sequences[COL_SEQ_FG].start) +
-	strlen(fg_bg_sequences[COL_SEQ_FG].end);
-
-    lenbg = strlen(fg_bg_sequences[COL_SEQ_BG].def);
-    /* always need 1 character for non-default code */
-    if (lenbg < 1)
-	lenbg = 1;
-    lenbg += strlen(fg_bg_sequences[COL_SEQ_BG].start) +
-	strlen(fg_bg_sequences[COL_SEQ_BG].end);
-
-    len = lenfg > lenbg ? lenfg : lenbg;
-    colseq_buf = (char *)zalloc(len+1);
+    set_colseq_buf();
 }
 
 
@@ -597,8 +607,10 @@
 static void
 zle_free_highlight(void)
 {
+    DPUTS(!colseq_buf, "Freeing colour sequence buffer without alloc");
     /* Free buffer for colour code composition */
     free(colseq_buf);
+    colseq_buf = NULL;
 }
 
 /*
@@ -615,63 +627,59 @@
 {
     int arrsize = n_region_highlights;
     char **retarr, **arrp;
+    struct region_highlight *rhp;
 
     /* region_highlights may not have been set yet */
-    if (!arrsize)
-	arrsize = N_SPECIAL_HIGHLIGHTS;
-    arrp = retarr = (char **)zhalloc(arrsize*sizeof(char *));
-    /* ignore NULL termination */
-    arrsize--;
-    if (arrsize) {
-	struct region_highlight *rhp;
-
-	/* ignore special highlighting */
-	for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS;
-	     arrsize--;
-	     rhp++, arrp++) {
-	    char digbuf1[DIGBUFSIZE], digbuf2[DIGBUFSIZE];
-	    int atrlen = 0, alloclen, done1;
-	    const struct highlight *hp;
+    if (arrsize)
+	arrsize -= N_SPECIAL_HIGHLIGHTS;
+    arrp = retarr = (char **)zhalloc((arrsize+1)*sizeof(char *));
 
-	    sprintf(digbuf1, "%d", rhp->start);
-	    sprintf(digbuf2, "%d", rhp->end);
-
-	    for (hp = highlights; hp->name; hp++) {
+    /* ignore special highlighting */
+    for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS;
+	 arrsize--;
+	 rhp++, arrp++) {
+	char digbuf1[DIGBUFSIZE], digbuf2[DIGBUFSIZE];
+	int atrlen = 0, alloclen, done1;
+	const struct highlight *hp;
+
+	sprintf(digbuf1, "%d", rhp->start);
+	sprintf(digbuf2, "%d", rhp->end);
+
+	for (hp = highlights; hp->name; hp++) {
+	    if (hp->mask_on & rhp->atr) {
+		if (atrlen)
+		    atrlen++; /* comma */
+		atrlen += strlen(hp->name);
+	    }
+	}
+	if (atrlen == 0)
+	    atrlen = 4; /* none */
+	alloclen = atrlen + strlen(digbuf1) + strlen(digbuf2) +
+	    3; /* 2 spaces, 1 0 */
+	if (rhp->flags & ZRH_PREDISPLAY)
+	    alloclen += 2; /* "P " */
+	*arrp = (char *)zhalloc(alloclen * sizeof(char));
+	/*
+	 * On input we allow a space after the flags.
+	 * I haven't put a space here because I think it's
+	 * marginally easier to have the output always split
+	 * into three words, and then check the first to
+	 * see if there are flags.  However, it's arguable.
+	 */
+	sprintf(*arrp, "%s%s %s ",
+		(rhp->flags & ZRH_PREDISPLAY) ? "P" : "",
+		digbuf1, digbuf2);
+	if (atrlen) {
+	    for (hp = highlights, done1 = 0; hp->name; hp++) {
 		if (hp->mask_on & rhp->atr) {
-		    if (atrlen)
-			atrlen++; /* comma */
-		    atrlen += strlen(hp->name);
+		    if (done1)
+			strcat(*arrp, ",");
+		    strcat(*arrp, hp->name);
+		    done1 = 1;
 		}
 	    }
-	    if (atrlen == 0)
-		atrlen = 4; /* none */
-	    alloclen = atrlen + strlen(digbuf1) + strlen(digbuf2) +
-		3; /* 2 spaces, 1 0 */
-	    if (rhp->flags & ZRH_PREDISPLAY)
-		alloclen += 2; /* "P " */
-	    *arrp = (char *)zhalloc(alloclen * sizeof(char));
-	    /*
-	     * On input we allow a space after the flags.
-	     * I haven't put a space here because I think it's
-	     * marginally easier to have the output always split
-	     * into three words, and then check the first to
-	     * see if there are flags.  However, it's arguable.
-	     */
-	    sprintf(*arrp, "%s%s %s ", 
-		    (rhp->flags & ZRH_PREDISPLAY) ? "P" : "",
-		    digbuf1, digbuf2);
-	    if (atrlen) {
-		for (hp = highlights, done1 = 0; hp->name; hp++) {
-		    if (hp->mask_on & rhp->atr) {
-			if (done1)
-			    strcat(*arrp, ",");
-			strcat(*arrp, hp->name);
-			done1 = 1;
-		    }
-		}
-	    } else
-		strcat(*arrp, "none");
-	}
+	} else
+	    strcat(*arrp, "none");
     }
     *arrp = '\0';
     return retarr;
@@ -748,6 +756,34 @@
 }
 
 
+/* The last attributes that were on. */
+static int lastatr;
+
+/*
+ * Clear the last attributes that we set:  used when we're going
+ * to be outputting stuff that shouldn't show up as text.
+ */
+static void
+clearattributes(void)
+{
+    if (lastatr) {
+	settextattributes(TXT_ATTR_OFF_FROM_ON(lastatr));
+	lastatr = 0;
+    }
+}
+
+/*
+ * Output a termcap capability, clearing any text attributes so
+ * as not to mess up the display.
+ */
+
+static void
+tcoutclear(int cap)
+{
+    clearattributes();
+    tcout(cap);
+}
+
 /*
  * Output the character.  This must come from the new video
  * buffer, nbuf, since we access the multiword buffer nmwbuf
@@ -767,7 +803,6 @@
      * This differs from *curatrp, which is an optimisation for
      * writing lots of stuff at once.
      */
-    static int lastatr;
 #ifdef MULTIBYTE_SUPPORT
     mbstate_t mbstate;
     int i;
@@ -1093,6 +1128,12 @@
 		   int use_termcap)
 {
     char *ptr;
+    int do_free;
+
+    if ((do_free = (colseq_buf == NULL))) {
+	/* This can happen when moving the cursor in trashzle() */
+	set_colseq_buf();
+    }
     /*
      * If we're not restoring the default, and either have a
      * colour value that is too large for ANSI, or have been told
@@ -1122,6 +1163,11 @@
 	*ptr++ = colour + '0';
     strcpy(ptr, fg_bg_sequences[fg_bg].end);
     tputs(colseq_buf, 1, putshout);
+
+    if (do_free) {
+	free(colseq_buf);
+	colseq_buf = NULL;
+    }
 }
 
 /**/
@@ -1310,7 +1356,7 @@
 
 	    nbuf[vln] = obuf[vln];
 	    moveto(nlnct, 0);
-	    tcout(TCCLEAREOD);
+	    tcoutclear(TCCLEAREOD);
 	    moveto(ovln, ovcs);
 	    nbuf[vln] = nb;
 	} else {
@@ -1370,7 +1416,7 @@
 
         if (!clearflag) {
             if (tccan(TCCLEAREOD))
-                tcout(TCCLEAREOD);
+                tcoutclear(TCCLEAREOD);
             else
                 cleareol = 1;   /* request: clear to end of line */
 	    if (listshown > 0)
@@ -1429,7 +1475,7 @@
     rpms.s = nbuf[rpms.ln = 0] + lpromptw;
     rpms.sen = *nbuf + winw;
     for (t = tmpline, tmppos = 0; tmppos < tmpll; t++, tmppos++) {
-	int base_atr_on = 0, base_atr_off = 0, ireg;
+	int base_atr_on = default_atr_on, base_atr_off = 0, ireg;
 	int all_atr_on, all_atr_off;
 	struct region_highlight *rhp;
 	/*
@@ -1445,9 +1491,10 @@
 		offset = predisplaylen; /* increment over it */
 	    if (rhp->start + offset <= tmppos &&
 		tmppos < rhp->end + offset) {
-		if (base_atr_on & (TXTFGCOLOUR|TXTBGCOLOUR)) {
-		    /* keep colour already set */
-		    base_atr_on |= rhp->atr & ~TXT_ATTR_COLOUR_ON_MASK;
+		if (rhp->atr & (TXTFGCOLOUR|TXTBGCOLOUR)) {
+		    /* override colour with later entry */
+		    base_atr_on = (base_atr_on & ~TXT_ATTR_ON_VALUES_MASK) |
+			rhp->atr;
 		} else {
 		    /* no colour set yet */
 		    base_atr_on |= rhp->atr;
@@ -2021,7 +2068,7 @@
     if (cleareol && !nllen && !(hasam && ln < nlnct - 1)
 	&& tccan(TCCLEAREOL)) {
 	moveto(ln, 0);
-	tcout(TCCLEAREOL);
+	tcoutclear(TCCLEAREOL);
 	return;	
     }
 
@@ -2161,7 +2208,7 @@
 
 	    /* if we can finish quickly, do so */
 	    if ((col_cleareol >= 0) && (ccs >= col_cleareol)) {
-		tcout(TCCLEAREOL);
+		tcoutclear(TCCLEAREOL);
 		return;
 	    }
 
@@ -2195,7 +2242,7 @@
 		zwrite(nl, i);
 		vcs += i;
 		if (col_cleareol >= 0)
-		    tcout(TCCLEAREOL);
+		    tcoutclear(TCCLEAREOL);
 		return;
 	    }
 
@@ -2505,7 +2552,7 @@
 mod_export int
 clearscreen(UNUSED(char **args))
 {
-    tcout(TCCLEARSCREEN);
+    tcoutclear(TCCLEARSCREEN);
     resetneeded = 1;
     clearflag = 0;
     return 0;
@@ -2823,7 +2870,7 @@
 	}
 	if (!vp->chr) {
 	    if (tccan(TCCLEAREOL))
-		tcout(TCCLEAREOL);
+		tcoutclear(TCCLEAREOL);
 	    else
 		for (; refreshop++->chr; vcs++)
 		    zputc(&zr_sp);



-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR PLC, Churchill House, Cambridge Business Park, Cowley Road
Cambridge, CB4 0WZ, UK                          Tel: +44 (0)1223 692070


  reply	other threads:[~2008-05-06 18:16 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-05-06  9:15 Peter Stephenson
2008-05-06 14:34 ` Bart Schaefer
2008-05-06 14:42   ` Peter Stephenson
2008-05-06 14:58     ` Bart Schaefer
2008-05-06 15:10       ` Peter Stephenson
2008-05-06 15:38         ` Bart Schaefer
2008-05-06 15:48           ` Peter Stephenson
2008-05-06 18:16             ` Peter Stephenson [this message]
2008-05-07 15:44               ` Oliver Kiddle
2008-05-07 15:49               ` Oliver Kiddle
2008-05-07 15:55                 ` Peter Stephenson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080506191611.79fdf69a@news01 \
    --to=pws@csr.com \
    --cc=zsh-workers@sunsite.dk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).