mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 00:56:10 +00:00 
			
		
		
		
	Improve cursor positioning after reflow by storing the position as an
offset into the entire history before reflow and restoring it aftewards.
This commit is contained in:
		
							
								
								
									
										85
									
								
								grid.c
									
									
									
									
									
								
							
							
						
						
									
										85
									
								
								grid.c
									
									
									
									
									
								
							@@ -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;
 | 
			
		||||
 | 
			
		||||
	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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 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;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										58
									
								
								screen.c
									
									
									
									
									
								
							
							
						
						
									
										58
									
								
								screen.c
									
									
									
									
									
								
							@@ -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;
 | 
			
		||||
@@ -225,28 +218,6 @@ screen_resize(struct screen *s, u_int sx, u_int sy, int reflow)
 | 
			
		||||
		screen_reflow(s, sx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
{
 | 
			
		||||
@@ -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);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										8
									
								
								tmux.h
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								tmux.h
									
									
									
									
									
								
							@@ -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 *);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user