Fix OSC 133 output ranges after resize and cursor movement.

This commit is contained in:
Michael Grant
2026-10-06 12:28:42 +01:00
parent fc84bb8088
commit b19a330cd3
3 changed files with 85 additions and 9 deletions

82
grid.c
View File

@@ -1347,6 +1347,53 @@ grid_reflow_move(struct grid *gd, struct grid_line *from)
return (to); return (to);
} }
/* A portion of a line being moved during reflow. */
struct grid_reflow_range {
u_int offset;
u_int count;
int last;
};
/* Move OSC 133 markers and adjust those left on the source line. */
static void
grid_reflow_move_osc133(struct grid_line *to, struct grid_line *from,
const struct grid_reflow_range *range)
{
struct osc133_data *src = &from->osc133_data;
struct osc133_data *dst = &to->osc133_data;
u_short *src_col[] = { &src->prompt_col, &src->cmd_col,
&src->out_start_col, &src->out_end_col };
u_short *dst_col[] = { &dst->prompt_col, &dst->cmd_col,
&dst->out_start_col, &dst->out_end_col };
u_int flags[] = {
GRID_LINE_START_PROMPT|GRID_LINE_SECOND_PROMPT,
GRID_LINE_START_COMMAND,
GRID_LINE_START_OUTPUT,
GRID_LINE_END_OUTPUT
};
u_int i, flag;
if ((from->flags & GRID_LINE_OSC133_FLAGS) == 0)
return;
for (i = 0; i < nitems(flags); i++) {
flag = from->flags & flags[i];
if (flag == 0)
continue;
if (!range->last && *src_col[i] >= range->count) {
*src_col[i] -= range->count;
continue;
}
*dst_col[i] = range->offset + *src_col[i];
to->flags |= flag;
from->flags &= ~flag;
*src_col[i] = 0;
if (flag == GRID_LINE_END_OUTPUT) {
dst->exit_status = src->exit_status;
src->exit_status = 0;
}
}
}
/* Join line below onto this one. */ /* Join line below onto this one. */
static void static void
grid_reflow_join(struct grid *target, struct grid *gd, u_int sx, u_int yy, grid_reflow_join(struct grid *target, struct grid *gd, u_int sx, u_int yy,
@@ -1354,6 +1401,7 @@ grid_reflow_join(struct grid *target, struct grid *gd, u_int sx, u_int yy,
{ {
struct grid_line *gl, *from = NULL; struct grid_line *gl, *from = NULL;
struct grid_cell gc; struct grid_cell gc;
struct grid_reflow_range range;
u_int lines, left, i, to, line, want = 0; u_int lines, left, i, to, line, want = 0;
u_int at; u_int at;
int wrapped = 1; int wrapped = 1;
@@ -1383,13 +1431,19 @@ grid_reflow_join(struct grid *target, struct grid *gd, u_int sx, u_int yy,
break; break;
line = yy + 1 + lines; line = yy + 1 + lines;
/* If the next line is empty, skip it. */ /* Consume empty lines, including any markers. */
if (~gd->linedata[line].flags & GRID_LINE_WRAPPED) if (~gd->linedata[line].flags & GRID_LINE_WRAPPED)
wrapped = 0; wrapped = 0;
if (gd->linedata[line].cellused == 0) { if (gd->linedata[line].cellused == 0) {
from = &gd->linedata[line];
want = 0;
range.offset = at;
range.count = 0;
range.last = 1;
grid_reflow_move_osc133(gl, from, &range);
lines++;
if (!wrapped) if (!wrapped)
break; break;
lines++;
continue; continue;
} }
@@ -1416,6 +1470,10 @@ grid_reflow_join(struct grid *target, struct grid *gd, u_int sx, u_int yy,
grid_set_cell(target, at, to, &gc); grid_set_cell(target, at, to, &gc);
at++; at++;
} }
range.offset = at - want;
range.count = want;
range.last = (want == from->cellused);
grid_reflow_move_osc133(gl, from, &range);
lines++; lines++;
/* /*
@@ -1462,6 +1520,7 @@ grid_reflow_split(struct grid *target, struct grid *gd, u_int sx, u_int yy,
{ {
struct grid_line *gl = &gd->linedata[yy], *first; struct grid_line *gl = &gd->linedata[yy], *first;
struct grid_cell gc; struct grid_cell gc;
struct grid_reflow_range range;
u_int line, lines, width, i, xx; u_int line, lines, width, i, xx;
u_int used = gl->cellused; u_int used = gl->cellused;
int flags = gl->flags; int flags = gl->flags;
@@ -1485,6 +1544,15 @@ grid_reflow_split(struct grid *target, struct grid *gd, u_int sx, u_int yy,
/* Insert new lines. */ /* Insert new lines. */
line = target->sy + 1; line = target->sy + 1;
first = grid_reflow_add(target, lines); first = grid_reflow_add(target, lines);
memcpy(first, gl, sizeof *first);
first->cellsize = first->cellused = at;
first->flags &= ~GRID_LINE_OSC133_FLAGS;
first->flags |= GRID_LINE_WRAPPED;
memset(&first->osc133_data, 0, sizeof first->osc133_data);
range.offset = 0;
range.count = at;
range.last = 0;
grid_reflow_move_osc133(first, gl, &range);
/* Copy sections from the original line. */ /* Copy sections from the original line. */
width = 0; width = 0;
@@ -1493,6 +1561,9 @@ grid_reflow_split(struct grid *target, struct grid *gd, u_int sx, u_int yy,
grid_get_cell1(gl, i, &gc); grid_get_cell1(gl, i, &gc);
if (width + gc.data.width > sx) { if (width + gc.data.width > sx) {
target->linedata[line].flags |= GRID_LINE_WRAPPED; target->linedata[line].flags |= GRID_LINE_WRAPPED;
range.count = xx;
grid_reflow_move_osc133(&target->linedata[line], gl,
&range);
line++; line++;
width = 0; width = 0;
@@ -1504,11 +1575,10 @@ grid_reflow_split(struct grid *target, struct grid *gd, u_int sx, u_int yy,
} }
if (flags & GRID_LINE_WRAPPED) if (flags & GRID_LINE_WRAPPED)
target->linedata[line].flags |= GRID_LINE_WRAPPED; target->linedata[line].flags |= GRID_LINE_WRAPPED;
range.count = xx;
range.last = 1;
grid_reflow_move_osc133(&target->linedata[line], gl, &range);
/* Move the remainder of the original line. */
gl->cellsize = gl->cellused = at;
gl->flags |= GRID_LINE_WRAPPED;
memcpy(first, gl, sizeof *first);
grid_reflow_dead(gl); grid_reflow_dead(gl);
/* Adjust the scroll position. */ /* Adjust the scroll position. */

3
tmux.1
View File

@@ -2577,7 +2577,8 @@ marker up to its matching
marker. marker.
If there is no If there is no
.Ql D .Ql D
marker, the output ends at the end of the copy-mode buffer. marker, the output ends at the last used cell in the copy-mode buffer,
omitting unused blank rows at the bottom.
At the following prompt or below it, they use the most recent nonempty output. At the following prompt or below it, they use the most recent nonempty output.
With With
.Fl a , .Fl a ,

View File

@@ -6387,8 +6387,13 @@ window_copy_find_previous_output_range(struct window_mode_entry *wme,
static void static void
window_copy_output_end(struct screen *s, u_int *x, u_int *y) window_copy_output_end(struct screen *s, u_int *x, u_int *y)
{ {
*x = s->cx; struct grid *gd = s->grid;
*y = screen_hsize(s) + s->cy; u_int last = gd->hsize + gd->sy - 1;
while (last > 0 && grid_get_line(gd, last)->cellused == 0)
last--;
*x = grid_get_line(gd, last)->cellused;
*y = last;
} }
static void * static void *