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

PATCH: 3.1.5: prompt truncation behaviour



"Bart Schaefer" wrote:
> PS1='%78>
> %m[%h] >%(0_.%/ %m[%h] .)'

Here's another possible implementation of truncation.  It's more
natural in that the whole string following the truncation code can be
truncated, either up to the end of the string, or to the next
truncation code (ignoring things in %( patterns which can however have
their own nested truncation behaviour), or the end of a %( group.

There are two caveats.  First, it's a bit incompatible with the old
behaviour.  For example, with '%10>...>%~%# ', only the %~ would have
been truncated, while now the '% ' or '# ' will be included and you
have to say explicitly '%10>...>%~%>>%# '.  This change could be
enough for us to receive death threats.  Second, the truncation string
itself is still not expanded, since I don't think that's what it's
for.

You attention is also drawn to the rewritten section on quoting the
delimiters.  I haven't altered the behaviour.  The point is that, when
you're using print -P, one set of \'s is removed for ordinary `print'
quoting, so you need to double them.  If you're using double quotes,
you need to double them again.

% print -P '%10<\\<<%~'
<3.1.5/Doc

The code is now more localised and so a bit more compact.

*** Doc/Zsh/prompt.yo.trunc	Mon Nov  9 14:59:11 1998
--- Doc/Zsh/prompt.yo	Wed Nov 11 09:49:04 1998
***************
*** 187,211 ****
  xitem(tt(%<)var(string)tt(<))
  xitem(tt(%>)var(string)tt(>))
  item(tt(%[)var(xstring)tt(]))(
! Specifies truncation behaviour.
  The third, deprecated, form is equivalent to `tt(%)var(xstringx)',
  i.e. var(x) may be `tt(<)' or `tt(>)'.
  The numeric argument, which in the third form may appear immediately
  after the `tt([)', specifies the maximum permitted length of
! the various strings that can be displayed in the prompt.  If this
! integer is zero, or missing, truncation is disabled.  Truncation is
! initially disabled.
  The var(string) will be displayed in
! place of the truncated portion of any string.
  
  The forms with `tt(<)' truncate at the left of the string,
  and the forms with `tt(>)' truncate at the right of the string.
  For example, if the current directory is `tt(/home/pike)',
  the prompt `tt(%8<..<%/)' will expand to `tt(..e/pike)'.
  In this string, the terminating character (`tt(<)', `tt(>)' or `tt(])'),
! or in fact any character, may be quoted by a preceding `tt(\)'.
! % escapes are em(not) recognised.
  If the var(string) is longer than the specified truncation length,
  it will appear in full, completely replacing the truncated string.
  )
  enditem()
--- 187,226 ----
  xitem(tt(%<)var(string)tt(<))
  xitem(tt(%>)var(string)tt(>))
  item(tt(%[)var(xstring)tt(]))(
! Specifies truncation behaviour for the remainder of the prompt string.
  The third, deprecated, form is equivalent to `tt(%)var(xstringx)',
  i.e. var(x) may be `tt(<)' or `tt(>)'.
  The numeric argument, which in the third form may appear immediately
  after the `tt([)', specifies the maximum permitted length of
! the various strings that can be displayed in the prompt.
  The var(string) will be displayed in
! place of the truncated portion of any string; note this does not
! undergo prompt expansion.
  
  The forms with `tt(<)' truncate at the left of the string,
  and the forms with `tt(>)' truncate at the right of the string.
  For example, if the current directory is `tt(/home/pike)',
  the prompt `tt(%8<..<%/)' will expand to `tt(..e/pike)'.
  In this string, the terminating character (`tt(<)', `tt(>)' or `tt(])'),
! or in fact any character, may be quoted by a preceding `tt(\)'; note
! when using tt(print -P), however, that this must be doubled as the
! string is also subject to standard tt(print) processing, in addition
! to any backslashes removed by a double quoted string:  the worst case
! is therefore `tt(print -P "%<\\\\<<...")'.
! 
  If the var(string) is longer than the specified truncation length,
  it will appear in full, completely replacing the truncated string.
+ 
+ The part of the prompt string to be truncated runs to the end of the
+ string, or to the end of the next enclosing group of the `tt(%LPAR())'
+ construct, or to the next truncation encountered at the same grouping
+ level (i.e. truncations inside a `tt(%LPAR())' are separate), which
+ ever comes first.  In particular, a truncation with argument zero
+ (e.g. `tt(%<<)') marks the end of the range of the string to be
+ truncated while turning off truncation from there on. For example, the
+ prompt '%10<...<%~%<<%# ' will print a truncated representation of the
+ current directory, followed by a `tt(%)' or `tt(#)', followed by a
+ space.  Without the `tt(%<<)', those two characters would be included
+ in the string to be truncated.
  )
  enditem()
*** Src/prompt.c.trunc	Tue Nov 10 14:14:09 1998
--- Src/prompt.c	Wed Nov 11 17:04:38 1998
***************
*** 85,95 ****
  
  static char *fm;
  
! /* Current truncation string (metafied), the length at which truncation *
!  * occurs, and the direction in which it occurs.                        */
  
! static char *truncstr;
! static int trunclen, truncatleft;
  
  /* Current level of nesting of %{ / %} sequences. */
  
--- 85,93 ----
  
  static char *fm;
  
! /* Non-zero if truncating the current segment of the buffer. */
  
! static int trunclen;
  
  /* Current level of nesting of %{ / %} sequences. */
  
***************
*** 172,178 ****
  		arg = zstrtol(fm, &fm, 10);
  	    }
  	    if (*fm == '(') {
! 		int tc;
  
  		if (idigit(*++fm)) {
  		    arg = zstrtol(fm, &fm, 10);
--- 170,176 ----
  		arg = zstrtol(fm, &fm, 10);
  	    }
  	    if (*fm == '(') {
! 		int tc, otrunclen;
  
  		if (idigit(*++fm)) {
  		    arg = zstrtol(fm, &fm, 10);
***************
*** 263,272 ****
--- 261,275 ----
  		if (!*fm || !(sep = *++fm))
  		    return 0;
  		fm++;
+ 		/* Don't do the current truncation until we get back */
+ 		otrunclen = trunclen;
+ 		trunclen = 0;
  		if (!putpromptchar(test == 1 && doprint, sep) || !*++fm ||
  		    !putpromptchar(test == 0 && doprint, ')')) {
+ 		    trunclen = otrunclen;
  		    return 0;
  		}
+ 		trunclen = otrunclen;
  		continue;
  	    }
  	    if (!doprint)
***************
*** 391,453 ****
  		tsetcap(TCUNDERLINEEND, 1);
  		break;
  	    case '[':
!                 if (idigit(*++fm))
!                     trunclen = zstrtol(fm, &fm, 10);
!                 else
!                     trunclen = arg;
!                 if (trunclen) {
! 		    truncatleft = *fm && *fm != ']' && *fm++ == '<';
! 		    bp1 = bp;
! 		    while (*fm && *fm != ']') {
! 			if (*fm == '\\' && fm[1])
! 			    ++fm;
! 			addbufspc(1);
! 			*bp++ = *fm++;
! 		    }
! 		    addbufspc(2);
! 		    if (bp1 == bp)
! 			*bp++ = '<';
!                     *bp = '\0';
! 		    zsfree(truncstr);
!                     truncstr = ztrdup(bp = bp1);
! 		    bp1 = NULL;
!                 } else {
! 		    while (*fm && *fm != ']') {
! 			if (*fm == '\\' && fm[1])
! 			    fm++;
! 			fm++;
! 		    }
! 		}
! 		if(!*fm)
! 		    return 0;
  		break;
  	    case '<':
  	    case '>':
! 		if((trunclen = arg)) {
! 		    char ch = *fm++;
! 		    truncatleft = ch == '<';
! 		    bp1 = bp;
! 		    while (*fm && *fm != ch) {
! 			if (*fm == '\\' && fm[1])
! 			    ++fm;
! 			addbufspc(1);
! 			*bp++ = *fm++;
! 		    }
! 		    addbufspc(1);
!                     *bp = '\0';
! 		    zsfree(truncstr);
!                     truncstr = ztrdup(bp = bp1);
! 		    bp1 = NULL;
! 		} else {
! 		    char ch = *fm++;
! 		    while(*fm && *fm != ch) {
! 			if (*fm == '\\' && fm[1])
! 			    fm++;
! 			fm++;
! 		    }
! 		}
! 		if(!*fm)
! 		    return 0;
  		break;
  	    case '{': /*}*/
  		if (!dontcount++) {
--- 394,408 ----
  		tsetcap(TCUNDERLINEEND, 1);
  		break;
  	    case '[':
! 		if (idigit(*++fm))
! 		    arg = zstrtol(fm, &fm, 10);
! 		if (!prompttrunc(arg, ']', doprint, endchar))
! 		    return *fm;
  		break;
  	    case '<':
  	    case '>':
! 		if (!prompttrunc(arg, *fm, doprint, endchar))
! 		    return *fm;
  		break;
  	    case '{': /*}*/
  		if (!dontcount++) {
***************
*** 583,589 ****
  		break;
  	    }
  	} else if(*fm == '!' && isset(PROMPTBANG)) {
! 	    if(doprint)
  		if(fm[1] == '!') {
  		    fm++;
  		    addbufspc(1);
--- 538,544 ----
  		break;
  	    }
  	} else if(*fm == '!' && isset(PROMPTBANG)) {
! 	    if(doprint) {
  		if(fm[1] == '!') {
  		    fm++;
  		    addbufspc(1);
***************
*** 593,598 ****
--- 548,554 ----
  		    sprintf(bp, "%d", curhist);
  		    bp += strlen(bp);
  		}
+ 	    }
  	} else {
  	    char c = *fm == Meta ? *++fm ^ 32 : *fm;
  
***************
*** 643,688 ****
  }
  
  /* stradd() adds a metafied string to the prompt, *
!  * in a visible representation, doing truncation. */
  
  /**/
  void
  stradd(char *d)
  {
!     /* dlen is the full length of the string we want to add */
!     int dlen = niceztrlen(d);
!     char *ps, *pd, *pc, *t;
!     int tlen, maxlen;
!     addbufspc(dlen);
      /* This loop puts the nice representation of the string into the prompt *
!      * buffer.  It might be modified later.  Note that bp isn't changed.    */
!     for(ps=d, pd=bp; *ps; ps++)
  	for(pc=nicechar(*ps == Meta ? STOUC(*++ps)^32 : STOUC(*ps)); *pc; pc++)
! 	    *pd++ = *pc;
!     if(!trunclen || dlen <= trunclen) {
! 	/* No truncation is needed, so update bp and return, *
! 	 * leaving the full string in the prompt.            */
! 	bp += dlen;
! 	return;
!     }
!     /* We need to truncate.  t points to the truncation string -- which is *
!      * inserted literally, without nice representation.  tlen is its       *
!      * length, and maxlen is the amout of the main string that we want to  *
!      * keep.  Note that if the truncation string is longer than the        *
!      * truncation length (tlen > trunclen), the truncation string is used  *
!      * in full.                                                            */
!     addbufspc(tlen = ztrlen(t = truncstr));
!     maxlen = tlen < trunclen ? trunclen - tlen : 0;
!     if(truncatleft) {
! 	memmove(bp + strlen(t), bp + dlen - maxlen, maxlen);
! 	while(*t)
! 	    *bp++ = *t++;
! 	bp += maxlen;
!     } else {
! 	bp += maxlen;
! 	while(*t)
! 	    *bp++ = *t++;
!     }
  }
  
  /* tsetcap(), among other things, can write a termcap string into the buffer. */
--- 599,617 ----
  }
  
  /* stradd() adds a metafied string to the prompt, *
!  * in a visible representation.                   */
  
  /**/
  void
  stradd(char *d)
  {
!     char *ps, *pc;
!     addbufspc(niceztrlen(d));
      /* This loop puts the nice representation of the string into the prompt *
!      * buffer.                                                              */
!     for(ps=d; *ps; ps++)
  	for(pc=nicechar(*ps == Meta ? STOUC(*++ps)^32 : STOUC(*ps)); *pc; pc++)
! 	    *bp++ = *pc;
  }
  
  /* tsetcap(), among other things, can write a termcap string into the buffer. */
***************
*** 779,782 ****
--- 708,816 ----
  	*wp = w;
      if(hp)
  	*hp = h;
+ }
+ 
+ /**/
+ static int
+ prompttrunc(int arg, int truncchar, int doprint, int endchar)
+ {
+     if (arg) {
+ 	char ch = *fm, *ptr = bp, *truncstr;
+ 	int truncatleft = ch == '<';
+ 
+ 	/*
+ 	 * If there is already a truncation active, return so that
+ 	 * can be finished, backing up so that the new truncation
+ 	 * can be started afterwards.
+ 	 */
+ 	if (trunclen) {
+ 	    while (*--fm != '%')
+ 		;
+ 	    fm--;
+ 	    return 0;
+ 	}
+ 
+ 	trunclen = arg;
+ 	if (*fm != ']')
+ 	    fm++;
+ 	while (*fm && *fm != truncchar) {
+ 	    if (*fm == '\\' && fm[1])
+ 		++fm;
+ 	    addbufspc(1);
+ 	    *bp++ = *fm++;
+ 	}
+ 	if (!*fm)
+ 	    return 0;
+ 	if (bp == ptr && truncchar == ']') {
+ 	    addbufspc(1);
+ 	    *bp++ = '<';
+ 	}
+ 	truncstr = ztrduppfx(ptr, bp - ptr);
+ 
+ 	bp = ptr;
+ 	fm++;
+ 	putpromptchar(doprint, endchar);
+ 	*bp = '\0';
+ 	if (bp - ptr > trunclen) {
+ 	    /*
+ 	     * We need to truncate.  t points to the truncation string -- *
+ 	     * which is inserted literally, without nice representation.  *
+ 	     * tlen is its length, and maxlen is the amount of the main	  *
+ 	     * string that we want to keep.  Note that if the truncation  *
+ 	     * string is longer than the truncation length (tlen >	  *
+ 	     * trunclen), the truncation string is used in full.	  *
+ 	     */
+ 	    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++;
+ 	    } else {
+ 		ptr += maxlen;
+ 		while (*t)
+ 		    *ptr++ = *t++;
+ 	    }
+ 	}
+ 	zsfree(truncstr);
+ 	trunclen = 0;
+ 	/*
+ 	 * We may have returned early from the previous putpromptchar *
+ 	 * because we found another truncation following this one.    *
+ 	 * In that case we need to do the rest now.                   *
+ 	 */
+ 	if (!*fm)
+ 	    return 0;
+ 	if (*fm != endchar) {
+ 	    fm++;
+ 	    /*
+ 	     * With trunclen set to zero, we always reach endchar *
+ 	     * (or the terminating NULL) this time round.         *
+ 	     */
+ 	    if (!putpromptchar(doprint, endchar))
+ 		return 0;
+ 	    /* Now we have to trick it into matching endchar again */
+ 	    fm--;
+ 	}
+     } else {
+ 	if (*fm != ']')
+ 	    fm++;
+ 	while(*fm && *fm != truncchar) {
+ 	    if (*fm == '\\' && fm[1])
+ 		fm++;
+ 	    fm++;
+ 	}
+ 	if (trunclen || !*fm)
+ 	    return 0;
+     }
+     return 1;
  }

-- 
Peter Stephenson <pws@xxxxxxxxxxxxxxxxx>       Tel: +39 050 844536
WWW:  http://www.ifh.de/~pws/
Dipartimento di Fisica, Via Buonarotti 2, 56100 Pisa, Italy



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