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