summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicholas Marriott <nicholas.marriott@gmail.com>2008-09-09 22:16:37 +0000
committerNicholas Marriott <nicholas.marriott@gmail.com>2008-09-09 22:16:37 +0000
commit19a2c87f049155439427e40d0cc78041da4d0b99 (patch)
tree03d67440bb693b3257850a54007f9b03027d1bdc
parent1e145a639be109f53381c64bd83483d32ffc8524 (diff)
Initial UTF-8 support.
-rw-r--r--CHANGES7
-rw-r--r--GNUmakefile4
-rw-r--r--Makefile4
-rw-r--r--TODO40
-rw-r--r--buffer-poll.c8
-rw-r--r--client.c6
-rw-r--r--cmd-list-windows.c8
-rw-r--r--input.c51
-rw-r--r--screen-display.c11
-rw-r--r--screen-write.c78
-rw-r--r--screen.c5
-rw-r--r--server-msg.c4
-rw-r--r--tmux.c13
-rw-r--r--tmux.h50
-rw-r--r--tty.c55
-rw-r--r--utf8.c114
16 files changed, 429 insertions, 29 deletions
diff --git a/CHANGES b/CHANGES
index 6de5c7ab..2a17df34 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,8 @@
+09 September 2008
+
+* Initial UTF-8 support. A bit ugly and with a limit of 4096 UTF-8
+ characters per window.
+
08 September 2008
* 256 colour support. tmux attempts to autodetect the terminal by looking
@@ -655,4 +660,4 @@
(including mutt, emacs). No status bar yet and no key remapping or other
customisation.
-$Id: CHANGES,v 1.158 2008-09-08 17:40:50 nicm Exp $
+$Id: CHANGES,v 1.159 2008-09-09 22:16:36 nicm Exp $
diff --git a/GNUmakefile b/GNUmakefile
index dcfc6b9f..abc13121 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -1,4 +1,4 @@
-# $Id: GNUmakefile,v 1.38 2008-08-28 17:45:24 nicm Exp $
+# $Id: GNUmakefile,v 1.39 2008-09-09 22:16:36 nicm Exp $
.PHONY: clean
@@ -31,7 +31,7 @@ SRCS= tmux.c server.c server-msg.c server-fn.c buffer.c buffer-poll.c status.c \
cmd-list-commands.c cmd-move-window.c cmd-select-prompt.c \
cmd-respawn-window.c \
window-scroll.c window-more.c window-copy.c options.c paste.c \
- tty.c tty-keys.c tty-write.c screen-write.c screen-redraw.c
+ tty.c tty-keys.c tty-write.c screen-write.c screen-redraw.c utf8.c
CC?= gcc
INCDIRS+= -I. -I-
diff --git a/Makefile b/Makefile
index e1fcd745..664bfb2e 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.72 2008-08-07 05:15:21 nicm Exp $
+# $Id: Makefile,v 1.73 2008-09-09 22:16:36 nicm Exp $
.SUFFIXES: .c .o .y .h
.PHONY: clean update-index.html upload-index.html
@@ -35,7 +35,7 @@ SRCS= tmux.c server.c server-msg.c server-fn.c buffer.c buffer-poll.c status.c \
cmd-list-commands.c cmd-move-window.c cmd-select-prompt.c \
cmd-respawn-window.c \
window-scroll.c window-more.c window-copy.c options.c paste.c \
- tty.c tty-keys.c tty-write.c screen-write.c screen-redraw.c
+ tty.c tty-keys.c tty-write.c screen-write.c screen-redraw.c utf8.c
CC?= cc
INCDIRS+= -I. -I- -I/usr/local/include
diff --git a/TODO b/TODO
index da2d2645..2794017c 100644
--- a/TODO
+++ b/TODO
@@ -41,6 +41,46 @@
-- For 0.5 --------------------------------------------------------------------
+- FINISH UTF8: fix copy and paste
+- SPLIT u_short attr into attr,flags?
+- maybe rethink backend data structure?
+ - utf8 can be 1-4 bytes
+ - most common is 1 bytes
+ - there can be double-width characters which take n bytes but 2 columns on screen
+ - they are not only drawn as two characters, they also require two backspaces to remove
+- three operations:
+ - simultaneously update screen and ttys
+ - redraw screen or section of screen to ttys
+ - write to ttys without updating screen
+
+---
+split off grid manip:
+ 16-bit characters
+ 8-bit flags
+ 8-bit attributes
+ 8-bit fg colour
+ 8-bit bg colour
+
+struct grid_data {
+ struct grid_cell **cells;
+ u_int sx;
+ u_int sy;
+};
+struct grid_cell {
+ u_short data;
+ u_char attr;
+ u_char flags;
+ u_char fg;
+ u_char bg;
+}
+---
+
+Would it be better to just expand char to 16-bits and use it as an index only
+for >2-byte characters? or - better - don't support entire UTF range? only the BMP?
+this would get rid of UTF table and limits, but still leave double-width character annoyances
+also would double memory usage
+----
+
21:09 < merdely> NicM: if I run 'tmux attach -t main' and there is no tmux session named main, start a new one.
- commands: save-buffer -b number filename
load-buffer -b number filename
diff --git a/buffer-poll.c b/buffer-poll.c
index e4a8ae73..efd294c2 100644
--- a/buffer-poll.c
+++ b/buffer-poll.c
@@ -1,4 +1,4 @@
-/* $Id: buffer-poll.c,v 1.9 2008-08-28 17:45:25 nicm Exp $ */
+/* $Id: buffer-poll.c,v 1.10 2008-09-09 22:16:36 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -40,9 +40,11 @@ buffer_poll(struct pollfd *pfd, struct buffer *in, struct buffer *out)
{
ssize_t n;
+#if 0
log_debug("buffer_poll (%ld): fd=%d, revents=%d; out=%zu in=%zu",
(long) getpid(),
pfd->fd, pfd->revents, BUFFER_USED(out), BUFFER_USED(in));
+#endif
#ifndef BROKEN_POLL
if (pfd->revents & (POLLERR|POLLNVAL|POLLHUP))
@@ -51,7 +53,9 @@ buffer_poll(struct pollfd *pfd, struct buffer *in, struct buffer *out)
if (pfd->revents & POLLIN) {
buffer_ensure(in, BUFSIZ);
n = read(pfd->fd, BUFFER_IN(in), BUFFER_FREE(in));
+#if 0
log_debug("buffer_poll: fd=%d, read=%zd", pfd->fd, n);
+#endif
if (n == 0)
return (-1);
if (n == -1) {
@@ -62,7 +66,9 @@ buffer_poll(struct pollfd *pfd, struct buffer *in, struct buffer *out)
}
if (BUFFER_USED(out) > 0 && pfd->revents & POLLOUT) {
n = write(pfd->fd, BUFFER_OUT(out), BUFFER_USED(out));
+#if 0
log_debug("buffer_poll: fd=%d, write=%zd", pfd->fd, n);
+#endif
if (n == -1) {
if (errno != EINTR && errno != EAGAIN)
return (-1);
diff --git a/client.c b/client.c
index a55b8e22..4ae5fc1a 100644
--- a/client.c
+++ b/client.c
@@ -1,4 +1,4 @@
-/* $Id: client.c,v 1.34 2008-07-01 19:47:02 nicm Exp $ */
+/* $Id: client.c,v 1.35 2008-09-09 22:16:36 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -34,7 +34,8 @@
void client_handle_winch(struct client_ctx *);
int
-client_init(const char *path, struct client_ctx *cctx, int start_server)
+client_init(
+ const char *path, struct client_ctx *cctx, int start_server, int flags)
{
struct sockaddr_un sa;
struct stat sb;
@@ -94,6 +95,7 @@ retry:
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)
fatal("ioctl(TIOCGWINSZ)");
data.version = PROTOCOL_VERSION;
+ data.flags = flags;
data.sx = ws.ws_col;
data.sy = ws.ws_row;
*data.tty = '\0';
diff --git a/cmd-list-windows.c b/cmd-list-windows.c
index 8713ad7a..d3cf24c0 100644
--- a/cmd-list-windows.c
+++ b/cmd-list-windows.c
@@ -1,4 +1,4 @@
-/* $Id: cmd-list-windows.c,v 1.22 2008-09-08 17:40:50 nicm Exp $ */
+/* $Id: cmd-list-windows.c,v 1.23 2008-09-09 22:16:36 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -72,10 +72,12 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx)
else
name = "";
ctx->print(ctx,
- "%d: %s \"%s\" (%s) [%ux%u] [history %u/%u, %llu bytes]",
+ "%d: %s \"%s\" (%s) [%ux%u] [history %u/%u, %llu bytes] "
+ "[UTF8 table %u/%u]",
wl->idx, w->name, w->base.title, name,
screen_size_x(&w->base), screen_size_y(&w->base),
- w->base.hsize, w->base.hlimit, size);
+ w->base.hsize, w->base.hlimit, size,
+ ARRAY_LENGTH(&w->base.utf8_table.array), UTF8_LIMIT);
}
if (ctx->cmdclient != NULL)
diff --git a/input.c b/input.c
index c7023a03..a15f60cb 100644
--- a/input.c
+++ b/input.c
@@ -1,4 +1,4 @@
-/* $Id: input.c,v 1.57 2008-09-09 17:35:04 nicm Exp $ */
+/* $Id: input.c,v 1.58 2008-09-09 22:16:36 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -56,6 +56,7 @@ void input_state_sequence_next(u_char, struct input_ctx *);
void input_state_sequence_intermediate(u_char, struct input_ctx *);
void input_state_string_next(u_char, struct input_ctx *);
void input_state_string_escape(u_char, struct input_ctx *);
+void input_state_utf8(u_char, struct input_ctx *);
void input_handle_character(u_char, struct input_ctx *);
void input_handle_c0_control(u_char, struct input_ctx *);
@@ -247,6 +248,7 @@ input_state_first(u_char ch, struct input_ctx *ictx)
return;
}
+#if 0
if (INPUT_C1CONTROL(ch)) {
ch -= 0x40;
if (ch == '[')
@@ -257,6 +259,10 @@ input_state_first(u_char ch, struct input_ctx *ictx)
input_handle_c1_control(ch, ictx);
return;
}
+#endif
+
+ if (INPUT_DELETE(ch))
+ return;
input_handle_character(ch, ictx);
}
@@ -482,10 +488,53 @@ input_state_string_escape(u_char ch, struct input_ctx *ictx)
}
void
+input_state_utf8(u_char ch, struct input_ctx *ictx)
+{
+ log_debug2("-- un %zu: %hhu (%c)", ictx->off, ch, ch);
+
+ ictx->utf8_buf.data[ictx->utf8_off++] = ch;
+ if (--ictx->utf8_len != 0)
+ return;
+ input_state(ictx, input_state_first);
+
+ screen_write_put_utf8(&ictx->ctx, &ictx->utf8_buf);
+}
+
+void
input_handle_character(u_char ch, struct input_ctx *ictx)
{
log_debug2("-- ch %zu: %hhu (%c)", ictx->off, ch, ch);
+ if (ch > 0x7f) {
+ /*
+ * UTF8 sequence.
+ *
+ * 11000010-11011111 C2-DF start of 2-byte sequence
+ * 11100000-11101111 E0-EF start of 3-byte sequence
+ * 11110000-11110100 F0-F4 start of 4-byte sequence
+ */
+ memset(&ictx->utf8_buf.data, 0xff, sizeof &ictx->utf8_buf.data);
+ ictx->utf8_buf.data[0] = ch;
+ ictx->utf8_off = 1;
+
+ if (ch >= 0xc2 && ch <= 0xdf) {
+ log_debug2(":: u2");
+ input_state(ictx, input_state_utf8);
+ ictx->utf8_len = 1;
+ }
+ if (ch >= 0xe0 && ch <= 0xef) {
+ log_debug2(":: u3");
+ input_state(ictx, input_state_utf8);
+ ictx->utf8_len = 2;
+ }
+ if (ch >= 0xf0 && ch <= 0xf4) {
+ log_debug2(":: u4");
+ input_state(ictx, input_state_utf8);
+ ictx->utf8_len = 3;
+ }
+ return;
+ }
+
screen_write_put_character(&ictx->ctx, ch);
}
diff --git a/screen-display.c b/screen-display.c
index be8c8e93..4760d8ee 100644
--- a/screen-display.c
+++ b/screen-display.c
@@ -1,4 +1,4 @@
-/* $Id: screen-display.c,v 1.20 2008-09-08 22:03:54 nicm Exp $ */
+/* $Id: screen-display.c,v 1.21 2008-09-09 22:16:36 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -22,6 +22,15 @@
#include "tmux.h"
+/* Get a cell. */
+void
+screen_display_get_cell(struct screen *s,
+ u_int px, u_int py, u_char *data, u_short *attr, u_char *fg, u_char *bg)
+{
+ screen_get_cell(
+ s, screen_x(s, px), screen_y(s, py), data, attr, fg, bg);
+}
+
/* Set a cell. */
void
screen_display_set_cell(struct screen *s,
diff --git a/screen-write.c b/screen-write.c
index c4f3fef1..35ac3a59 100644
--- a/screen-write.c
+++ b/screen-write.c
@@ -1,4 +1,4 @@
-/* $Id: screen-write.c,v 1.12 2008-09-08 22:03:54 nicm Exp $ */
+/* $Id: screen-write.c,v 1.13 2008-09-09 22:16:36 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -99,6 +99,7 @@ void
screen_write_put_character(struct screen_write_ctx *ctx, u_char ch)
{
struct screen *s = ctx->s;
+ u_short attr;
if (s->cx == screen_size_x(s)) {
s->cx = 0;
@@ -109,14 +110,87 @@ screen_write_put_character(struct screen_write_ctx *ctx, u_char ch)
SCREEN_DEBUG(s);
return;
}
+ attr = s->attr & ~(ATTR_UTF8|ATTR_PAD);
- screen_display_set_cell(s, s->cx, s->cy, ch, s->attr, s->fg, s->bg);
+ screen_display_set_cell(s, s->cx, s->cy, ch, attr, s->fg, s->bg);
s->cx++;
if (ctx->write != NULL)
ctx->write(ctx->data, TTY_CHARACTER, ch);
}
+/* Put a UTF8 character. */
+void
+screen_write_put_utf8(struct screen_write_ctx *ctx, struct utf8_data *udat)
+{
+ struct screen *s = ctx->s;
+ u_char ch, ch2, fg, bg;
+ u_short attr, attr2;
+ int idx, wide;
+ u_int n;
+
+ wide = 0;
+ if (udat->data[2] == 0xff)
+ n = ((udat->data[0] & 0x1f)<<6) + (udat->data[1] & 0x3f);
+ else if (udat->data[3] == 0xff) {
+ n = ((udat->data[0] & 0x0f)<<12) +
+ ((udat->data[1] & 0x3f)<<6) + (udat->data[2] & 0x3f);
+ } else
+ n = 0;
+ if ((n >= 0x1100 && n <= 0x115f) || n == 0x2329 || n == 0x232a ||
+ (n >= 0x2e80 && n <= 0xa4cf && n != 0x303f) ||
+ (n >= 0xac00 && n <= 0xd7a3) || (n >= 0xf900 && n <= 0xfaff) ||
+ (n >= 0xfe10 && n <= 0xfe19) || (n >= 0xfe30 && n <= 0xfe6f) ||
+ (n >= 0xff00 && n <= 0xff60) || (n >= 0xffe0 && n <= 0xffe6) ||
+ (n >= 0x20000 && n <= 0x2fffd) || (n >= 0x30000 && n <= 0x3fffd))
+ wide = 1;
+
+ if (s->cx >= screen_size_x(s) - wide) {
+ s->cx = 0;
+ if (ctx->write != NULL)
+ ctx->write(ctx->data, TTY_CHARACTER, '\r');
+ screen_write_cursor_down_scroll(ctx);
+ } else if (!screen_in_x(s, s->cx) || !screen_in_y(s, s->cy)) {
+ SCREEN_DEBUG(s);
+ return;
+ }
+ attr = s->attr & ~(ATTR_UTF8|ATTR_PAD);
+
+ if ((idx = utf8_add(&s->utf8_table, udat)) == -1)
+ ch = '_';
+ else {
+ utf8_pack(idx, &ch, &attr);
+ attr |= ATTR_UTF8;
+ }
+
+ /* Remove padding before and after, if any. */
+ screen_display_get_cell(s, s->cx, s->cy, &ch2, &attr2, &fg, &bg);
+ if (s->cx > 0 && (attr2 & ATTR_PAD))
+ screen_display_set_cell(s, s->cx - 1, s->cy, ' ', 0, 8, 8);
+ if (s->cx < screen_last_x(s) && (attr2 & ATTR_UTF8)) {
+ screen_display_get_cell(
+ s, s->cx + 1, s->cy, &ch2, &attr2, &fg, &bg);
+ if (s->cx > 0 && (attr2 & ATTR_PAD)) {
+ screen_display_set_cell(
+ s, s->cx + 1, s->cy, ' ', 0, 8, 8);
+ }
+ }
+
+ screen_display_set_cell(s, s->cx, s->cy, ch, attr, s->fg, s->bg);
+ s->cx++;
+
+ if (wide) {
+ screen_display_set_cell(s, s->cx, s->cy, ' ', ATTR_PAD, 8, 8);
+ s->cx++;
+ }
+
+ if (ctx->write != NULL) {
+ ctx->write(ctx->data, TTY_ATTRIBUTES, attr, s->fg, s->bg);
+ ctx->write(ctx->data, TTY_CHARACTER, ch);
+ ctx->write(ctx->data, TTY_ATTRIBUTES, s->attr, s->fg, s->bg);
+ }
+}
+
/* Put a string right-justified. */
size_t printflike2
screen_write_put_string_rjust(
diff --git a/screen.c b/screen.c
index 06d34083..ec3d244b 100644
--- a/screen.c
+++ b/screen.c
@@ -1,4 +1,4 @@
-/* $Id: screen.c,v 1.68 2008-09-08 22:03:54 nicm Exp $ */
+/* $Id: screen.c,v 1.69 2008-09-09 22:16:36 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -155,6 +155,8 @@ screen_create(struct screen *s, u_int dx, u_int dy, u_int hlimit)
s->grid_size = xmalloc(dy * (sizeof *s->grid_size));
screen_make_lines(s, 0, dy);
+ utf8_init(&s->utf8_table, UTF8_LIMIT);
+
screen_clear_selection(s);
}
@@ -348,6 +350,7 @@ screen_set_cell(struct screen *s,
void
screen_destroy(struct screen *s)
{
+ utf8_free(&s->utf8_table);
xfree(s->title);
screen_free_lines(s, 0, s->dy + s->hsize);
xfree(s->grid_data);
diff --git a/server-msg.c b/server-msg.c
index fef163d1..f7dfe2bb 100644
--- a/server-msg.c
+++ b/server-msg.c
@@ -1,4 +1,4 @@
-/* $Id: server-msg.c,v 1.49 2008-07-01 19:47:02 nicm Exp $ */
+/* $Id: server-msg.c,v 1.50 2008-09-09 22:16:37 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -187,6 +187,8 @@ server_msg_fn_identify(struct hdr *hdr, struct client *c)
data.tty[(sizeof data.tty) - 1] = '\0';
tty_init(&c->tty, data.tty, xstrdup(term));
+ if (data.flags & IDENTIFY_UTF8)
+ c->tty.flags |= TTY_UTF8;
xfree(term);
c->flags |= CLIENT_TERMINAL;
diff --git a/tmux.c b/tmux.c
index 605f6854..fb7e56f7 100644
--- a/tmux.c
+++ b/tmux.c
@@ -1,4 +1,4 @@
-/* $Id: tmux.c,v 1.74 2008-08-28 17:45:27 nicm Exp $ */
+/* $Id: tmux.c,v 1.75 2008-09-09 22:16:37 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -175,10 +175,11 @@ main(int argc, char **argv)
struct passwd *pw;
char *path, *cause, *home;
char rpath[MAXPATHLEN];
- int n, opt;
+ int n, opt, flags;
+ flags = 0;
path = NULL;
- while ((opt = getopt(argc, argv, "f:qS:Vv")) != EOF) {
+ while ((opt = getopt(argc, argv, "f:qS:uVv")) != EOF) {
switch (opt) {
case 'f':
cfg_file = xstrdup(optarg);
@@ -189,6 +190,9 @@ main(int argc, char **argv)
case 'q':
be_quiet = 1;
break;
+ case 'u':
+ flags |= IDENTIFY_UTF8;
+ break;
case 'v':
debug_level++;
break;
@@ -286,7 +290,8 @@ main(int argc, char **argv)
memset(&cctx, 0, sizeof cctx);
client_fill_session(&data);
- if (client_init(rpath, &cctx, cmd->entry->flags & CMD_STARTSERVER) != 0)
+ if (client_init(
+ rpath, &cctx, cmd->entry->flags & CMD_STARTSERVER, flags) != 0)
exit(1);
b = buffer_create(BUFSIZ);
cmd_send(cmd, b);
diff --git a/tmux.h b/tmux.h
index 61bf5935..77fb6680 100644
--- a/tmux.h
+++ b/tmux.h
@@ -1,4 +1,4 @@
-/* $Id: tmux.h,v 1.185 2008-09-08 22:18:03 nicm Exp $ */
+/* $Id: tmux.h,v 1.186 2008-09-09 22:16:37 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -19,7 +19,7 @@
#ifndef TMUX_H
#define TMUX_H
-#define PROTOCOL_VERSION -1
+#define PROTOCOL_VERSION -2
/* Shut up gcc warnings about empty if bodies. */
#define RB_AUGMENT(x) do {} while (0)
@@ -375,6 +375,9 @@ struct msg_identify_data {
char tty[TTY_NAME_MAX];
int version;
+#define IDENTIFY_UTF8 0x1
+ int flags;
+
u_int sx;
u_int sy;
@@ -386,6 +389,17 @@ struct msg_resize_data {
u_int sy;
};
+/* UTF8 data. */
+struct utf8_data {
+ u_char data[4];
+};
+
+struct utf8_table {
+ u_int limit;
+ ARRAY_DECL(, struct utf8_data) array;
+};
+#define UTF8_LIMIT ((1<<11) - 1)
+
/* Attributes. */
#define ATTR_BRIGHT 0x1
#define ATTR_DIM 0x2
@@ -395,9 +409,18 @@ struct msg_resize_data {
#define ATTR_HIDDEN 0x20
#define ATTR_ITALICS 0x40
#define ATTR_CHARSET 0x80 /* alternative character set */
+
#define ATTR_FG256 0x100
#define ATTR_BG256 0x200
+#define ATTR_UTF8 0x400
+#define ATTR_PAD 0x800
+
+#define ATTR_UTF8b8 0x8000
+#define ATTR_UTF8b9 0x4000
+#define ATTR_UTF8b10 0x2000
+#define ATTR_UTF8b11 0x1000
+
/* Modes. */
#define MODE_CURSOR 0x1
#define MODE_INSERT 0x2
@@ -442,6 +465,8 @@ struct screen {
u_char fg;
u_char bg;
+ struct utf8_table utf8_table;
+
u_int saved_cx;
u_int saved_cy;
u_short saved_attr;
@@ -541,6 +566,10 @@ struct input_ctx {
#define STRING_NAME 1
#define STRING_IGNORE 2
+ struct utf8_data utf8_buf;
+ u_int utf8_len;
+ u_int utf8_off;
+
void *(*state)(u_char, struct input_ctx *);
u_char private;
@@ -692,6 +721,8 @@ struct tty {
struct buffer *in;
struct buffer *out;
+ int log_fd;
+
struct termios tio;
u_short attr;
@@ -703,6 +734,7 @@ struct tty {
#define TTY_NOCURSOR 0x1
#define TTY_FREEZE 0x2
#define TTY_ESCAPE 0x4
+#define TTY_UTF8 0x8
int flags;
struct timeval key_timer;
@@ -1066,7 +1098,7 @@ void cmd_buffer_free(struct cmd *);
void cmd_buffer_print(struct cmd *, char *, size_t);
/* client.c */
-int client_init(const char *, struct client_ctx *, int);
+int client_init(const char *, struct client_ctx *, int, int);
int client_flush(struct client_ctx *);
int client_main(struct client_ctx *);
@@ -1140,6 +1172,8 @@ void input_parse(struct window *);
void input_key(struct window *, int);
/* screen-display.c */
+void screen_display_get_cell(struct screen *,
+ u_int, u_int, u_char *, u_short *, u_char *, u_char *);
void screen_display_set_cell(
struct screen *, u_int, u_int, u_char, u_short, u_char, u_char);
void screen_display_make_lines(struct screen *, u_int, u_int);
@@ -1168,6 +1202,7 @@ void screen_write_start(struct screen_write_ctx *,
void screen_write_stop(struct screen_write_ctx *);
void screen_write_set_title(struct screen_write_ctx *, char *);
void screen_write_put_character(struct screen_write_ctx *, u_char);
+void screen_write_put_utf8(struct screen_write_ctx *, struct utf8_data *);
size_t printflike2 screen_write_put_string_rjust(
struct screen_write_ctx *, const char *, ...);
void printflike2 screen_write_put_string(
@@ -1290,6 +1325,15 @@ int session_previous(struct session *);
int session_select(struct session *, int);
int session_last(struct session *);
+/* utf8.c */
+void utf8_pack(int, u_char *, u_short *);
+int utf8_unpack(u_char, u_short);
+void utf8_init(struct utf8_table *, int);
+void utf8_free(struct utf8_table *);
+struct utf8_data *utf8_lookup(struct utf8_table *, int);
+int utf8_search(struct utf8_table *, struct utf8_data *);
+int utf8_add(struct utf8_table *, struct utf8_data *);
+
/* buffer.c */
struct buffer *buffer_create(size_t);
void buffer_destroy(struct buffer *);
diff --git a/tty.c b/tty.c
index 9f99cc61..657ff54f 100644
--- a/tty.c
+++ b/tty.c
@@ -1,4 +1,4 @@
-/* $Id: tty.c,v 1.40 2008-09-08 22:03:56 nicm Exp $ */
+/* $Id: tty.c,v 1.41 2008-09-09 22:16:37 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -54,6 +54,7 @@ tty_init(struct tty *tty, char *path, char *term)
tty->termname = xstrdup("unknown");
else
tty->termname = xstrdup(term);
+ tty->flags = 0;
}
int
@@ -73,18 +74,23 @@ tty_open(struct tty *tty, char **cause)
if (fcntl(tty->fd, F_SETFL, mode|O_NONBLOCK) == -1)
fatal("fcntl");
+ if (debug_level > 3) {
+ tty->log_fd = open("tmux.out", O_WRONLY|O_CREAT|O_TRUNC, 0644);
+ } else
+ tty->log_fd = -1;
+
if ((tty->term = tty_find_term(tty->termname, tty->fd, cause)) == NULL)
goto error;
tty->in = buffer_create(BUFSIZ);
tty->out = buffer_create(BUFSIZ);
+ tty->flags &= TTY_UTF8;
+
tty->attr = 0;
tty->fg = 8;
tty->bg = 8;
- tty->flags = 0;
-
if (tcgetattr(tty->fd, &tty->tio) != 0)
fatal("tcgetattr failed");
memcpy(&tio, &tty->tio, sizeof tio);
@@ -140,6 +146,11 @@ tty_close(struct tty *tty)
if (tty->fd == -1)
return;
+ if (tty->log_fd != -1) {
+ close(tty->log_fd);
+ tty->log_fd = -1;
+ }
+
/*
* Skip any writing if the fd is invalid. Things like ssh -t can
* easily leave us with a dead tty.
@@ -384,6 +395,9 @@ tty_puts(struct tty *tty, const char *s)
t = tty_strip(s);
buffer_write(tty->out, t, strlen(t));
+
+ if (tty->log_fd != -1)
+ write(tty->log_fd, t, strlen(t));
}
void
@@ -392,6 +406,9 @@ tty_putc(struct tty *tty, char ch)
if (tty->attr & ATTR_CHARSET)
ch = tty_get_acs(tty, ch);
buffer_write8(tty->out, ch);
+
+ if (tty->log_fd != -1)
+ write(tty->log_fd, &ch, 1);
}
void
@@ -410,8 +427,9 @@ tty_set_title(struct tty *tty, const char *title)
void
tty_vwrite(struct tty *tty, struct screen *s, int cmd, va_list ap)
{
- char ch;
- u_int i, ua, ub, uc;
+ struct utf8_data *udat;
+ char ch;
+ u_int i, ua, ub, uc;
if (tty->flags & TTY_FREEZE)
return;
@@ -423,6 +441,33 @@ tty_vwrite(struct tty *tty, struct screen *s, int cmd, va_list ap)
switch (cmd) {
case TTY_CHARACTER:
ch = va_arg(ap, int);
+
+ if (tty->attr & ATTR_PAD)
+ break;
+
+ if ((tty->attr & ATTR_UTF8) && (tty->flags & TTY_UTF8)) {
+ udat = utf8_lookup(
+ &s->utf8_table, utf8_unpack(ch, tty->attr));
+ if (udat == NULL)
+ ch = '_';
+ else {
+ if (udat->data[0] == 0xff)
+ break;
+ tty_putc(tty, udat->data[0]);
+ if (udat->data[1] == 0xff)
+ break;
+ tty_putc(tty, udat->data[1]);
+ if (udat->data[2] == 0xff)
+ break;
+ tty_putc(tty, udat->data[2]);
+ if (udat->data[3] == 0xff)
+ break;
+ tty_putc(tty, udat->data[3]);
+ break;
+ }
+ } else if (tty->attr & ATTR_UTF8)
+ ch = '_';
+
switch (ch) {
case '\n': /* LF */
tty_putc(tty, '\n');
diff --git a/utf8.c b/utf8.c
new file mode 100644
index 00000000..77179e77
--- /dev/null
+++ b/utf8.c
@@ -0,0 +1,114 @@
+/* $Id: utf8.c,v 1.1 2008-09-09 22:16:37 nicm Exp $ */
+
+/*
+ * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <string.h>
+
+#include "tmux.h"
+
+/*
+ * UTF8 data structures. Just crappy array + linear search for now.
+ */
+
+/* Pack UTF8 index into attr, data. */
+void
+utf8_pack(int idx, u_char *data, u_short *attr)
+{
+ *data = idx & 0xff;
+
+ *attr &= ~(ATTR_UTF8b8|ATTR_UTF8b9);
+ if (idx & 0x100)
+ *attr |= ATTR_UTF8b8;
+ if (idx & 0x200)
+ *attr |= ATTR_UTF8b9;
+ if (idx & 0x400)
+ *attr |= ATTR_UTF8b10;
+ if (idx & 0x800)
+ *attr |= ATTR_UTF8b11;
+}
+
+/* Unpack UTF8 index from attr, data. */
+int
+utf8_unpack(u_char data, u_short attr)
+{
+ int idx;
+
+ idx = data;
+ if (attr & ATTR_UTF8b8)
+ idx |= 0x100;
+ if (attr & ATTR_UTF8b9)
+ idx |= 0x200;
+ if (attr & ATTR_UTF8b10)
+ idx |= 0x400;
+ if (attr & ATTR_UTF8b11)
+ idx |= 0x800;
+
+ return (idx);
+}
+
+void
+utf8_init(struct utf8_table *utab, int limit)
+{
+ utab->limit = limit;
+ ARRAY_INIT(&utab->array);
+}
+
+void
+utf8_free(struct utf8_table *utab)
+{
+ ARRAY_FREE(&utab->array);
+}
+
+struct utf8_data *
+utf8_lookup(struct utf8_table *utab, int idx)
+{
+ if (idx < 0 || idx >= (int) ARRAY_LENGTH(&utab->array))
+ return (NULL);
+ return (&ARRAY_ITEM(&utab->array, idx));
+}
+
+int
+utf8_search(struct utf8_table *utab, struct utf8_data *udat)
+{
+ u_int idx;
+
+ for (idx = 0; idx < ARRAY_LENGTH(&utab->array); idx++) {
+ if (memcmp(udat->data,
+ ARRAY_ITEM(&utab->array, idx).data, sizeof udat->data) == 0)
+ return (idx);
+ }
+ return (-1);
+}
+
+int
+utf8_add(struct utf8_table *utab, struct utf8_data *udat)
+{
+ int idx;
+
+ if (ARRAY_LENGTH(&utab->array) == utab->limit)
+ return (-1);
+
+ if ((idx = utf8_search(utab, udat)) != -1)
+ return (idx);
+
+ ARRAY_EXPAND(&utab->array, 1);
+ memcpy(
+ &ARRAY_LAST(&utab->array), udat, sizeof ARRAY_LAST(&utab->array));
+ return (ARRAY_LENGTH(&utab->array) - 1);
+}