Change overlay_ranges to visible_ranges.

This commit is contained in:
Nicholas Marriott
2026-01-20 21:09:30 +00:00
parent 25f72cf240
commit b108653f02
7 changed files with 209 additions and 92 deletions

10
menu.c
View File

@@ -181,15 +181,17 @@ menu_mode_cb(__unused struct client *c, void *data, u_int *cx, u_int *cy)
}
/* Return parts of the input range which are not obstructed by the menu. */
void
struct visible_ranges *
menu_check_cb(__unused struct client *c, void *data, u_int px, u_int py,
u_int nx, struct overlay_ranges *r)
u_int nx)
{
struct menu_data *md = data;
struct menu *menu = md->menu;
struct visible_ranges *r;
server_client_overlay_range(md->px, md->py, menu->width + 4,
menu->count + 2, px, py, nx, r);
r = server_client_overlay_range(md->px, md->py, menu->width + 4,
menu->count + 2, px, py, nx);
return (r);
}
void

39
popup.c
View File

@@ -164,48 +164,41 @@ popup_mode_cb(__unused struct client *c, void *data, u_int *cx, u_int *cy)
}
/* Return parts of the input range which are not obstructed by the popup. */
static void
popup_check_cb(struct client* c, void *data, u_int px, u_int py, u_int nx,
struct overlay_ranges *r)
static struct visible_ranges *
popup_check_cb(struct client* c, void *data, u_int px, u_int py, u_int nx)
{
struct popup_data *pd = data;
struct overlay_ranges or[2];
struct visible_ranges *or[2], *r;
u_int i, j, k = 0;
if (pd->md != NULL) {
/* Check each returned range for the menu against the popup. */
menu_check_cb(c, pd->md, px, py, nx, r);
for (i = 0; i < 2; i++) {
server_client_overlay_range(pd->px, pd->py, pd->sx,
pd->sy, r->px[i], py, r->nx[i], &or[i]);
r = menu_check_cb(c, pd->md, px, py, nx);
for (i = 0; i < r->used; i++) {
or[i] = server_client_overlay_range(pd->px, pd->py, pd->sx,
pd->sy, r->px[i], py, r->nx[i]);
}
/*
* or has up to OVERLAY_MAX_RANGES non-overlapping ranges,
* ordered from left to right. Collect them in the output.
*/
for (i = 0; i < 2; i++) {
/* Each or[i] only has 2 ranges. */
for (j = 0; j < 2; j++) {
if (or[i].nx[j] > 0) {
r->px[k] = or[i].px[j];
r->nx[k] = or[i].nx[j];
for (i = 0; i < r->used; i++) {
/* Each or[i] only has up to 2 ranges. */
for (j = 0; j < or[i]->used; j++) {
if (or[i]->nx[j] > 0) {
r->px[k] = or[i]->px[j];
r->nx[k] = or[i]->nx[j];
k++;
}
}
}
/* Zero remaining ranges if any. */
for (i = k; i < OVERLAY_MAX_RANGES; i++) {
r->px[i] = 0;
r->nx[i] = 0;
}
return;
return (r);
}
server_client_overlay_range(pd->px, pd->py, pd->sx, pd->sy, px, py, nx,
r);
return (server_client_overlay_range(pd->px, pd->py, pd->sx, pd->sy, px, py,
nx));
}
static void

View File

@@ -817,13 +817,13 @@ screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j)
struct window_pane *wp, *active = server_client_get_pane(c);
struct grid_cell gc;
const struct grid_cell *tmp;
struct overlay_ranges r;
struct visible_ranges *r;
u_int cell_type, x = ctx->ox + i, y = ctx->oy + j;
int isolates;
if (c->overlay_check != NULL) {
c->overlay_check(c, c->overlay_data, x, y, 1, &r);
if (r.nx[0] + r.nx[1] == 0)
r = c->overlay_check(c, c->overlay_data, x, y, 1);
if (r->nx[0] + r->nx[1] == 0)
return;
}
@@ -943,7 +943,8 @@ screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp)
struct screen *s = wp->screen;
struct colour_palette *palette = &wp->palette;
struct grid_cell defaults;
u_int i, j, top, x, y, width;
struct visible_ranges *vr;
u_int i, j, top, x, y, px, width, r;
if (wp->base.mode & MODE_SYNC)
screen_write_stop_sync(wp);
@@ -987,8 +988,23 @@ screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp)
log_debug("%s: %s %%%u line %u,%u at %u,%u, width %u",
__func__, c->name, wp->id, i, j, x, y, width);
/* xxxx Breaking up the tty_draw_line like this isn't fully working. */
vr = tty_check_overlay_range(tty, x, y, width);
tty_default_colours(&defaults, wp);
tty_draw_line(tty, s, i, j, width, x, y, &defaults, palette);
for (r=0; r < vr->used; r++) {
if (vr->nx[r] == 0)
continue;
/* Convert window coordinates to tty coordinates. */
px = vr->px[r];
/* i is px of cell, add px of region, sub the
* pane offset. If you don't sub offset,
* contents of pane shifted. note: i apparently unnec.
*/
tty_draw_line(tty, s, /* i + */ vr->px[r] - wp->xoff, j,
vr->nx[r], px, y, &defaults, palette);
}
}
#ifdef ENABLE_SIXEL

