mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 00:56:10 +00:00 
			
		
		
		
	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:
		
							
								
								
									
										172
									
								
								screen-write.c
									
									
									
									
									
								
							
							
						
						
									
										172
									
								
								screen-write.c
									
									
									
									
									
								
							@@ -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,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										22
									
								
								status.c
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								status.c
									
									
									
									
									
								
							@@ -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;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										20
									
								
								tmux.1
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								tmux.1
									
									
									
									
									
								
							@@ -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 .
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								tmux.h
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								tmux.h
									
									
									
									
									
								
							@@ -1533,6 +1533,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 *, ...);
 | 
			
		||||
@@ -1540,6 +1543,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 *,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user