mirror of
				https://github.com/tmux/tmux.git
				synced 2025-10-26 12:27:15 +00:00 
			
		
		
		
	Add -C and -J to capture pane to escape control sequences and to join
wrapped line, based on a diff from George Nachman.
This commit is contained in:
		| @@ -31,8 +31,8 @@ enum cmd_retval	 cmd_capture_pane_exec(struct cmd *, struct cmd_ctx *); | |||||||
|  |  | ||||||
| const struct cmd_entry cmd_capture_pane_entry = { | const struct cmd_entry cmd_capture_pane_entry = { | ||||||
| 	"capture-pane", "capturep", | 	"capture-pane", "capturep", | ||||||
| 	"b:E:pS:t:", 0, 0, | 	"b:CeE:JpS:t:", 0, 0, | ||||||
| 	"[-p] [-b buffer-index] [-E end-line] [-S start-line]" | 	"[-CeJp] [-b buffer-index] [-E end-line] [-S start-line]" | ||||||
| 	CMD_TARGET_PANE_USAGE, | 	CMD_TARGET_PANE_USAGE, | ||||||
| 	0, | 	0, | ||||||
| 	NULL, | 	NULL, | ||||||
| @@ -44,14 +44,16 @@ enum cmd_retval | |||||||
| cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) | cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) | ||||||
| { | { | ||||||
| 	struct args		*args = self->args; | 	struct args		*args = self->args; | ||||||
| 	struct client		*c = ctx->cmdclient; | 	struct client		*c; | ||||||
| 	struct window_pane	*wp; | 	struct window_pane	*wp; | ||||||
| 	char			*buf, *line, *cause; | 	char			*buf, *line, *cause; | ||||||
| 	struct screen		*s; | 	struct screen		*s; | ||||||
| 	struct grid		*gd; | 	struct grid		*gd; | ||||||
| 	int			 buffer, n; | 	int			 buffer, n, with_codes, escape_c0, join_lines; | ||||||
| 	u_int			 i, limit, top, bottom, tmp; | 	u_int			 i, limit, top, bottom, tmp; | ||||||
| 	size_t			 len, linelen; | 	size_t			 len, linelen; | ||||||
|  | 	struct grid_cell	*gc; | ||||||
|  | 	const struct grid_line	*gl; | ||||||
|  |  | ||||||
| 	if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL) | 	if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL) | ||||||
| 		return (CMD_RETURN_ERROR); | 		return (CMD_RETURN_ERROR); | ||||||
| @@ -89,19 +91,31 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) | |||||||
| 		top = tmp; | 		top = tmp; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	with_codes = args_has(args, 'e'); | ||||||
|  | 	escape_c0 = args_has(args, 'C'); | ||||||
|  | 	join_lines = args_has(args, 'J'); | ||||||
|  |  | ||||||
|  | 	gc = NULL; | ||||||
| 	for (i = top; i <= bottom; i++) { | 	for (i = top; i <= bottom; i++) { | ||||||
| 	       line = grid_string_cells(s->grid, 0, i, screen_size_x(s)); | 		line = grid_string_cells(s->grid, 0, i, screen_size_x(s), | ||||||
|  | 		    &gc, with_codes, escape_c0); | ||||||
| 		linelen = strlen(line); | 		linelen = strlen(line); | ||||||
|  |  | ||||||
| 		buf = xrealloc(buf, 1, len + linelen + 1); | 		buf = xrealloc(buf, 1, len + linelen + 1); | ||||||
| 		memcpy(buf + len, line, linelen); | 		memcpy(buf + len, line, linelen); | ||||||
| 		len += linelen; | 		len += linelen; | ||||||
|  |  | ||||||
|  | 		gl = grid_peek_line(s->grid, i); | ||||||
|  | 		if (!join_lines || !(gl->flags & GRID_LINE_WRAPPED)) | ||||||
| 			buf[len++] = '\n'; | 			buf[len++] = '\n'; | ||||||
|  |  | ||||||
| 		free(line); | 		free(line); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (args_has(args, 'p')) { | 	if (args_has(args, 'p')) { | ||||||
|  | 		c = ctx->curclient; | ||||||
|  | 		if (c == NULL || !(c->flags & CLIENT_CONTROL)) | ||||||
|  | 			c = ctx->cmdclient; | ||||||
| 		if (c == NULL) { | 		if (c == NULL) { | ||||||
| 			ctx->error(ctx, "can't write to stdout"); | 			ctx->error(ctx, "can't write to stdout"); | ||||||
| 			return (CMD_RETURN_ERROR); | 			return (CMD_RETURN_ERROR); | ||||||
|   | |||||||
| @@ -234,5 +234,5 @@ grid_view_string_cells(struct grid *gd, u_int px, u_int py, u_int nx) | |||||||
| 	px = grid_view_x(gd, px); | 	px = grid_view_x(gd, px); | ||||||
| 	py = grid_view_y(gd, py); | 	py = grid_view_y(gd, py); | ||||||
|  |  | ||||||
| 	return (grid_string_cells(gd, px, py, nx)); | 	return (grid_string_cells(gd, px, py, nx, NULL, 0, 0)); | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										228
									
								
								grid.c
									
									
									
									
									
								
							
							
						
						
									
										228
									
								
								grid.c
									
									
									
									
									
								
							| @@ -74,6 +74,10 @@ void	grid_reflow_join(struct grid *, u_int *, struct grid_line *, u_int); | |||||||
| void	grid_reflow_split(struct grid *, u_int *, struct grid_line *, u_int, | void	grid_reflow_split(struct grid *, u_int *, struct grid_line *, u_int, | ||||||
| 	    u_int); | 	    u_int); | ||||||
| void	grid_reflow_move(struct grid *, u_int *, struct grid_line *); | void	grid_reflow_move(struct grid *, u_int *, struct grid_line *); | ||||||
|  | size_t	grid_string_cells_fg(const struct grid_cell *, int *); | ||||||
|  | size_t	grid_string_cells_bg(const struct grid_cell *, int *); | ||||||
|  | void	grid_string_cells_code(const struct grid_cell *, | ||||||
|  | 	    const struct grid_cell *, char *, size_t, int); | ||||||
|  |  | ||||||
| /* Create a new grid. */ | /* Create a new grid. */ | ||||||
| struct grid * | struct grid * | ||||||
| @@ -230,6 +234,15 @@ grid_expand_line(struct grid *gd, u_int py, u_int sx) | |||||||
| 	gl->cellsize = sx; | 	gl->cellsize = sx; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* Peek at grid line. */ | ||||||
|  | const struct grid_line * | ||||||
|  | grid_peek_line(struct grid *gd, u_int py) | ||||||
|  | { | ||||||
|  | 	if (grid_check_y(gd, py) != 0) | ||||||
|  | 		return (NULL); | ||||||
|  | 	return (&gd->linedata[py]); | ||||||
|  | } | ||||||
|  |  | ||||||
| /* Get cell for reading. */ | /* Get cell for reading. */ | ||||||
| const struct grid_cell * | const struct grid_cell * | ||||||
| grid_peek_cell(struct grid *gd, u_int px, u_int py) | grid_peek_cell(struct grid *gd, u_int px, u_int py) | ||||||
| @@ -392,18 +405,201 @@ grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx) | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* Get ANSI foreground sequence. */ | ||||||
|  | size_t | ||||||
|  | grid_string_cells_fg(const struct grid_cell *gc, int *values) | ||||||
|  | { | ||||||
|  | 	size_t	n; | ||||||
|  |  | ||||||
|  | 	n = 0; | ||||||
|  | 	if (gc->flags & GRID_FLAG_FG256) { | ||||||
|  | 		values[n++] = 38; | ||||||
|  | 		values[n++] = 5; | ||||||
|  | 		values[n++] = gc->fg; | ||||||
|  | 	} else { | ||||||
|  | 		switch (gc->fg) { | ||||||
|  | 			case 0: | ||||||
|  | 			case 1: | ||||||
|  | 			case 2: | ||||||
|  | 			case 3: | ||||||
|  | 			case 4: | ||||||
|  | 			case 5: | ||||||
|  | 			case 6: | ||||||
|  | 			case 7: | ||||||
|  | 				values[n++] = gc->fg + 30; | ||||||
|  | 				break; | ||||||
|  | 			case 8: | ||||||
|  | 				values[n++] = 39; | ||||||
|  | 				break; | ||||||
|  | 			case 90: | ||||||
|  | 			case 91: | ||||||
|  | 			case 92: | ||||||
|  | 			case 93: | ||||||
|  | 			case 94: | ||||||
|  | 			case 95: | ||||||
|  | 			case 96: | ||||||
|  | 			case 97: | ||||||
|  | 				values[n++] = gc->fg; | ||||||
|  | 				break; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return (n); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Get ANSI background sequence. */ | ||||||
|  | size_t | ||||||
|  | grid_string_cells_bg(const struct grid_cell *gc, int *values) | ||||||
|  | { | ||||||
|  | 	size_t	n; | ||||||
|  |  | ||||||
|  | 	n = 0; | ||||||
|  | 	if (gc->flags & GRID_FLAG_BG256) { | ||||||
|  | 		values[n++] = 48; | ||||||
|  | 		values[n++] = 5; | ||||||
|  | 		values[n++] = gc->bg; | ||||||
|  | 	} else { | ||||||
|  | 		switch (gc->bg) { | ||||||
|  | 		case 0: | ||||||
|  | 		case 1: | ||||||
|  | 		case 2: | ||||||
|  | 		case 3: | ||||||
|  | 		case 4: | ||||||
|  | 		case 5: | ||||||
|  | 		case 6: | ||||||
|  | 		case 7: | ||||||
|  | 			values[n++] = gc->bg + 40; | ||||||
|  | 			break; | ||||||
|  | 		case 8: | ||||||
|  | 			values[n++] = 49; | ||||||
|  | 			break; | ||||||
|  | 		case 100: | ||||||
|  | 		case 101: | ||||||
|  | 		case 102: | ||||||
|  | 		case 103: | ||||||
|  | 		case 104: | ||||||
|  | 			case 105: | ||||||
|  | 		case 106: | ||||||
|  | 		case 107: | ||||||
|  | 			values[n++] = gc->bg - 10; | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return (n); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Returns ANSI code to set particular attributes (colour, bold and so on) | ||||||
|  |  * given a current state. The output buffer must be able to hold at least 57 | ||||||
|  |  * bytes. | ||||||
|  |  */ | ||||||
|  | void | ||||||
|  | grid_string_cells_code(const struct grid_cell *lastgc, | ||||||
|  |     const struct grid_cell *gc, char *buf, size_t len, int escape_c0) | ||||||
|  | { | ||||||
|  | 	int	oldc[16], newc[16], s[32]; | ||||||
|  | 	size_t	noldc, nnewc, n, i; | ||||||
|  | 	u_int	attr = gc->attr; | ||||||
|  | 	u_int	lastattr = lastgc->attr; | ||||||
|  | 	char	tmp[64]; | ||||||
|  |  | ||||||
|  | 	struct { | ||||||
|  | 		u_int	mask; | ||||||
|  | 		u_int	code; | ||||||
|  | 	} attrs[] = { | ||||||
|  | 		{ GRID_ATTR_BRIGHT, 1 }, | ||||||
|  | 		{ GRID_ATTR_DIM, 2 }, | ||||||
|  | 		{ GRID_ATTR_ITALICS, 3 }, | ||||||
|  | 		{ GRID_ATTR_UNDERSCORE, 4 }, | ||||||
|  | 		{ GRID_ATTR_BLINK, 5 }, | ||||||
|  | 		{ GRID_ATTR_REVERSE, 7 }, | ||||||
|  | 		{ GRID_ATTR_HIDDEN, 8 } | ||||||
|  | 	}; | ||||||
|  | 	n = 0; | ||||||
|  |  | ||||||
|  | 	/* If any attribute is removed, begin with 0. */ | ||||||
|  | 	for (i = 0; i < nitems(attrs); i++) { | ||||||
|  | 		if (!(attr & attrs[i].mask) && (lastattr & attrs[i].mask)) { | ||||||
|  | 			s[n++] = 0; | ||||||
|  | 			lastattr &= GRID_ATTR_CHARSET; | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	/* For each attribute that is newly set, add its code. */ | ||||||
|  | 	for (i = 0; i < nitems(attrs); i++) { | ||||||
|  | 		if ((attr & attrs[i].mask) && !(lastattr & attrs[i].mask)) | ||||||
|  | 			s[n++] = attrs[i].code; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* If the foreground c changed, append its parameters. */ | ||||||
|  | 	nnewc = grid_string_cells_fg(gc, newc); | ||||||
|  | 	noldc = grid_string_cells_fg(lastgc, oldc); | ||||||
|  | 	if (nnewc != noldc || | ||||||
|  | 	    memcmp(newc,oldc, nnewc * sizeof newc[0]) != 0) { | ||||||
|  | 		for (i = 0; i < nnewc; i++) | ||||||
|  | 			s[n++] = newc[i]; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* If the background c changed, append its parameters. */ | ||||||
|  | 	nnewc = grid_string_cells_bg(gc, newc); | ||||||
|  | 	noldc = grid_string_cells_bg(lastgc, oldc); | ||||||
|  | 	if (nnewc != noldc || | ||||||
|  | 	    memcmp(newc, oldc, nnewc * sizeof newc[0]) != 0) { | ||||||
|  | 		for (i = 0; i < nnewc; i++) | ||||||
|  | 			s[n++] = newc[i]; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* If there are any parameters, append an SGR code. */ | ||||||
|  | 	*buf = '\0'; | ||||||
|  | 	if (n > 0) { | ||||||
|  | 		if (escape_c0) | ||||||
|  | 			strlcat(buf, "\\033[", len); | ||||||
|  | 		else | ||||||
|  | 			strlcat(buf, "\033[", len); | ||||||
|  | 		for (i = 0; i < n; i++) { | ||||||
|  | 			if (i + 1 < n) | ||||||
|  | 				xsnprintf(tmp, sizeof tmp, "%d;", s[i]); | ||||||
|  | 			else | ||||||
|  | 				xsnprintf(tmp, sizeof tmp, "%d", s[i]); | ||||||
|  | 			strlcat(buf, tmp, len); | ||||||
|  | 		} | ||||||
|  | 		strlcat(buf, "m", len); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* Append shift in/shift out if needed. */ | ||||||
|  | 	if ((attr & GRID_ATTR_CHARSET) && !(lastattr & GRID_ATTR_CHARSET)) { | ||||||
|  | 		if (escape_c0) | ||||||
|  | 			strlcat(buf, "\\016", len);  /* SO */ | ||||||
|  | 		else | ||||||
|  | 			strlcat(buf, "\016", len);  /* SO */ | ||||||
|  | 	} | ||||||
|  | 	if (!(attr & GRID_ATTR_CHARSET) && (lastattr & GRID_ATTR_CHARSET)) { | ||||||
|  | 		if (escape_c0) | ||||||
|  | 			strlcat(buf, "\\017", len);  /* SI */ | ||||||
|  | 		else | ||||||
|  | 			strlcat(buf, "\017", len);  /* SI */ | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| /* Convert cells into a string. */ | /* Convert cells into a string. */ | ||||||
| char * | char * | ||||||
| grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx) | grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx, | ||||||
|  |     struct grid_cell **lastgc, int with_codes, int escape_c0) | ||||||
| { | { | ||||||
| 	const struct grid_cell	*gc; | 	const struct grid_cell	*gc; | ||||||
|  | 	static struct grid_cell	 lastgc1; | ||||||
| 	struct utf8_data	 ud; | 	struct utf8_data	 ud; | ||||||
| 	char			*buf; | 	const char*		 data; | ||||||
| 	size_t			 len, off; | 	char			*buf, code[128]; | ||||||
|  | 	size_t			 len, off, size, codelen; | ||||||
| 	u_int			 xx; | 	u_int			 xx; | ||||||
|  |  | ||||||
| 	GRID_DEBUG(gd, "px=%u, py=%u, nx=%u", px, py, nx); | 	GRID_DEBUG(gd, "px=%u, py=%u, nx=%u", px, py, nx); | ||||||
|  |  | ||||||
|  | 	if (*lastgc == NULL) { | ||||||
|  | 		memcpy(&lastgc1, &grid_default_cell, sizeof lastgc1); | ||||||
|  | 		*lastgc = &lastgc1; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	len = 128; | 	len = 128; | ||||||
| 	buf = xmalloc(len); | 	buf = xmalloc(len); | ||||||
| 	off = 0; | 	off = 0; | ||||||
| @@ -414,18 +610,38 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx) | |||||||
| 			continue; | 			continue; | ||||||
| 		grid_cell_get(gc, &ud); | 		grid_cell_get(gc, &ud); | ||||||
|  |  | ||||||
| 		while (len < off + ud.size + 1) { | 		if (with_codes) { | ||||||
|  | 			grid_string_cells_code(*lastgc, gc, code, sizeof code, | ||||||
|  | 			    escape_c0); | ||||||
|  | 			codelen = strlen(code); | ||||||
|  | 			memcpy(*lastgc, gc, sizeof *gc); | ||||||
|  | 		} else | ||||||
|  | 			codelen = 0; | ||||||
|  |  | ||||||
|  | 		data = ud.data; | ||||||
|  | 		size = ud.size; | ||||||
|  | 		if (escape_c0 && size == 1 && *data == '\\') { | ||||||
|  | 			data = "\\"; | ||||||
|  | 			size = 2; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		while (len < off + size + codelen + 1) { | ||||||
| 			buf = xrealloc(buf, 2, len); | 			buf = xrealloc(buf, 2, len); | ||||||
| 			len *= 2; | 			len *= 2; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		memcpy(buf + off, ud.data, ud.size); | 		if (codelen != 0) { | ||||||
| 		off += ud.size; | 			memcpy(buf + off, code, codelen); | ||||||
|  | 			off += codelen; | ||||||
|  | 		} | ||||||
|  | 		memcpy(buf + off, data, size); | ||||||
|  | 		off += size; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	while (off > 0 && buf[off - 1] == ' ') | 	while (off > 0 && buf[off - 1] == ' ') | ||||||
| 		off--; | 		off--; | ||||||
| 	buf[off] = '\0'; | 	buf[off] = '\0'; | ||||||
|  |  | ||||||
| 	return (buf); | 	return (buf); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Nicholas Marriott
					Nicholas Marriott