View File

@@ -770,3 +770,72 @@ screen_mode_to_string(int mode)
tmp[strlen(tmp) - 1] = '\0';
return (tmp);
}
#ifdef DEBUG
/* Debug function. Usage in gdb:
* printf "%S",screen_print(s)
*/
__unused char *
screen_print(struct screen *s) {
static char buf[16384];
const char *acs;
u_int x, y;
size_t last = 0, n;
struct utf8_data ud;
struct grid_line *gl;
struct grid_cell_entry *gce;
for (y = 0; y < screen_hsize(s)+s->grid->sy; y++) {
if (last + 6 > sizeof buf) goto out;
n = snprintf(buf + last, sizeof buf - last, "%.4d ", y);
last += n;
buf[last++] = '"';
gl = &s->grid->linedata[y];
for (x = 0; x < gl->cellused; x++) {
gce = &gl->celldata[x];
if (gce->flags & GRID_FLAG_PADDING)
continue;
if (~gce->flags & GRID_FLAG_EXTENDED) {
/* single-byte cell stored inline */
if (last + 2 > sizeof buf) goto out;
buf[last++] = gce->data.data;
} else if (gce->flags & GRID_FLAG_TAB) {
if (last + 2 > sizeof buf) goto out;
buf[last++] = '\t';
} else if ((gce->data.data & 0xff) &&
(gce->flags & GRID_ATTR_CHARSET)) {
/* single-byte ACS inline: try to map */
acs = tty_acs_get(NULL, gce->data.data);
if (acs != NULL) {
n = strlen(acs);
if (last + n + 1 > sizeof buf) goto out;
memcpy(buf + last, acs, n);
last += n;
continue;
}
buf[last++] = gce->data.data;
} else {
/* extended cell: convert utf8_char -> bytes */
utf8_to_data(gl->extddata[gce->offset].data,
&ud);
if (ud.size > 0) {
if (last + ud.size + 1 > sizeof buf)
goto out;
memcpy(buf + last, ud.data, ud.size);
last += ud.size;
}
}
}
if (last + 3 > sizeof buf) goto out;
buf[last++] = '"';
buf[last++] = '\n';
}
out: buf[last] = '\0';
return (buf);
}
#endif

View File

