Add a UTF-8 aware string length function and make UTF-8 in

status-left/status-right work properly. At the moment any top-bit-set
characters are assumed to be UTF-8: a status-utf8 option to configure this will
come shortly.
This commit is contained in:
Nicholas Marriott 2009-06-25 15:47:07 +00:00
parent 0828e06ad7
commit 1e06ec41dc
3 changed files with 130 additions and 18 deletions

View File

@ -1,4 +1,4 @@
/* $Id: screen-write.c,v 1.45 2009-05-04 17:58:27 nicm Exp $ */ /* $OpenBSD: screen-write.c,v 1.2 2009/06/03 16:05:46 nicm Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -52,20 +52,126 @@ screen_write_putc(
screen_write_cell(ctx, gc, NULL); screen_write_cell(ctx, gc, NULL);
} }
/* Calculate string length. */
size_t printflike1
screen_write_strlen(const char *fmt, ...)
{
va_list ap;
char *msg;
u_char *ptr, utf8buf[4];
size_t left, size = 0;
va_start(ap, fmt);
xvasprintf(&msg, fmt, ap);
va_end(ap);
ptr = msg;
while (*ptr != '\0') {
if (*ptr > 0x7f) { /* Assume this is UTF-8. */
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++;
}
size += utf8_width(utf8buf);
} else {
size++;
ptr++;
}
}
return (size);
}
/* Write string. */ /* Write string. */
void printflike3 void printflike3
screen_write_puts( screen_write_puts(
struct screen_write_ctx *ctx, struct grid_cell *gc, const char *fmt, ...) struct screen_write_ctx *ctx, struct grid_cell *gc, const char *fmt, ...)
{ {
va_list ap; va_list ap;
char *msg, *ptr;
va_start(ap, fmt); va_start(ap, fmt);
xvasprintf(&msg, fmt, ap); screen_write_vnputs(ctx, -1, gc, fmt, ap);
va_end(ap); va_end(ap);
}
for (ptr = msg; *ptr != '\0'; ptr++) /* Write string with length limit (-1 for unlimited). */
screen_write_putc(ctx, gc, (u_char) *ptr); void printflike4
screen_write_nputs(struct screen_write_ctx *ctx,
ssize_t maxlen, struct grid_cell *gc, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
screen_write_vnputs(ctx, maxlen, gc, fmt, ap);
va_end(ap);
}
void
screen_write_vnputs(struct screen_write_ctx *ctx,
ssize_t maxlen, struct grid_cell *gc, const char *fmt, va_list ap)
{
char *msg;
u_char *ptr, utf8buf[4];
size_t left, size = 0;
int width;
xvasprintf(&msg, fmt, ap);
ptr = msg;
while (*ptr != '\0') {
if (*ptr > 0x7f) { /* Assume this is UTF-8. */
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;
gc->flags |= GRID_FLAG_UTF8;
screen_write_cell(ctx, gc, utf8buf);
gc->flags &= ~GRID_FLAG_UTF8;
} else {
if (maxlen > 0 && size > (size_t) maxlen)
break;
size++;
screen_write_putc(ctx, gc, *ptr);
ptr++;
}
}
xfree(msg); xfree(msg);
} }

View File

@ -1,4 +1,4 @@
/* $Id: status.c,v 1.83 2009-05-29 05:40:56 nicm Exp $ */ /* $OpenBSD: status.c,v 1.2 2009/06/03 16:05:46 nicm Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -47,8 +47,8 @@ status_redraw(struct client *c)
struct window_pane *wp; struct window_pane *wp;
struct screen *sc = NULL, old_status; struct screen *sc = NULL, old_status;
char *left, *right, *text, *ptr; char *left, *right, *text, *ptr;
size_t llen, rlen, offset, xx, yy, sy; size_t llen, llen2, rlen, rlen2, offset;
size_t size, start, width; size_t xx, yy, sy, size, start, width;
struct grid_cell stdgc, gc; struct grid_cell stdgc, gc;
int larrow, rarrow; int larrow, rarrow;
@ -78,15 +78,16 @@ 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");
if (strlen(left) < llen) llen2 = screen_write_strlen("%s", left);
llen = strlen(left); if (llen2 < llen)
left[llen] = '\0'; 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");
if (strlen(right) < rlen) rlen2 = screen_write_strlen("%s", right);
rlen = strlen(right); if (rlen2 < rlen)
rlen = rlen2;
right[rlen] = '\0'; right[rlen] = '\0';
/* /*
@ -163,7 +164,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_puts(&ctx, &stdgc, "%s ", left); screen_write_nputs(&ctx, llen + 1, &stdgc, "%s ", left);
if (larrow) if (larrow)
screen_write_putc(&ctx, &stdgc, ' '); screen_write_putc(&ctx, &stdgc, ' ');
} else { } else {
@ -220,7 +221,7 @@ draw:
/* Draw the last item. */ /* Draw the last item. */
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_puts(&ctx, &stdgc, " %s", right); screen_write_nputs(&ctx, rlen + 1, &stdgc, " %s", right);
} }
/* Draw the arrows. */ /* Draw the arrows. */

11
tmux.h
View File

@ -1,4 +1,4 @@
/* $Id: tmux.h,v 1.328 2009-06-25 15:46:09 nicm Exp $ */ /* $OpenBSD: tmux.h,v 1.3 2009/06/03 16:05:46 nicm Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -1468,8 +1468,13 @@ void grid_view_delete_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 *);
void printflike3 screen_write_puts( size_t printflike1 screen_write_strlen(const char *, ...);
struct screen_write_ctx *, struct grid_cell *, const char *, ...); void printflike3 screen_write_puts(struct screen_write_ctx *,
struct grid_cell *, const char *, ...);
void printflike4 screen_write_nputs(struct screen_write_ctx *,
ssize_t, struct grid_cell *, const char *, ...);
void screen_write_vnputs(struct screen_write_ctx *,
ssize_t, struct grid_cell *, const char *, va_list);
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 *,