diff options
author | Nicholas Marriott <nicm@cvs.openbsd.org> | 2019-03-20 19:19:12 +0000 |
---|---|---|
committer | Nicholas Marriott <nicm@cvs.openbsd.org> | 2019-03-20 19:19:12 +0000 |
commit | d78036c7a2473520d65a7069d1cc5152aa160c19 (patch) | |
tree | f568d16753508155c8e69a13bf39dda810c798b1 /usr.bin | |
parent | be1fa2aa9b199c1e2c2d7b3a04c1867f1ffeea4f (diff) |
Improve cursor positioning after reflow by storing the position as an
offset into the entire history before reflow and restoring it aftewards.
Diffstat (limited to 'usr.bin')
-rw-r--r-- | usr.bin/tmux/grid.c | 83 | ||||
-rw-r--r-- | usr.bin/tmux/screen.c | 60 | ||||
-rw-r--r-- | usr.bin/tmux/tmux.h | 10 |
3 files changed, 80 insertions, 73 deletions
diff --git a/usr.bin/tmux/grid.c b/usr.bin/tmux/grid.c index a12ba180702..fbbc0712109 100644 --- a/usr.bin/tmux/grid.c +++ b/usr.bin/tmux/grid.c @@ -1,4 +1,4 @@ -/* $OpenBSD: grid.c,v 1.90 2019/03/18 15:25:36 nicm Exp $ */ +/* $OpenBSD: grid.c,v 1.91 2019/03/20 19:19:11 nicm Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -1030,7 +1030,7 @@ grid_reflow_move(struct grid *gd, struct grid_line *from) /* Join line below onto this one. */ static void grid_reflow_join(struct grid *target, struct grid *gd, u_int sx, u_int yy, - u_int width, u_int *cy, int already) + u_int width, int already) { struct grid_line *gl, *from = NULL; struct grid_cell gc; @@ -1128,11 +1128,7 @@ grid_reflow_join(struct grid *target, struct grid *gd, u_int sx, u_int yy, grid_reflow_dead(&gd->linedata[i]); } - /* Adjust cursor and scroll positions. */ - if (*cy > to + lines) - *cy -= lines; - else if (*cy > to) - *cy = to; + /* Adjust scroll position. */ if (gd->hscrolled > to + lines) gd->hscrolled -= lines; else if (gd->hscrolled > to) @@ -1142,7 +1138,7 @@ grid_reflow_join(struct grid *target, struct grid *gd, u_int sx, u_int yy, /* Split this line into several new ones */ static void grid_reflow_split(struct grid *target, struct grid *gd, u_int sx, u_int yy, - u_int at, u_int *cy) + u_int at) { struct grid_line *gl = &gd->linedata[yy], *first; struct grid_cell gc; @@ -1195,9 +1191,7 @@ grid_reflow_split(struct grid *target, struct grid *gd, u_int sx, u_int yy, memcpy(first, gl, sizeof *first); grid_reflow_dead(gl); - /* Adjust the cursor and scroll positions. */ - if (yy <= *cy) - (*cy) += lines - 1; + /* Adjust the scroll position. */ if (yy <= gd->hscrolled) gd->hscrolled += lines - 1; @@ -1206,24 +1200,17 @@ grid_reflow_split(struct grid *target, struct grid *gd, u_int sx, u_int yy, * in the last new line, try to join with the next lines. */ if (width < sx && (flags & GRID_LINE_WRAPPED)) - grid_reflow_join(target, gd, sx, yy, width, cy, 1); + grid_reflow_join(target, gd, sx, yy, width, 1); } /* Reflow lines on grid to new width. */ void -grid_reflow(struct grid *gd, u_int sx, u_int *cursor) +grid_reflow(struct grid *gd, u_int sx) { struct grid *target; struct grid_line *gl; struct grid_cell gc; - u_int yy, cy, width, i, at, first; - struct timeval start, tv; - - gettimeofday(&start, NULL); - - log_debug("%s: %u lines, new width %u", __func__, gd->hsize + gd->sy, - sx); - cy = gd->hsize + (*cursor); + u_int yy, width, i, at, first; /* * Create a destination grid. This is just used as a container for the @@ -1277,7 +1264,7 @@ grid_reflow(struct grid *gd, u_int sx, u_int *cursor) * it was previously wrapped. */ if (width > sx) { - grid_reflow_split(target, gd, sx, yy, at, &cy); + grid_reflow_split(target, gd, sx, yy, at); continue; } @@ -1286,7 +1273,7 @@ grid_reflow(struct grid *gd, u_int sx, u_int *cursor) * of the next line. */ if (gl->flags & GRID_LINE_WRAPPED) - grid_reflow_join(target, gd, sx, yy, width, &cy, 0); + grid_reflow_join(target, gd, sx, yy, width, 0); else grid_reflow_move(target, gl); } @@ -1300,20 +1287,42 @@ grid_reflow(struct grid *gd, u_int sx, u_int *cursor) free(gd->linedata); gd->linedata = target->linedata; free(target); +} - /* - * Update scrolled and cursor positions. - */ - if (gd->hscrolled > gd->hsize) - gd->hscrolled = gd->hsize; - if (cy < gd->hsize) - *cursor = 0; - else - *cursor = cy - gd->hsize; +/* Convert point position to offset from the start of the grid. */ +u_int +grid_to_offset(struct grid *gd, u_int px, u_int py) +{ + u_int yy, offset = 0; + + if (py > gd->hsize + gd->sy - 1) { + px = UINT_MAX; + py = gd->hsize + gd->sy - 1; + } - gettimeofday(&tv, NULL); - timersub(&tv, &start, &tv); - log_debug("%s: now %u lines (in %llu.%06u seconds)", __func__, - gd->hsize + gd->sy, (unsigned long long)tv.tv_sec, - (u_int)tv.tv_usec); + for (yy = 0; yy < py; yy++) + offset += gd->linedata[yy].cellused; + if (px > gd->linedata[yy].cellused) + px = gd->linedata[yy].cellused; + return (offset + px); +} + +/* Convert offset from the start of the grid to point position. */ +void +grid_from_offset(struct grid *gd, u_int offset, u_int *px, u_int *py) +{ + u_int yy; + + *px = *py = 0; + + for (yy = 0; yy < gd->hsize + gd->sy - 1; yy++) { + if (offset <= gd->linedata[yy].cellused) + break; + offset -= gd->linedata[yy].cellused; + } + if (offset < gd->linedata[yy].cellused) + *px = offset; + else + *px = gd->linedata[yy].cellused; + *py = yy; } diff --git a/usr.bin/tmux/screen.c b/usr.bin/tmux/screen.c index 6fa6cd4eb7d..14872531dba 100644 --- a/usr.bin/tmux/screen.c +++ b/usr.bin/tmux/screen.c @@ -1,4 +1,4 @@ -/* $OpenBSD: screen.c,v 1.53 2019/01/15 09:56:31 nicm Exp $ */ +/* $OpenBSD: screen.c,v 1.54 2019/03/20 19:19:11 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -48,7 +48,6 @@ struct screen_title_entry { }; TAILQ_HEAD(screen_titles, screen_title_entry); -static void screen_resize_x(struct screen *, u_int); static void screen_resize_y(struct screen *, u_int); static void screen_reflow(struct screen *, u_int); @@ -207,13 +206,7 @@ screen_resize(struct screen *s, u_int sx, u_int sy, int reflow) sy = 1; if (sx != screen_size_x(s)) { - screen_resize_x(s, sx); - - /* - * It is unclear what should happen to tabs on resize. xterm - * seems to try and maintain them, rxvt resets them. Resetting - * is simpler and more reliable so let's do that. - */ + s->grid->sx = sx; screen_reset_tabs(s); } else reflow = 0; @@ -226,28 +219,6 @@ screen_resize(struct screen *s, u_int sx, u_int sy, int reflow) } static void -screen_resize_x(struct screen *s, u_int sx) -{ - struct grid *gd = s->grid; - - if (sx == 0) - fatalx("zero size"); - - /* - * Treat resizing horizontally simply: just ensure the cursor is - * on-screen and change the size. Don't bother to truncate any lines - - * then the data should be accessible if the size is then increased. - * - * The only potential wrinkle is if UTF-8 double-width characters are - * left in the last column, but UTF-8 terminals should deal with this - * sanely. - */ - if (s->cx >= sx) - s->cx = sx - 1; - gd->sx = sx; -} - -static void screen_resize_y(struct screen *s, u_int sy) { struct grid *gd = s->grid; @@ -493,5 +464,30 @@ screen_select_cell(struct screen *s, struct grid_cell *dst, static void screen_reflow(struct screen *s, u_int new_x) { - grid_reflow(s->grid, new_x, &s->cy); + u_int offset, cx = s->cx, cy = s->grid->hsize + s->cy; + struct timeval start, tv; + + gettimeofday(&start, NULL); + + offset = grid_to_offset(s->grid, cx, cy); + log_debug("%s: cursor %u,%u offset is %u", __func__, cx, cy, offset); + + grid_reflow(s->grid, new_x); + + grid_from_offset(s->grid, offset, &cx, &cy); + log_debug("%s: new cursor is %u,%u", __func__, cx, cy); + + if (cy >= s->grid->hsize) { + s->cx = cx; + s->cy = cy - s->grid->hsize; + } else { + s->cx = 0; + s->cy = 0; + } + + gettimeofday(&tv, NULL); + timersub(&tv, &start, &tv); + + log_debug("%s: reflow took %llu.%06u seconds", __func__, + (unsigned long long)tv.tv_sec, (u_int)tv.tv_usec); } diff --git a/usr.bin/tmux/tmux.h b/usr.bin/tmux/tmux.h index 6ce73b24bfb..944ab89aeaf 100644 --- a/usr.bin/tmux/tmux.h +++ b/usr.bin/tmux/tmux.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tmux.h,v 1.875 2019/03/18 21:46:02 nicm Exp $ */ +/* $OpenBSD: tmux.h,v 1.876 2019/03/20 19:19:11 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -2088,6 +2088,8 @@ void grid_get_cell(struct grid *, u_int, u_int, struct grid_cell *); void grid_set_cell(struct grid *, u_int, u_int, const struct grid_cell *); void grid_set_cells(struct grid *, u_int, u_int, const struct grid_cell *, const char *, size_t); +struct grid_line *grid_get_line(struct grid *, u_int); +void grid_adjust_lines(struct grid *, u_int); void grid_clear(struct grid *, u_int, u_int, u_int, u_int, u_int); void grid_clear_lines(struct grid *, u_int, u_int, u_int); void grid_move_lines(struct grid *, u_int, u_int, u_int, u_int); @@ -2096,9 +2098,9 @@ char *grid_string_cells(struct grid *, u_int, u_int, u_int, struct grid_cell **, int, int, int); void grid_duplicate_lines(struct grid *, u_int, struct grid *, u_int, u_int); -void grid_reflow(struct grid *, u_int, u_int *); -struct grid_line *grid_get_line(struct grid *, u_int); -void grid_adjust_lines(struct grid *, u_int); +void grid_reflow(struct grid *, u_int); +u_int grid_to_offset(struct grid *, u_int, u_int); +void grid_from_offset(struct grid *, u_int, u_int *, u_int *); /* grid-view.c */ void grid_view_get_cell(struct grid *, u_int, u_int, struct grid_cell *); |