Permit embedded colour and attributes in status-left and status-right using new

#[] special characters, for example #[fg=red,bg=blue,blink].
This commit is contained in:
Nicholas Marriott 2009-09-07 10:49:32 +00:00
parent ffab22bb35
commit e97006b102
4 changed files with 214 additions and 5 deletions

View File

@ -52,6 +52,41 @@ screen_write_putc(
screen_write_cell(ctx, gc, NULL); screen_write_cell(ctx, gc, NULL);
} }
/* Calculate string length, with embedded formatting. */
size_t printflike2
screen_write_cstrlen(int utf8flag, const char *fmt, ...)
{
va_list ap;
char *msg, *msg2, *ptr, *ptr2;
size_t size;
va_start(ap, fmt);
xvasprintf(&msg, fmt, ap);
va_end(ap);
msg2 = xmalloc(strlen(msg) + 1);
ptr = msg;
ptr2 = msg2;
while (*ptr != '\0') {
if (ptr[0] == '#' && ptr[1] == '[') {
while (*ptr != ']' && *ptr != '\0')
ptr++;
if (*ptr == ']')
ptr++;
continue;
}
*ptr2++ = *ptr++;
}
*ptr2 = '\0';
size = screen_write_strlen(utf8flag, "%s", msg2);
xfree(msg);
xfree(msg2);
return (size);
}
/* Calculate string length. */ /* Calculate string length. */
size_t printflike2 size_t printflike2
screen_write_strlen(int utf8flag, const char *fmt, ...) screen_write_strlen(int utf8flag, const char *fmt, ...)
@ -177,6 +212,143 @@ screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
xfree(msg); xfree(msg);
} }
/* Write string, similar to nputs, but with embedded formatting (#[]). */
void printflike5
screen_write_cnputs(struct screen_write_ctx *ctx,
ssize_t maxlen, struct grid_cell *gc, int utf8flag, const char *fmt, ...)
{
struct grid_cell lgc;
va_list ap;
char *msg;
u_char *ptr, *last, utf8buf[4];
size_t left, size = 0;
int width;
va_start(ap, fmt);
xvasprintf(&msg, fmt, ap);
va_end(ap);
memcpy(&lgc, gc, sizeof lgc);
ptr = msg;
while (*ptr != '\0') {
if (ptr[0] == '#' && ptr[1] == '[') {
ptr += 2;
last = ptr + strcspn(ptr, "]");
if (*last == '\0') {
/* No ]. Not much point in doing anything. */
break;
}
*last = '\0';
screen_write_parsestyle(gc, &lgc, ptr);
ptr = last + 1;
continue;
}
if (utf8flag && *ptr > 0x7f) {
memset(utf8buf, 0xff, sizeof utf8buf);
left = strlen(ptr);
if (*ptr >= 0xc2 && *ptr <= 0xdf && left >= 2) {
memcpy(utf8buf, ptr, 2);
ptr += 2;
} else if (*ptr >= 0xe0 && *ptr <= 0xef && left >= 3) {
memcpy(utf8buf, ptr, 3);
ptr += 3;
} else if (*ptr >= 0xf0 && *ptr <= 0xf4 && left >= 4) {
memcpy(utf8buf, ptr, 4);
ptr += 4;
} else {
*utf8buf = *ptr;
ptr++;
}
width = utf8_width(utf8buf);
if (maxlen > 0 && size + width > (size_t) maxlen) {
while (size < (size_t) maxlen) {
screen_write_putc(ctx, gc, ' ');
size++;
}
break;
}
size += width;
lgc.flags |= GRID_FLAG_UTF8;
screen_write_cell(ctx, &lgc, utf8buf);
lgc.flags &= ~GRID_FLAG_UTF8;
} else {
if (maxlen > 0 && size + 1 > (size_t) maxlen)
break;
size++;
screen_write_putc(ctx, &lgc, *ptr);
ptr++;
}
}
xfree(msg);
}
/* Parse an embedded style of the form "fg=colour,bg=colour,bright,...". */
void
screen_write_parsestyle(
struct grid_cell *defgc, struct grid_cell *gc, const char *in)
{
const char delimiters[] = " ,";
char tmp[32];
int val;
size_t end;
u_char fg, bg, attr;
if (*in == '\0')
return;
if (strchr(delimiters, in[strlen(in) - 1]) != NULL)
return;
fg = gc->fg;
bg = gc->bg;
attr = 0;
do {
end = strcspn(in, delimiters);
if (end > (sizeof tmp) - 1)
return;
memcpy(tmp, in, end);
tmp[end] = '\0';
if (strcasecmp(tmp, "default") == 0) {
fg = defgc->fg;
bg = defgc->bg;
attr = defgc->attr;
} else if (end > 3 && strncasecmp(tmp + 1, "g=", 2) == 0) {
if ((val = colour_fromstring(tmp + 3)) == -1)
return;
if (*in == 'f' || *in == 'F') {
if (val != 8)
fg = val;
else
fg = defgc->fg;
} else if (*in == 'b' || *in == 'B') {
if (val != 8)
bg = val;
else
bg = defgc->bg;
} else
return;
} else {
if ((val = attributes_fromstring(tmp)) == -1)
return;
attr |= val;
}
in += end + strspn(in + end, delimiters);
} while (*in != '\0');
gc->fg = fg;
gc->bg = bg;
gc->attr = attr;
}
/* Copy from another screen. */ /* Copy from another screen. */
void void
screen_write_copy(struct screen_write_ctx *ctx, screen_write_copy(struct screen_write_ctx *ctx,

View File

@ -107,14 +107,14 @@ status_redraw(struct client *c)
left = status_replace(s, options_get_string( left = status_replace(s, options_get_string(
&s->options, "status-left"), c->status_timer.tv_sec); &s->options, "status-left"), c->status_timer.tv_sec);
llen = options_get_number(&s->options, "status-left-length"); llen = options_get_number(&s->options, "status-left-length");
llen2 = screen_write_strlen(utf8flag, "%s", left); llen2 = screen_write_cstrlen(utf8flag, "%s", left);
if (llen2 < llen) if (llen2 < llen)
llen = llen2; llen = llen2;
right = status_replace(s, options_get_string( right = status_replace(s, options_get_string(
&s->options, "status-right"), c->status_timer.tv_sec); &s->options, "status-right"), c->status_timer.tv_sec);
rlen = options_get_number(&s->options, "status-right-length"); rlen = options_get_number(&s->options, "status-right-length");
rlen2 = screen_write_strlen(utf8flag, "%s", right); rlen2 = screen_write_cstrlen(utf8flag, "%s", right);
if (rlen2 < rlen) if (rlen2 < rlen)
rlen = rlen2; rlen = rlen2;
@ -192,7 +192,7 @@ draw:
screen_write_start(&ctx, NULL, &c->status); screen_write_start(&ctx, NULL, &c->status);
if (llen != 0) { if (llen != 0) {
screen_write_cursormove(&ctx, 0, yy); screen_write_cursormove(&ctx, 0, yy);
screen_write_nputs(&ctx, llen, &sl_stdgc, utf8flag, "%s", left); screen_write_cnputs(&ctx, llen, &sl_stdgc, utf8flag, "%s", left);
screen_write_putc(&ctx, &stdgc, ' '); screen_write_putc(&ctx, &stdgc, ' ');
if (larrow) if (larrow)
screen_write_putc(&ctx, &stdgc, ' '); screen_write_putc(&ctx, &stdgc, ' ');
@ -266,7 +266,7 @@ draw:
if (rlen != 0) { if (rlen != 0) {
screen_write_cursormove(&ctx, c->tty.sx - rlen - 1, yy); screen_write_cursormove(&ctx, c->tty.sx - rlen - 1, yy);
screen_write_putc(&ctx, &stdgc, ' '); screen_write_putc(&ctx, &stdgc, ' ');
screen_write_nputs(&ctx, rlen, &sr_stdgc, utf8flag, "%s", right); screen_write_cnputs(&ctx, rlen, &sr_stdgc, utf8flag, "%s", right);
} }
/* Draw the arrows. */ /* Draw the arrows. */
@ -400,6 +400,20 @@ status_replace(struct session *s, const char *fmt, time_t t)
len--; len--;
} }
break; break;
case '[':
/*
* Embedded style, handled at display time.
* Leave present and skip input until ].
*/
*optr++ = '#';
iptr--; /* include [ */
while (*iptr != ']' && *iptr != '\0') {
if (optr >= out + (sizeof out) - 1)
break;
*optr++ = *iptr++;
}
break;
case '#': case '#':
*optr++ = '#'; *optr++ = '#';
break; break;

20
tmux.1
View File

@ -1316,10 +1316,11 @@ will be passed through
before being used. before being used.
By default, the session name is shown. By default, the session name is shown.
.Ar string .Ar string
may contain any of the following special character pairs: may contain any of the following special character sequences:
.Bl -column "Character pair" "Replaced with" -offset indent .Bl -column "Character pair" "Replaced with" -offset indent
.It Sy "Character pair" Ta Sy "Replaced with" .It Sy "Character pair" Ta Sy "Replaced with"
.It Li "#(command)" Ta "First line of command's output" .It Li "#(command)" Ta "First line of command's output"
.It Li "#[attributes]" Ta "Colour or attribute change"
.It Li "#H" Ta "Hostname of local host" .It Li "#H" Ta "Hostname of local host"
.It Li "#I" Ta "Current window index" .It Li "#I" Ta "Current window index"
.It Li "#P" Ta "Current pane index" .It Li "#P" Ta "Current pane index"
@ -1329,6 +1330,23 @@ may contain any of the following special character pairs:
.It Li "##" Ta "A literal" Ql # .It Li "##" Ta "A literal" Ql #
.El .El
.Pp .Pp
The #(command) form executes
.Ql command
as a shell command and inserts the first line of its output.
#[attributes] allows a comma-separated list of attributes to be specified,
these may be
.Ql fg=colour
to set the foreground colour,
.Ql bg=colour
to set the background colour, or one of the attributes described under the
.Ic message-attr
option.
Examples are:
.Bd -literal -offset indent
#(sysctl vm.loadavg)
#[fg=yellow,bold]#(apm -l)%%#[default] [#S]
.Ed
.Pp
Where appropriate, these may be prefixed with a number to specify the maximum Where appropriate, these may be prefixed with a number to specify the maximum
length, for example length, for example
.Ql #24T . .Ql #24T .

5
tmux.h
View File

@ -1533,6 +1533,9 @@ char *grid_view_string_cells(struct grid *, u_int, u_int, u_int);
void screen_write_start( void screen_write_start(
struct screen_write_ctx *, struct window_pane *, struct screen *); struct screen_write_ctx *, struct window_pane *, struct screen *);
void screen_write_stop(struct screen_write_ctx *); void screen_write_stop(struct screen_write_ctx *);
size_t printflike2 screen_write_cstrlen(int, const char *, ...);
void printflike5 screen_write_cnputs(struct screen_write_ctx *,
ssize_t, struct grid_cell *, int, const char *, ...);
size_t printflike2 screen_write_strlen(int, const char *, ...); size_t printflike2 screen_write_strlen(int, const char *, ...);
void printflike3 screen_write_puts(struct screen_write_ctx *, void printflike3 screen_write_puts(struct screen_write_ctx *,
struct grid_cell *, const char *, ...); struct grid_cell *, const char *, ...);
@ -1540,6 +1543,8 @@ void printflike5 screen_write_nputs(struct screen_write_ctx *,
ssize_t, struct grid_cell *, int, const char *, ...); ssize_t, struct grid_cell *, int, const char *, ...);
void screen_write_vnputs(struct screen_write_ctx *, void screen_write_vnputs(struct screen_write_ctx *,
ssize_t, struct grid_cell *, int, const char *, va_list); ssize_t, struct grid_cell *, int, const char *, va_list);
void screen_write_parsestyle(
struct grid_cell *, struct grid_cell *, const char *);
void screen_write_putc( void screen_write_putc(
struct screen_write_ctx *, struct grid_cell *, u_char); struct screen_write_ctx *, struct grid_cell *, u_char);
void screen_write_copy(struct screen_write_ctx *, void screen_write_copy(struct screen_write_ctx *,