From 81d610c284cd1f87a965de60e185242af59bc220 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 27 May 2026 21:33:50 +0100 Subject: [PATCH] Redraw line directly for wide cells in screen_write_cell, fix up selection and generally tidy. --- screen-write.c | 90 ++++++++++++++++++++++++++++++-------------------- tmux.h | 5 ++- tty.c | 9 +---- 3 files changed, 57 insertions(+), 47 deletions(-) diff --git a/screen-write.c b/screen-write.c index 6a9e7e01..86a48d61 100644 --- a/screen-write.c +++ b/screen-write.c @@ -629,25 +629,25 @@ screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src, if (nx == 0 || ny == 0) return; + if (wp != NULL) + yoff = wp->yoff; for (yy = py; yy < py + ny; yy++) { if (yy >= gd->hsize + gd->sy) break; s->cx = cx; screen_write_initctx(ctx, &ttyctx, 0, 0); - if (wp != NULL) - yoff = wp->yoff; r = screen_redraw_get_visible_ranges(wp, px, s->cy + yoff, nx, NULL); for (xx = px; xx < px + nx; xx++) { gl = grid_get_line(gd, yy); - sgl = grid_get_line(ctx->s->grid, s->cy); + sgl = grid_get_line(s->grid, s->cy); if (xx >= gl->cellsize && s->cx >= sgl->cellsize) break; grid_get_cell(gd, xx, yy, &gc); if (xx + gc.data.width > px + nx) break; - grid_view_set_cell(ctx->s->grid, s->cx, s->cy, &gc); + grid_view_set_cell(s->grid, s->cx, s->cy, &gc); if (!screen_redraw_is_visible(r, px)) break; ttyctx.cell = &gc; @@ -1124,7 +1124,7 @@ screen_write_redraw_line(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx, { struct window_pane *wp = ctx->wp; struct screen *s = ctx->s; - struct grid_cell gc; + struct grid_cell gc, ngc; u_int sx = screen_size_x(s), cx, i, n; u_int xoff = wp->xoff, yoff = wp->yoff; struct visible_ranges *r; @@ -1139,9 +1139,15 @@ screen_write_redraw_line(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx, cx = ri->px - xoff; for (n = 0; n < ri->nx && cx < sx; n++, cx++) { grid_view_get_cell(s->grid, cx, yy, &gc); + if (~gc.flags & GRID_FLAG_SELECTED) + ttyctx->cell = &gc; + else { + screen_select_cell(s, &ngc, &gc); + ttyctx->cell = &ngc; + } + ttyctx->ocx = cx; ttyctx->ocy = yy; - ttyctx->cell = &gc; tty_write(tty_cmd_cell, ttyctx); } } @@ -2169,7 +2175,8 @@ screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only, written = 0; for (i = 0; i < r->used; i++) { ri = &r->ranges[i]; - if (ri->nx == 0) continue; + if (ri->nx == 0) + continue; r_start = ri->px; r_end = ri->px + ri->nx; ci_start = ci->x; @@ -2521,6 +2528,7 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) if (selected) skip = 0; + /* Get visible ranges for the character before moving the cursor. */ if (wp != NULL) yoff = wp->yoff; r = screen_redraw_get_visible_ranges(wp, s->cx, s->cy + yoff, width, @@ -2534,7 +2542,7 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) if (s->cx <= sx - not_wrap - width) screen_write_set_cursor(ctx, s->cx + width, -1); else - screen_write_set_cursor(ctx, sx - not_wrap, -1); + screen_write_set_cursor(ctx, sx - not_wrap, -1); /* Create space for character in insert mode. */ if (s->mode & MODE_INSERT) { @@ -2543,33 +2551,42 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) tty_write(tty_cmd_insertcharacter, &ttyctx); } - /* Write to the screen. */ - if (!skip && !(s->mode & MODE_SYNC)) { - if (selected) { - screen_select_cell(s, &tmp_gc, gc); - } else - memcpy(&tmp_gc, gc, sizeof tmp_gc); - ttyctx.cell = &tmp_gc; - if (redraw) - ttyctx.flags |= TTY_CTX_CELL_DRAW_LINE; - for (i=0, vis=0; i < r->used; i++) vis += r->ranges[i].nx; - if (vis < width) { - /* Wide character or tab partly obscured. Write - * spaces one by one in unobscured region(s). - */ - *tmp_gc.data.data = ' '; - tmp_gc.data.width = tmp_gc.data.size = - tmp_gc.data.have = 1; - for (i=0; i < r->used; i++) { - ri = &r->ranges[i]; - if (ri->nx == 0) continue; - for (n = 0; n < ri->nx; n++) { - screen_write_set_cursor(ctx, ri->px + n, - -1); - tty_write(tty_cmd_cell, &ttyctx); - } - } - } else { + /* If not writing, done now. */ + if (skip || s->mode & MODE_SYNC) + return; + + /* Do a full line redraw if needed. */ + if (redraw) { + screen_write_redraw_line(ctx, &ttyctx, s->cy); + return; + } + + /* Work out the cell attributes. */ + if (selected) + screen_select_cell(s, &tmp_gc, gc); + else + memcpy(&tmp_gc, gc, sizeof tmp_gc); + ttyctx.cell = &tmp_gc; + + /* If the cell is fully visible, it can be written entirely. */ + for (i = 0, vis = 0; i < r->used; i++) + vis += r->ranges[i].nx; + if (vis >= width) { + tty_write(tty_cmd_cell, &ttyctx); + return; + } + + /* + * Otherwise this is a wide character or tab partly obscured. Write + * spaces in the visible regions. + */ + utf8_set(&tmp_gc.data, ' '); + for (i = 0; i < r->used; i++) { + ri = &r->ranges[i]; + if (ri->nx == 0) + continue; + for (n = 0; n < ri->nx; n++) { + ttyctx.ocx = ri->px + n; tty_write(tty_cmd_cell, &ttyctx); } } @@ -2583,6 +2600,7 @@ screen_write_combine(struct screen_write_ctx *ctx, const struct grid_cell *gc) struct window_pane *wp = ctx->wp; struct grid *gd = s->grid; const struct utf8_data *ud = &gc->data; + struct options *oo = global_options; u_int i, n, cx = s->cx, cy = s->cy, vis, yoff = 0; struct grid_cell last; struct tty_ctx ttyctx; @@ -2602,7 +2620,7 @@ screen_write_combine(struct screen_write_ctx *ctx, const struct grid_cell *gc) zero_width = 1; else if (utf8_is_vs(ud)) { zero_width = 1; - if (options_get_number(global_options, "variation-selector-always-wide")) + if (options_get_number(oo, "variation-selector-always-wide")) force_wide = 1; } else if (ud->width == 0) zero_width = 1; diff --git a/tmux.h b/tmux.h index c3f7fff4..23f831cc 100644 --- a/tmux.h +++ b/tmux.h @@ -1742,9 +1742,8 @@ struct tty_ctx { #define TTY_CTX_WINDOW_BIGGER 0x4 #define TTY_CTX_SYNC 0x8 #define TTY_CTX_OVERLAY_SYNC 0x10 -#define TTY_CTX_CELL_DRAW_LINE 0x20 -#define TTY_CTX_CELL_INVALIDATE 0x40 -#define TTY_CTX_PANE_OBSCURED 0x80 +#define TTY_CTX_CELL_INVALIDATE 0x20 +#define TTY_CTX_PANE_OBSCURED 0x40 union { u_int n; diff --git a/tty.c b/tty.c index eb94eaa1..233bcb1e 100644 --- a/tty.c +++ b/tty.c @@ -2054,14 +2054,7 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) (gcp->data.width == 1 && !tty_check_overlay(tty, px, py))) return; - if (ctx->flags & TTY_CTX_CELL_DRAW_LINE) { - tty_draw_line(tty, s, 0, s->cy, screen_size_x(s), - ctx->xoff - ctx->wox, py, &ctx->defaults, ctx->palette); - return; - } - - /* Handle partially obstructed wide characters. */ - if (gcp->data.width > 1) { + if (gcp->data.width > 1) { /* could be partially obscured */ r = tty_check_overlay_range(tty, px, py, gcp->data.width); for (i = 0; i < r->used; i++) vis += r->ranges[i].nx;