Redraw line directly for wide cells in screen_write_cell, fix up selection and

generally tidy.
This commit is contained in:
Nicholas Marriott
2026-05-27 21:33:50 +01:00
parent bfa2ff2bdf
commit 52250d518d
3 changed files with 57 additions and 47 deletions

View File

@@ -632,25 +632,25 @@ screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src,
if (nx == 0 || ny == 0) if (nx == 0 || ny == 0)
return; return;
if (wp != NULL)
yoff = wp->yoff;
for (yy = py; yy < py + ny; yy++) { for (yy = py; yy < py + ny; yy++) {
if (yy >= gd->hsize + gd->sy) if (yy >= gd->hsize + gd->sy)
break; break;
s->cx = cx; s->cx = cx;
screen_write_initctx(ctx, &ttyctx, 0, 0); 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, r = screen_redraw_get_visible_ranges(wp, px, s->cy + yoff, nx,
NULL); NULL);
for (xx = px; xx < px + nx; xx++) { for (xx = px; xx < px + nx; xx++) {
gl = grid_get_line(gd, yy); 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) if (xx >= gl->cellsize && s->cx >= sgl->cellsize)
break; break;
grid_get_cell(gd, xx, yy, &gc); grid_get_cell(gd, xx, yy, &gc);
if (xx + gc.data.width > px + nx) if (xx + gc.data.width > px + nx)
break; 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)) if (!screen_redraw_is_visible(r, px))
break; break;
ttyctx.cell = &gc; ttyctx.cell = &gc;
@@ -1127,7 +1127,7 @@ screen_write_redraw_line(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx,
{ {
struct window_pane *wp = ctx->wp; struct window_pane *wp = ctx->wp;
struct screen *s = ctx->s; 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 sx = screen_size_x(s), cx, i, n;
u_int xoff = wp->xoff, yoff = wp->yoff; u_int xoff = wp->xoff, yoff = wp->yoff;
struct visible_ranges *r; 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; cx = ri->px - xoff;
for (n = 0; n < ri->nx && cx < sx; n++, cx++) { for (n = 0; n < ri->nx && cx < sx; n++, cx++) {
grid_view_get_cell(s->grid, cx, yy, &gc); 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->ocx = cx;
ttyctx->ocy = yy; ttyctx->ocy = yy;
ttyctx->cell = &gc;
tty_write(tty_cmd_cell, ttyctx); tty_write(tty_cmd_cell, ttyctx);
} }
} }
@@ -2175,7 +2181,8 @@ screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only,
written = 0; written = 0;
for (i = 0; i < r->used; i++) { for (i = 0; i < r->used; i++) {
ri = &r->ranges[i]; ri = &r->ranges[i];
if (ri->nx == 0) continue; if (ri->nx == 0)
continue;
r_start = ri->px; r_start = ri->px;
r_end = ri->px + ri->nx; r_end = ri->px + ri->nx;
ci_start = ci->x; ci_start = ci->x;
@@ -2527,6 +2534,7 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
if (selected) if (selected)
skip = 0; skip = 0;
/* Get visible ranges for the character before moving the cursor. */
if (wp != NULL) if (wp != NULL)
yoff = wp->yoff; yoff = wp->yoff;
r = screen_redraw_get_visible_ranges(wp, s->cx, s->cy + yoff, width, r = screen_redraw_get_visible_ranges(wp, s->cx, s->cy + yoff, width,
@@ -2540,7 +2548,7 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
if (s->cx <= sx - not_wrap - width) if (s->cx <= sx - not_wrap - width)
screen_write_set_cursor(ctx, s->cx + width, -1); screen_write_set_cursor(ctx, s->cx + width, -1);
else 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. */ /* Create space for character in insert mode. */
if (s->mode & MODE_INSERT) { if (s->mode & MODE_INSERT) {
@@ -2549,33 +2557,42 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
tty_write(tty_cmd_insertcharacter, &ttyctx); tty_write(tty_cmd_insertcharacter, &ttyctx);
} }
/* Write to the screen. */ /* If not writing, done now. */
if (!skip && !(s->mode & MODE_SYNC)) { if (skip || s->mode & MODE_SYNC)
if (selected) { return;
screen_select_cell(s, &tmp_gc, gc);
} else /* Do a full line redraw if needed. */
memcpy(&tmp_gc, gc, sizeof tmp_gc); if (redraw) {
ttyctx.cell = &tmp_gc; screen_write_redraw_line(ctx, &ttyctx, s->cy);
if (redraw) return;
ttyctx.flags |= TTY_CTX_CELL_DRAW_LINE; }
for (i=0, vis=0; i < r->used; i++) vis += r->ranges[i].nx;
if (vis < width) { /* Work out the cell attributes. */
/* Wide character or tab partly obscured. Write if (selected)
* spaces one by one in unobscured region(s). screen_select_cell(s, &tmp_gc, gc);
*/ else
*tmp_gc.data.data = ' '; memcpy(&tmp_gc, gc, sizeof tmp_gc);
tmp_gc.data.width = tmp_gc.data.size = ttyctx.cell = &tmp_gc;
tmp_gc.data.have = 1;
for (i=0; i < r->used; i++) { /* If the cell is fully visible, it can be written entirely. */
ri = &r->ranges[i]; for (i = 0, vis = 0; i < r->used; i++)
if (ri->nx == 0) continue; vis += r->ranges[i].nx;
for (n = 0; n < ri->nx; n++) { if (vis >= width) {
screen_write_set_cursor(ctx, ri->px + n, tty_write(tty_cmd_cell, &ttyctx);
-1); return;
tty_write(tty_cmd_cell, &ttyctx); }
}
} /*
} else { * 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); tty_write(tty_cmd_cell, &ttyctx);
} }
} }
@@ -2589,6 +2606,7 @@ screen_write_combine(struct screen_write_ctx *ctx, const struct grid_cell *gc)
struct window_pane *wp = ctx->wp; struct window_pane *wp = ctx->wp;
struct grid *gd = s->grid; struct grid *gd = s->grid;
const struct utf8_data *ud = &gc->data; 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; u_int i, n, cx = s->cx, cy = s->cy, vis, yoff = 0;
struct grid_cell last; struct grid_cell last;
struct tty_ctx ttyctx; struct tty_ctx ttyctx;
@@ -2608,7 +2626,7 @@ screen_write_combine(struct screen_write_ctx *ctx, const struct grid_cell *gc)
zero_width = 1; zero_width = 1;
else if (utf8_is_vs(ud)) { else if (utf8_is_vs(ud)) {
zero_width = 1; 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; force_wide = 1;
} else if (ud->width == 0) } else if (ud->width == 0)
zero_width = 1; zero_width = 1;

5
tmux.h
View File

@@ -1751,9 +1751,8 @@ struct tty_ctx {
#define TTY_CTX_WINDOW_BIGGER 0x4 #define TTY_CTX_WINDOW_BIGGER 0x4
#define TTY_CTX_SYNC 0x8 #define TTY_CTX_SYNC 0x8
#define TTY_CTX_OVERLAY_SYNC 0x10 #define TTY_CTX_OVERLAY_SYNC 0x10
#define TTY_CTX_CELL_DRAW_LINE 0x20 #define TTY_CTX_CELL_INVALIDATE 0x20
#define TTY_CTX_CELL_INVALIDATE 0x40 #define TTY_CTX_PANE_OBSCURED 0x40
#define TTY_CTX_PANE_OBSCURED 0x80
union { union {
u_int n; u_int n;

9
tty.c
View File

@@ -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))) (gcp->data.width == 1 && !tty_check_overlay(tty, px, py)))
return; return;
if (ctx->flags & TTY_CTX_CELL_DRAW_LINE) { if (gcp->data.width > 1) { /* could be partially obscured */
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) {
r = tty_check_overlay_range(tty, px, py, gcp->data.width); r = tty_check_overlay_range(tty, px, py, gcp->data.width);
for (i = 0; i < r->used; i++) for (i = 0; i < r->used; i++)
vis += r->ranges[i].nx; vis += r->ranges[i].nx;