=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/tmux/screen-write.c,v retrieving revision 1.108 retrieving revision 1.109 diff -c -r1.108 -r1.109 *** src/usr.bin/tmux/screen-write.c 2017/02/08 15:49:29 1.108 --- src/usr.bin/tmux/screen-write.c 2017/02/08 16:45:18 1.109 *************** *** 1,4 **** ! /* $OpenBSD: screen-write.c,v 1.108 2017/02/08 15:49:29 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott --- 1,4 ---- ! /* $OpenBSD: screen-write.c,v 1.109 2017/02/08 16:45:18 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott *************** *** 25,31 **** static void screen_write_initctx(struct screen_write_ctx *, struct tty_ctx *); ! static void screen_write_flush(struct screen_write_ctx *); static int screen_write_overwrite(struct screen_write_ctx *, struct grid_cell *, u_int); --- 25,34 ---- static void screen_write_initctx(struct screen_write_ctx *, struct tty_ctx *); ! static void screen_write_collect_clear(struct screen_write_ctx *, u_int, ! u_int); ! static void screen_write_collect_scroll(struct screen_write_ctx *); ! static void screen_write_collect_flush(struct screen_write_ctx *); static int screen_write_overwrite(struct screen_write_ctx *, struct grid_cell *, u_int); *************** *** 36,75 **** GRID_FLAG_PADDING, 0, 8, 8, { { 0 }, 0, 0, 0 } }; ! #define screen_dirty_bit(s, x, y) (((y) * screen_size_x(s)) + (x)) ! #define screen_dirty_clear(s, sx, sy, ex, ey) \ ! do { \ ! if (s->dirty != NULL) { \ ! bit_nclear(s->dirty, \ ! screen_dirty_bit(s, sx, sy), \ ! screen_dirty_bit(s, ex, ey)); \ ! } \ ! } while (0) /* Initialize writing with a window. */ void screen_write_start(struct screen_write_ctx *ctx, struct window_pane *wp, struct screen *s) { - u_int size; char tmp[16]; ctx->wp = wp; if (wp != NULL && s == NULL) ctx->s = wp->screen; else ctx->s = s; ! size = screen_size_x(ctx->s) * screen_size_y(ctx->s); ! if (ctx->s->dirtysize != size) { ! free(ctx->s->dirty); ! ctx->s->dirty = NULL; ! ctx->s->dirtysize = size; ! } ! ctx->dirty = 0; - ctx->cells = ctx->written = ctx->skipped = 0; - if (wp != NULL) snprintf(tmp, sizeof tmp, "pane %%%u", wp->id); log_debug("%s: size %ux%u, %s", __func__, screen_size_x(ctx->s), --- 39,79 ---- GRID_FLAG_PADDING, 0, 8, 8, { { 0 }, 0, 0, 0 } }; ! struct screen_write_collect_item { ! u_int x; + u_int used; + char data[256]; + + struct grid_cell gc; + + TAILQ_ENTRY (screen_write_collect_item) entry; + }; + struct screen_write_collect_line { + TAILQ_HEAD(, screen_write_collect_item) items; + }; + /* Initialize writing with a window. */ void screen_write_start(struct screen_write_ctx *ctx, struct window_pane *wp, struct screen *s) { char tmp[16]; + u_int y; + memset(ctx, 0, sizeof *ctx); + ctx->wp = wp; if (wp != NULL && s == NULL) ctx->s = wp->screen; else ctx->s = s; ! ctx->list = xcalloc(screen_size_y(ctx->s), sizeof *ctx->list); ! for (y = 0; y < screen_size_y(ctx->s); y++) ! TAILQ_INIT(&ctx->list[y].items); ! ctx->item = xcalloc(1, sizeof *ctx->item); if (wp != NULL) snprintf(tmp, sizeof tmp, "pane %%%u", wp->id); log_debug("%s: size %ux%u, %s", __func__, screen_size_x(ctx->s), *************** *** 80,134 **** void screen_write_stop(struct screen_write_ctx *ctx) { ! screen_write_flush(ctx); ! log_debug("%s: %u of %u written (dirty %u, skipped %u)", __func__, ! ctx->written, ctx->cells, ctx->cells - ctx->written, ctx->skipped); ! } ! /* Flush outstanding cell writes. */ ! static void ! screen_write_flush(struct screen_write_ctx *ctx) ! { ! struct screen *s = ctx->s; ! struct tty_ctx ttyctx; ! u_int x, y, offset, cx, cy, dirty; ! struct grid_cell gc; ! ! if (ctx->dirty == 0) ! return; ! dirty = 0; ! log_debug("%s: dirty %u", __func__, ctx->dirty); ! ! cx = s->cx; ! cy = s->cy; ! ! offset = 0; ! for (y = 0; y < screen_size_y(s); y++) { ! for (x = 0; x < screen_size_x(s); x++) { ! offset++; ! if (!bit_test(s->dirty, offset - 1)) ! continue; ! bit_clear(s->dirty, offset - 1); ! ! screen_write_cursormove(ctx, x, y); ! grid_view_get_cell(s->grid, x, y, &gc); ! ! screen_write_initctx(ctx, &ttyctx); ! ttyctx.cell = &gc; ! tty_write(tty_cmd_cell, &ttyctx); ! ctx->written++; ! ! if (++dirty == ctx->dirty) ! break; ! } ! if (dirty == ctx->dirty) ! break; ! } ! ctx->dirty = 0; ! ! s->cx = cx; ! s->cy = cy; } /* Reset screen state. */ --- 84,97 ---- void screen_write_stop(struct screen_write_ctx *ctx) { ! screen_write_collect_end(ctx); ! screen_write_collect_flush(ctx); ! log_debug("%s: %u cells (%u written, %u skipped)", __func__, ! ctx->cells, ctx->written, ctx->skipped); ! free(ctx->item); ! free(ctx->list); /* flush will have emptied */ } /* Reset screen state. */ *************** *** 563,574 **** struct tty_ctx ttyctx; struct grid_cell gc; u_int xx, yy; - u_int sx = screen_size_x(s), sy = screen_size_y(s); screen_write_initctx(ctx, &ttyctx); - screen_dirty_clear(s, 0, 0, sx - 1, sy - 1); - memcpy(&gc, &grid_default_cell, sizeof gc); utf8_set(&gc.data, 'E'); --- 526,534 ---- *************** *** 583,588 **** --- 543,549 ---- s->rupper = 0; s->rlower = screen_size_y(s) - 1; + screen_write_collect_clear(ctx, 0, screen_size_y(s) - 1); tty_write(tty_cmd_alignmenttest, &ttyctx); } *************** *** 604,615 **** if (s->cx > screen_size_x(s) - 1) return; - screen_write_flush(ctx); screen_write_initctx(ctx, &ttyctx); ttyctx.bg = bg; grid_view_insert_cells(s->grid, s->cx, s->cy, nx, bg); ttyctx.num = nx; tty_write(tty_cmd_insertcharacter, &ttyctx); } --- 565,576 ---- if (s->cx > screen_size_x(s) - 1) return; screen_write_initctx(ctx, &ttyctx); ttyctx.bg = bg; grid_view_insert_cells(s->grid, s->cx, s->cy, nx, bg); + screen_write_collect_flush(ctx); ttyctx.num = nx; tty_write(tty_cmd_insertcharacter, &ttyctx); } *************** *** 632,643 **** if (s->cx > screen_size_x(s) - 1) return; - screen_write_flush(ctx); screen_write_initctx(ctx, &ttyctx); ttyctx.bg = bg; grid_view_delete_cells(s->grid, s->cx, s->cy, nx, bg); ttyctx.num = nx; tty_write(tty_cmd_deletecharacter, &ttyctx); } --- 593,604 ---- if (s->cx > screen_size_x(s) - 1) return; screen_write_initctx(ctx, &ttyctx); ttyctx.bg = bg; grid_view_delete_cells(s->grid, s->cx, s->cy, nx, bg); + screen_write_collect_flush(ctx); ttyctx.num = nx; tty_write(tty_cmd_deletecharacter, &ttyctx); } *************** *** 662,670 **** screen_write_initctx(ctx, &ttyctx); - screen_dirty_clear(s, s->cx, s->cy, s->cx + nx - 1, s->cy); grid_view_clear(s->grid, s->cx, s->cy, nx, 1, 8); ttyctx.num = nx; tty_write(tty_cmd_clearcharacter, &ttyctx); } --- 623,631 ---- screen_write_initctx(ctx, &ttyctx); grid_view_clear(s->grid, s->cx, s->cy, nx, 1, 8); + screen_write_collect_flush(ctx); ttyctx.num = nx; tty_write(tty_cmd_clearcharacter, &ttyctx); } *************** *** 686,697 **** if (ny == 0) return; - screen_write_flush(ctx); screen_write_initctx(ctx, &ttyctx); ttyctx.bg = bg; grid_view_insert_lines(gd, s->cy, ny, bg); ttyctx.num = ny; tty_write(tty_cmd_insertline, &ttyctx); return; --- 647,658 ---- if (ny == 0) return; screen_write_initctx(ctx, &ttyctx); ttyctx.bg = bg; grid_view_insert_lines(gd, s->cy, ny, bg); + screen_write_collect_flush(ctx); ttyctx.num = ny; tty_write(tty_cmd_insertline, &ttyctx); return; *************** *** 702,708 **** if (ny == 0) return; - screen_write_flush(ctx); screen_write_initctx(ctx, &ttyctx); ttyctx.bg = bg; --- 663,668 ---- *************** *** 711,716 **** --- 671,677 ---- else grid_view_insert_lines_region(gd, s->rlower, s->cy, ny, bg); + screen_write_collect_flush(ctx); ttyctx.num = ny; tty_write(tty_cmd_insertline, &ttyctx); } *************** *** 732,743 **** if (ny == 0) return; - screen_write_flush(ctx); screen_write_initctx(ctx, &ttyctx); ttyctx.bg = bg; grid_view_delete_lines(gd, s->cy, ny, bg); ttyctx.num = ny; tty_write(tty_cmd_deleteline, &ttyctx); return; --- 693,704 ---- if (ny == 0) return; screen_write_initctx(ctx, &ttyctx); ttyctx.bg = bg; grid_view_delete_lines(gd, s->cy, ny, bg); + screen_write_collect_flush(ctx); ttyctx.num = ny; tty_write(tty_cmd_deleteline, &ttyctx); return; *************** *** 748,754 **** if (ny == 0) return; - screen_write_flush(ctx); screen_write_initctx(ctx, &ttyctx); ttyctx.bg = bg; --- 709,714 ---- *************** *** 757,762 **** --- 717,723 ---- else grid_view_delete_lines_region(gd, s->rlower, s->cy, ny, bg); + screen_write_collect_flush(ctx); ttyctx.num = ny; tty_write(tty_cmd_deleteline, &ttyctx); } *************** *** 777,785 **** screen_write_initctx(ctx, &ttyctx); ttyctx.bg = bg; - screen_dirty_clear(s, 0, s->cy, sx - 1, s->cy); grid_view_clear(s->grid, 0, s->cy, sx, 1, bg); tty_write(tty_cmd_clearline, &ttyctx); } --- 738,746 ---- screen_write_initctx(ctx, &ttyctx); ttyctx.bg = bg; grid_view_clear(s->grid, 0, s->cy, sx, 1, bg); + screen_write_collect_clear(ctx, s->cy, 1); tty_write(tty_cmd_clearline, &ttyctx); } *************** *** 799,807 **** screen_write_initctx(ctx, &ttyctx); ttyctx.bg = bg; - screen_dirty_clear(s, s->cx, s->cy, sx - 1, s->cy); grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1, bg); tty_write(tty_cmd_clearendofline, &ttyctx); } --- 760,771 ---- screen_write_initctx(ctx, &ttyctx); ttyctx.bg = bg; grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1, bg); + if (s->cx == 0) + screen_write_collect_clear(ctx, s->cy, 1); + else + screen_write_collect_flush(ctx); tty_write(tty_cmd_clearendofline, &ttyctx); } *************** *** 816,829 **** screen_write_initctx(ctx, &ttyctx); ttyctx.bg = bg; ! if (s->cx > sx - 1) { ! screen_dirty_clear(s, 0, s->cy, sx - 1, s->cy); grid_view_clear(s->grid, 0, s->cy, sx, 1, bg); ! } else { ! screen_dirty_clear(s, 0, s->cy, s->cx, s->cy); grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, bg); - } tty_write(tty_cmd_clearstartofline, &ttyctx); } --- 780,794 ---- screen_write_initctx(ctx, &ttyctx); ttyctx.bg = bg; ! if (s->cx > sx - 1) grid_view_clear(s->grid, 0, s->cy, sx, 1, bg); ! else grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, bg); + if (s->cx > sx - 1) + screen_write_collect_clear(ctx, s->cy, 1); + else + screen_write_collect_flush(ctx); tty_write(tty_cmd_clearstartofline, &ttyctx); } *************** *** 851,862 **** screen_write_initctx(ctx, &ttyctx); ! if (s->cy == s->rupper) { ! screen_write_flush(ctx); grid_view_scroll_region_down(s->grid, s->rupper, s->rlower); ! } else if (s->cy > 0) s->cy--; tty_write(tty_cmd_reverseindex, &ttyctx); } --- 816,827 ---- screen_write_initctx(ctx, &ttyctx); ! if (s->cy == s->rupper) grid_view_scroll_region_down(s->grid, s->rupper, s->rlower); ! else if (s->cy > 0) s->cy--; + screen_write_collect_flush(ctx); tty_write(tty_cmd_reverseindex, &ttyctx); } *************** *** 887,913 **** screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped) { struct screen *s = ctx->s; struct grid_line *gl; ! struct tty_ctx ttyctx; ! u_int sx = screen_size_x(s), sy = screen_size_y(s); ! screen_write_initctx(ctx, &ttyctx); ! ! gl = &s->grid->linedata[s->grid->hsize + s->cy]; if (wrapped) gl->flags |= GRID_LINE_WRAPPED; else gl->flags &= ~GRID_LINE_WRAPPED; if (s->cy == s->rlower) { ! screen_dirty_clear(s, 0, s->rupper, sx - 1, s->rupper); ! screen_write_flush(ctx); ! grid_view_scroll_region_up(s->grid, s->rupper, s->rlower); ! } else if (s->cy < sy - 1) ! s->cy++; ! ttyctx.num = wrapped; ! tty_write(tty_cmd_linefeed, &ttyctx); } /* Carriage return (cursor to start of line). */ --- 852,875 ---- screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped) { struct screen *s = ctx->s; + struct grid *gd = s->grid; struct grid_line *gl; ! struct tty_ctx ttyctx; ! gl = &gd->linedata[gd->hsize + s->cy]; if (wrapped) gl->flags |= GRID_LINE_WRAPPED; else gl->flags &= ~GRID_LINE_WRAPPED; if (s->cy == s->rlower) { ! grid_view_scroll_region_up(gd, s->rupper, s->rlower); ! screen_write_collect_scroll(ctx); ! screen_write_initctx(ctx, &ttyctx); ! tty_write(tty_cmd_linefeed, &ttyctx); ! } else if (s->cy < screen_size_y(s) - 1) ! s->cy++; } /* Carriage return (cursor to start of line). */ *************** *** 932,949 **** ttyctx.bg = bg; /* Scroll into history if it is enabled and clearing entire screen. */ ! if (s->cx == 0 && s->cy == 0 && gd->flags & GRID_HISTORY) { ! screen_dirty_clear(s, 0, 0, sx - 1, sy - 1); grid_view_clear_history(gd, bg); ! } else { ! if (s->cx <= sx - 1) { ! screen_dirty_clear(s, s->cx, s->cy, sx - 1, s->cy); grid_view_clear(gd, s->cx, s->cy, sx - s->cx, 1, bg); - } - screen_dirty_clear(s, 0, s->cy + 1, sx - 1, sy - 1); grid_view_clear(gd, 0, s->cy + 1, sx, sy - (s->cy + 1), bg); } tty_write(tty_cmd_clearendofscreen, &ttyctx); } --- 894,909 ---- ttyctx.bg = bg; /* Scroll into history if it is enabled and clearing entire screen. */ ! if (s->cx == 0 && s->cy == 0 && (gd->flags & GRID_HISTORY)) grid_view_clear_history(gd, bg); ! else { ! if (s->cx <= sx - 1) grid_view_clear(gd, s->cx, s->cy, sx - s->cx, 1, bg); grid_view_clear(gd, 0, s->cy + 1, sx, sy - (s->cy + 1), bg); } + screen_write_collect_clear(ctx, s->cy + 1, sy - (s->cy + 1)); + screen_write_collect_flush(ctx); tty_write(tty_cmd_clearendofscreen, &ttyctx); } *************** *** 958,975 **** screen_write_initctx(ctx, &ttyctx); ttyctx.bg = bg; ! if (s->cy > 0) { ! screen_dirty_clear(s, 0, 0, sx - 1, s->cy); grid_view_clear(s->grid, 0, 0, sx, s->cy, bg); ! } ! if (s->cx > sx - 1) { ! screen_dirty_clear(s, 0, s->cy, sx - 1, s->cy); ! grid_view_clear(s->grid, 0, s->cy, sx, 1, bg); ! } else { ! screen_dirty_clear(s, 0, s->cy, s->cx, s->cy); ! grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, bg); ! } tty_write(tty_cmd_clearstartofscreen, &ttyctx); } --- 918,932 ---- screen_write_initctx(ctx, &ttyctx); ttyctx.bg = bg; ! if (s->cy > 0) grid_view_clear(s->grid, 0, 0, sx, s->cy, bg); ! if (s->cx > sx - 1) ! grid_view_clear(s->grid, 0, s->cy, sx, 1, 8); ! else ! grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, 8); + screen_write_collect_clear(ctx, 0, s->cy); + screen_write_collect_flush(ctx); tty_write(tty_cmd_clearstartofscreen, &ttyctx); } *************** *** 984,997 **** screen_write_initctx(ctx, &ttyctx); ttyctx.bg = bg; - screen_dirty_clear(s, 0, 0, sx - 1, sy - 1); - /* Scroll into history if it is enabled. */ if (s->grid->flags & GRID_HISTORY) grid_view_clear_history(s->grid, bg); else grid_view_clear(s->grid, 0, 0, sx, sy, bg); tty_write(tty_cmd_clearscreen, &ttyctx); } --- 941,953 ---- screen_write_initctx(ctx, &ttyctx); ttyctx.bg = bg; /* Scroll into history if it is enabled. */ if (s->grid->flags & GRID_HISTORY) grid_view_clear_history(s->grid, bg); else grid_view_clear(s->grid, 0, 0, sx, sy, bg); + screen_write_collect_clear(ctx, 0, sy); tty_write(tty_cmd_clearscreen, &ttyctx); } *************** *** 1006,1044 **** gd->hscrolled = gd->hsize = 0; } /* Write cell data. */ void screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) { struct screen *s = ctx->s; struct grid *gd = s->grid; - struct tty_ctx ttyctx; - u_int width, xx, last; - u_int sx = screen_size_x(s), sy = screen_size_y(s); struct grid_line *gl; - struct grid_cell tmp_gc, now_gc; struct grid_cell_entry *gce; ! int insert, skip, selected; ! ctx->cells++; ! ! /* Ignore padding. */ if (gc->flags & GRID_FLAG_PADDING) return; ! width = gc->data.width; ! /* ! * If this is a wide character and there is no room on the screen for ! * the entire character, don't print it. ! */ ! if (!(s->mode & MODE_WRAP) && (width > 1 && ! (width > sx || (s->cx != sx && s->cx > sx - width)))) ! return; ! ! /* ! * If the width is zero, combine onto the previous character, if ! * there is space. ! */ if (width == 0) { if ((gc = screen_write_combine(ctx, &gc->data, &xx)) != 0) { screen_write_cursormove(ctx, xx, s->cy); --- 962,1126 ---- gd->hscrolled = gd->hsize = 0; } + /* Clear a collected line. */ + static void + screen_write_collect_clear(struct screen_write_ctx *ctx, u_int y, u_int n) + { + struct screen_write_collect_item *ci, *tmp; + u_int i; + size_t size; + + for (i = y ; i < y + n; i++) { + if (TAILQ_EMPTY(&ctx->list[i].items)) + continue; + size = 0; + TAILQ_FOREACH_SAFE(ci, &ctx->list[i].items, entry, tmp) { + size += ci->used; + TAILQ_REMOVE(&ctx->list[i].items, ci, entry); + free(ci); + } + ctx->skipped += size; + log_debug("discarding %zu bytes on line %u", size, i); + } + } + + /* Scroll collected lines up. */ + static void + screen_write_collect_scroll(struct screen_write_ctx *ctx) + { + struct screen *s = ctx->s; + struct screen_write_collect_line *cl; + u_int y; + + screen_write_collect_clear(ctx, s->rupper, 1); + for (y = s->rupper; y < s->rlower; y++) { + cl = &ctx->list[y + 1]; + TAILQ_CONCAT(&ctx->list[y].items, &cl->items, entry); + TAILQ_INIT(&cl->items); + } + } + + /* Flush collected lines. */ + static void + screen_write_collect_flush(struct screen_write_ctx *ctx) + { + struct screen *s = ctx->s; + struct screen_write_collect_item *ci, *tmp; + u_int y, cx, cy; + struct tty_ctx ttyctx; + + cx = s->cx; cy = s->cy; + for (y = 0; y < screen_size_y(s); y++) { + TAILQ_FOREACH_SAFE(ci, &ctx->list[y].items, entry, tmp) { + screen_write_cursormove(ctx, ci->x, y); + screen_write_initctx(ctx, &ttyctx); + ttyctx.cell = &ci->gc; + ttyctx.ptr = ci->data; + ttyctx.num = ci->used; + tty_write(tty_cmd_cells, &ttyctx); + ctx->written += ci->used; + + TAILQ_REMOVE(&ctx->list[y].items, ci, entry); + free(ci); + } + } + s->cx = cx; s->cy = cy; + } + + /* Finish and store collected cells. */ + void + screen_write_collect_end(struct screen_write_ctx *ctx) + { + struct screen *s = ctx->s; + struct screen_write_collect_item *ci = ctx->item; + struct grid_cell gc; + + if (ci->used == 0) + return; + ci->data[ci->used] = '\0'; + + ci->x = s->cx; + TAILQ_INSERT_TAIL(&ctx->list[s->cy].items, ci, entry); + ctx->item = xcalloc(1, sizeof *ctx->item); + + log_debug("%s: %u %s (at %u,%u)", __func__, ci->used, ci->data, s->cx, + s->cy); + + memcpy(&gc, &ci->gc, sizeof gc); + grid_view_set_cells(s->grid, s->cx, s->cy, &gc, ci->data, ci->used); + s->cx += ci->used; + } + + /* Write cell data, collecting if necessary. */ + void + screen_write_collect_add(struct screen_write_ctx *ctx, + const struct grid_cell *gc) + { + struct screen *s = ctx->s; + struct screen_write_collect_item *ci; + u_int sx = screen_size_x(s); + int collect; + + /* + * Don't need to check that the attributes and whatnot are still the + * same - input_parse will do a flush when anything that isn't a plain + * character is encountered. Also nothing should make it here that + * isn't a single ASCII character. + */ + + collect = 1; + if (gc->data.width != 1) + collect = 0; + else if (gc->attr & GRID_ATTR_CHARSET) + collect = 0; + else if (~s->mode & MODE_WRAP) + collect = 0; + else if (s->mode & MODE_INSERT) + collect = 0; + else if (s->sel.flag) + collect = 0; + if (!collect) { + screen_write_collect_end(ctx); + screen_write_cell(ctx, gc); + return; + } + ctx->cells++; + + if (s->cx > sx - 1 || ctx->item->used > sx - 1 - s->cx) + screen_write_collect_end(ctx); + if (s->cx > sx - 1) { + screen_write_linefeed(ctx, 1); + s->cx = 0; + } + + ci = ctx->item; /* may have changed */ + if (ci->used == 0) + memcpy(&ci->gc, gc, sizeof ci->gc); + ci->data[ci->used++] = gc->data.data[0]; + if (ci->used == (sizeof ci->data) - 1) + screen_write_collect_end(ctx); + } + /* Write cell data. */ void screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) { struct screen *s = ctx->s; struct grid *gd = s->grid; struct grid_line *gl; struct grid_cell_entry *gce; ! struct grid_cell tmp_gc, now_gc; ! struct tty_ctx ttyctx; ! u_int sx = screen_size_x(s), sy = screen_size_y(s); ! u_int width = gc->data.width, xx, last; ! int selected, skip = 1; ! /* Ignore padding cells. */ if (gc->flags & GRID_FLAG_PADDING) return; ! ctx->cells++; ! /* If the width is zero, combine onto the previous character. */ if (width == 0) { if ((gc = screen_write_combine(ctx, &gc->data, &xx)) != 0) { screen_write_cursormove(ctx, xx, s->cy); *************** *** 1049,1077 **** return; } /* If in insert mode, make space for the cells. */ if (s->mode & MODE_INSERT) { ! if (s->cx <= sx - width) { ! screen_write_flush(ctx); ! xx = sx - s->cx - width; ! grid_view_insert_cells(s->grid, s->cx, s->cy, xx, 8); ! } ! insert = 1; ! } else ! insert = 0; ! skip = !insert; /* Check this will fit on the current line and wrap if not. */ if ((s->mode & MODE_WRAP) && s->cx > sx - width) { screen_write_linefeed(ctx, 1); ! s->cx = 0; /* carriage return */ } /* Sanity check cursor position. */ if (s->cx > sx - width || s->cy > sy - 1) return; - - /* Initialise the redraw context. */ screen_write_initctx(ctx, &ttyctx); /* Handle overwriting of UTF-8 characters. */ --- 1131,1157 ---- return; } + /* If this character doesn't fit, ignore it. */ + if ((~s->mode & MODE_WRAP) && + width > 1 && + (width > sx || (s->cx != sx && s->cx > sx - width))) + return; + /* If in insert mode, make space for the cells. */ if (s->mode & MODE_INSERT) { ! grid_view_insert_cells(s->grid, s->cx, s->cy, width, 8); ! skip = 0; ! } /* Check this will fit on the current line and wrap if not. */ if ((s->mode & MODE_WRAP) && s->cx > sx - width) { screen_write_linefeed(ctx, 1); ! s->cx = 0; } /* Sanity check cursor position. */ if (s->cx > sx - width || s->cy > sy - 1) return; screen_write_initctx(ctx, &ttyctx); /* Handle overwriting of UTF-8 characters. */ *************** *** 1109,1114 **** --- 1189,1196 ---- skip = 0; else if (gc->data.width != 1) skip = 0; + else if (gc->data.size != 1) + skip = 0; else if (gce->data.data != gc->data.data[0]) skip = 0; } *************** *** 1116,1133 **** /* Update the selection the flag and set the cell. */ selected = screen_check_selection(s, s->cx, s->cy); ! if (selected && ~gc->flags & GRID_FLAG_SELECTED) { ! skip = 0; memcpy(&tmp_gc, gc, sizeof tmp_gc); tmp_gc.flags |= GRID_FLAG_SELECTED; grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc); ! } else if (!selected && gc->flags & GRID_FLAG_SELECTED) { ! skip = 0; memcpy(&tmp_gc, gc, sizeof tmp_gc); tmp_gc.flags &= ~GRID_FLAG_SELECTED; grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc); } else if (!skip) grid_view_set_cell(gd, s->cx, s->cy, gc); /* * Move the cursor. If not wrapping, stick at the last character and --- 1198,1215 ---- /* Update the selection the flag and set the cell. */ selected = screen_check_selection(s, s->cx, s->cy); ! if (selected && (~gc->flags & GRID_FLAG_SELECTED)) { memcpy(&tmp_gc, gc, sizeof tmp_gc); tmp_gc.flags |= GRID_FLAG_SELECTED; grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc); ! } else if (!selected && (gc->flags & GRID_FLAG_SELECTED)) { memcpy(&tmp_gc, gc, sizeof tmp_gc); tmp_gc.flags &= ~GRID_FLAG_SELECTED; grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc); } else if (!skip) grid_view_set_cell(gd, s->cx, s->cy, gc); + if (selected) + skip = 0; /* * Move the cursor. If not wrapping, stick at the last character and *************** *** 1140,1173 **** s->cx = sx - last; /* Create space for character in insert mode. */ ! if (insert) { ttyctx.num = width; tty_write(tty_cmd_insertcharacter, &ttyctx); } /* Write to the screen. */ ! if (selected) { ! screen_write_flush(ctx); ! screen_select_cell(s, &tmp_gc, gc); ! ttyctx.cell = &tmp_gc; tty_write(tty_cmd_cell, &ttyctx); ctx->written++; - } else if (!skip) { - /* - * If wp is NULL, we are not updating the terminal and don't - * care about actually writing the cells (tty_write will just - * return). So don't even bother allocating the dirty array. - */ - if (ctx->wp != NULL && s->dirty == NULL) { - log_debug("%s: allocating %u bits", __func__, - s->dirtysize); - s->dirty = bit_alloc(s->dirtysize); - } - if (s->dirty != NULL) { - bit_set(s->dirty, screen_dirty_bit(s, - ttyctx.ocx, ttyctx.ocy)); - ctx->dirty++; - } } else ctx->skipped++; } --- 1222,1242 ---- s->cx = sx - last; /* Create space for character in insert mode. */ ! if (s->mode & MODE_INSERT) { ! screen_write_collect_flush(ctx); ttyctx.num = width; tty_write(tty_cmd_insertcharacter, &ttyctx); } /* Write to the screen. */ ! if (!skip) { ! if (selected) { ! screen_select_cell(s, &tmp_gc, gc); ! ttyctx.cell = &tmp_gc; ! } else ! ttyctx.cell = gc; tty_write(tty_cmd_cell, &ttyctx); ctx->written++; } else ctx->skipped++; }