From 5c40cc43b250382f3e73f1729104dfd98c504321 Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 27 May 2026 20:57:53 +0000 Subject: [PATCH] Bring in the single-cell redraw parts for floating panes. --- screen-redraw.c | 9 ++--- screen-write.c | 96 ++++++++++++++++++++++++++++++++++++++++--------- tty.c | 9 +---- 3 files changed, 86 insertions(+), 28 deletions(-) diff --git a/screen-redraw.c b/screen-redraw.c index 36307f94..1b41a9a6 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -1351,12 +1351,13 @@ screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp) ri = &r->ranges[k]; if (ri->nx == 0) continue; - log_debug("%s: %s %%%u range pane (%u,%u) width %u, tty (%u,%u) width %u", - __func__, c->name, wp->id, + log_debug("%s: %s %%%u range %u (%u,%u) width %u, " + "tty (%u,%u) width %u", + __func__, c->name, wp->id, k, ri->px + (int)ctx->ox - wp->xoff, j, ri->nx, ri->px, py, ri->nx); - tty_draw_line(tty, s, ri->px + (int)ctx->ox - wp->xoff, j, ri->nx, - ri->px, py, &defaults, palette); + tty_draw_line(tty, s, ri->px + (int)ctx->ox - wp->xoff, + j, ri->nx, ri->px, py, &defaults, palette); } } } diff --git a/screen-write.c b/screen-write.c index 35bdec8a..1fe44ed7 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1127,7 +1127,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; @@ -1142,9 +1142,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); } } @@ -2262,6 +2268,7 @@ void screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) { struct screen *s = ctx->s; + struct window_pane *wp = ctx->wp; struct grid *gd = s->grid; const struct utf8_data *ud = &gc->data; struct grid_line *gl; @@ -2269,8 +2276,10 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) 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 = ud->width, xx, not_wrap; - int selected, skip = 1, redraw = 0; + u_int width = ud->width, xx, not_wrap, i, n, vis; + int selected, skip = 1, redraw = 0, yoff = 0; + struct visible_ranges *r; + struct visible_range *ri; /* Ignore padding cells. */ if (gc->flags & GRID_FLAG_PADDING) @@ -2368,6 +2377,12 @@ 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, + NULL); + /* * Move the cursor. If not wrapping, stick at the last character and * replace it. @@ -2376,7 +2391,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) { @@ -2385,16 +2400,44 @@ 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); - ttyctx.cell = &tmp_gc; - } else - ttyctx.cell = gc; - if (redraw) - ttyctx.flags |= TTY_CTX_CELL_DRAW_LINE; + /* 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); + } } } @@ -2403,12 +2446,15 @@ static int screen_write_combine(struct screen_write_ctx *ctx, const struct grid_cell *gc) { struct screen *s = ctx->s; + struct window_pane *wp = ctx->wp; struct grid *gd = s->grid; const struct utf8_data *ud = &gc->data; - u_int n, cx = s->cx, cy = s->cy; + 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; int force_wide = 0, zero_width = 0; + struct visible_ranges *r; /* Ignore U+3164 HANGUL_FILLER entirely. */ if (utf8_is_hangul_filler(ud)) @@ -2423,7 +2469,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; @@ -2496,6 +2542,24 @@ screen_write_combine(struct screen_write_ctx *ctx, const struct grid_cell *gc) if (force_wide) grid_view_set_padding(gd, cx - 1, cy); + /* + * Check if all of this character is visible. No character will be + * obscured in the middle, only on left or right, but there could be an + * empty range in the visible ranges so we add them all up. + */ + if (wp != NULL) + yoff = wp->yoff; + r = screen_redraw_get_visible_ranges(wp, cx - n, cy + yoff, n, NULL); + for (i = 0, vis = 0; i < r->used; i++) + vis += r->ranges[i].nx; + if (vis < n) { + /* + * Part of this character is obscured. Return 1 and let + * screen_write_cell write a space. + */ + return (1); + } + /* * Redraw the combined cell. If forcing the cell to width 2, reset the * cached cursor position in the tty, since we don't really know diff --git a/tty.c b/tty.c index f4382abb..95fe90e4 100644 --- a/tty.c +++ b/tty.c @@ -1952,14 +1952,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;