zsh-workers
 help / color / mirror / code / Atom feed
From: "Bart Schaefer" <schaefer@candle.brasslantern.com>
To: zsh-workers@sunsite.auc.dk
Subject: PATCH: %<...< and %{...%}
Date: Wed, 1 Mar 2000 00:34:52 +0000	[thread overview]
Message-ID: <1000301003452.ZM28876@candle.brasslantern.com> (raw)

Here's the fix (?) for the bug Tanaka reported.  It takes the approach of
preserving ALL "invisble" substrings, even if that means that the visible
stuff in between them becomes empty.  It inserts the replacement (that's
the `...' in $<...<) as far left as is reasonable, even when truncating
on the right.  E.g., given

PS1=$'[%20>..>%/]%{\e[33m%} %%'

when e.g. PWD=/usr/local/src/zsh/zsh-3.1.6 you should see

[/usr/local/src/zsh..
                     ^with a yellow cursor here.  Thus the truncation was
first applied to the visible text and then the remaining invisible part of
the prompt was inserted; the remaining visible part beyond the invisible
bit was omitted.  If instead PWD=/usr/local you should see

[/usr/local] %
            ^with yellow beginning right here.

The messiest bit was getting right-side-truncation working (well, left-
side started out messier until I gave up on being clever and just shoved
the whole string over and back, but ...).  I'm still not certain that I
have nul-terminated everything properly, so someone should check this.

Index: Src/prompt.c
===================================================================
@@ -684,7 +684,8 @@
 
 /* Count height etc. of a prompt string returned by promptexpand(). *
  * This depends on the current terminal width, and tabs and         *
- * newlines require nontrivial processing.                          */
+ * newlines require nontrivial processing.                          *
+ * Passing `overf' as -1 means to ignore columns (absolute width).  */
 
 /**/
 mod_export void
@@ -693,7 +694,7 @@
     int w = 0, h = 1;
     int s = 1;
     for(; *str; str++) {
-	if(w >= columns) {
+	if(w >= columns && overf >= 0) {
 	    w = 0;
 	    h++;
 	}
@@ -715,7 +716,7 @@
 		w++;
 	}
     }
-    if(w >= columns) {
+    if(w >= columns && overf >= 0) {
 	if (!overf || w > columns) {
 	    w = 0;
 	    h++;
@@ -734,6 +735,7 @@
     if (arg) {
 	char ch = *fm, *ptr = bp, *truncstr;
 	int truncatleft = ch == '<';
+	int w;
 
 	/*
 	 * If there is already a truncation active, return so that
@@ -768,7 +770,8 @@
 	fm++;
 	putpromptchar(doprint, endchar);
 	*bp = '\0';
-	if (bp - ptr > trunclen) {
+	countprompt(ptr, &w, 0, -1);
+	if (w > trunclen) {
 	    /*
 	     * We need to truncate.  t points to the truncation string -- *
 	     * which is inserted literally, without nice representation.  *
@@ -780,23 +783,82 @@
 	    char *t = truncstr;
 	    int fullen = bp - ptr;
 	    int tlen = ztrlen(t), maxlen;
-	    if (tlen > fullen) {
-		addbufspc(tlen - fullen);
-		bp += tlen - fullen;
-	    } else
-		bp -= fullen - trunclen;
 	    maxlen = tlen < trunclen ? trunclen - tlen : 0;
-	    if (truncatleft) {
-		if (maxlen)
-		    memmove(ptr + strlen(t), ptr + fullen - maxlen,
-			    maxlen);
-		while (*t)
-		    *ptr++ = *t++;
+	    if (w < fullen) {
+		/* Invisible substrings, lots of shuffling. */
+		int n = strlen(t);
+		addbufspc(n);
+
+		if (truncatleft) {
+		    char *p = ptr + n, *q = p;
+
+		    n = fullen - w;
+
+		    /* Shift the whole string right, then *
+		     * selectively copy to the left.      */
+		    memmove(p, ptr, fullen);
+		    while (w > 0 || n > 0) {
+			if (*p == Inpar)
+			    do {
+				*q++ = *p;
+				--n;
+			    } while (*p++ != Outpar && *p && n);
+			else if (w) {
+			    if (--w < maxlen)
+				*q++ = *p;
+			    ++p;
+			}
+		    }
+		    bp = q;
+		} else {
+		    /* Truncate on the right, selectively */
+		    char *q = ptr + fullen;
+
+		    /* First skip over as much as will "fit". */
+		    while (w > 0 && maxlen > 0) {
+			if (*ptr == Inpar)
+			    while (*ptr++ != Outpar && *ptr) {;}
+			else
+			    ++ptr, --w, --maxlen;
+		    }
+		    if (ptr < q) {
+			/* We didn't reach the end of the string. *
+			 * In case there are more invisible bits, *
+			 * insert the truncstr and keep looking.  */
+			memmove(ptr + n, ptr, q - ptr);
+			q = ptr + n;
+			while (*t)
+			    *ptr++ = *t++;
+			while (*q) {
+			    if (*q == Inpar)
+				do {
+				    *ptr++ = *q;
+				} while (*q++ != Outpar && *q);
+			    else
+				++q;
+			}
+			bp = ptr;
+			*bp = 0;
+		    } else
+			bp = ptr + n;
+		}
 	    } else {
-		ptr += maxlen;
-		while (*t)
-		    *ptr++ = *t++;
+		/* No invisible substrings. */
+		if (tlen > fullen) {
+		    addbufspc(tlen - fullen);
+		    bp += tlen - fullen;
+		} else
+		    bp -= fullen - trunclen;
+		if (truncatleft) {
+		    if (maxlen)
+			memmove(ptr + strlen(t), ptr + fullen - maxlen,
+				maxlen);
+		} else
+		    ptr += maxlen;
 	    }
+	    /* Finally, copy the truncstr into place. */
+	    while (*t)
+		*ptr++ = *t++;
 	}
 	zsfree(truncstr);
 	trunclen = 0;

-- 
Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com


                 reply	other threads:[~2000-03-01  0:35 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

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=1000301003452.ZM28876@candle.brasslantern.com \
    --to=schaefer@candle.brasslantern.com \
    --cc=zsh-workers@sunsite.auc.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).