aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Marriott <nicm@openbsd.org>2009-06-03 16:05:46 +0000
committerNicholas Marriott <nicm@openbsd.org>2009-06-03 16:05:46 +0000
commit7d45e29683119b31179295b3712142ebf8897a0d (patch)
tree28dc49e1fe895cb7d1bd472126b201eaeb534460
parent41d985ace3189c7375a8f1c2d1d2d028a20cf731 (diff)
downloadrtmux-7d45e29683119b31179295b3712142ebf8897a0d.tar.gz
rtmux-7d45e29683119b31179295b3712142ebf8897a0d.tar.bz2
rtmux-7d45e29683119b31179295b3712142ebf8897a0d.zip
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.
-rw-r--r--screen-write.c114
-rw-r--r--status.c19
-rw-r--r--tmux.h9
3 files changed, 127 insertions, 15 deletions
diff --git a/screen-write.c b/screen-write.c
index ac31fc6f..d55a29a4 100644
--- a/screen-write.c
+++ b/screen-write.c
@@ -52,20 +52,126 @@ screen_write_putc(
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. */
void printflike3
screen_write_puts(
struct screen_write_ctx *ctx, struct grid_cell *gc, const char *fmt, ...)
{
va_list ap;
- char *msg, *ptr;
va_start(ap, fmt);
- xvasprintf(&msg, fmt, ap);
+ screen_write_vnputs(ctx, -1, gc, fmt, ap);
va_end(ap);
+}
- for (ptr = msg; *ptr != '\0'; ptr++)
- screen_write_putc(ctx, gc, (u_char) *ptr);
+/* Write string with length limit (-1 for unlimited). */
+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);
}
diff --git a/status.c b/status.c
index a72e5a26..9d43803a 100644
--- a/status.c
+++ b/status.c
@@ -47,8 +47,8 @@ status_redraw(struct client *c)
struct window_pane *wp;
struct screen *sc = NULL, old_status;
char *left, *right, *text, *ptr;
- size_t llen, rlen, offset, xx, yy, sy;
- size_t size, start, width;
+ size_t llen, llen2, rlen, rlen2, offset;
+ size_t xx, yy, sy, size, start, width;
struct grid_cell stdgc, gc;
int larrow, rarrow;
@@ -78,15 +78,16 @@ 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");
- if (strlen(left) < llen)
- llen = strlen(left);
- left[llen] = '\0';
+ llen2 = screen_write_strlen("%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");
- if (strlen(right) < rlen)
- rlen = strlen(right);
+ rlen2 = screen_write_strlen("%s", right);
+ if (rlen2 < rlen)
+ rlen = rlen2;
right[rlen] = '\0';
/*
@@ -163,7 +164,7 @@ draw:
screen_write_start(&ctx, NULL, &c->status);
if (llen != 0) {
screen_write_cursormove(&ctx, 0, yy);
- screen_write_puts(&ctx, &stdgc, "%s ", left);
+ screen_write_nputs(&ctx, llen + 1, &stdgc, "%s ", left);
if (larrow)
screen_write_putc(&ctx, &stdgc, ' ');
} else {
@@ -220,7 +221,7 @@ draw:
/* Draw the last item. */
if (rlen != 0) {
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. */
diff --git a/tmux.h b/tmux.h
index 0c8e5929..fef8394c 100644
--- a/tmux.h
+++ b/tmux.h
@@ -1347,8 +1347,13 @@ void grid_view_delete_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 *);
-void printflike3 screen_write_puts(
- struct screen_write_ctx *, struct grid_cell *, const char *, ...);
+size_t printflike1 screen_write_strlen(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(
struct screen_write_ctx *, struct grid_cell *, u_char);
void screen_write_copy(struct screen_write_ctx *,