xref: /netbsd-src/external/bsd/tmux/dist/cmd-capture-pane.c (revision f844e94ef29eebc7999c12636b87f541bb86868b)
199e242abSchristos /* $OpenBSD$ */
2698d5317Sjmmv 
3698d5317Sjmmv /*
4698d5317Sjmmv  * Copyright (c) 2009 Jonathan Alvarado <radobobo@users.sourceforge.net>
5698d5317Sjmmv  *
6698d5317Sjmmv  * Permission to use, copy, modify, and distribute this software for any
7698d5317Sjmmv  * purpose with or without fee is hereby granted, provided that the above
8698d5317Sjmmv  * copyright notice and this permission notice appear in all copies.
9698d5317Sjmmv  *
10698d5317Sjmmv  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11698d5317Sjmmv  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12698d5317Sjmmv  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13698d5317Sjmmv  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14698d5317Sjmmv  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15698d5317Sjmmv  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16698d5317Sjmmv  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17698d5317Sjmmv  */
18698d5317Sjmmv 
19698d5317Sjmmv #include <sys/types.h>
20698d5317Sjmmv 
21d530c4d0Sjmmv #include <stdlib.h>
22698d5317Sjmmv #include <string.h>
23698d5317Sjmmv 
24698d5317Sjmmv #include "tmux.h"
25698d5317Sjmmv 
26698d5317Sjmmv /*
27928fc495Schristos  * Write the entire contents of a pane to a buffer or stdout.
28698d5317Sjmmv  */
29698d5317Sjmmv 
30e9a2d6faSchristos static enum cmd_retval	cmd_capture_pane_exec(struct cmd *, struct cmdq_item *);
31928fc495Schristos 
32e9a2d6faSchristos static char	*cmd_capture_pane_append(char *, size_t *, char *, size_t);
33e9a2d6faSchristos static char	*cmd_capture_pane_pending(struct args *, struct window_pane *,
34928fc495Schristos 		     size_t *);
35e9a2d6faSchristos static char	*cmd_capture_pane_history(struct args *, struct cmdq_item *,
36928fc495Schristos 		     struct window_pane *, size_t *);
37698d5317Sjmmv 
38698d5317Sjmmv const struct cmd_entry cmd_capture_pane_entry = {
39f26e8bc9Schristos 	.name = "capture-pane",
40f26e8bc9Schristos 	.alias = "capturep",
41f26e8bc9Schristos 
42*f844e94eSwiz 	.args = { "ab:CeE:JNpPqS:Tt:", 0, 0, NULL },
43*f844e94eSwiz 	.usage = "[-aCeJNpPqT] " CMD_BUFFER_USAGE " [-E end-line] "
44f26e8bc9Schristos 		 "[-S start-line] " CMD_TARGET_PANE_USAGE,
45f26e8bc9Schristos 
46fe99a117Schristos 	.target = { 't', CMD_FIND_PANE, 0 },
47f26e8bc9Schristos 
48e9a2d6faSchristos 	.flags = CMD_AFTERHOOK,
49f26e8bc9Schristos 	.exec = cmd_capture_pane_exec
50698d5317Sjmmv };
51698d5317Sjmmv 
52e9a2d6faSchristos const struct cmd_entry cmd_clear_history_entry = {
53e9a2d6faSchristos 	.name = "clear-history",
54e9a2d6faSchristos 	.alias = "clearhist",
55e9a2d6faSchristos 
56*f844e94eSwiz 	.args = { "Ht:", 0, 0, NULL },
57*f844e94eSwiz 	.usage = "[-H] " CMD_TARGET_PANE_USAGE,
58e9a2d6faSchristos 
59fe99a117Schristos 	.target = { 't', CMD_FIND_PANE, 0 },
60e9a2d6faSchristos 
61e9a2d6faSchristos 	.flags = CMD_AFTERHOOK,
62e9a2d6faSchristos 	.exec = cmd_capture_pane_exec
63e9a2d6faSchristos };
64e9a2d6faSchristos 
65e9a2d6faSchristos static char *
cmd_capture_pane_append(char * buf,size_t * len,char * line,size_t linelen)66928fc495Schristos cmd_capture_pane_append(char *buf, size_t *len, char *line, size_t linelen)
67698d5317Sjmmv {
6899e242abSchristos 	buf = xrealloc(buf, *len + linelen + 1);
69928fc495Schristos 	memcpy(buf + *len, line, linelen);
70928fc495Schristos 	*len += linelen;
71928fc495Schristos 	return (buf);
72928fc495Schristos }
73928fc495Schristos 
74e9a2d6faSchristos static char *
cmd_capture_pane_pending(struct args * args,struct window_pane * wp,size_t * len)75928fc495Schristos cmd_capture_pane_pending(struct args *args, struct window_pane *wp,
76928fc495Schristos     size_t *len)
77928fc495Schristos {
7899e242abSchristos 	struct evbuffer	*pending;
79928fc495Schristos 	char		*buf, *line, tmp[5];
80928fc495Schristos 	size_t		 linelen;
81928fc495Schristos 	u_int		 i;
82928fc495Schristos 
83e271dbb8Schristos 	pending = input_pending(wp->ictx);
8499e242abSchristos 	if (pending == NULL)
85928fc495Schristos 		return (xstrdup(""));
86928fc495Schristos 
8799e242abSchristos 	line = (char *)EVBUFFER_DATA(pending);
8899e242abSchristos 	linelen = EVBUFFER_LENGTH(pending);
89928fc495Schristos 
90928fc495Schristos 	buf = xstrdup("");
91928fc495Schristos 	if (args_has(args, 'C')) {
92928fc495Schristos 		for (i = 0; i < linelen; i++) {
93e9a2d6faSchristos 			if (line[i] >= ' ' && line[i] != '\\') {
94928fc495Schristos 				tmp[0] = line[i];
95928fc495Schristos 				tmp[1] = '\0';
96928fc495Schristos 			} else
9799e242abSchristos 				xsnprintf(tmp, sizeof tmp, "\\%03hho", line[i]);
98928fc495Schristos 			buf = cmd_capture_pane_append(buf, len, tmp,
99928fc495Schristos 			    strlen(tmp));
100928fc495Schristos 		}
101928fc495Schristos 	} else
102928fc495Schristos 		buf = cmd_capture_pane_append(buf, len, line, linelen);
103928fc495Schristos 	return (buf);
104928fc495Schristos }
105928fc495Schristos 
106e9a2d6faSchristos static char *
cmd_capture_pane_history(struct args * args,struct cmdq_item * item,struct window_pane * wp,size_t * len)107e9a2d6faSchristos cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
108928fc495Schristos     struct window_pane *wp, size_t *len)
109928fc495Schristos {
110d530c4d0Sjmmv 	struct grid		*gd;
111928fc495Schristos 	const struct grid_line	*gl;
112928fc495Schristos 	struct grid_cell	*gc = NULL;
113*f844e94eSwiz 	int			 n, join_lines, flags = 0;
114928fc495Schristos 	u_int			 i, sx, top, bottom, tmp;
115928fc495Schristos 	char			*cause, *buf, *line;
11699e242abSchristos 	const char		*Sflag, *Eflag;
117928fc495Schristos 	size_t			 linelen;
118698d5317Sjmmv 
119928fc495Schristos 	sx = screen_size_x(&wp->base);
120928fc495Schristos 	if (args_has(args, 'a')) {
121e271dbb8Schristos 		gd = wp->base.saved_grid;
122928fc495Schristos 		if (gd == NULL) {
123928fc495Schristos 			if (!args_has(args, 'q')) {
124e9a2d6faSchristos 				cmdq_error(item, "no alternate screen");
125928fc495Schristos 				return (NULL);
126928fc495Schristos 			}
127928fc495Schristos 			return (xstrdup(""));
128928fc495Schristos 		}
129928fc495Schristos 	} else
130928fc495Schristos 		gd = wp->base.grid;
131698d5317Sjmmv 
13299e242abSchristos 	Sflag = args_get(args, 'S');
13399e242abSchristos 	if (Sflag != NULL && strcmp(Sflag, "-") == 0)
13499e242abSchristos 		top = 0;
13599e242abSchristos 	else {
136*f844e94eSwiz 		n = args_strtonum_and_expand(args, 'S', INT_MIN, SHRT_MAX,
137*f844e94eSwiz 			item, &cause);
138d530c4d0Sjmmv 		if (cause != NULL) {
139d530c4d0Sjmmv 			top = gd->hsize;
140928fc495Schristos 			free(cause);
141d530c4d0Sjmmv 		} else if (n < 0 && (u_int) -n > gd->hsize)
142d530c4d0Sjmmv 			top = 0;
143d530c4d0Sjmmv 		else
144d530c4d0Sjmmv 			top = gd->hsize + n;
145d530c4d0Sjmmv 		if (top > gd->hsize + gd->sy - 1)
146d530c4d0Sjmmv 			top = gd->hsize + gd->sy - 1;
14799e242abSchristos 	}
148d530c4d0Sjmmv 
14999e242abSchristos 	Eflag = args_get(args, 'E');
15099e242abSchristos 	if (Eflag != NULL && strcmp(Eflag, "-") == 0)
15199e242abSchristos 		bottom = gd->hsize + gd->sy - 1;
15299e242abSchristos 	else {
153*f844e94eSwiz 		n = args_strtonum_and_expand(args, 'E', INT_MIN, SHRT_MAX,
154*f844e94eSwiz 			item, &cause);
155d530c4d0Sjmmv 		if (cause != NULL) {
156d530c4d0Sjmmv 			bottom = gd->hsize + gd->sy - 1;
157928fc495Schristos 			free(cause);
158d530c4d0Sjmmv 		} else if (n < 0 && (u_int) -n > gd->hsize)
159d530c4d0Sjmmv 			bottom = 0;
160d530c4d0Sjmmv 		else
161d530c4d0Sjmmv 			bottom = gd->hsize + n;
162d530c4d0Sjmmv 		if (bottom > gd->hsize + gd->sy - 1)
163d530c4d0Sjmmv 			bottom = gd->hsize + gd->sy - 1;
16499e242abSchristos 	}
165d530c4d0Sjmmv 
166d530c4d0Sjmmv 	if (bottom < top) {
167d530c4d0Sjmmv 		tmp = bottom;
168d530c4d0Sjmmv 		bottom = top;
169d530c4d0Sjmmv 		top = tmp;
170d530c4d0Sjmmv 	}
171d530c4d0Sjmmv 
172928fc495Schristos 	join_lines = args_has(args, 'J');
173*f844e94eSwiz 	if (args_has(args, 'e'))
174*f844e94eSwiz 		flags |= GRID_STRING_WITH_SEQUENCES;
175*f844e94eSwiz 	if (args_has(args, 'C'))
176*f844e94eSwiz 		flags |= GRID_STRING_ESCAPE_SEQUENCES;
177*f844e94eSwiz 	if (!join_lines && !args_has(args, 'T'))
178*f844e94eSwiz 		flags |= GRID_STRING_EMPTY_CELLS;
179*f844e94eSwiz 	if (!join_lines && !args_has(args, 'N'))
180*f844e94eSwiz 		flags |= GRID_STRING_TRIM_SPACES;
181928fc495Schristos 
182928fc495Schristos 	buf = NULL;
183d530c4d0Sjmmv 	for (i = top; i <= bottom; i++) {
184*f844e94eSwiz 		line = grid_string_cells(gd, 0, i, sx, &gc, flags, wp->screen);
185698d5317Sjmmv 		linelen = strlen(line);
186698d5317Sjmmv 
187928fc495Schristos 		buf = cmd_capture_pane_append(buf, len, line, linelen);
188698d5317Sjmmv 
189928fc495Schristos 		gl = grid_peek_line(gd, i);
190928fc495Schristos 		if (!join_lines || !(gl->flags & GRID_LINE_WRAPPED))
191928fc495Schristos 			buf[(*len)++] = '\n';
192928fc495Schristos 
193928fc495Schristos 		free(line);
194928fc495Schristos 	}
195928fc495Schristos 	return (buf);
196698d5317Sjmmv }
197698d5317Sjmmv 
198e9a2d6faSchristos static enum cmd_retval
cmd_capture_pane_exec(struct cmd * self,struct cmdq_item * item)199e9a2d6faSchristos cmd_capture_pane_exec(struct cmd *self, struct cmdq_item *item)
200928fc495Schristos {
201e271dbb8Schristos 	struct args		*args = cmd_get_args(self);
202e271dbb8Schristos 	struct client		*c = cmdq_get_client(item);
203e271dbb8Schristos 	struct window_pane	*wp = cmdq_get_target(item)->wp;
204928fc495Schristos 	char			*buf, *cause;
20599e242abSchristos 	const char		*bufname;
206928fc495Schristos 	size_t			 len;
207d530c4d0Sjmmv 
208e271dbb8Schristos 	if (cmd_get_entry(self) == &cmd_clear_history_entry) {
2090a274e86Schristos 		window_pane_reset_mode_all(wp);
210e9a2d6faSchristos 		grid_clear_history(wp->base.grid);
211*f844e94eSwiz 		if (args_has(args, 'H'))
212*f844e94eSwiz 			screen_reset_hyperlinks(wp->screen);
213e9a2d6faSchristos 		return (CMD_RETURN_NORMAL);
214e9a2d6faSchristos 	}
215e9a2d6faSchristos 
216928fc495Schristos 	len = 0;
217928fc495Schristos 	if (args_has(args, 'P'))
218928fc495Schristos 		buf = cmd_capture_pane_pending(args, wp, &len);
219928fc495Schristos 	else
220e9a2d6faSchristos 		buf = cmd_capture_pane_history(args, item, wp, &len);
221928fc495Schristos 	if (buf == NULL)
222928fc495Schristos 		return (CMD_RETURN_ERROR);
223928fc495Schristos 
224928fc495Schristos 	if (args_has(args, 'p')) {
225e271dbb8Schristos 		if (len > 0 && buf[len - 1] == '\n')
226e271dbb8Schristos 			len--;
227e271dbb8Schristos 		if (c->flags & CLIENT_CONTROL)
228e271dbb8Schristos 			control_write(c, "%.*s", (int)len, buf);
229e271dbb8Schristos 		else {
23068e6ba84Schristos 			if (!file_can_print(c)) {
231e271dbb8Schristos 				cmdq_error(item, "can't write to client");
23299e242abSchristos 				free(buf);
233928fc495Schristos 				return (CMD_RETURN_ERROR);
234928fc495Schristos 			}
23568e6ba84Schristos 			file_print_buffer(c, buf, len);
23668e6ba84Schristos 			file_print(c, "\n");
23768e6ba84Schristos 			free(buf);
238e271dbb8Schristos 		}
239928fc495Schristos 	} else {
24099e242abSchristos 		bufname = NULL;
24199e242abSchristos 		if (args_has(args, 'b'))
24299e242abSchristos 			bufname = args_get(args, 'b');
243d530c4d0Sjmmv 
24499e242abSchristos 		if (paste_set(buf, len, bufname, &cause) != 0) {
245e9a2d6faSchristos 			cmdq_error(item, "%s", cause);
246928fc495Schristos 			free(cause);
247928fc495Schristos 			free(buf);
248928fc495Schristos 			return (CMD_RETURN_ERROR);
249928fc495Schristos 		}
250698d5317Sjmmv 	}
251d530c4d0Sjmmv 
252928fc495Schristos 	return (CMD_RETURN_NORMAL);
253698d5317Sjmmv }
254