mirror of
https://github.com/tmate-io/tmate.git
synced 2024-12-22 23:00:51 +01:00
Initial UTF-8 support.
This commit is contained in:
parent
1e145a639b
commit
19a2c87f04
7
CHANGES
7
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 $
|
||||
|
@ -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-
|
||||
|
4
Makefile
4
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
|
||||
|
40
TODO
40
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
|
||||
|
@ -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);
|
||||
|
6
client.c
6
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';
|
||||
|
@ -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)
|
||||
|
51
input.c
51
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);
|
||||
}
|
||||
@ -481,11 +487,54 @@ input_state_string_escape(u_char ch, struct input_ctx *ictx)
|
||||
input_state_string_next(ch, 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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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(
|
||||
|
5
screen.c
5
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);
|
||||
|
@ -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;
|
||||
|
13
tmux.c
13
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);
|
||||
|
50
tmux.h
50
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 *);
|
||||
|
55
tty.c
55
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');
|
||||
|
114
utf8.c
Normal file
114
utf8.c
Normal file
@ -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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user