Store and restore cursor across reflow by working out a position based

on unwrapped lines, rather than a grid offset. Fixes problems reported
by Thomas Sattler and Paul de Weerd.
This commit is contained in:
nicm 2019-04-02 08:45:32 +00:00 committed by Nicholas Marriott
parent 6d071c468c
commit bbcfee362f
3 changed files with 51 additions and 30 deletions

69
grid.c
View File

@ -1291,40 +1291,61 @@ grid_reflow(struct grid *gd, u_int sx)
free(target); free(target);
} }
/* Convert point position to offset from the start of the grid. */ /* Convert to position based on wrapped lines. */
u_int void
grid_to_offset(struct grid *gd, u_int px, u_int py) grid_wrap_position(struct grid *gd, u_int px, u_int py, u_int *wx, u_int *wy)
{ {
u_int yy, offset = 0; u_int ax = 0, ay = 0, yy;
if (py > gd->hsize + gd->sy - 1) { for (yy = 0; yy < py; yy++) {
px = UINT_MAX; if (gd->linedata[yy].flags & GRID_LINE_WRAPPED)
py = gd->hsize + gd->sy - 1; ax += gd->linedata[yy].cellused;
else {
ax = 0;
ay++;
}
} }
if (px >= gd->linedata[yy].cellused)
for (yy = 0; yy < py; yy++) ax = UINT_MAX;
offset += gd->linedata[yy].cellused; else
if (px > gd->linedata[yy].cellused) ax += px;
px = gd->linedata[yy].cellused; *wx = ax;
return (offset + px); *wy = ay;
} }
/* Convert offset from the start of the grid to point position. */ /* Convert position based on wrapped lines back. */
void void
grid_from_offset(struct grid *gd, u_int offset, u_int *px, u_int *py) grid_unwrap_position(struct grid *gd, u_int *px, u_int *py, u_int wx, u_int wy)
{ {
u_int yy; u_int yy, ax = 0, ay = 0;
*px = *py = 0;
for (yy = 0; yy < gd->hsize + gd->sy - 1; yy++) { for (yy = 0; yy < gd->hsize + gd->sy - 1; yy++) {
if (offset <= gd->linedata[yy].cellused) if (ay == wy)
break; break;
offset -= gd->linedata[yy].cellused; if (gd->linedata[yy].flags & GRID_LINE_WRAPPED)
ax += gd->linedata[yy].cellused;
else {
ax = 0;
ay++;
}
} }
if (offset < gd->linedata[yy].cellused)
*px = offset; /*
else * yy is now 0 on the unwrapped line which contains wx. Walk forwards
*px = gd->linedata[yy].cellused; * until we find the end or the line now containing wx.
*/
if (wx == UINT_MAX) {
while (gd->linedata[yy].flags & GRID_LINE_WRAPPED)
yy++;
wx = gd->linedata[yy].cellused;
} else {
while (gd->linedata[yy].flags & GRID_LINE_WRAPPED) {
if (wx < gd->linedata[yy].cellused)
break;
wx -= gd->linedata[yy].cellused;
yy++;
}
}
*px = wx;
*py = yy; *py = yy;
} }

View File

@ -463,17 +463,17 @@ screen_select_cell(struct screen *s, struct grid_cell *dst,
static void static void
screen_reflow(struct screen *s, u_int new_x) screen_reflow(struct screen *s, u_int new_x)
{ {
u_int offset, cx = s->cx, cy = s->grid->hsize + s->cy; u_int cx = s->cx, cy = s->grid->hsize + s->cy, wx, wy;
struct timeval start, tv; struct timeval start, tv;
gettimeofday(&start, NULL); gettimeofday(&start, NULL);
offset = grid_to_offset(s->grid, cx, cy); grid_wrap_position(s->grid, cx, cy, &wx, &wy);
log_debug("%s: cursor %u,%u offset is %u", __func__, cx, cy, offset); log_debug("%s: cursor %u,%u is %u,%u", __func__, cx, cy, wx, wy);
grid_reflow(s->grid, new_x); grid_reflow(s->grid, new_x);
grid_from_offset(s->grid, offset, &cx, &cy); grid_unwrap_position(s->grid, &cx, &cy, wx, wy);
log_debug("%s: new cursor is %u,%u", __func__, cx, cy); log_debug("%s: new cursor is %u,%u", __func__, cx, cy);
if (cy >= s->grid->hsize) { if (cy >= s->grid->hsize) {

4
tmux.h
View File

@ -2103,8 +2103,8 @@ char *grid_string_cells(struct grid *, u_int, u_int, u_int,
void grid_duplicate_lines(struct grid *, u_int, struct grid *, u_int, void grid_duplicate_lines(struct grid *, u_int, struct grid *, u_int,
u_int); u_int);
void grid_reflow(struct grid *, u_int); void grid_reflow(struct grid *, u_int);
u_int grid_to_offset(struct grid *, u_int, u_int); void grid_wrap_position(struct grid *, u_int, u_int, u_int *, u_int *);
void grid_from_offset(struct grid *, u_int, u_int *, u_int *); void grid_unwrap_position(struct grid *, u_int *, u_int *, u_int, u_int);
/* grid-view.c */ /* grid-view.c */
void grid_view_get_cell(struct grid *, u_int, u_int, struct grid_cell *); void grid_view_get_cell(struct grid *, u_int, u_int, struct grid_cell *);