From 5edc4658028b47d975f8685be63f5876a12a3a4f Mon Sep 17 00:00:00 2001 From: Tiago Cunha Date: Mon, 7 Sep 2009 23:37:48 +0000 Subject: [PATCH] Sync OpenBSD patchset 317: Permit embedded colour and attributes in status-left and status-right using new #[] special characters, for example #[fg=red,bg=blue,blink]. --- screen-write.c | 174 ++++++++++++++++++++++++++++++++++++++++++++++++- status.c | 24 +++++-- tmux.1 | 24 ++++++- tmux.h | 7 +- 4 files changed, 219 insertions(+), 10 deletions(-) diff --git a/screen-write.c b/screen-write.c index d2e3c51b..fbab37c9 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1,4 +1,4 @@ -/* $Id: screen-write.c,v 1.70 2009-08-21 21:13:20 tcunha Exp $ */ +/* $Id: screen-write.c,v 1.71 2009-09-07 23:37:48 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -52,6 +52,41 @@ screen_write_putc( 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. */ size_t printflike2 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); } +/* 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. */ void screen_write_copy(struct screen_write_ctx *ctx, diff --git a/status.c b/status.c index 3057d138..eb965842 100644 --- a/status.c +++ b/status.c @@ -1,4 +1,4 @@ -/* $Id: status.c,v 1.115 2009-09-02 22:45:17 tcunha Exp $ */ +/* $Id: status.c,v 1.116 2009-09-07 23:37:48 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -107,14 +107,14 @@ status_redraw(struct client *c) left = status_replace(s, options_get_string( &s->options, "status-left"), c->status_timer.tv_sec); 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) llen = llen2; right = status_replace(s, options_get_string( &s->options, "status-right"), c->status_timer.tv_sec); 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) rlen = rlen2; @@ -192,7 +192,7 @@ draw: screen_write_start(&ctx, NULL, &c->status); if (llen != 0) { 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, ' '); if (larrow) screen_write_putc(&ctx, &stdgc, ' '); @@ -266,7 +266,7 @@ draw: if (rlen != 0) { screen_write_cursormove(&ctx, c->tty.sx - rlen - 1, yy); 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. */ @@ -400,6 +400,20 @@ status_replace(struct session *s, const char *fmt, time_t t) len--; } 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 '#': *optr++ = '#'; break; diff --git a/tmux.1 b/tmux.1 index 31c4897c..1408ffa2 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1,4 +1,4 @@ -.\" $Id: tmux.1,v 1.164 2009-09-03 21:02:55 tcunha Exp $ +.\" $Id: tmux.1,v 1.165 2009-09-07 23:37:48 tcunha Exp $ .\" .\" Copyright (c) 2007 Nicholas Marriott .\" @@ -14,7 +14,7 @@ .\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING .\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: September 2 2009 $ +.Dd $Mdocdate: September 7 2009 $ .Dt TMUX 1 .Os .Sh NAME @@ -1316,10 +1316,11 @@ will be passed through before being used. By default, the session name is shown. .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 .It Sy "Character pair" Ta Sy "Replaced with" .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 "#I" Ta "Current window 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 # .El .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 length, for example .Ql #24T . diff --git a/tmux.h b/tmux.h index d6c58488..f4cc7b39 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $Id: tmux.h,v 1.436 2009-09-03 21:02:55 tcunha Exp $ */ +/* $Id: tmux.h,v 1.437 2009-09-07 23:37:48 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -1531,6 +1531,9 @@ char *grid_view_string_cells(struct grid *, u_int, u_int, u_int); void screen_write_start( struct screen_write_ctx *, struct window_pane *, struct screen *); 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 *, ...); void printflike3 screen_write_puts(struct screen_write_ctx *, struct grid_cell *, const char *, ...); @@ -1538,6 +1541,8 @@ void printflike5 screen_write_nputs(struct screen_write_ctx *, ssize_t, struct grid_cell *, int, const char *, ...); void screen_write_vnputs(struct screen_write_ctx *, 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( struct screen_write_ctx *, struct grid_cell *, u_char); void screen_write_copy(struct screen_write_ctx *,