mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 00:56:10 +00:00 
			
		
		
		
	Merge branch 'obsd-master'
This commit is contained in:
		
							
								
								
									
										451
									
								
								grid.c
									
									
									
									
									
								
							
							
						
						
									
										451
									
								
								grid.c
									
									
									
									
									
								
							@@ -43,22 +43,8 @@ static const struct grid_cell_entry grid_default_entry = {
 | 
			
		||||
	0, { .data = { 0, 8, 8, ' ' } }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void	grid_expand_line(struct grid *, u_int, u_int, u_int);
 | 
			
		||||
static void	grid_empty_line(struct grid *, u_int, u_int);
 | 
			
		||||
 | 
			
		||||
static void	grid_reflow_copy(struct grid_line *, u_int, struct grid_line *,
 | 
			
		||||
		    u_int, u_int);
 | 
			
		||||
static void	grid_reflow_join(struct grid *, u_int *, struct grid_line *,
 | 
			
		||||
		    u_int);
 | 
			
		||||
static void	grid_reflow_split(struct grid *, u_int *, struct grid_line *,
 | 
			
		||||
		    u_int, u_int);
 | 
			
		||||
static void	grid_reflow_move(struct grid *, u_int *, struct grid_line *);
 | 
			
		||||
 | 
			
		||||
static size_t	grid_string_cells_fg(const struct grid_cell *, int *);
 | 
			
		||||
static size_t	grid_string_cells_bg(const struct grid_cell *, int *);
 | 
			
		||||
static void	grid_string_cells_code(const struct grid_cell *,
 | 
			
		||||
		    const struct grid_cell *, char *, size_t, int);
 | 
			
		||||
 | 
			
		||||
/* Store cell in entry. */
 | 
			
		||||
static void
 | 
			
		||||
grid_store_cell(struct grid_cell_entry *gce, const struct grid_cell *gc,
 | 
			
		||||
@@ -423,20 +409,11 @@ grid_peek_line(struct grid *gd, u_int py)
 | 
			
		||||
	return (&gd->linedata[py]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Get cell for reading. */
 | 
			
		||||
void
 | 
			
		||||
grid_get_cell(struct grid *gd, u_int px, u_int py, struct grid_cell *gc)
 | 
			
		||||
/* Get cell from line. */
 | 
			
		||||
static void
 | 
			
		||||
grid_get_cell1(struct grid_line *gl, u_int px, struct grid_cell *gc)
 | 
			
		||||
{
 | 
			
		||||
	struct grid_line	*gl;
 | 
			
		||||
	struct grid_cell_entry	*gce;
 | 
			
		||||
 | 
			
		||||
	if (grid_check_y(gd, py) != 0 || px >= gd->linedata[py].cellsize) {
 | 
			
		||||
		memcpy(gc, &grid_default_cell, sizeof *gc);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gl = &gd->linedata[py];
 | 
			
		||||
	gce = &gl->celldata[px];
 | 
			
		||||
	struct grid_cell_entry	*gce = &gl->celldata[px];
 | 
			
		||||
 | 
			
		||||
	if (gce->flags & GRID_FLAG_EXTENDED) {
 | 
			
		||||
		if (gce->offset >= gl->extdsize)
 | 
			
		||||
@@ -457,6 +434,17 @@ grid_get_cell(struct grid *gd, u_int px, u_int py, struct grid_cell *gc)
 | 
			
		||||
	utf8_set(&gc->data, gce->data.data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Get cell for reading. */
 | 
			
		||||
void
 | 
			
		||||
grid_get_cell(struct grid *gd, u_int px, u_int py, struct grid_cell *gc)
 | 
			
		||||
{
 | 
			
		||||
	if (grid_check_y(gd, py) != 0 || px >= gd->linedata[py].cellsize) {
 | 
			
		||||
		memcpy(gc, &grid_default_cell, sizeof *gc);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	return (grid_get_cell1(&gd->linedata[py], px, gc));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Set cell at relative position. */
 | 
			
		||||
void
 | 
			
		||||
grid_set_cell(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc)
 | 
			
		||||
@@ -953,164 +941,269 @@ grid_duplicate_lines(struct grid *dst, u_int dy, struct grid *src, u_int sy,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Copy a section of a line. */
 | 
			
		||||
/* Join line below onto this one. */
 | 
			
		||||
static void
 | 
			
		||||
grid_reflow_copy(struct grid_line *dst_gl, u_int to, struct grid_line *src_gl,
 | 
			
		||||
    u_int from, u_int to_copy)
 | 
			
		||||
grid_reflow_join(struct grid *gd, u_int sx, u_int yy, u_int width, u_int *cy)
 | 
			
		||||
{
 | 
			
		||||
	struct grid_cell_entry	*gce;
 | 
			
		||||
	u_int			 i, was;
 | 
			
		||||
	struct grid_line	*gl = &gd->linedata[yy], *from;
 | 
			
		||||
	struct grid_cell	 gc;
 | 
			
		||||
	u_int			 lines, want, left, i, at = gl->cellused, line;
 | 
			
		||||
	int			 wrapped = 1;
 | 
			
		||||
 | 
			
		||||
	memcpy(&dst_gl->celldata[to], &src_gl->celldata[from],
 | 
			
		||||
	    to_copy * sizeof *dst_gl->celldata);
 | 
			
		||||
 | 
			
		||||
	for (i = to; i < to + to_copy; i++) {
 | 
			
		||||
		gce = &dst_gl->celldata[i];
 | 
			
		||||
		if (~gce->flags & GRID_FLAG_EXTENDED)
 | 
			
		||||
			continue;
 | 
			
		||||
		was = gce->offset;
 | 
			
		||||
 | 
			
		||||
		dst_gl->extddata = xreallocarray(dst_gl->extddata,
 | 
			
		||||
		    dst_gl->extdsize + 1, sizeof *dst_gl->extddata);
 | 
			
		||||
		gce->offset = dst_gl->extdsize++;
 | 
			
		||||
		memcpy(&dst_gl->extddata[gce->offset], &src_gl->extddata[was],
 | 
			
		||||
		    sizeof *dst_gl->extddata);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Join line data. */
 | 
			
		||||
static void
 | 
			
		||||
grid_reflow_join(struct grid *dst, u_int *py, struct grid_line *src_gl,
 | 
			
		||||
    u_int new_x)
 | 
			
		||||
{
 | 
			
		||||
	struct grid_line	*dst_gl = &dst->linedata[(*py) - 1];
 | 
			
		||||
	u_int			 left, to_copy, ox, nx;
 | 
			
		||||
 | 
			
		||||
	/* How much is left on the old line? */
 | 
			
		||||
	left = new_x - dst_gl->cellused;
 | 
			
		||||
 | 
			
		||||
	/* Work out how much to append. */
 | 
			
		||||
	to_copy = src_gl->cellused;
 | 
			
		||||
	if (to_copy > left)
 | 
			
		||||
		to_copy = left;
 | 
			
		||||
	ox = dst_gl->cellused;
 | 
			
		||||
	nx = ox + to_copy;
 | 
			
		||||
 | 
			
		||||
	/* Resize the destination line. */
 | 
			
		||||
	dst_gl->celldata = xreallocarray(dst_gl->celldata, nx,
 | 
			
		||||
	    sizeof *dst_gl->celldata);
 | 
			
		||||
	dst_gl->cellsize = dst_gl->cellused = nx;
 | 
			
		||||
 | 
			
		||||
	/* Append as much as possible. */
 | 
			
		||||
	grid_reflow_copy(dst_gl, ox, src_gl, 0, to_copy);
 | 
			
		||||
 | 
			
		||||
	/* If there is any left in the source, split it. */
 | 
			
		||||
	if (src_gl->cellused > to_copy) {
 | 
			
		||||
		dst_gl->flags |= GRID_LINE_WRAPPED;
 | 
			
		||||
 | 
			
		||||
		src_gl->cellused -= to_copy;
 | 
			
		||||
		grid_reflow_split(dst, py, src_gl, new_x, to_copy);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Split line data. */
 | 
			
		||||
static void
 | 
			
		||||
grid_reflow_split(struct grid *dst, u_int *py, struct grid_line *src_gl,
 | 
			
		||||
    u_int new_x, u_int offset)
 | 
			
		||||
{
 | 
			
		||||
	struct grid_line	*dst_gl = NULL;
 | 
			
		||||
	u_int			 to_copy;
 | 
			
		||||
 | 
			
		||||
	/* Loop and copy sections of the source line. */
 | 
			
		||||
	while (src_gl->cellused > 0) {
 | 
			
		||||
		/* Create new line. */
 | 
			
		||||
		if (*py >= dst->hsize + dst->sy)
 | 
			
		||||
			grid_scroll_history(dst, 8);
 | 
			
		||||
		dst_gl = &dst->linedata[*py];
 | 
			
		||||
		(*py)++;
 | 
			
		||||
 | 
			
		||||
		/* How much should we copy? */
 | 
			
		||||
		to_copy = new_x;
 | 
			
		||||
		if (to_copy > src_gl->cellused)
 | 
			
		||||
			to_copy = src_gl->cellused;
 | 
			
		||||
 | 
			
		||||
		/* Expand destination line. */
 | 
			
		||||
		dst_gl->celldata = xreallocarray(NULL, to_copy,
 | 
			
		||||
		    sizeof *dst_gl->celldata);
 | 
			
		||||
		dst_gl->cellsize = dst_gl->cellused = to_copy;
 | 
			
		||||
		dst_gl->flags |= GRID_LINE_WRAPPED;
 | 
			
		||||
 | 
			
		||||
		/* Copy the data. */
 | 
			
		||||
		grid_reflow_copy(dst_gl, 0, src_gl, offset, to_copy);
 | 
			
		||||
 | 
			
		||||
		/* Move offset and reduce old line size. */
 | 
			
		||||
		offset += to_copy;
 | 
			
		||||
		src_gl->cellused -= to_copy;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Last line is not wrapped. */
 | 
			
		||||
	if (dst_gl != NULL)
 | 
			
		||||
		dst_gl->flags &= ~GRID_LINE_WRAPPED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Move line data. */
 | 
			
		||||
static void
 | 
			
		||||
grid_reflow_move(struct grid *dst, u_int *py, struct grid_line *src_gl)
 | 
			
		||||
{
 | 
			
		||||
	struct grid_line	*dst_gl;
 | 
			
		||||
 | 
			
		||||
	/* Create new line. */
 | 
			
		||||
	if (*py >= dst->hsize + dst->sy)
 | 
			
		||||
		grid_scroll_history(dst, 8);
 | 
			
		||||
	dst_gl = &dst->linedata[*py];
 | 
			
		||||
	(*py)++;
 | 
			
		||||
 | 
			
		||||
	/* Copy the old line. */
 | 
			
		||||
	memcpy(dst_gl, src_gl, sizeof *dst_gl);
 | 
			
		||||
	dst_gl->flags &= ~GRID_LINE_WRAPPED;
 | 
			
		||||
 | 
			
		||||
	/* Clear old line. */
 | 
			
		||||
	src_gl->celldata = NULL;
 | 
			
		||||
	src_gl->extddata = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Reflow lines from src grid into dst grid of width new_x. Returns number of
 | 
			
		||||
 * lines fewer in the visible area. The source grid is destroyed.
 | 
			
		||||
	lines = 0;
 | 
			
		||||
	for (;;) {
 | 
			
		||||
		/*
 | 
			
		||||
		 * If this is now the last line, there is nothing more to be
 | 
			
		||||
		 * done.
 | 
			
		||||
		 */
 | 
			
		||||
u_int
 | 
			
		||||
grid_reflow(struct grid *dst, struct grid *src, u_int new_x)
 | 
			
		||||
{
 | 
			
		||||
	u_int			 py, sy, line;
 | 
			
		||||
	int			 previous_wrapped;
 | 
			
		||||
	struct grid_line	*src_gl;
 | 
			
		||||
		if (yy + lines == gd->hsize + gd->sy)
 | 
			
		||||
			break;
 | 
			
		||||
		line = yy + 1 + lines;
 | 
			
		||||
 | 
			
		||||
	py = 0;
 | 
			
		||||
	sy = src->sy;
 | 
			
		||||
 | 
			
		||||
	previous_wrapped = 0;
 | 
			
		||||
	for (line = 0; line < sy + src->hsize; line++) {
 | 
			
		||||
		src_gl = src->linedata + line;
 | 
			
		||||
		if (!previous_wrapped) {
 | 
			
		||||
			/* Wasn't wrapped. If smaller, move to destination. */
 | 
			
		||||
			if (src_gl->cellused <= new_x)
 | 
			
		||||
				grid_reflow_move(dst, &py, src_gl);
 | 
			
		||||
			else
 | 
			
		||||
				grid_reflow_split(dst, &py, src_gl, new_x, 0);
 | 
			
		||||
		} else {
 | 
			
		||||
			/* Previous was wrapped. Try to join. */
 | 
			
		||||
			grid_reflow_join(dst, &py, src_gl, new_x);
 | 
			
		||||
		}
 | 
			
		||||
		previous_wrapped = (src_gl->flags & GRID_LINE_WRAPPED);
 | 
			
		||||
 | 
			
		||||
		/* This is where we started scrolling. */
 | 
			
		||||
		if (line == sy + src->hsize - src->hscrolled - 1)
 | 
			
		||||
			dst->hscrolled = 0;
 | 
			
		||||
		/* If the next line is empty, skip it. */
 | 
			
		||||
		if (~gd->linedata[line].flags & GRID_LINE_WRAPPED)
 | 
			
		||||
			wrapped = 0;
 | 
			
		||||
		if (gd->linedata[line].cellused == 0) {
 | 
			
		||||
			if (!wrapped)
 | 
			
		||||
				break;
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	grid_destroy(src);
 | 
			
		||||
		/*
 | 
			
		||||
		 * Is the destination line now full? Copy the first character
 | 
			
		||||
		 * separately because we need to leave "from" set to the last
 | 
			
		||||
		 * line if this line is full.
 | 
			
		||||
		 */
 | 
			
		||||
		grid_get_cell1(&gd->linedata[line], 0, &gc);
 | 
			
		||||
		if (width + gc.data.width > sx)
 | 
			
		||||
			break;
 | 
			
		||||
		width += gc.data.width;
 | 
			
		||||
		grid_set_cell(gd, at, yy, &gc);
 | 
			
		||||
		at++;
 | 
			
		||||
 | 
			
		||||
	if (py > sy)
 | 
			
		||||
		return (0);
 | 
			
		||||
	return (sy - py);
 | 
			
		||||
		/* Join as much more as possible onto the current line. */
 | 
			
		||||
		from = &gd->linedata[line];
 | 
			
		||||
		for (want = 1; want < from->cellused; want++) {
 | 
			
		||||
			grid_get_cell1(from, want, &gc);
 | 
			
		||||
			if (width + gc.data.width > sx)
 | 
			
		||||
				break;
 | 
			
		||||
			width += gc.data.width;
 | 
			
		||||
 | 
			
		||||
			grid_set_cell(gd, at, yy, &gc);
 | 
			
		||||
			at++;
 | 
			
		||||
		}
 | 
			
		||||
		lines++;
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * If this line wasn't wrapped or we didn't consume the entire
 | 
			
		||||
		 * line, don't try to join any further lines.
 | 
			
		||||
		 */
 | 
			
		||||
		if (!wrapped || want != from->cellused || width == sx)
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
	if (lines == 0)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If we didn't consume the entire final line, then remove what we did
 | 
			
		||||
	 * consume. If we consumed the entire line and it wasn't wrapped,
 | 
			
		||||
	 * remove the wrap flag from this line.
 | 
			
		||||
	 */
 | 
			
		||||
	left = from->cellused - want;
 | 
			
		||||
	if (left != 0) {
 | 
			
		||||
		grid_move_cells(gd, 0, want, yy + lines, left, 8);
 | 
			
		||||
		from->cellsize = from->cellused = left;
 | 
			
		||||
		lines--;
 | 
			
		||||
	} else if (!wrapped)
 | 
			
		||||
		gl->flags &= ~GRID_LINE_WRAPPED;
 | 
			
		||||
 | 
			
		||||
	/* Remove the lines that were completely consumed. */
 | 
			
		||||
	if (lines != 0) {
 | 
			
		||||
		if (yy + lines != gd->hsize + gd->sy) {
 | 
			
		||||
			memmove(&gd->linedata[yy + 1],
 | 
			
		||||
			    &gd->linedata[yy + lines + 1],
 | 
			
		||||
			    ((gd->hsize + gd->sy) - (yy + lines + 1)) *
 | 
			
		||||
			    (sizeof *gd->linedata));
 | 
			
		||||
		}
 | 
			
		||||
		if (gd->hsize >= lines)
 | 
			
		||||
			gd->hsize -= lines;
 | 
			
		||||
		else {
 | 
			
		||||
			lines -= gd->hsize;
 | 
			
		||||
			gd->hsize = 0;
 | 
			
		||||
			for (i = 1; i < lines + 1; i++)
 | 
			
		||||
				grid_empty_line(gd, gd->hsize + gd->sy - i, 8);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Adjust cursor and scroll positions. */
 | 
			
		||||
	if (*cy > yy + lines)
 | 
			
		||||
		*cy -= lines;
 | 
			
		||||
	else if (*cy > yy)
 | 
			
		||||
		*cy = yy;
 | 
			
		||||
	if (gd->hscrolled > yy + lines)
 | 
			
		||||
		gd->hscrolled -= lines;
 | 
			
		||||
	else if (gd->hscrolled > yy)
 | 
			
		||||
		gd->hscrolled = yy;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Split this line into several new ones */
 | 
			
		||||
static void
 | 
			
		||||
grid_reflow_split(struct grid *gd, u_int sx, u_int yy, u_int at, u_int *cy)
 | 
			
		||||
{
 | 
			
		||||
	struct grid_line	*gl = &gd->linedata[yy];
 | 
			
		||||
	struct grid_cell	 gc;
 | 
			
		||||
	u_int			 line, lines, width, i, used = gl->cellused, xx;
 | 
			
		||||
	int			 flags = gl->flags;
 | 
			
		||||
 | 
			
		||||
	/* How many lines do we need to insert? We know we need at least one. */
 | 
			
		||||
	if (~gl->flags & GRID_LINE_EXTENDED)
 | 
			
		||||
		lines = (gl->cellused - 1) / sx;
 | 
			
		||||
	else {
 | 
			
		||||
		lines = 1;
 | 
			
		||||
		width = 0;
 | 
			
		||||
		for (i = at; i < used; i++) {
 | 
			
		||||
			grid_get_cell1(gl, i, &gc);
 | 
			
		||||
			if (width + gc.data.width > sx) {
 | 
			
		||||
				lines++;
 | 
			
		||||
				width = 0;
 | 
			
		||||
			}
 | 
			
		||||
			width += gc.data.width;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Trim the original line size. */
 | 
			
		||||
	gl->cellsize = gl->cellused = at;
 | 
			
		||||
	gl->flags |= GRID_LINE_WRAPPED;
 | 
			
		||||
 | 
			
		||||
	/* Insert new lines. */
 | 
			
		||||
	gd->linedata = xreallocarray(gd->linedata, gd->hsize + gd->sy + lines,
 | 
			
		||||
	    sizeof *gd->linedata);
 | 
			
		||||
	memmove(&gd->linedata[yy + lines + 1], &gd->linedata[yy + 1],
 | 
			
		||||
	    ((gd->hsize + gd->sy) - (yy + 1)) * (sizeof *gd->linedata));
 | 
			
		||||
	gd->hsize += lines;
 | 
			
		||||
	for (i = 0; i < lines; i++)
 | 
			
		||||
		grid_empty_line(gd, yy + 1 + i, 8);
 | 
			
		||||
	gl = &gd->linedata[yy];
 | 
			
		||||
 | 
			
		||||
	/* Copy sections from the original line. */
 | 
			
		||||
	line = yy + 1;
 | 
			
		||||
	width = 0;
 | 
			
		||||
	xx = 0;
 | 
			
		||||
	for (i = at; i < used; i++) {
 | 
			
		||||
		grid_get_cell1(gl, i, &gc);
 | 
			
		||||
		if (width + gc.data.width > sx) {
 | 
			
		||||
			gd->linedata[line].flags |= GRID_LINE_WRAPPED;
 | 
			
		||||
 | 
			
		||||
			line++;
 | 
			
		||||
			width = 0;
 | 
			
		||||
			xx = 0;
 | 
			
		||||
		}
 | 
			
		||||
		width += gc.data.width;
 | 
			
		||||
		grid_set_cell(gd, xx, line, &gc);
 | 
			
		||||
		xx++;
 | 
			
		||||
	}
 | 
			
		||||
	if (flags & GRID_LINE_WRAPPED)
 | 
			
		||||
		gd->linedata[line].flags |= GRID_LINE_WRAPPED;
 | 
			
		||||
 | 
			
		||||
	/* Adjust the cursor and scroll positions. */
 | 
			
		||||
	if (yy <= *cy)
 | 
			
		||||
		(*cy) += lines;
 | 
			
		||||
	if (yy <= gd->hscrolled)
 | 
			
		||||
		gd->hscrolled += lines;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If the original line had the wrapped flag and there is still space
 | 
			
		||||
	 * in the last new line, try to join with the next lines.
 | 
			
		||||
	 */
 | 
			
		||||
	if (width < sx && (flags & GRID_LINE_WRAPPED))
 | 
			
		||||
		grid_reflow_join(gd, sx, line, width, cy);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Reflow lines on grid to new width. */
 | 
			
		||||
void
 | 
			
		||||
grid_reflow(struct grid *gd, u_int sx, u_int *cursor)
 | 
			
		||||
{
 | 
			
		||||
	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);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Loop over lines from top to bottom. The size may change during the
 | 
			
		||||
	 * loop, but it is OK because we are always adding or removing lines
 | 
			
		||||
	 * below the current one.
 | 
			
		||||
	 */
 | 
			
		||||
	for (yy = 0; yy < gd->hsize + gd->sy; yy++) {
 | 
			
		||||
		gl = &gd->linedata[yy];
 | 
			
		||||
 | 
			
		||||
		/* Work out the width of this line. */
 | 
			
		||||
		first = at = width = 0;
 | 
			
		||||
		if (~gl->flags & GRID_LINE_EXTENDED) {
 | 
			
		||||
			first = 1;
 | 
			
		||||
			width = gl->cellused;
 | 
			
		||||
			if (width > sx)
 | 
			
		||||
				at = sx;
 | 
			
		||||
			else
 | 
			
		||||
				at = width;
 | 
			
		||||
		} else {
 | 
			
		||||
			for (i = 0; i < gl->cellused; i++) {
 | 
			
		||||
				grid_get_cell1(gl, i, &gc);
 | 
			
		||||
				if (i == 0)
 | 
			
		||||
					first = gc.data.width;
 | 
			
		||||
				if (at == 0 && width + gc.data.width > sx)
 | 
			
		||||
					at = i;
 | 
			
		||||
				width += gc.data.width;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * If the line is exactly right, there is no need to do
 | 
			
		||||
		 * anything.
 | 
			
		||||
		 */
 | 
			
		||||
		if (width == sx)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * If the first character is wider than the target width, there
 | 
			
		||||
		 * is no point in trying to do anything.
 | 
			
		||||
		 */
 | 
			
		||||
		if (first > sx)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * If the line is too big, it needs to be split, whether or not
 | 
			
		||||
		 * it was previously wrapped.
 | 
			
		||||
		 */
 | 
			
		||||
		if (width > sx) {
 | 
			
		||||
			grid_reflow_split(gd, sx, yy, at, &cy);
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * If the line was previously wrapped, join as much as possible
 | 
			
		||||
		 * of the next line.
 | 
			
		||||
		 */
 | 
			
		||||
		if (gl->flags & GRID_LINE_WRAPPED)
 | 
			
		||||
			grid_reflow_join(gd, sx, yy, width, &cy);
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -378,6 +378,7 @@ screen_write_copy(struct screen_write_ctx *ctx, struct screen *src, u_int px,
 | 
			
		||||
					gc.bg = mgc->bg;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if (xx + gc.data.width <= px + nx)
 | 
			
		||||
				screen_write_cell(ctx, &gc);
 | 
			
		||||
		}
 | 
			
		||||
		cy++;
 | 
			
		||||
@@ -410,6 +411,8 @@ screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src,
 | 
			
		||||
			if (xx >= gd->linedata[yy].cellsize)
 | 
			
		||||
				break;
 | 
			
		||||
			grid_get_cell(gd, xx, yy, &gc);
 | 
			
		||||
			if (xx + gc.data.width > px + nx)
 | 
			
		||||
				break;
 | 
			
		||||
			if (!grid_cells_equal(&gc, &grid_default_cell))
 | 
			
		||||
				grid_view_set_cell(ctx->s->grid, cx, cy, &gc);
 | 
			
		||||
			cx++;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								screen.c
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								screen.c
									
									
									
									
									
								
							@@ -469,14 +469,5 @@ screen_select_cell(struct screen *s, struct grid_cell *dst,
 | 
			
		||||
static void
 | 
			
		||||
screen_reflow(struct screen *s, u_int new_x)
 | 
			
		||||
{
 | 
			
		||||
	struct grid	*old = s->grid;
 | 
			
		||||
	u_int		 change;
 | 
			
		||||
 | 
			
		||||
	s->grid = grid_create(old->sx, old->sy, old->hlimit);
 | 
			
		||||
 | 
			
		||||
	change = grid_reflow(s->grid, old, new_x);
 | 
			
		||||
	if (change < s->cy)
 | 
			
		||||
		s->cy -= change;
 | 
			
		||||
	else
 | 
			
		||||
		s->cy = 0;
 | 
			
		||||
	grid_reflow(s->grid, new_x, &s->cy);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								tmux.h
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								tmux.h
									
									
									
									
									
								
							@@ -2000,7 +2000,7 @@ 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);
 | 
			
		||||
u_int	 grid_reflow(struct grid *, struct grid *, u_int);
 | 
			
		||||
void	 grid_reflow(struct grid *, u_int, u_int *);
 | 
			
		||||
 | 
			
		||||
/* grid-view.c */
 | 
			
		||||
void	 grid_view_get_cell(struct grid *, u_int, u_int, struct grid_cell *);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										21
									
								
								tty.c
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								tty.c
									
									
									
									
									
								
							@@ -882,6 +882,7 @@ void
 | 
			
		||||
tty_draw_line(struct tty *tty, const struct window_pane *wp,
 | 
			
		||||
    struct screen *s, u_int py, u_int ox, u_int oy)
 | 
			
		||||
{
 | 
			
		||||
	struct grid		*gd = s->grid;
 | 
			
		||||
	struct grid_cell	 gc, last;
 | 
			
		||||
	u_int			 i, j, ux, sx, nx, width;
 | 
			
		||||
	int			 flags, cleared = 0;
 | 
			
		||||
@@ -900,15 +901,15 @@ tty_draw_line(struct tty *tty, const struct window_pane *wp,
 | 
			
		||||
	 * there may be empty background cells after it (from BCE).
 | 
			
		||||
	 */
 | 
			
		||||
	sx = screen_size_x(s);
 | 
			
		||||
	if (sx > s->grid->linedata[s->grid->hsize + py].cellsize)
 | 
			
		||||
		sx = s->grid->linedata[s->grid->hsize + py].cellsize;
 | 
			
		||||
	if (sx > gd->linedata[gd->hsize + py].cellsize)
 | 
			
		||||
		sx = gd->linedata[gd->hsize + py].cellsize;
 | 
			
		||||
	if (sx > tty->sx)
 | 
			
		||||
		sx = tty->sx;
 | 
			
		||||
	ux = 0;
 | 
			
		||||
 | 
			
		||||
	if (wp == NULL ||
 | 
			
		||||
	    py == 0 ||
 | 
			
		||||
	    (~s->grid->linedata[s->grid->hsize + py - 1].flags & GRID_LINE_WRAPPED) ||
 | 
			
		||||
	    (~gd->linedata[gd->hsize + py - 1].flags & GRID_LINE_WRAPPED) ||
 | 
			
		||||
	    ox != 0 ||
 | 
			
		||||
	    tty->cx < tty->sx ||
 | 
			
		||||
	    screen_size_x(s) < tty->sx) {
 | 
			
		||||
@@ -932,7 +933,7 @@ tty_draw_line(struct tty *tty, const struct window_pane *wp,
 | 
			
		||||
	width = 0;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < sx; i++) {
 | 
			
		||||
		grid_view_get_cell(s->grid, i, py, &gc);
 | 
			
		||||
		grid_view_get_cell(gd, i, py, &gc);
 | 
			
		||||
		if (len != 0 &&
 | 
			
		||||
		    (((~tty->flags & TTY_UTF8) &&
 | 
			
		||||
		    (gc.data.size != 1 ||
 | 
			
		||||
@@ -943,6 +944,7 @@ tty_draw_line(struct tty *tty, const struct window_pane *wp,
 | 
			
		||||
		    gc.attr != last.attr ||
 | 
			
		||||
		    gc.fg != last.fg ||
 | 
			
		||||
		    gc.bg != last.bg ||
 | 
			
		||||
		    ux + width + gc.data.width >= screen_size_x(s) ||
 | 
			
		||||
		    (sizeof buf) - len < gc.data.size)) {
 | 
			
		||||
			tty_attributes(tty, &last, wp);
 | 
			
		||||
			tty_putn(tty, buf, len, width);
 | 
			
		||||
@@ -956,7 +958,14 @@ tty_draw_line(struct tty *tty, const struct window_pane *wp,
 | 
			
		||||
			screen_select_cell(s, &last, &gc);
 | 
			
		||||
		else
 | 
			
		||||
			memcpy(&last, &gc, sizeof last);
 | 
			
		||||
		if (((~tty->flags & TTY_UTF8) &&
 | 
			
		||||
		if (ux + gc.data.width > screen_size_x(s))
 | 
			
		||||
			for (j = 0; j < gc.data.width; j++) {
 | 
			
		||||
				if (ux + j > screen_size_x(s))
 | 
			
		||||
					break;
 | 
			
		||||
				tty_putc(tty, ' ');
 | 
			
		||||
				ux++;
 | 
			
		||||
			}
 | 
			
		||||
		else if (((~tty->flags & TTY_UTF8) &&
 | 
			
		||||
		    (gc.data.size != 1 ||
 | 
			
		||||
		    *gc.data.data >= 0x7f ||
 | 
			
		||||
		    gc.data.width != 1)) ||
 | 
			
		||||
@@ -993,8 +1002,8 @@ tty_draw_line(struct tty *tty, const struct window_pane *wp,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!cleared && ux < screen_size_x(s)) {
 | 
			
		||||
		nx = screen_size_x(s) - ux;
 | 
			
		||||
	if (!cleared && ux < tty->sx && nx != 0) {
 | 
			
		||||
		tty_default_attributes(tty, wp, 8);
 | 
			
		||||
		tty_clear_line(tty, wp, oy + py, ox + ux, nx, 8);
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user