@@ -165,34 +165,37 @@ server_client_clear_overlay(struct client *c)
* Given overlay position and dimensions, return parts of the input range which
* are visible.
*/
void
struct visible_ranges *
server_client_overlay_range(u_int x, u_int y, u_int sx, u_int sy, u_int px,
u_int py, u_int nx, struct overlay_ranges *r)
u_int py, u_int nx)
{
u_int ox, onx;
u_int ox, onx;
static struct visible_ranges r = {NULL, NULL, 0, 0};
/* Return up to 2 ranges. */
r->px[2] = 0;
r->nx[2] = 0;
/* For efficiency vr is static and space reused. */
if (r.size == 0) {
r.px = xcalloc(2, sizeof(u_int));
r.nx = xcalloc(2, sizeof(u_int));
r.size = 2;
}
/* Trivial case of no overlap in the y direction. */
if (py < y || py > y + sy - 1) {
r->px[0] = px;
r->nx[0] = nx;
r->px[1] = 0;
r->nx[1] = 0;
return;
r.px[0] = px;
r.nx[0] = nx;
r.used = 1;
return (&r);
}
/* Visible bit to the left of the popup. */
if (px < x) {
r->px[0] = px;
r->nx[0] = x - px;
if (r->nx[0] > nx)
r->nx[0] = nx;
r.px[0] = px;
r.nx[0] = x - px;
if (r.nx[0] > nx)
r.nx[0] = nx;
} else {
r->px[0] = 0;
r->nx[0] = 0;
r.px[0] = 0;
r.nx[0] = 0;
}
/* Visible bit to the right of the popup. */
@@ -201,12 +204,14 @@ server_client_overlay_range(u_int x, u_int y, u_int sx, u_int sy, u_int px,
ox = px;
onx = px + nx;
if (onx > ox) {
r->px[1] = ox;
r->nx[1] = onx - ox;
r.px[1] = ox;
r.nx[1] = onx - ox;
} else {
r->px[1] = 0;
r->nx[1] = 0;
r.px[1] = 0;
r.nx[1] = 0;
}
r.used = 2;
return (&r);
}
/* Check if this client is inside this server. */

23
tmux.h
View File

@@ -1922,11 +1922,19 @@ struct overlay_ranges {
u_int nx[OVERLAY_MAX_RANGES];
};
/* Visible range array element. */
struct visible_ranges {
u_int *px; /* Start */
u_int *nx; /* Length */
size_t used;
size_t size;
};
/* Client connection. */
typedef int (*prompt_input_cb)(struct client *, void *, const char *, int);
typedef void (*prompt_free_cb)(void *);
typedef void (*overlay_check_cb)(struct client*, void *, u_int, u_int, u_int,
struct overlay_ranges *);
typedef struct visible_ranges *(*overlay_check_cb)(struct client*, void *,
u_int, u_int, u_int);
typedef struct screen *(*overlay_mode_cb)(struct client *, void *, u_int *,
u_int *);
typedef void (*overlay_draw_cb)(struct client *, void *,
@@ -2551,6 +2559,8 @@ void tty_set_path(struct tty *, const char *);
void tty_default_attributes(struct tty *, const struct grid_cell *,
struct colour_palette *, u_int, struct hyperlinks *);
void tty_update_mode(struct tty *, int, struct screen *);
struct visible_ranges *tty_check_overlay_range(struct tty *, u_int, u_int,
u_int);
/* tty-draw.c */
void tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int,
@@ -2567,6 +2577,7 @@ void tty_close(struct tty *);
void tty_free(struct tty *);
void tty_update_features(struct tty *);
void tty_set_selection(struct tty *, const char *, const char *, size_t);
u_int tty_cell_width(const struct grid_cell *, u_int);
void tty_write(void (*)(struct tty *, const struct tty_ctx *),
struct tty_ctx *);
void tty_cmd_alignmenttest(struct tty *, const struct tty_ctx *);
@@ -2909,8 +2920,8 @@ void server_client_set_overlay(struct client *, u_int, overlay_check_cb,
overlay_mode_cb, overlay_draw_cb, overlay_key_cb,
overlay_free_cb, overlay_resize_cb, void *);
void server_client_clear_overlay(struct client *);
void server_client_overlay_range(u_int, u_int, u_int, u_int, u_int, u_int,
u_int, struct overlay_ranges *);
struct visible_ranges *server_client_overlay_range(u_int, u_int, u_int, u_int, u_int, u_int,
u_int);
void server_client_set_key_table(struct client *, const char *);
const char *server_client_get_key_table(struct client *);
int server_client_check_nested(struct client *);
@@ -3231,6 +3242,7 @@ void screen_select_cell(struct screen *, struct grid_cell *,
void screen_alternate_on(struct screen *, struct grid_cell *, int);
void screen_alternate_off(struct screen *, struct grid_cell *, int);
const char *screen_mode_to_string(int);
__unused char * screen_print(struct screen *s);
/* window.c */
extern struct windows windows;
@@ -3611,8 +3623,7 @@ int menu_display(struct menu *, int, int, struct cmdq_item *,
const char *, const char *, struct cmd_find_state *,
menu_choice_cb, void *);
struct screen *menu_mode_cb(struct client *, void *, u_int *, u_int *);
void menu_check_cb(struct client *, void *, u_int, u_int, u_int,
struct overlay_ranges *);
struct visible_ranges *menu_check_cb(struct client *, void *, u_int, u_int, u_int);
void menu_draw_cb(struct client *, void *,
struct screen_redraw_ctx *);
void menu_free_cb(struct client *, void *);

87
tty.c
View File

@@ -66,8 +66,7 @@ static void tty_emulate_repeat(struct tty *, enum tty_code_code,
enum tty_code_code, u_int);
static void tty_draw_pane(struct tty *, const struct tty_ctx *, u_int);
static int tty_check_overlay(struct tty *, u_int, u_int);
static void tty_check_overlay_range(struct tty *, u_int, u_int, u_int,
struct overlay_ranges *);
struct visible_ranges *tty_check_overlay_range(struct tty *, u_int, u_int, u_int);
#ifdef ENABLE_SIXEL
static void tty_write_one(void (*)(struct tty *, const struct tty_ctx *),
@@ -1161,7 +1160,7 @@ tty_clear_line(struct tty *tty, const struct grid_cell *defaults, u_int py,
u_int px, u_int nx, u_int bg)
{
struct client *c = tty->client;
struct overlay_ranges r;
struct visible_ranges *r;
u_int i;
log_debug("%s: %s, %u at %u,%u", __func__, c->name, nx, px, py);
@@ -1198,13 +1197,17 @@ tty_clear_line(struct tty *tty, const struct grid_cell *defaults, u_int py,
* Couldn't use an escape sequence, use spaces. Clear only the visible
* bit if there is an overlay.
*/
tty_check_overlay_range(tty, px, py, nx, &r);
for (i = 0; i < OVERLAY_MAX_RANGES; i++) {
if (r.nx[i] == 0)
tty_cursor(tty, px, py);
tty_repeat_space(tty, nx);
/*
r = tty_check_overlay_range(tty, px, py, nx);
for (i = 0; i < r->used; i++) {
if (r->nx[i] == 0)
continue;
tty_cursor(tty, r.px[i], py);
tty_repeat_space(tty, r.nx[i]);
tty_cursor(tty, r->px[i], py);
tty_repeat_space(tty, r->nx[i]);
}
*/
}
/* Clear a line, adjusting to visible part of pane. */
@@ -1418,6 +1421,20 @@ tty_check_codeset(struct tty *tty, const struct grid_cell *gc)
return (&new);
}
/*
* Compute the effective display width (in terminal columns) of a grid cell
* when it will be drawn at terminal column atcol.
*/
u_int
tty_cell_width(const struct grid_cell *gcp, u_int atcol)
{
/* Tabs expand to the next tab stop (tab width = 8). */
if (gcp->flags & GRID_FLAG_TAB)
return (8 - (atcol % 8));
/* Normal characters: width stored in cell (1 or 2 usually). */
return (gcp->data.width);
}
/*
* Check if a single character is obstructed by the overlay and return a
* boolean.
@@ -1425,37 +1442,41 @@ tty_check_codeset(struct tty *tty, const struct grid_cell *gc)
static int
tty_check_overlay(struct tty *tty, u_int px, u_int py)
{
struct overlay_ranges r;
struct visible_ranges *r;
/*
* A unit width range will always return nx[2] == 0 from a check, even
* with multiple overlays, so it's sufficient to check just the first
* two entries.
*/
tty_check_overlay_range(tty, px, py, 1, &r);
if (r.nx[0] + r.nx[1] == 0)
r = tty_check_overlay_range(tty, px, py, 1);
if (r->nx[0] + r->nx[1] == 0)
return (0);
return (1);
}
/* Return parts of the input range which are visible. */
static void
tty_check_overlay_range(struct tty *tty, u_int px, u_int py, u_int nx,
struct overlay_ranges *r)
struct visible_ranges *
tty_check_overlay_range(struct tty *tty, u_int px, u_int py, u_int nx)
{
static struct visible_ranges r = {NULL, NULL, 0, 0};
struct client *c = tty->client;
if (c->overlay_check == NULL) {
r->px[0] = px;
r->nx[0] = nx;
r->px[1] = 0;
r->nx[1] = 0;
r->px[2] = 0;
r->nx[2] = 0;
return;
/* For efficiency vr is static and space reused. */
if (r.size == 0) {
r.px = xcalloc(1, sizeof(u_int));
r.nx = xcalloc(1, sizeof(u_int));
r.size = 1;
}
c->overlay_check(c, c->overlay_data, px, py, nx, r);
if (c->overlay_check == NULL) {
r.px[0] = px;
r.nx[0] = nx;
r.used = 1;
return (&r);
}
return (c->overlay_check(c, c->overlay_data, px, py, nx));
}
#ifdef ENABLE_SIXEL
@@ -1983,7 +2004,7 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx)
{
const struct grid_cell *gcp = ctx->cell;
struct screen *s = ctx->s;
struct overlay_ranges r;
struct visible_ranges *r;
u_int px, py, i, vis = 0;
px = ctx->xoff + ctx->ocx - ctx->wox;
@@ -2000,9 +2021,9 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx)
/* Handle partially obstructed wide characters. */
if (gcp->data.width > 1) {
tty_check_overlay_range(tty, px, py, gcp->data.width, &r);
for (i = 0; i < OVERLAY_MAX_RANGES; i++)
vis += r.nx[i];
r = tty_check_overlay_range(tty, px, py, gcp->data.width);
for (i = 0; i < r->used; i++)
vis += r->nx[i];
if (vis < gcp->data.width) {
tty_draw_line(tty, s, s->cx, s->cy, gcp->data.width,
px, py, &ctx->defaults, ctx->palette);
@@ -2028,7 +2049,7 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx)
void
tty_cmd_cells(struct tty *tty, const struct tty_ctx *ctx)
{
struct overlay_ranges r;
struct visible_ranges *r;
u_int i, px, py, cx;
char *cp = ctx->ptr;
@@ -2059,14 +2080,14 @@ tty_cmd_cells(struct tty *tty, const struct tty_ctx *ctx)
px = ctx->xoff + ctx->ocx - ctx->wox;
py = ctx->yoff + ctx->ocy - ctx->woy;
tty_check_overlay_range(tty, px, py, ctx->num, &r);
for (i = 0; i < OVERLAY_MAX_RANGES; i++) {
if (r.nx[i] == 0)
r = tty_check_overlay_range(tty, px, py, ctx->num);
for (i = 0; i < r->used; i++) {
if (r->nx[i] == 0)
continue;
/* Convert back to pane position for printing. */
cx = r.px[i] - ctx->xoff + ctx->wox;
cx = r->px[i] - ctx->xoff + ctx->wox;
tty_cursor_pane_unless_wrap(tty, ctx, cx, ctx->ocy);
tty_putn(tty, cp + r.px[i] - px, r.nx[i], r.nx[i]);
tty_putn(tty, cp + r->px[i] - px, r->nx[i], r->nx[i]);
}
}