diff options
-rw-r--r-- | CHANGES | 10 | ||||
-rw-r--r-- | TODO | 6 | ||||
-rw-r--r-- | cmd-find-window.c | 32 | ||||
-rw-r--r-- | cmd-list-windows.c | 4 | ||||
-rw-r--r-- | grid-view.c | 30 | ||||
-rw-r--r-- | grid.c | 144 | ||||
-rw-r--r-- | input.c | 19 | ||||
-rw-r--r-- | screen-write.c | 170 | ||||
-rw-r--r-- | screen.c | 22 | ||||
-rw-r--r-- | tmux.h | 41 | ||||
-rw-r--r-- | tty.c | 60 | ||||
-rw-r--r-- | window-copy.c | 48 |
12 files changed, 362 insertions, 224 deletions
@@ -1,5 +1,13 @@ 28 March 2009 +* Better UTF-8 support, including combined characters. Unicode data is now + stored as UTF-8 in a separate array, the code does a lookup into this every + time it gets to a UTF-8 cell. Zero width characters are just appended onto + the UTF-8 data for the previous cell. This also means that almost no bytes + extra are wasted non-Unicode data (yay). + + Still some oddities, such as copy mode skips over wide characters in a + strange way, and the code could do with some tidying. * Key repeating is now a property of the key binding not of the command. Repeat is turned on when the key is bound with the -r flag to bind-key. next/previous-window no longer repeat by default as it turned out to annoy @@ -1152,7 +1160,7 @@ (including mutt, emacs). No status bar yet and no key remapping or other customisation. -$Id: CHANGES,v 1.262 2009-03-28 14:08:09 nicm Exp $ +$Id: CHANGES,v 1.263 2009-03-28 20:17:29 nicm Exp $ LocalWords: showw utf UTF fulvio ciriaco joshe OSC APC gettime abc DEF OA clr LocalWords: rivo nurges lscm Erdely eol smysession mysession ek dstname RB ms @@ -69,11 +69,6 @@ errors better - would be nice if tmux could be the shell (tmux attach, but hard link to tmux binary as "tmuxsh" or wrapper script?) -- problems with tty dev permissions -- UTF-8 combining characters don't work. store in one cell - pointer to table - of chains. bit of a hack and would mean max of 65536 per screen. OR maybe - utf8 should work differently; could store as multiple cells, 1 of width >0 - and n of width 0, then translate cursor indexes on-the-fly would need to - adjust all cursor movement and also handle different width lines properly. - support other mouse modes (highlight etc) and use it in copy mode - set-remain-on-exit is a bit of a hack, some way to do it generically? - set-option should be set-session-option and should be overall global options @@ -92,6 +87,7 @@ - refer to windows by name etc (duplicates? fnmatch?) - a confirm-before command which asks "Are you sure? (y/n)" before executing command, eg bind-key "&" confirm-before "kill-window" +- c&p is funny w/ UTF-8 - document repeat behaviour and -r on bind-key - document status-keys diff --git a/cmd-find-window.c b/cmd-find-window.c index 333969c9..8177b8a2 100644 --- a/cmd-find-window.c +++ b/cmd-find-window.c @@ -1,4 +1,4 @@ -/* $Id: cmd-find-window.c,v 1.4 2009-03-28 16:30:05 nicm Exp $ */ +/* $Id: cmd-find-window.c,v 1.5 2009-03-28 20:17:29 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> @@ -163,25 +163,29 @@ cmd_find_window_callback(void *data, int idx) char * cmd_find_window_search(struct window_pane *wp, const char *searchstr) { - char *buf, *s; - size_t off; - uint64_t text; - u_int i, j, k; - u_char data[4]; + const struct grid_cell *gc; + const struct grid_utf8 *gu; + char *buf, *s; + size_t off; + u_int i, j, k; buf = xmalloc(1); for (j = 0; j < screen_size_y(&wp->base); j++) { off = 0; for (i = 0; i < screen_size_x(&wp->base); i++) { - text = grid_view_peek_text(wp->base.grid, i, j); - utf8_split(text, data); - - buf = xrealloc(buf, 1, off + 4); - for (k = 0; k < sizeof data; k++) { - if (data[k] == 0xff) - break; - buf[off++] = data[k]; + gc = grid_view_peek_cell(wp->base.grid, i, j); + if (gc->flags & GRID_FLAG_UTF8) { + gu = grid_view_peek_utf8(wp->base.grid, i, j); + buf = xrealloc(buf, 1, off + 8); + for (k = 0; k < 8; k++) { + if (gu->data[k] == 0xff) + break; + buf[off++] = gu->data[k]; + } + } else { + buf = xrealloc(buf, 1, off + 1); + buf[off++] = gc->data; } } while (off > 0 && buf[off - 1] == ' ') diff --git a/cmd-list-windows.c b/cmd-list-windows.c index eaf34ba8..9cfc255a 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -1,4 +1,4 @@ -/* $Id: cmd-list-windows.c,v 1.32 2009-03-28 16:30:05 nicm Exp $ */ +/* $Id: cmd-list-windows.c,v 1.33 2009-03-28 20:17:29 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> @@ -68,7 +68,7 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx) size = 0; for (i = 0; i < gd->hsize; i++) { size += gd->size[i] * sizeof **gd->data; - size += gd->size[i] * sizeof (u_short); + size += gd->usize[i] * sizeof **gd->udata; } size += gd->hsize * (sizeof *gd->data); size += gd->hsize * (sizeof *gd->size); diff --git a/grid-view.c b/grid-view.c index 407fdb9c..c6a56af8 100644 --- a/grid-view.c +++ b/grid-view.c @@ -1,4 +1,4 @@ -/* $Id: grid-view.c,v 1.10 2009-03-28 16:57:03 nicm Exp $ */ +/* $Id: grid-view.c,v 1.11 2009-03-28 20:17:29 nicm Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> @@ -37,13 +37,6 @@ grid_view_peek_cell(struct grid *gd, u_int px, u_int py) return (grid_peek_cell(gd, grid_view_x(gd, px), grid_view_y(gd, py))); } -/* Get cell text. */ -uint64_t -grid_view_peek_text(struct grid *gd, u_int px, u_int py) -{ - return (grid_peek_text(gd, grid_view_x(gd, px), grid_view_y(gd, py))); -} - /* Get cell for writing. */ struct grid_cell * grid_view_get_cell(struct grid *gd, u_int px, u_int py) @@ -59,11 +52,26 @@ grid_view_set_cell( grid_set_cell(gd, grid_view_x(gd, px), grid_view_y(gd, py), gc); } -/* Set text. */ +/* Get UTF-8 for reading. */ +const struct grid_utf8 * +grid_view_peek_utf8(struct grid *gd, u_int px, u_int py) +{ + return (grid_peek_utf8(gd, grid_view_x(gd, px), grid_view_y(gd, py))); +} + +/* Get UTF-8 for writing. */ +struct grid_utf8 * +grid_view_get_utf8(struct grid *gd, u_int px, u_int py) +{ + return (grid_get_utf8(gd, grid_view_x(gd, px), grid_view_y(gd, py))); +} + +/* Set UTF-8. */ void -grid_view_set_text(struct grid *gd, u_int px, u_int py, uint64_t text) +grid_view_set_utf8( + struct grid *gd, u_int px, u_int py, const struct grid_utf8 *gu) { - grid_set_text(gd, grid_view_x(gd, px), grid_view_y(gd, py), text); + grid_set_utf8(gd, grid_view_x(gd, px), grid_view_y(gd, py), gu); } /* Clear area. */ @@ -1,4 +1,4 @@ -/* $Id: grid.c,v 1.13 2009-03-28 16:57:03 nicm Exp $ */ +/* $Id: grid.c,v 1.14 2009-03-28 20:17:29 nicm Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> @@ -35,13 +35,13 @@ */ /* Default grid cell data. */ -const struct grid_cell grid_default_cell = { 0, 0, 8, 8 }; +const struct grid_cell grid_default_cell = { 0, 0, 8, 8, ' ' }; #define grid_put_cell(gd, px, py, gc) do { \ memcpy(&gd->data[py][px], gc, sizeof gd->data[py][px]); \ } while (0) -#define grid_put_text(gd, px, py, xtext) do { \ - gd->text[py][px] = xtext; \ +#define grid_put_utf8(gd, px, py, gc) do { \ + memcpy(&gd->udata[py][px], gc, sizeof gd->udata[py][px]); \ } while (0) int grid_check_x(struct grid *, u_int); @@ -100,7 +100,9 @@ grid_create(u_int sx, u_int sy, u_int hlimit) gd->size = xcalloc(gd->sy, sizeof *gd->size); gd->data = xcalloc(gd->sy, sizeof *gd->data); - gd->text = xcalloc(gd->sy, sizeof *gd->text); + + gd->usize = xcalloc(gd->sy, sizeof *gd->usize); + gd->udata = xcalloc(gd->sy, sizeof *gd->udata); return (gd); } @@ -112,18 +114,22 @@ grid_destroy(struct grid *gd) u_int yy; for (yy = 0; yy < gd->hsize + gd->sy; yy++) { - if (gd->text[yy] != NULL) - xfree(gd->text[yy]); + if (gd->udata[yy] != NULL) + xfree(gd->udata[yy]); if (gd->data[yy] != NULL) xfree(gd->data[yy]); } - if (gd->text != NULL) - xfree(gd->text); + if (gd->udata != NULL) + xfree(gd->udata); + if (gd->usize != NULL) + xfree(gd->usize); + if (gd->data != NULL) xfree(gd->data); if (gd->size != NULL) xfree(gd->size); + xfree(gd); } @@ -145,6 +151,7 @@ grid_compare(struct grid *ga, struct grid *gb) gcb = &gb->data[yy][xx]; if (memcmp(gca, gcb, sizeof (struct grid_cell)) != 0) return (1); + /* XXX */ } } @@ -170,13 +177,16 @@ grid_scroll_line(struct grid *gd) } yy = gd->hsize + gd->sy; + gd->size = xrealloc(gd->size, yy + 1, sizeof *gd->size); + gd->size[yy] = 0; gd->data = xrealloc(gd->data, yy + 1, sizeof *gd->data); - gd->text = xrealloc(gd->text, yy + 1, sizeof *gd->text); - gd->data[yy] = NULL; - gd->text[yy] = NULL; - gd->size[yy] = 0; + + gd->usize = xrealloc(gd->usize, yy + 1, sizeof *gd->usize); + gd->usize[yy] = 0; + gd->udata = xrealloc(gd->udata, yy + 1, sizeof *gd->udata); + gd->udata[yy] = NULL; gd->hsize++; } @@ -185,12 +195,14 @@ grid_scroll_line(struct grid *gd) void grid_reduce_line(struct grid *gd, u_int py, u_int sx) { - if (sx >= gd->size[py]) - return; - - gd->data[py] = xrealloc(gd->data[py], sx, sizeof **gd->data); - gd->text[py] = xrealloc(gd->text[py], sx, sizeof **gd->text); - gd->size[py] = sx; + if (sx < gd->size[py]) { + gd->data[py] = xrealloc(gd->data[py], sx, sizeof **gd->data); + gd->size[py] = sx; + } + if (sx < gd->usize[py]) { + gd->udata[py] = xrealloc(gd->udata[py], sx, sizeof **gd->udata); + gd->usize[py] = sx; + } } /* Expand line to fit to cell. */ @@ -203,14 +215,22 @@ grid_expand_line(struct grid *gd, u_int py, u_int sx) return; gd->data[py] = xrealloc(gd->data[py], sx, sizeof **gd->data); - gd->text[py] = xrealloc(gd->text[py], sx, sizeof **gd->text); - for (xx = gd->size[py]; xx < sx; xx++) { + for (xx = gd->size[py]; xx < sx; xx++) grid_put_cell(gd, xx, py, &grid_default_cell); - grid_put_text(gd, xx, py, ' '); - } gd->size[py] = sx; } +/* Expand line to fit to cell for UTF-8. */ +void +grid_expand_line_utf8(struct grid *gd, u_int py, u_int sx) +{ + if (sx <= gd->usize[py]) + return; + + gd->udata[py] = xrealloc(gd->udata[py], sx, sizeof **gd->udata); + gd->usize[py] = sx; +} + /* Get cell for reading. */ const struct grid_cell * grid_peek_cell(struct grid *gd, u_int px, u_int py) @@ -225,20 +245,6 @@ grid_peek_cell(struct grid *gd, u_int px, u_int py) return (&gd->data[py][px]); } -/* Get text for reading. */ -uint64_t -grid_peek_text(struct grid *gd, u_int px, u_int py) -{ - if (grid_check_x(gd, px) != 0) - return (' '); - if (grid_check_y(gd, py) != 0) - return (' '); - - if (px >= gd->size[py]) - return (' '); - return (gd->text[py][px]); -} - /* Get cell at relative position (for writing). */ struct grid_cell * grid_get_cell(struct grid *gd, u_int px, u_int py) @@ -266,17 +272,45 @@ grid_set_cell( grid_put_cell(gd, px, py, gc); } -/* Set text at relative position. */ +/* Get UTF-8 for reading. */ +const struct grid_utf8 * +grid_peek_utf8(struct grid *gd, u_int px, u_int py) +{ + if (grid_check_x(gd, px) != 0) + return (NULL); + if (grid_check_y(gd, py) != 0) + return (NULL); + + if (px >= gd->usize[py]) + return (NULL); + return (&gd->udata[py][px]); +} + +/* Get utf8 at relative position (for writing). */ +struct grid_utf8 * +grid_get_utf8(struct grid *gd, u_int px, u_int py) +{ + if (grid_check_x(gd, px) != 0) + return (NULL); + if (grid_check_y(gd, py) != 0) + return (NULL); + + grid_expand_line_utf8(gd, py, px + 1); + return (&gd->udata[py][px]); +} + +/* Set utf8 at relative position. */ void -grid_set_text(struct grid *gd, u_int px, u_int py, uint64_t text) +grid_set_utf8( + struct grid *gd, u_int px, u_int py, const struct grid_utf8 *gc) { if (grid_check_x(gd, px) != 0) return; if (grid_check_y(gd, py) != 0) return; - grid_expand_line(gd, py, px + 1); - grid_put_text(gd, px, py, text); + grid_expand_line_utf8(gd, py, px + 1); + grid_put_utf8(gd, px, py, gc); } /* @@ -312,7 +346,6 @@ grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny) if (xx >= gd->size[yy]) break; grid_put_cell(gd, xx, yy, &grid_default_cell); - grid_put_text(gd, xx, yy, ' '); } } } @@ -334,13 +367,16 @@ grid_clear_lines(struct grid *gd, u_int py, u_int ny) return; for (yy = py; yy < py + ny; yy++) { - if (gd->data[yy] != NULL || gd->text[yy] != NULL) { + if (gd->data[yy] != NULL) { xfree(gd->data[yy]); - xfree(gd->text[yy]); gd->data[yy] = NULL; - gd->text[yy] = NULL; gd->size[yy] = 0; } + if (gd->udata[yy] != NULL) { + xfree(gd->udata[yy]); + gd->udata[yy] = NULL; + gd->usize[yy] = 0; + } } } @@ -372,16 +408,19 @@ grid_move_lines(struct grid *gd, u_int dy, u_int py, u_int ny) } memmove(&gd->data[dy], &gd->data[py], ny * (sizeof *gd->data)); - memmove(&gd->text[dy], &gd->text[py], ny * (sizeof *gd->text)); memmove(&gd->size[dy], &gd->size[py], ny * (sizeof *gd->size)); + memmove(&gd->udata[dy], &gd->udata[py], ny * (sizeof *gd->udata)); + memmove(&gd->usize[dy], &gd->usize[py], ny * (sizeof *gd->usize)); + /* Wipe any lines that have been moved (without freeing them). */ for (yy = py; yy < py + ny; yy++) { if (yy >= dy && yy < dy + ny) continue; gd->data[yy] = NULL; - gd->text[yy] = NULL; gd->size[yy] = 0; + gd->udata[yy] = NULL; + gd->usize[yy] = 0; } } @@ -407,7 +446,6 @@ grid_clear_cells(struct grid *gd, u_int px, u_int py, u_int nx) if (xx >= gd->size[py]) break; grid_put_cell(gd, xx, py, &grid_default_cell); - grid_put_text(gd, xx, py, ' '); } } @@ -434,14 +472,20 @@ grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx) grid_expand_line(gd, py, px + nx); grid_expand_line(gd, py, dx + nx); memmove(&gd->data[py][dx], &gd->data[py][px], nx * (sizeof **gd->data)); - memmove(&gd->text[py][dx], &gd->text[py][px], nx * (sizeof **gd->text)); + + if (gd->udata[py] != NULL) { + grid_expand_line_utf8(gd, py, px + nx); + grid_expand_line_utf8(gd, py, dx + nx); + memmove(&gd->udata[py][dx], + &gd->udata[py][px], nx * (sizeof **gd->udata)); + } /* Wipe any cells that have been moved. */ for (xx = px; xx < px + nx; xx++) { if (xx >= dx && xx < dx + nx) continue; grid_put_cell(gd, xx, py, &grid_default_cell); - grid_put_text(gd, xx, py, ' ' ); } } + @@ -1,4 +1,4 @@ -/* $Id: input.c,v 1.75 2009-03-28 16:30:05 nicm Exp $ */ +/* $Id: input.c,v 1.76 2009-03-28 20:17:29 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> @@ -528,8 +528,6 @@ input_state_string_escape(u_char ch, struct input_ctx *ictx) void input_state_utf8(u_char ch, struct input_ctx *ictx) { - u_int value; - log_debug2("-- un %zu: %hhu (%c)", ictx->off, ch, ch); ictx->utf8_buf[ictx->utf8_off++] = ch; @@ -537,14 +535,9 @@ input_state_utf8(u_char ch, struct input_ctx *ictx) return; input_state(ictx, input_state_first); - value = utf8_combine(ictx->utf8_buf); - if (value > 0xffff) /* non-BMP not supported */ - value = '_'; - - ictx->text = value; - ictx->cell.flags |= GRID_FLAG_UTF8; - screen_write_cell(&ictx->ctx, &ictx->cell, ictx->text); - ictx->cell.flags &= ~GRID_FLAG_UTF8; + ictx->cell.flags |= GRID_FLAG_UTF8; + screen_write_cell(&ictx->ctx, &ictx->cell, ictx->utf8_buf); + ictx->cell.flags &= ~GRID_FLAG_UTF8; } void @@ -585,8 +578,8 @@ input_handle_character(u_char ch, struct input_ctx *ictx) } log_debug2("-- ch %zu: %hhu (%c)", ictx->off, ch, ch); - ictx->text = ch; - screen_write_cell(&ictx->ctx, &ictx->cell, ictx->text); + ictx->cell.data = ch; + screen_write_cell(&ictx->ctx, &ictx->cell, ictx->utf8_buf); } void diff --git a/screen-write.c b/screen-write.c index 1dc51915..c1808a71 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1,4 +1,4 @@ -/* $Id: screen-write.c,v 1.39 2009-03-28 16:30:05 nicm Exp $ */ +/* $Id: screen-write.c,v 1.40 2009-03-28 20:17:29 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> @@ -23,6 +23,7 @@ #include "tmux.h" void screen_write_save(struct screen_write_ctx *); +void screen_write_overwrite(struct screen_write_ctx *); /* Initialise writing with a window. */ void @@ -47,7 +48,8 @@ void screen_write_putc( struct screen_write_ctx *ctx, struct grid_cell *gc, u_char ch) { - screen_write_cell(ctx, gc, ch); + gc->data = ch; + screen_write_cell(ctx, gc, NULL); } /* Write string. */ @@ -76,21 +78,26 @@ screen_write_copy(struct screen_write_ctx *ctx, struct screen *s = ctx->s; struct grid *gd = src->grid; const struct grid_cell *gc; - uint64_t text; + struct grid_utf8 *gu; + u_char *udata; u_int xx, yy, cx, cy; cx = s->cx; cy = s->cy; for (yy = py; yy < py + ny; yy++) { for (xx = px; xx < px + nx; xx++) { - if (xx >= gd->sx || yy >= gd->hsize + gd->sy) { + if (xx >= gd->sx || yy >= gd->hsize + gd->sy) gc = &grid_default_cell; - text = ' '; - } else { + else gc = grid_peek_cell(gd, xx, yy); - text = grid_peek_text(gd, xx, yy); + + udata = NULL; + if (gc->flags & GRID_FLAG_UTF8) { + gu = grid_get_utf8(gd, xx, yy); + udata = gu->data; } - screen_write_cell(ctx, gc, text); + + screen_write_cell(ctx, gc, udata); } cy++; screen_write_cursormove(ctx, cx, cy); @@ -517,31 +524,55 @@ screen_write_clearscreen(struct screen_write_ctx *ctx) /* Write cell data. */ void screen_write_cell( - struct screen_write_ctx *ctx, const struct grid_cell *gc, uint64_t text) + struct screen_write_ctx *ctx, const struct grid_cell *gc, u_char *udata) { struct screen *s = ctx->s; struct grid *gd = s->grid; - u_int width, xx; - const struct grid_cell *hc; - uint64_t htext; - struct grid_cell *ic, tc; + struct grid_utf8 gu, *tmp_gu; + u_int width, uvalue, xx, i; + struct grid_cell tmp_gc, *tmp_gc2; + size_t size; /* Find character width. */ - if (gc->flags & GRID_FLAG_UTF8) - width = utf8_width(text); - else + if (gc->flags & GRID_FLAG_UTF8) { + uvalue = utf8_combine(udata); + width = utf8_width(uvalue); + + gu.width = width; + memcpy(&gu.data, udata, sizeof gu.data); + } else width = 1; - /* Discard zero-width characters. */ - if (width == 0) + /* If the width is zero, combine onto the previous character. */ + if (width == 0) { + if (s->cx == 0) + return; + gc = grid_view_peek_cell(gd, s->cx - 1, s->cy); + if (!(gc->flags & GRID_FLAG_UTF8)) + return; + tmp_gu = grid_view_get_utf8(gd, s->cx - 1, s->cy); + + for (i = 0; i < 8; i++) { + if (tmp_gu->data[i] == 0xff) + break; + } + memcpy(tmp_gu->data + i, udata, 8 - i); + + /* Assume the previous character has just been input. */ + for (size = 0; size < 8; size++) { + if (udata[size] == 0xff) + break; + } + tty_write_cmd(ctx->wp, TTY_RAW, udata, size); return; + } /* If the character is wider than the screen, don't print it. */ if (width > screen_size_x(s)) { - memcpy(&tc, gc, sizeof tc); - text = '_'; + memcpy(&tmp_gc, gc, sizeof tmp_gc); + tmp_gc.data = '_'; width = 1; - gc = &tc; + gc = &tmp_gc; } /* Check this will fit on the current line; scroll if not. */ @@ -554,18 +585,57 @@ screen_write_cell( if (s->cx > screen_size_x(s) - 1 || s->cy > screen_size_y(s) - 1) return; + /* Handle overwriting of UTF-8 characters. */ + screen_write_overwrite(ctx); + /* - * UTF-8 wide characters are a bit of an annoyance. They take up more - * than one cell on the screen, so following cells must not be drawn by - * marking them as padding. - * - * So far, so good. The problem is, when overwriting a padding cell, or - * a UTF-8 character, it is necessary to also overwrite any other cells - * which covered by the same character. + * If the new character is UTF-8 wide, fill in padding cells. Have + * already ensured there is enough room. */ - hc = grid_view_peek_cell(gd, s->cx, s->cy); - htext = grid_view_peek_text(gd, s->cx, s->cy); - if (hc->flags & GRID_FLAG_PADDING) { + for (xx = s->cx + 1; xx < s->cx + width; xx++) { + tmp_gc2 = grid_view_get_cell(gd, xx, s->cy); + if (tmp_gc2 != NULL) + tmp_gc2->flags |= GRID_FLAG_PADDING; + } + + /* Set the cell. */ + grid_view_set_cell(gd, s->cx, s->cy, gc); + if (gc->flags & GRID_FLAG_UTF8) + grid_view_set_utf8(gd, s->cx, s->cy, &gu); + + /* Move the cursor. */ + screen_write_save(ctx); + s->cx += width; + + /* Draw to the screen if necessary. */ + if (screen_check_selection(s, s->cx - width, s->cy)) + tty_write_cmd(ctx->wp, TTY_CELL, &s->sel.cell, &gu); + else + tty_write_cmd(ctx->wp, TTY_CELL, gc, &gu); +} + +/* + * UTF-8 wide characters are a bit of an annoyance. They take up more than one + * cell on the screen, so following cells must not be drawn by marking them as + * padding. + * + * So far, so good. The problem is, when overwriting a padding cell, or a UTF-8 + * character, it is necessary to also overwrite any other cells which covered + * by the same character. + */ +void +screen_write_overwrite(struct screen_write_ctx *ctx) +{ + struct screen *s = ctx->s; + struct grid *gd = s->grid; + const struct grid_cell *gc; + const struct grid_utf8 *gu; + u_int xx; + + gc = grid_view_peek_cell(gd, s->cx, s->cy); + gu = grid_view_peek_utf8(gd, s->cx, s->cy); + + if (gc->flags & GRID_FLAG_PADDING) { /* * A padding cell, so clear any following and leading padding * cells back to the character. Don't overwrite the current @@ -573,8 +643,8 @@ screen_write_cell( */ xx = s->cx + 1; while (--xx > 0) { - hc = grid_view_peek_cell(gd, xx, s->cy); - if (!(hc->flags & GRID_FLAG_PADDING)) + gc = grid_view_peek_cell(gd, xx, s->cy); + if (!(gc->flags & GRID_FLAG_PADDING)) break; grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); } @@ -585,45 +655,21 @@ screen_write_cell( /* Overwrite following padding cells. */ xx = s->cx; while (++xx < screen_size_x(s)) { - hc = grid_view_peek_cell(gd, xx, s->cy); - if (!(hc->flags & GRID_FLAG_PADDING)) + gc = grid_view_peek_cell(gd, xx, s->cy); + if (!(gc->flags & GRID_FLAG_PADDING)) break; grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); } - } else if (hc->flags & GRID_FLAG_UTF8 && utf8_width(htext) > 1) { + } else if (gc->flags & GRID_FLAG_UTF8 && gu->width > 1) { /* * An UTF-8 wide cell; overwrite following padding cells only. */ xx = s->cx; while (++xx < screen_size_x(s)) { - hc = grid_view_peek_cell(gd, xx, s->cy); - if (!(hc->flags & GRID_FLAG_PADDING)) + gc = grid_view_peek_cell(gd, xx, s->cy); + if (!(gc->flags & GRID_FLAG_PADDING)) break; grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); } } - - /* - * If the new character is UTF-8 wide, fill in padding cells. Have - * already ensured there is enough room. - */ - for (xx = s->cx + 1; xx < s->cx + width; xx++) { - ic = grid_view_get_cell(gd, xx, s->cy); - if (ic != NULL) - ic->flags |= GRID_FLAG_PADDING; - } - - /* Set the cell. */ - grid_view_set_cell(gd, s->cx, s->cy, gc); - grid_view_set_text(gd, s->cx, s->cy, text); - - /* Move the cursor. */ - screen_write_save(ctx); - s->cx += width; - - /* Draw to the screen if necessary. */ - if (screen_check_selection(s, s->cx - width, s->cy)) - tty_write_cmd(ctx->wp, TTY_CELL, &s->sel.cell, text); - else - tty_write_cmd(ctx->wp, TTY_CELL, gc, text); } @@ -1,4 +1,4 @@ -/* $Id: screen.c,v 1.80 2009-03-28 16:30:05 nicm Exp $ */ +/* $Id: screen.c,v 1.81 2009-03-28 20:17:29 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> @@ -89,7 +89,7 @@ screen_resize_x(struct screen *s, u_int sx) { struct grid *gd = s->grid; const struct grid_cell *gc; - uint64_t text; + const struct grid_utf8 *gu; u_int xx, yy; if (sx == 0) @@ -107,16 +107,20 @@ screen_resize_x(struct screen *s, u_int sx) * If the character after the last is wide or padding, remove * it and any leading padding. */ - text = ' '; + gc = &grid_default_cell; for (xx = sx; xx > 0; xx--) { gc = grid_peek_cell(gd, xx - 1, yy); - text = grid_peek_text(gd, xx - 1, yy); if (!(gc->flags & GRID_FLAG_PADDING)) break; grid_set_cell(gd, xx - 1, yy, &grid_default_cell); } - if (xx > 0 && xx != sx && utf8_width(text) != 1) - grid_set_cell(gd, xx - 1, yy, &grid_default_cell); + if (xx > 0 && xx != sx && gc->flags & GRID_FLAG_UTF8) { + gu = grid_peek_utf8(gd, xx - 1, yy); + if (gu->width > 1) { + grid_set_cell( + gd, xx - 1, yy, &grid_default_cell); + } + } /* Reduce the line size. */ grid_reduce_line(gd, yy, sx); @@ -167,7 +171,8 @@ screen_resize_y(struct screen *s, u_int sy) /* Resize line arrays. */ gd->size = xrealloc(gd->size, gd->hsize + sy, sizeof *gd->size); gd->data = xrealloc(gd->data, gd->hsize + sy, sizeof *gd->data); - gd->text = xrealloc(gd->text, gd->hsize + sy, sizeof *gd->text); + gd->usize = xrealloc(gd->usize, gd->hsize + sy, sizeof *gd->usize); + gd->udata = xrealloc(gd->udata, gd->hsize + sy, sizeof *gd->udata); /* Size increasing. */ if (sy > screen_size_y(s)) { @@ -175,7 +180,8 @@ screen_resize_y(struct screen *s, u_int sy) for (yy = gd->hsize + oy; yy < gd->hsize + sy; yy++) { gd->size[yy] = 0; gd->data[yy] = NULL; - gd->text[yy] = NULL; + gd->usize[yy] = 0; + gd->udata[yy] = NULL; } } @@ -1,4 +1,4 @@ -/* $Id: tmux.h,v 1.290 2009-03-28 16:57:03 nicm Exp $ */ +/* $Id: tmux.h,v 1.291 2009-03-28 20:17:29 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> @@ -346,7 +346,7 @@ struct tty_term_code_entry { /* Output commands. */ enum tty_cmd { - TTY_CELL, + TTY_CELL, TTY_CLEARENDOFLINE, TTY_CLEARENDOFSCREEN, TTY_CLEARLINE, @@ -358,6 +358,7 @@ enum tty_cmd { TTY_INSERTCHARACTER, TTY_INSERTLINE, TTY_LINEFEED, + TTY_RAW, TTY_REVERSEINDEX, }; @@ -482,12 +483,19 @@ struct mode_key_data { #define GRID_FLAG_PADDING 0x4 #define GRID_FLAG_UTF8 0x8 -/* Grid cell attributes. */ +/* Grid cell data. */ struct grid_cell { u_char attr; u_char flags; u_char fg; u_char bg; + u_char data; +} __packed; + +/* Grid cell UTF-8 data. Used instead of data in grid_cell for UTF-8 cells. */ +struct grid_utf8 { + u_char width; + u_char data[8]; } __packed; /* Entire grid of cells. */ @@ -498,10 +506,11 @@ struct grid { u_int hsize; u_int hlimit; - u_int *size; /* row size */ - + u_int *size; struct grid_cell **data; - uint16_t **text; + + u_int *usize; + struct grid_utf8 **udata; }; /* Option data structures. */ @@ -591,7 +600,7 @@ struct input_ctx { size_t off; struct grid_cell cell; - uint64_t text; + struct grid_cell saved_cell; u_int saved_cx; @@ -1056,7 +1065,8 @@ long long options_get_number(struct options *, const char *); void tty_reset(struct tty *); void tty_region(struct tty *, u_int, u_int, u_int); void tty_cursor(struct tty *, u_int, u_int, u_int); -void tty_cell(struct tty *, const struct grid_cell *, uint64_t); +void tty_cell(struct tty *, + const struct grid_cell *, const struct grid_utf8 *); void tty_putcode(struct tty *, enum tty_code_code); void tty_putcode1(struct tty *, enum tty_code_code, int); void tty_putcode2(struct tty *, enum tty_code_code, int, int); @@ -1372,12 +1382,14 @@ void grid_destroy(struct grid *); int grid_compare(struct grid *, struct grid *); void grid_reduce_line(struct grid *, u_int, u_int); void grid_expand_line(struct grid *, u_int, u_int); +void grid_expand_line_utf8(struct grid *, u_int, u_int); void grid_scroll_line(struct grid *); const struct grid_cell *grid_peek_cell(struct grid *, u_int, u_int); struct grid_cell *grid_get_cell(struct grid *, u_int, u_int); void grid_set_cell(struct grid *, u_int, u_int, const struct grid_cell *); -uint64_t grid_peek_text(struct grid *, u_int, u_int); -void grid_set_text(struct grid *, u_int, u_int, uint64_t); +const struct grid_utf8 *grid_peek_utf8(struct grid *, u_int, u_int); +struct grid_utf8 *grid_get_utf8(struct grid *, u_int, u_int); +void grid_set_utf8(struct grid *, u_int, u_int, const struct grid_utf8 *); void grid_clear(struct grid *, u_int, u_int, u_int, u_int); void grid_clear_lines(struct grid *, u_int, u_int); void grid_move_lines(struct grid *, u_int, u_int, u_int); @@ -1386,12 +1398,13 @@ void grid_move_cells(struct grid *, u_int, u_int, u_int, u_int); /* grid-view.c */ const struct grid_cell *grid_view_peek_cell(struct grid *, u_int, u_int); -uint64_t grid_view_peek_text(struct grid *, u_int, u_int); struct grid_cell *grid_view_get_cell(struct grid *, u_int, u_int); void grid_view_set_cell( struct grid *, u_int, u_int, const struct grid_cell *); -uint64_t grid_view_peek_text(struct grid *, u_int, u_int); -void grid_view_set_text(struct grid *, u_int, u_int, uint64_t); +const struct grid_utf8 *grid_view_peek_utf8(struct grid *, u_int, u_int); +struct grid_utf8 *grid_view_get_utf8(struct grid *, u_int, u_int); +void grid_view_set_utf8( + struct grid *, u_int, u_int, const struct grid_utf8 *); void grid_view_clear(struct grid *, u_int, u_int, u_int, u_int); void grid_view_scroll_region_up(struct grid *, u_int, u_int); void grid_view_scroll_region_down(struct grid *, u_int, u_int); @@ -1439,7 +1452,7 @@ void screen_write_clearendofscreen(struct screen_write_ctx *); void screen_write_clearstartofscreen(struct screen_write_ctx *); void screen_write_clearscreen(struct screen_write_ctx *); void screen_write_cell( - struct screen_write_ctx *, const struct grid_cell *, uint64_t); + struct screen_write_ctx *, const struct grid_cell *, u_char *); /* screen-redraw.c */ void screen_redraw_screen(struct client *, struct screen *); @@ -1,4 +1,4 @@ -/* $Id: tty.c,v 1.84 2009-03-28 16:30:05 nicm Exp $ */ +/* $Id: tty.c,v 1.85 2009-03-28 20:17:29 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> @@ -54,6 +54,7 @@ void tty_cmd_deleteline(struct tty *, struct window_pane *, va_list); void tty_cmd_insertcharacter(struct tty *, struct window_pane *, va_list); void tty_cmd_insertline(struct tty *, struct window_pane *, va_list); void tty_cmd_linefeed(struct tty *, struct window_pane *, va_list); +void tty_cmd_raw(struct tty *, struct window_pane *, va_list); void tty_cmd_reverseindex(struct tty *, struct window_pane *, va_list); void (*tty_cmds[])(struct tty *, struct window_pane *, va_list) = { @@ -69,6 +70,7 @@ void (*tty_cmds[])(struct tty *, struct window_pane *, va_list) = { tty_cmd_insertcharacter, tty_cmd_insertline, tty_cmd_linefeed, + tty_cmd_raw, tty_cmd_reverseindex, }; @@ -382,7 +384,8 @@ void tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int oy) { const struct grid_cell *gc; - uint64_t text; + struct grid_cell tmp_gc; + const struct grid_utf8 *gu; u_int i, sx; sx = screen_size_x(s); @@ -393,13 +396,17 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int py, u_int oy) for (i = 0; i < sx; i++) { gc = grid_view_peek_cell(s->grid, i, py); - text = grid_view_peek_text(s->grid, i, py); + + gu = NULL; + if (gc->flags & GRID_FLAG_UTF8) + gu = grid_view_peek_utf8(s->grid, i, py); tty_cursor(tty, i, py, oy); - if (screen_check_selection(s, i, py)) - tty_cell(tty, &s->sel.cell, text); - else - tty_cell(tty, gc, text); + if (screen_check_selection(s, i, py)) { + memcpy(&tmp_gc, &s->sel.cell, sizeof tmp_gc); + tty_cell(tty, &tmp_gc, gu); + } else + tty_cell(tty, gc, gu); } if (sx >= tty->sx) @@ -737,21 +744,34 @@ tty_cmd_cell(struct tty *tty, struct window_pane *wp, va_list ap) { struct screen *s = wp->screen; struct grid_cell *gc; - uint64_t text; + struct grid_utf8 *gu; gc = va_arg(ap, struct grid_cell *); - text = va_arg(ap, uint64_t); + gu = va_arg(ap, struct grid_utf8 *); tty_cursor(tty, s->old_cx, s->old_cy, wp->yoff); - tty_cell(tty, gc, text); + tty_cell(tty, gc, gu); +} + +void +tty_cmd_raw(struct tty *tty, unused struct window_pane *wp, va_list ap) +{ + u_char *buf; + size_t i, len; + + buf = va_arg(ap, u_char *); + len = va_arg(ap, size_t); + + for (i = 0; i < len; i++) + tty_putc(tty, buf[i]); } void -tty_cell(struct tty *tty, const struct grid_cell *gc, uint64_t text) +tty_cell( + struct tty *tty, const struct grid_cell *gc, const struct grid_utf8 *gu) { - u_int i, width; - u_char out[4]; + u_int i; /* Skip last character if terminal is stupid. */ if (tty->term->flags & TERM_EARLYWRAP && @@ -767,26 +787,24 @@ tty_cell(struct tty *tty, const struct grid_cell *gc, uint64_t text) /* If not UTF-8, write directly. */ if (!(gc->flags & GRID_FLAG_UTF8)) { - if (text > 0xff || text < 0x20 || text == 0x7f) + if (gc->data < 0x20 || gc->data == 0x7f) return; - tty_putc(tty, text); + tty_putc(tty, gc->data); return; } /* If the terminal doesn't support UTF-8, write underscores. */ if (!(tty->flags & TTY_UTF8)) { - width = utf8_width(text); - while (width-- > 0) + for (i = 0; i < gu->width; i++) tty_putc(tty, '_'); return; } /* Otherwise, unpack UTF-8 and write it. */ - utf8_split(text, out); - for (i = 0; i < 4; i++) { - if (out[i] == 0xff) + for (i = 0; i < 8; i++) { + if (gu->data[i] == 0xff) break; - tty_putc(tty, out[i]); + tty_putc(tty, gu->data[i]); } } diff --git a/window-copy.c b/window-copy.c index efe102e6..728418fc 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1,4 +1,4 @@ -/* $Id: window-copy.c,v 1.51 2009-03-28 16:30:05 nicm Exp $ */ +/* $Id: window-copy.c,v 1.52 2009-03-28 20:17:29 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> @@ -462,12 +462,12 @@ window_copy_copy_selection(struct window_pane *wp, struct client *c) } void -window_copy_copy_line( - struct window_pane *wp, char **buf, size_t *off, u_int sy, u_int sx, u_int ex) +window_copy_copy_line(struct window_pane *wp, + char **buf, size_t *off, u_int sy, u_int sx, u_int ex) { - u_int i, j, xx; - uint64_t text; - u_char data[4]; + const struct grid_cell *gc; + const struct grid_utf8 *gu; + u_int i, j, xx; if (sx > ex) return; @@ -480,14 +480,18 @@ window_copy_copy_line( if (sx < ex) { for (i = sx; i < ex; i++) { - text = grid_peek_text(wp->base.grid, i, sy); - utf8_split(text, data); - - *buf = xrealloc(*buf, 1, (*off) + 4); - for (j = 0; j < sizeof data; j++) { - if (data[j] == 0xff) - break; - (*buf)[(*off)++] = data[j]; + gc = grid_peek_cell(wp->base.grid, i, sy); + if (gc->flags & GRID_FLAG_UTF8) { + *buf = xrealloc(*buf, 1, (*off) + 1); + (*buf)[(*off)++] = gc->data; + } else { + gu = grid_peek_utf8(wp->base.grid, i, sy); + *buf = xrealloc(*buf, 1, (*off) + 8); + for (j = 0; j < 8; j++) { + if (gu->data[i] == 0xff) + break; + (*buf)[(*off)++] = gc->data; + } } } } @@ -501,28 +505,26 @@ int window_copy_is_space(struct window_pane *wp, u_int px, u_int py) { const struct grid_cell *gc; - uint64_t text; const char *spaces = " -_@"; gc = grid_peek_cell(wp->base.grid, px, py); - if (gc->flags & GRID_FLAG_PADDING) + if (gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) return (0); - text = grid_peek_text(wp->base.grid, px, py); - if (text == 0x00 || text == 0x7f || text > 0xff) + if (gc->data == 0x00 || gc->data == 0x7f) return (0); - return (strchr(spaces, text) != NULL); + return (strchr(spaces, gc->data) != NULL); } u_int window_copy_find_length(struct window_pane *wp, u_int py) { - uint64_t text; - u_int px; + const struct grid_cell *gc; + u_int px; px = wp->base.grid->size[py]; while (px > 0) { - text = grid_peek_text(wp->base.grid, px - 1, py); - if (text != 0x20) + gc = grid_peek_cell(wp->base.grid, px - 1, py); + if (!(gc->flags & GRID_FLAG_UTF8) && gc->data != ' ') break; px--; } |