diff --git a/Makefile.am b/Makefile.am index 9cf3bc87..02784c4a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -136,7 +136,6 @@ dist_tmux_SOURCES = \ control-notify.c \ environ.c \ format.c \ - grid-cell.c \ grid-view.c \ grid.c \ input-keys.c \ diff --git a/format.c b/format.c index 5c193038..229e9f42 100644 --- a/format.c +++ b/format.c @@ -432,6 +432,7 @@ format_cb_history_bytes(struct format_tree *ft, struct format_entry *fe) for (i = 0; i < gd->hsize; i++) { gl = &gd->linedata[i]; size += gl->cellsize * sizeof *gl->celldata; + size += gl->extdsize * sizeof *gl->extddata; } size += gd->hsize * sizeof *gd->linedata; diff --git a/grid-cell.c b/grid-cell.c deleted file mode 100644 index 09643a9c..00000000 --- a/grid-cell.c +++ /dev/null @@ -1,55 +0,0 @@ -/* $OpenBSD$ */ - -/* - * Copyright (c) 2012 Nicholas Marriott - * - * 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 - -#include - -#include "tmux.h" - -/* Get cell width. */ -u_int -grid_cell_width(const struct grid_cell *gc) -{ - return (gc->xstate >> 4); -} - -/* Get cell data. */ -void -grid_cell_get(const struct grid_cell *gc, struct utf8_data *ud) -{ - ud->size = gc->xstate & 0xf; - ud->width = gc->xstate >> 4; - memcpy(ud->data, gc->xdata, ud->size); -} - -/* Set cell data. */ -void -grid_cell_set(struct grid_cell *gc, const struct utf8_data *ud) -{ - memcpy(gc->xdata, ud->data, ud->size); - gc->xstate = (ud->width << 4) | ud->size; -} - -/* Set a single character as cell data. */ -void -grid_cell_one(struct grid_cell *gc, u_char ch) -{ - *gc->xdata = ch; - gc->xstate = (1 << 4) | 1; -} diff --git a/grid-view.c b/grid-view.c index badabd56..5edcfd53 100644 --- a/grid-view.c +++ b/grid-view.c @@ -30,24 +30,17 @@ #define grid_view_x(gd, x) (x) #define grid_view_y(gd, y) ((gd)->hsize + (y)) -/* Get cell for reading. */ -const struct grid_cell * -grid_view_peek_cell(struct grid *gd, u_int px, u_int py) +/* Get cel. */ +void +grid_view_get_cell(struct grid *gd, u_int px, u_int py, struct grid_cell *gc) { - return (grid_peek_cell(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) -{ - return (grid_get_cell(gd, grid_view_x(gd, px), grid_view_y(gd, py))); + grid_get_cell(gd, grid_view_x(gd, px), grid_view_y(gd, py), gc); } /* Set cell. */ void -grid_view_set_cell( - struct grid *gd, u_int px, u_int py, const struct grid_cell *gc) +grid_view_set_cell(struct grid *gd, u_int px, u_int py, + const struct grid_cell *gc) { grid_set_cell(gd, grid_view_x(gd, px), grid_view_y(gd, py), gc); } diff --git a/grid.c b/grid.c index b8c9cbb7..36cde074 100644 --- a/grid.c +++ b/grid.c @@ -36,15 +36,17 @@ */ /* Default grid cell data. */ -const struct grid_cell grid_default_cell = { 0, 0, 8, 8, (1 << 4) | 1, " " }; - -#define grid_put_cell(gd, px, py, gc) do { \ - memcpy(&gd->linedata[py].celldata[px], \ - gc, sizeof gd->linedata[py].celldata[px]); \ -} while (0) +const struct grid_cell grid_default_cell = { + 0, 0, 8, 8, { { ' ' }, 0, 1, 1 } +}; +const struct grid_cell_entry grid_default_entry = { + 0, { .data = { 0, 8, 8, ' ' } } +}; int grid_check_y(struct grid *, u_int); +void grid_reflow_copy(struct grid_line *, u_int, struct grid_line *l, + u_int, u_int); void grid_reflow_join(struct grid *, u_int *, struct grid_line *, u_int); void grid_reflow_split(struct grid *, u_int *, struct grid_line *, u_int, u_int); @@ -54,6 +56,13 @@ size_t grid_string_cells_bg(const struct grid_cell *, int *); void grid_string_cells_code(const struct grid_cell *, const struct grid_cell *, char *, size_t, int); +/* Copy default into a cell. */ +static void +grid_clear_cell(struct grid *gd, u_int px, u_int py) +{ + gd->linedata[py].celldata[px] = grid_default_entry; +} + /* Check grid y position. */ int grid_check_y(struct grid *gd, u_int py) @@ -95,6 +104,7 @@ grid_destroy(struct grid *gd) for (yy = 0; yy < gd->hsize + gd->sy; yy++) { gl = &gd->linedata[yy]; free(gl->celldata); + free(gl->extddata); } free(gd->linedata); @@ -107,7 +117,7 @@ int grid_compare(struct grid *ga, struct grid *gb) { struct grid_line *gla, *glb; - struct grid_cell *gca, *gcb; + struct grid_cell gca, gcb; u_int xx, yy; if (ga->sx != gb->sx || ga->sy != gb->sy) @@ -118,10 +128,10 @@ grid_compare(struct grid *ga, struct grid *gb) glb = &gb->linedata[yy]; if (gla->cellsize != glb->cellsize) return (1); - for (xx = 0; xx < ga->sx; xx++) { - gca = &gla->celldata[xx]; - gcb = &glb->celldata[xx]; - if (memcmp(gca, gcb, sizeof (struct grid_cell)) != 0) + for (xx = 0; xx < gla->cellsize; xx++) { + grid_get_cell(ga, xx, yy, &gca); + grid_get_cell(gb, xx, yy, &gcb); + if (memcmp(&gca, &gcb, sizeof (struct grid_cell)) != 0) return (1); } } @@ -224,7 +234,7 @@ grid_expand_line(struct grid *gd, u_int py, u_int sx) gl->celldata = xreallocarray(gl->celldata, sx, sizeof *gl->celldata); for (xx = gl->cellsize; xx < sx; xx++) - grid_put_cell(gd, xx, py, &grid_default_cell); + grid_clear_cell(gd, xx, py); gl->cellsize = sx; } @@ -238,37 +248,72 @@ grid_peek_line(struct grid *gd, u_int py) } /* Get cell for reading. */ -const struct grid_cell * -grid_peek_cell(struct grid *gd, u_int px, u_int py) +void +grid_get_cell(struct grid *gd, u_int px, u_int py, struct grid_cell *gc) { - if (grid_check_y(gd, py) != 0) - return (&grid_default_cell); + struct grid_line *gl; + struct grid_cell_entry *gce; - if (px >= gd->linedata[py].cellsize) - return (&grid_default_cell); - return (&gd->linedata[py].celldata[px]); -} + if (grid_check_y(gd, py) != 0 || px >= gd->linedata[py].cellsize) { + memcpy(gc, &grid_default_cell, sizeof *gc); + return; + } -/* Get cell at relative position (for writing). */ -struct grid_cell * -grid_get_cell(struct grid *gd, u_int px, u_int py) -{ - if (grid_check_y(gd, py) != 0) - return (NULL); + gl = &gd->linedata[py]; + gce = &gl->celldata[px]; - grid_expand_line(gd, py, px + 1); - return (&gd->linedata[py].celldata[px]); + if (gce->flags & GRID_FLAG_EXTENDED) { + if (gce->offset >= gl->extdsize) + memcpy(gc, &grid_default_cell, sizeof *gc); + else + memcpy(gc, &gl->extddata[gce->offset], sizeof *gc); + return; + } + + gc->flags = gce->flags & ~GRID_FLAG_EXTENDED; + gc->attr = gce->data.attr; + gc->fg = gce->data.fg; + gc->bg = gce->data.bg; + utf8_set(&gc->data, gce->data.data); } /* Set cell at relative position. */ void grid_set_cell(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc) { + struct grid_line *gl; + struct grid_cell_entry *gce; + struct grid_cell *gcp; + if (grid_check_y(gd, py) != 0) return; grid_expand_line(gd, py, px + 1); - grid_put_cell(gd, px, py, gc); + + gl = &gd->linedata[py]; + gce = &gl->celldata[px]; + + if ((gce->flags & GRID_FLAG_EXTENDED) || gc->data.size != 1 || + gc->data.width != 1) { + if (~gce->flags & GRID_FLAG_EXTENDED) { + gl->extddata = xreallocarray(gl->extddata, + gl->extdsize + 1, sizeof *gl->extddata); + gce->offset = gl->extdsize++; + gce->flags = gc->flags | GRID_FLAG_EXTENDED; + } + + if (gce->offset >= gl->extdsize) + fatalx("offset too big"); + gcp = &gl->extddata[gce->offset]; + memcpy(gcp, gc, sizeof *gcp); + return; + } + + gce->flags = gc->flags & ~GRID_FLAG_EXTENDED; + gce->data.attr = gc->attr; + gce->data.fg = gc->fg; + gce->data.bg = gc->bg; + gce->data.data = gc->data.data[0]; } /* Clear area. */ @@ -300,7 +345,7 @@ grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny) for (xx = px; xx < px + nx; xx++) { if (xx >= gd->linedata[yy].cellsize) break; - grid_put_cell(gd, xx, yy, &grid_default_cell); + grid_clear_cell(gd, xx, yy); } } } @@ -324,6 +369,10 @@ grid_clear_lines(struct grid *gd, u_int py, u_int ny) gl = &gd->linedata[yy]; free(gl->celldata); memset(gl, 0, sizeof *gl); + + free(gl->extddata); + gl->extddata = NULL; + gl->extdsize = 0; } } @@ -386,7 +435,7 @@ grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx) for (xx = px; xx < px + nx; xx++) { if (xx >= dx && xx < dx + nx) continue; - grid_put_cell(gd, xx, py, &grid_default_cell); + grid_clear_cell(gd, xx, py); } } @@ -568,9 +617,8 @@ char * grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx, struct grid_cell **lastgc, int with_codes, int escape_c0, int trim) { - const struct grid_cell *gc; + struct grid_cell gc; static struct grid_cell lastgc1; - struct utf8_data ud; const char *data; char *buf, code[128]; size_t len, off, size, codelen; @@ -590,21 +638,20 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx, for (xx = px; xx < px + nx; xx++) { if (gl == NULL || xx >= gl->cellsize) break; - gc = &gl->celldata[xx]; - if (gc->flags & GRID_FLAG_PADDING) + grid_get_cell(gd, xx, py, &gc); + if (gc.flags & GRID_FLAG_PADDING) continue; - grid_cell_get(gc, &ud); if (with_codes) { - grid_string_cells_code(*lastgc, gc, code, sizeof code, + grid_string_cells_code(*lastgc, &gc, code, sizeof code, escape_c0); codelen = strlen(code); - memcpy(*lastgc, gc, sizeof *gc); + memcpy(*lastgc, &gc, sizeof **lastgc); } else codelen = 0; - data = ud.data; - size = ud.size; + data = gc.data.data; + size = gc.data.size; if (escape_c0 && size == 1 && *data == '\\') { data = "\\\\"; size = 2; @@ -663,11 +710,44 @@ grid_duplicate_lines(struct grid *dst, u_int dy, struct grid *src, u_int sy, } else dstl->celldata = NULL; + if (srcl->extdsize != 0) { + dstl->extdsize = srcl->extdsize; + dstl->extddata = xreallocarray(NULL, dstl->extdsize, + sizeof *dstl->extddata); + memcpy(dstl->extddata, srcl->extddata, dstl->extdsize * + sizeof *dstl->extddata); + } + sy++; dy++; } } +/* Copy a section of a line. */ +void +grid_reflow_copy(struct grid_line *dst_gl, u_int to, struct grid_line *src_gl, + u_int from, u_int to_copy) +{ + struct grid_cell_entry *gce; + u_int i, was; + + memcpy(&dst_gl->celldata[to], &src_gl->celldata[from], + to_copy * sizeof *dst_gl->celldata); + + for (i = to; i < to + to_copy; i++) { + gce = &dst_gl->celldata[i]; + if (~gce->flags & GRID_FLAG_EXTENDED) + continue; + was = gce->offset; + + dst_gl->extddata = xreallocarray(dst_gl->extddata, + dst_gl->extdsize + 1, sizeof *dst_gl->extddata); + gce->offset = dst_gl->extdsize++; + memcpy(&dst_gl->extddata[gce->offset], &src_gl->extddata[was], + sizeof *dst_gl->extddata); + } +} + /* Join line data. */ void grid_reflow_join(struct grid *dst, u_int *py, struct grid_line *src_gl, @@ -692,8 +772,7 @@ grid_reflow_join(struct grid *dst, u_int *py, struct grid_line *src_gl, dst_gl->cellsize = nx; /* Append as much as possible. */ - memcpy(&dst_gl->celldata[ox], &src_gl->celldata[0], - to_copy * sizeof src_gl->celldata[0]); + grid_reflow_copy(dst_gl, ox, src_gl, 0, to_copy); /* If there is any left in the source, split it. */ if (src_gl->cellsize > to_copy) { @@ -732,8 +811,7 @@ grid_reflow_split(struct grid *dst, u_int *py, struct grid_line *src_gl, dst_gl->flags |= GRID_LINE_WRAPPED; /* Copy the data. */ - memcpy(&dst_gl->celldata[0], &src_gl->celldata[offset], - to_copy * sizeof dst_gl->celldata[0]); + grid_reflow_copy(dst_gl, 0, src_gl, offset, to_copy); /* Move offset and reduce old line size. */ offset += to_copy; @@ -763,6 +841,7 @@ grid_reflow_move(struct grid *dst, u_int *py, struct grid_line *src_gl) /* Clear old line. */ src_gl->celldata = NULL; + src_gl->extddata = NULL; } /* @@ -792,7 +871,7 @@ grid_reflow(struct grid *dst, struct grid *src, u_int new_x) /* Previous was wrapped. Try to join. */ grid_reflow_join(dst, &py, src_gl, new_x); } - previous_wrapped = src_gl->flags & GRID_LINE_WRAPPED; + previous_wrapped = (src_gl->flags & GRID_LINE_WRAPPED); } grid_destroy(src); diff --git a/input.c b/input.c index 41276d9a..c56cdc35 100644 --- a/input.c +++ b/input.c @@ -1006,7 +1006,7 @@ input_print(struct input_ctx *ictx) else ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET; - grid_cell_one(&ictx->cell.cell, ictx->ch); + utf8_set(&ictx->cell.cell.data, ictx->ch); screen_write_cell(&ictx->ctx, &ictx->cell.cell); ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET; @@ -1945,7 +1945,7 @@ input_utf8_close(struct input_ctx *ictx) utf8_append(&ictx->utf8data, ictx->ch); - grid_cell_set(&ictx->cell.cell, &ictx->utf8data); + utf8_copy(&ictx->cell.cell.data, &ictx->utf8data); screen_write_cell(&ictx->ctx, &ictx->cell.cell); return (0); diff --git a/screen-write.c b/screen-write.c index 4bf3ec72..14b8a41a 100644 --- a/screen-write.c +++ b/screen-write.c @@ -67,7 +67,7 @@ void screen_write_putc(struct screen_write_ctx *ctx, struct grid_cell *gc, u_char ch) { - grid_cell_one(gc, ch); + utf8_set(&gc->data, ch); screen_write_cell(ctx, gc); } @@ -126,7 +126,7 @@ screen_write_strlen(const char *fmt, ...) ptr++; left = strlen(ptr); - if (left < ud.size - 1) + if (left < (size_t)ud.size - 1) break; while (utf8_append(&ud, *ptr)) ptr++; @@ -185,7 +185,7 @@ screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen, ptr++; left = strlen(ptr); - if (left < ud.size - 1) + if (left < (size_t)ud.size - 1) break; while (utf8_append(&ud, *ptr)) ptr++; @@ -201,7 +201,7 @@ screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen, } size += ud.width; - grid_cell_set(gc, &ud); + utf8_copy(&gc->data, &ud); screen_write_cell(ctx, gc); } else { if (maxlen > 0 && size + 1 > (size_t) maxlen) @@ -258,7 +258,7 @@ screen_write_cnputs(struct screen_write_ctx *ctx, ssize_t maxlen, ptr++; left = strlen(ptr); - if (left < ud.size - 1) + if (left < (size_t)ud.size - 1) break; while (utf8_append(&ud, *ptr)) ptr++; @@ -274,7 +274,7 @@ screen_write_cnputs(struct screen_write_ctx *ctx, ssize_t maxlen, } size += ud.width; - grid_cell_set(&lgc, &ud); + utf8_copy(&lgc.data, &ud); screen_write_cell(ctx, &lgc); } else { if (maxlen > 0 && size + 1 > (size_t) maxlen) @@ -299,8 +299,7 @@ screen_write_copy(struct screen_write_ctx *ctx, struct screen *s = ctx->s; struct grid *gd = src->grid; struct grid_line *gl; - const struct grid_cell *gc; - struct utf8_data ud; + struct grid_cell gc; u_int xx, yy, cx, cy, ax, bx; cx = s->cx; @@ -324,12 +323,8 @@ screen_write_copy(struct screen_write_ctx *ctx, bx = px + nx; for (xx = ax; xx < bx; xx++) { - if (xx >= gl->cellsize) - gc = &grid_default_cell; - else - gc = &gl->celldata[xx]; - grid_cell_get(gc, &ud); - screen_write_cell(ctx, gc); + grid_get_cell(gd, xx, yy, &gc); + screen_write_cell(ctx, &gc); } if (px + nx == gd->sx && px + nx > gl->cellsize) screen_write_clearendofline(ctx); @@ -342,12 +337,12 @@ screen_write_copy(struct screen_write_ctx *ctx, /* Set up context for TTY command. */ void -screen_write_initctx( - struct screen_write_ctx *ctx, struct tty_ctx *ttyctx, int save_last) +screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx, + int save_last) { struct screen *s = ctx->s; struct grid *gd = s->grid; - const struct grid_cell *gc; + struct grid_cell gc; u_int xx; ttyctx->wp = ctx->wp; @@ -362,14 +357,14 @@ screen_write_initctx( return; /* Save the last cell on the screen. */ - gc = &grid_default_cell; + memcpy(&gc, &grid_default_cell, sizeof gc); for (xx = 1; xx <= screen_size_x(s); xx++) { - gc = grid_view_peek_cell(gd, screen_size_x(s) - xx, s->cy); - if (!(gc->flags & GRID_FLAG_PADDING)) + grid_view_get_cell(gd, screen_size_x(s) - xx, s->cy, &gc); + if (~gc.flags & GRID_FLAG_PADDING) break; } ttyctx->last_width = xx; - memcpy(&ttyctx->last_cell, gc, sizeof ttyctx->last_cell); + memcpy(&ttyctx->last_cell, &gc, sizeof ttyctx->last_cell); } /* Set a mode. */ @@ -507,7 +502,7 @@ screen_write_alignmenttest(struct screen_write_ctx *ctx) screen_write_initctx(ctx, &ttyctx, 0); memcpy(&gc, &grid_default_cell, sizeof gc); - grid_cell_one(&gc, 'E'); + utf8_set(&gc.data, 'E'); for (yy = 0; yy < screen_size_y(s); yy++) { for (xx = 0; xx < screen_size_x(s); xx++) @@ -904,14 +899,13 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) struct grid *gd = s->grid; struct tty_ctx ttyctx; u_int width, xx, last; - struct grid_cell tmp_gc, *tmp_gcp; - struct utf8_data ud; + struct grid_cell tmp_gc; int insert; /* Ignore padding. */ if (gc->flags & GRID_FLAG_PADDING) return; - width = grid_cell_width(gc); + width = gc->data.width; /* * If this is a wide character and there is no room on the screen, for @@ -928,8 +922,7 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) * there is space. */ if (width == 0) { - grid_cell_get(gc, &ud); - if (screen_write_combine(ctx, &ud) == 0) { + if (screen_write_combine(ctx, &gc->data) == 0) { screen_write_initctx(ctx, &ttyctx, 0); tty_write(tty_cmd_utf8character, &ttyctx); } @@ -964,11 +957,11 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) * 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++) { - tmp_gcp = grid_view_get_cell(gd, xx, s->cy); - if (tmp_gcp != NULL) - tmp_gcp->flags |= GRID_FLAG_PADDING; - } + memcpy(&tmp_gc, &grid_default_cell, sizeof tmp_gc); + tmp_gc.flags |= GRID_FLAG_PADDING; + tmp_gc.data.width = 0; + for (xx = s->cx + 1; xx < s->cx + width; xx++) + grid_view_set_cell(gd, xx, s->cy, &tmp_gc); /* Set the cell. */ grid_view_set_cell(gd, s->cx, s->cy, gc); @@ -990,8 +983,7 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) } if (screen_check_selection(s, s->cx - width, s->cy)) { memcpy(&tmp_gc, &s->sel.cell, sizeof tmp_gc); - grid_cell_get(gc, &ud); - grid_cell_set(&tmp_gc, &ud); + utf8_copy(&tmp_gc.data, &gc->data); tmp_gc.attr = tmp_gc.attr & ~GRID_ATTR_CHARSET; tmp_gc.attr |= gc->attr & GRID_ATTR_CHARSET; tmp_gc.flags = gc->flags & ~(GRID_FLAG_FG256|GRID_FLAG_BG256); @@ -1011,8 +1003,7 @@ screen_write_combine(struct screen_write_ctx *ctx, const struct utf8_data *ud) { struct screen *s = ctx->s; struct grid *gd = s->grid; - struct grid_cell *gc; - struct utf8_data ud1; + struct grid_cell gc; /* Can't combine if at 0. */ if (s->cx == 0) @@ -1023,17 +1014,18 @@ screen_write_combine(struct screen_write_ctx *ctx, const struct utf8_data *ud) fatalx("UTF-8 data empty"); /* Retrieve the previous cell. */ - gc = grid_view_get_cell(gd, s->cx - 1, s->cy); - grid_cell_get(gc, &ud1); + grid_view_get_cell(gd, s->cx - 1, s->cy, &gc); /* Check there is enough space. */ - if (ud1.size + ud->size > sizeof ud1.data) + if (gc.data.size + ud->size > sizeof gc.data.data) return (-1); - /* Append the data and set the cell. */ - memcpy(ud1.data + ud1.size, ud->data, ud->size); - ud1.size += ud->size; - grid_cell_set(gc, &ud1); + /* Append the data. */ + memcpy(gc.data.data + gc.data.size, ud->data, ud->size); + gc.data.size += ud->size; + + /* Set the new cell. */ + grid_view_set_cell(gd, s->cx - 1, s->cy, &gc); return (0); } @@ -1052,11 +1044,11 @@ screen_write_overwrite(struct screen_write_ctx *ctx, u_int width) { struct screen *s = ctx->s; struct grid *gd = s->grid; - const struct grid_cell *gc; + struct grid_cell gc; u_int xx; - gc = grid_view_peek_cell(gd, s->cx, s->cy); - if (gc->flags & GRID_FLAG_PADDING) { + grid_view_get_cell(gd, s->cx, s->cy, &gc); + 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 @@ -1064,8 +1056,8 @@ screen_write_overwrite(struct screen_write_ctx *ctx, u_int width) */ xx = s->cx + 1; while (--xx > 0) { - gc = grid_view_peek_cell(gd, xx, s->cy); - if (!(gc->flags & GRID_FLAG_PADDING)) + grid_view_get_cell(gd, xx, s->cy, &gc); + if (~gc.flags & GRID_FLAG_PADDING) break; grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); } @@ -1080,8 +1072,8 @@ screen_write_overwrite(struct screen_write_ctx *ctx, u_int width) */ xx = s->cx + width - 1; while (++xx < screen_size_x(s)) { - gc = grid_view_peek_cell(gd, xx, s->cy); - if (!(gc->flags & GRID_FLAG_PADDING)) + grid_view_get_cell(gd, xx, s->cy, &gc); + if (~gc.flags & GRID_FLAG_PADDING) break; grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); } diff --git a/status.c b/status.c index a4bdf6fa..326e5ad8 100644 --- a/status.c +++ b/status.c @@ -746,7 +746,7 @@ status_prompt_redraw(struct client *c) struct session *s = c->session; struct screen old_status; size_t i, size, left, len, off; - struct grid_cell gc, *gcp; + struct grid_cell gc; if (c->tty.sx == 0 || c->tty.sy == 0) return (0); @@ -789,8 +789,9 @@ status_prompt_redraw(struct client *c) /* Apply fake cursor. */ off = len + c->prompt_index - off; - gcp = grid_view_get_cell(c->status.grid, off, 0); - gcp->attr ^= GRID_ATTR_REVERSE; + grid_view_get_cell(c->status.grid, off, 0, &gc); + gc.attr ^= GRID_ATTR_REVERSE; + grid_view_set_cell(c->status.grid, off, 0, &gc); if (grid_compare(c->status.grid, old_status.grid) == 0) { screen_free(&old_status); diff --git a/tmux.h b/tmux.h index 886392fc..7439a844 100644 --- a/tmux.h +++ b/tmux.h @@ -624,11 +624,11 @@ struct mode_key_table { struct utf8_data { u_char data[UTF8_SIZE]; - size_t have; - size_t size; + u_char have; + u_char size; - u_int width; -}; + u_char width; +} __packed; /* Grid attributes. */ #define GRID_ATTR_BRIGHT 0x1 @@ -644,41 +644,56 @@ struct utf8_data { #define GRID_FLAG_FG256 0x1 #define GRID_FLAG_BG256 0x2 #define GRID_FLAG_PADDING 0x4 +#define GRID_FLAG_EXTENDED 0x8 /* Grid line flags. */ #define GRID_LINE_WRAPPED 0x1 /* Grid cell data. */ struct grid_cell { - u_char attr; - u_char flags; - u_char fg; - u_char bg; + u_char flags; + u_char attr; + u_char fg; + u_char bg; + struct utf8_data data; - u_char xstate; /* top 4 bits width, bottom 4 bits size */ - u_char xdata[UTF8_SIZE]; +}; +struct grid_cell_entry { + u_char flags; + union { + u_int offset; + struct { + u_char attr; + u_char fg; + u_char bg; + u_char data; + } data; + }; } __packed; /* Grid line. */ struct grid_line { - u_int cellsize; - struct grid_cell *celldata; + u_int cellsize; + struct grid_cell_entry *celldata; - int flags; + u_int extdsize; + struct grid_cell *extddata; + + int flags; } __packed; /* Entire grid of cells. */ struct grid { - int flags; -#define GRID_HISTORY 0x1 /* scroll lines into history */ + int flags; +#define GRID_HISTORY 0x1 /* scroll lines into history */ - u_int sx; - u_int sy; + u_int sx; + u_int sy; - u_int hsize; - u_int hlimit; + u_int hsize; + u_int hlimit; - struct grid_line *linedata; + struct grid_line *linedata; }; /* Option data structures. */ @@ -1857,9 +1872,8 @@ void grid_scroll_history(struct grid *); void grid_scroll_history_region(struct grid *, u_int, u_int); void grid_clear_history(struct grid *); void grid_expand_line(struct grid *, u_int, u_int); -const struct grid_cell *grid_peek_cell(struct grid *, u_int, u_int); const struct grid_line *grid_peek_line(struct grid *, u_int); -struct grid_cell *grid_get_cell(struct grid *, u_int, u_int); +void grid_get_cell(struct grid *, u_int, u_int, struct grid_cell *); void grid_set_cell(struct grid *, u_int, u_int, const struct grid_cell *); void grid_clear(struct grid *, u_int, u_int, u_int, u_int); void grid_clear_lines(struct grid *, u_int, u_int); @@ -1871,17 +1885,10 @@ void grid_duplicate_lines( struct grid *, u_int, struct grid *, u_int, u_int); u_int grid_reflow(struct grid *, struct grid *, u_int); -/* grid-cell.c */ -u_int grid_cell_width(const struct grid_cell *); -void grid_cell_get(const struct grid_cell *, struct utf8_data *); -void grid_cell_set(struct grid_cell *, const struct utf8_data *); -void grid_cell_one(struct grid_cell *, u_char); - /* grid-view.c */ -const struct grid_cell *grid_view_peek_cell(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 *); +void grid_view_get_cell(struct grid *, u_int, u_int, struct grid_cell *); +void grid_view_set_cell(struct grid *, u_int, u_int, + const struct grid_cell *); void grid_view_clear_history(struct grid *); 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); @@ -2186,6 +2193,7 @@ void session_renumber_windows(struct session *); /* utf8.c */ u_int utf8_width(u_int); void utf8_set(struct utf8_data *, u_char); +void utf8_copy(struct utf8_data *, const struct utf8_data *); int utf8_open(struct utf8_data *, u_char); int utf8_append(struct utf8_data *, u_char); u_int utf8_combine(const struct utf8_data *); diff --git a/tty.c b/tty.c index c0ae79bb..e67ebbb6 100644 --- a/tty.c +++ b/tty.c @@ -656,10 +656,8 @@ void tty_draw_line(struct tty *tty, const struct window_pane *wp, struct screen *s, u_int py, u_int ox, u_int oy) { - const struct grid_cell *gc; + struct grid_cell gc; struct grid_line *gl; - struct grid_cell tmpgc; - struct utf8_data ud; u_int i, sx; int flags; @@ -686,18 +684,13 @@ tty_draw_line(struct tty *tty, const struct window_pane *wp, tty_cursor(tty, ox, oy + py); for (i = 0; i < sx; i++) { - gc = grid_view_peek_cell(s->grid, i, py); + grid_view_get_cell(s->grid, i, py, &gc); if (screen_check_selection(s, i, py)) { - memcpy(&tmpgc, &s->sel.cell, sizeof tmpgc); - grid_cell_get(gc, &ud); - grid_cell_set(&tmpgc, &ud); - tmpgc.flags = gc->flags & - ~(GRID_FLAG_FG256|GRID_FLAG_BG256); - tmpgc.flags |= s->sel.cell.flags & + gc.flags &= ~(GRID_FLAG_FG256|GRID_FLAG_BG256); + gc.flags |= s->sel.cell.flags & (GRID_FLAG_FG256|GRID_FLAG_BG256); - tty_cell(tty, &tmpgc, wp); - } else - tty_cell(tty, gc, wp); + } + tty_cell(tty, &gc, wp); } if (sx < tty->sx) { @@ -1078,7 +1071,7 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); /* Is the cursor in the very last position? */ - width = grid_cell_width(ctx->cell); + width = ctx->cell->data.width; if (ctx->ocx > wp->sx - width) { if (ctx->xoff != 0 || wp->sx != tty->sx) { /* @@ -1095,7 +1088,7 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) * move as far left as possible and redraw the last * cell to move into the last position. */ - cx = screen_size_x(s) - grid_cell_width(&ctx->last_cell); + cx = screen_size_x(s) - ctx->last_cell.data.width; tty_cursor_pane(tty, ctx, cx, ctx->ocy); tty_cell(tty, &ctx->last_cell, wp); } @@ -1155,8 +1148,7 @@ void tty_cell(struct tty *tty, const struct grid_cell *gc, const struct window_pane *wp) { - struct utf8_data ud; - u_int i; + u_int i; /* Skip last character if terminal is stupid. */ if (tty->term->flags & TERM_EARLYWRAP && @@ -1171,23 +1163,22 @@ tty_cell(struct tty *tty, const struct grid_cell *gc, tty_attributes(tty, gc, wp); /* Get the cell and if ASCII write with putc to do ACS translation. */ - grid_cell_get(gc, &ud); - if (ud.size == 1) { - if (*ud.data < 0x20 || *ud.data == 0x7f) + if (gc->data.size == 1) { + if (*gc->data.data < 0x20 || *gc->data.data == 0x7f) return; - tty_putc(tty, *ud.data); + tty_putc(tty, *gc->data.data); return; } /* If not UTF-8, write _. */ if (!(tty->flags & TTY_UTF8)) { - for (i = 0; i < ud.width; i++) + for (i = 0; i < gc->data.width; i++) tty_putc(tty, '_'); return; } /* Write the data. */ - tty_putn(tty, ud.data, ud.size, ud.width); + tty_putn(tty, gc->data.data, gc->data.size, gc->data.width); } void diff --git a/utf8.c b/utf8.c index 781dbbbf..350d6c06 100644 --- a/utf8.c +++ b/utf8.c @@ -351,10 +351,27 @@ static void utf8_build(void); void utf8_set(struct utf8_data *ud, u_char ch) { + u_int i; + *ud->data = ch; ud->size = 1; ud->width = 1; + + for (i = ud->size; i < sizeof ud->data; i++) + ud->data[i] = '\0'; +} + +/* Copy UTF-8 character. */ +void +utf8_copy(struct utf8_data *to, const struct utf8_data *from) +{ + u_int i; + + memcpy(to, from, sizeof *to); + + for (i = to->size; i < sizeof to->data; i++) + to->data[i] = '\0'; } /* diff --git a/window-copy.c b/window-copy.c index 1c1ea29c..a28cdecc 100644 --- a/window-copy.c +++ b/window-copy.c @@ -942,21 +942,21 @@ int window_copy_search_compare(struct grid *gd, u_int px, u_int py, struct grid *sgd, u_int spx, int cis) { - const struct grid_cell *gc, *sgc; - struct utf8_data ud, sud; + struct grid_cell gc, sgc; + const struct utf8_data *ud, *sud; - gc = grid_peek_cell(gd, px, py); - grid_cell_get(gc, &ud); - sgc = grid_peek_cell(sgd, spx, 0); - grid_cell_get(sgc, &sud); + grid_get_cell(gd, px, py, &gc); + ud = &gc.data; + grid_get_cell(sgd, spx, 0, &sgc); + sud = &sgc.data; - if (ud.size != sud.size || ud.width != sud.width) + if (ud->size != sud->size || ud->width != sud->width) return (0); - if (cis && ud.size == 1) - return (tolower(ud.data[0]) == sud.data[0]); + if (cis && ud->size == 1) + return (tolower(ud->data[0]) == sud->data[0]); - return (memcmp(ud.data, sud.data, ud.size) == 0); + return (memcmp(ud->data, sud->data, ud->size) == 0); } int @@ -1541,12 +1541,12 @@ window_copy_append_selection(struct window_pane *wp, const char *bufname) } 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) { struct window_copy_mode_data *data = wp->modedata; struct grid *gd = data->backing->grid; - const struct grid_cell *gc; + struct grid_cell gc; struct grid_line *gl; struct utf8_data ud; u_int i, xx, wrapped = 0; @@ -1575,11 +1575,11 @@ window_copy_copy_line(struct window_pane *wp, if (sx < ex) { for (i = sx; i < ex; i++) { - gc = grid_peek_cell(gd, i, sy); - if (gc->flags & GRID_FLAG_PADDING) + grid_get_cell(gd, i, sy, &gc); + if (gc.flags & GRID_FLAG_PADDING) continue; - grid_cell_get(gc, &ud); - if (ud.size == 1 && (gc->attr & GRID_ATTR_CHARSET)) { + utf8_copy(&ud, &gc.data); + if (ud.size == 1 && (gc.attr & GRID_ATTR_CHARSET)) { s = tty_acs_get(NULL, ud.data[0]); if (s != NULL && strlen(s) <= sizeof ud.data) { ud.size = strlen(s); @@ -1618,16 +1618,17 @@ int window_copy_in_set(struct window_pane *wp, u_int px, u_int py, const char *set) { struct window_copy_mode_data *data = wp->modedata; - const struct grid_cell *gc; - struct utf8_data ud; + struct grid_cell gc; + const struct utf8_data *ud; - gc = grid_peek_cell(data->backing->grid, px, py); - grid_cell_get(gc, &ud); - if (ud.size != 1 || gc->flags & GRID_FLAG_PADDING) + grid_get_cell(data->backing->grid, px, py, &gc); + + ud = &gc.data; + if (ud->size != 1 || (gc.flags & GRID_FLAG_PADDING)) return (0); - if (*ud.data == 0x00 || *ud.data == 0x7f) + if (*ud->data == 0x00 || *ud->data == 0x7f) return (0); - return (strchr(set, *ud.data) != NULL); + return (strchr(set, *ud->data) != NULL); } u_int @@ -1635,8 +1636,7 @@ window_copy_find_length(struct window_pane *wp, u_int py) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = data->backing; - const struct grid_cell *gc; - struct utf8_data ud; + struct grid_cell gc; u_int px; /* @@ -1649,9 +1649,8 @@ window_copy_find_length(struct window_pane *wp, u_int py) if (px > screen_size_x(s)) px = screen_size_x(s); while (px > 0) { - gc = grid_peek_cell(s->grid, px - 1, py); - grid_cell_get(gc, &ud); - if (ud.size != 1 || *ud.data != ' ') + grid_get_cell(s->grid, px - 1, py, &gc); + if (gc.data.size != 1 || *gc.data.data != ' ') break; px--; } @@ -1685,17 +1684,15 @@ window_copy_cursor_back_to_indentation(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; u_int px, py, xx; - const struct grid_cell *gc; - struct utf8_data ud; + struct grid_cell gc; px = 0; py = screen_hsize(data->backing) + data->cy - data->oy; xx = window_copy_find_length(wp, py); while (px < xx) { - gc = grid_peek_cell(data->backing->grid, px, py); - grid_cell_get(gc, &ud); - if (ud.size != 1 || *ud.data != ' ') + grid_get_cell(data->backing->grid, px, py, &gc); + if (gc.data.size != 1 || *gc.data.data != ' ') break; px++; } @@ -1909,8 +1906,7 @@ window_copy_cursor_jump(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; struct screen *back_s = data->backing; - const struct grid_cell *gc; - struct utf8_data ud; + struct grid_cell gc; u_int px, py, xx; px = data->cx + 1; @@ -1918,10 +1914,9 @@ window_copy_cursor_jump(struct window_pane *wp) xx = window_copy_find_length(wp, py); while (px < xx) { - gc = grid_peek_cell(back_s->grid, px, py); - grid_cell_get(gc, &ud); - if (!(gc->flags & GRID_FLAG_PADDING) && - ud.size == 1 && *ud.data == data->jumpchar) { + grid_get_cell(back_s->grid, px, py, &gc); + if (!(gc.flags & GRID_FLAG_PADDING) && + gc.data.size == 1 && *gc.data.data == data->jumpchar) { window_copy_update_cursor(wp, px, data->cy); if (window_copy_update_selection(wp, 1)) window_copy_redraw_lines(wp, data->cy, 1); @@ -1936,8 +1931,7 @@ window_copy_cursor_jump_back(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; struct screen *back_s = data->backing; - const struct grid_cell *gc; - struct utf8_data ud; + struct grid_cell gc; u_int px, py; px = data->cx; @@ -1947,10 +1941,9 @@ window_copy_cursor_jump_back(struct window_pane *wp) px--; for (;;) { - gc = grid_peek_cell(back_s->grid, px, py); - grid_cell_get(gc, &ud); - if (!(gc->flags & GRID_FLAG_PADDING) && - ud.size == 1 && *ud.data == data->jumpchar) { + grid_get_cell(back_s->grid, px, py, &gc); + if (!(gc.flags & GRID_FLAG_PADDING) && + gc.data.size == 1 && *gc.data.data == data->jumpchar) { window_copy_update_cursor(wp, px, data->cy); if (window_copy_update_selection(wp, 1)) window_copy_redraw_lines(wp, data->cy, 1); @@ -1967,8 +1960,7 @@ window_copy_cursor_jump_to(struct window_pane *wp, int jump_again) { struct window_copy_mode_data *data = wp->modedata; struct screen *back_s = data->backing; - const struct grid_cell *gc; - struct utf8_data ud; + struct grid_cell gc; u_int px, py, xx; px = data->cx + 1 + jump_again; @@ -1976,10 +1968,9 @@ window_copy_cursor_jump_to(struct window_pane *wp, int jump_again) xx = window_copy_find_length(wp, py); while (px < xx) { - gc = grid_peek_cell(back_s->grid, px, py); - grid_cell_get(gc, &ud); - if (!(gc->flags & GRID_FLAG_PADDING) && - ud.size == 1 && *ud.data == data->jumpchar) { + grid_get_cell(back_s->grid, px, py, &gc); + if (!(gc.flags & GRID_FLAG_PADDING) && + gc.data.size == 1 && *gc.data.data == data->jumpchar) { window_copy_update_cursor(wp, px - 1, data->cy); if (window_copy_update_selection(wp, 1)) window_copy_redraw_lines(wp, data->cy, 1); @@ -1994,8 +1985,7 @@ window_copy_cursor_jump_to_back(struct window_pane *wp, int jump_again) { struct window_copy_mode_data *data = wp->modedata; struct screen *back_s = data->backing; - const struct grid_cell *gc; - struct utf8_data ud; + struct grid_cell gc; u_int px, py; px = data->cx; @@ -2008,10 +1998,9 @@ window_copy_cursor_jump_to_back(struct window_pane *wp, int jump_again) px--; for (;;) { - gc = grid_peek_cell(back_s->grid, px, py); - grid_cell_get(gc, &ud); - if (!(gc->flags & GRID_FLAG_PADDING) && - ud.size == 1 && *ud.data == data->jumpchar) { + grid_get_cell(back_s->grid, px, py, &gc); + if (!(gc.flags & GRID_FLAG_PADDING) && + gc.data.size == 1 && *gc.data.data == data->jumpchar) { window_copy_update_cursor(wp, px + 1, data->cy); if (window_copy_update_selection(wp, 1)) window_copy_redraw_lines(wp, data->cy, 1);