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

[PATCH] Better prompt width calculations (Re: Possible bug to RPROMPT)



On Aug 6, 12:57am, Bart Schaefer wrote:
}
} However, there's some odd behavior when the computed result is actually
} zero or less; it's then treated as %<< (i.e., as if with no numeric
} argument), and no truncation occurs at all.  That's very unintuitive,
} but it stems from being able to use %<< as an end marker for a preceding
} truncation.
} 
} Merely documenting this doesn't seem sufficient.  On the other hand, a
} similar odd thing happens with positive truncation because of implicit
} line wrapping; try %90>=> followed by 100+ characters on an 80-column
} terminal to see what I mean.

Here is a revised patch, including documentation, which I think makes
this fairly useful and more importantly comprehensible.  I've made two
changes:

First, a negative argument with the 'l' conditional counts the number
of characters remaining instead of the number of characters printed:

	%40(l.MORE THAN.LESS THAN) FORTY characters printed
	%-40(l.MORE THAN.LESS THAN) FORTY characters remain

Previously the absolute value of the argument was always used here
(and still is, for all other ternary conditionals).

Second, as in the previous patch a negative argument with truncation
leaves at least N characters unused to the right of the truncated
portion.  However, I've now made the minimum width 1 character, so
that we don't run into the special meaning of zero (or less).

Finally, I also fixed a couple of comments that got messed up by the
global-text-replace of "buf" with "bv->buf" several years ago.


diff --git a/Doc/Zsh/prompt.yo b/Doc/Zsh/prompt.yo
index 36f351b..963207f 100644
--- a/Doc/Zsh/prompt.yo
+++ b/Doc/Zsh/prompt.yo
@@ -302,7 +302,8 @@ sitem(tt(g))(True if the effective gid of the current process is var(n).)
 sitem(tt(j))(True if the number of jobs is at least var(n).)
 sitem(tt(L))(True if the tt(SHLVL) parameter is at least var(n).)
 sitem(tt(l))(True if at least var(n) characters have already been
-printed on the current line.)
+printed on the current line.  When var(n) is negative, true if at least
+var(n) characters remain before the right margin.)
 sitem(tt(S))(True if the tt(SECONDS) parameter is at least var(n).)
 sitem(tt(T))(True if the time in hours is equal to var(n).)
 sitem(tt(t))(True if the time in minutes is equal to var(n).)
@@ -318,13 +319,21 @@ 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 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.
+In the first two forms, this numeric argument may be negative, in which
+case the truncation length is determined by subtracting the absolute
+value of the numeric argument from the number of character positions
+remaining on the current prompt line.  If this results in a zero or
+negative length, a length of 1 is used.  In other words, a negative
+argument arranges that after truncation at least var(n) characters
+remain before the right margin.
+
 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)',
@@ -344,11 +353,19 @@ 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
+(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.
+in the string to be truncated.  Note that `tt(%-0<<)' is a distinct
+
+Truncation applies only within each individual line of the prompt, as
+delimited by embedded newlines (if any).  If the total length of any line
+of the prompt after truncation is greater than the terminal width, or if
+the part to be truncated contains embedded newlines, truncation behavior
+is undefined and may change in a future version of the shell.  Use
+`tt(%-var(n)LPAR()l.var(true-text).var(false-text)RPAR())' to remove parts
+of the prompt when the available space is less than var(n).
 )
 enditem()
diff --git a/Src/prompt.c b/Src/prompt.c
index c16d781..328ae3c 100644
--- a/Src/prompt.c
+++ b/Src/prompt.c
@@ -367,6 +367,8 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep)
 		case 'l':
 		    *bv->bp = '\0';
 		    countprompt(bv->bufline, &t0, 0, 0);
+		    if (minus)
+			t0 = zterm_columns - t0;
 		    if (t0 >= arg)
 			test = 1;
 		    break;
@@ -560,6 +562,14 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep)
 		break;
 	    case '<':
 	    case '>':
+		/* Test (minus) here so -0 means "at the right margin" */
+		if (minus) {
+		    *bv->bp = '\0';
+		    countprompt(bv->bufline, &t0, 0, 0);
+		    arg = zterm_columns - t0 + arg;
+		    if (arg <= 0)
+			arg = 1;
+		}
 		if (!prompttrunc(arg, *bv->fm, doprint, endchar, txtchangep))
 		    return *bv->fm;
 		break;
@@ -1174,7 +1184,7 @@ prompttrunc(int arg, int truncchar, int doprint, int endchar,
 	    addbufspc(1);
 	    *bv->bp++ = '<';
 	}
-	ptr = bv->buf + w;		/* addbv->bufspc() may have realloc()'d bv->buf */
+	ptr = bv->buf + w;	/* addbufspc() may have realloc()'d bv->buf */
 	/*
 	 * Now:
 	 *   bv->buf is the start of the output prompt buffer
@@ -1189,7 +1199,7 @@ prompttrunc(int arg, int truncchar, int doprint, int endchar,
 	bv->trunccount = bv->dontcount;
 	putpromptchar(doprint, endchar, txtchangep);
 	bv->trunccount = 0;
-	ptr = bv->buf + w;		/* putpromptchar() may have realloc()'d */
+	ptr = bv->buf + w;	/* putpromptchar() may have realloc()'d */
 	*bv->bp = '\0';
 	/*
 	 * Now:
@@ -1475,7 +1485,7 @@ prompttrunc(int arg, int truncchar, int doprint, int endchar,
 	/* Now we have to trick it into matching endchar again */
 	bv->fm--;
     } else {
-	if (*bv->fm != ']')
+	if (*bv->fm != endchar)
 	    bv->fm++;
 	while(*bv->fm && *bv->fm != truncchar) {
 	    if (*bv->fm == '\\' && bv->fm[1])



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