1 1.3 christos /* $OpenBSD$ */ 2 1.1 jmmv 3 1.1 jmmv /* 4 1.1 jmmv * Copyright (c) 2009 Jonathan Alvarado <radobobo (at) users.sourceforge.net> 5 1.1 jmmv * 6 1.1 jmmv * Permission to use, copy, modify, and distribute this software for any 7 1.1 jmmv * purpose with or without fee is hereby granted, provided that the above 8 1.1 jmmv * copyright notice and this permission notice appear in all copies. 9 1.1 jmmv * 10 1.1 jmmv * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 1.1 jmmv * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 1.1 jmmv * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 1.1 jmmv * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 1.1 jmmv * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 1.1 jmmv * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 1.1 jmmv * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 1.1 jmmv */ 18 1.1 jmmv 19 1.1 jmmv #include <sys/types.h> 20 1.1 jmmv 21 1.2 christos #include <stdlib.h> 22 1.1 jmmv #include <string.h> 23 1.1 jmmv 24 1.1 jmmv #include "tmux.h" 25 1.1 jmmv 26 1.1 jmmv /* 27 1.2 christos * Write the entire contents of a pane to a buffer or stdout. 28 1.1 jmmv */ 29 1.1 jmmv 30 1.5 christos static enum cmd_retval cmd_capture_pane_exec(struct cmd *, struct cmdq_item *); 31 1.2 christos 32 1.5 christos static char *cmd_capture_pane_append(char *, size_t *, char *, size_t); 33 1.5 christos static char *cmd_capture_pane_pending(struct args *, struct window_pane *, 34 1.2 christos size_t *); 35 1.5 christos static char *cmd_capture_pane_history(struct args *, struct cmdq_item *, 36 1.2 christos struct window_pane *, size_t *); 37 1.1 jmmv 38 1.1 jmmv const struct cmd_entry cmd_capture_pane_entry = { 39 1.4 christos .name = "capture-pane", 40 1.4 christos .alias = "capturep", 41 1.4 christos 42 1.12 wiz .args = { "ab:CeE:JMNpPqS:Tt:", 0, 0, NULL }, 43 1.12 wiz .usage = "[-aCeJMNpPqT] " CMD_BUFFER_USAGE " [-E end-line] " 44 1.7 christos "[-S start-line] " CMD_TARGET_PANE_USAGE, 45 1.4 christos 46 1.6 christos .target = { 't', CMD_FIND_PANE, 0 }, 47 1.4 christos 48 1.5 christos .flags = CMD_AFTERHOOK, 49 1.4 christos .exec = cmd_capture_pane_exec 50 1.1 jmmv }; 51 1.1 jmmv 52 1.5 christos const struct cmd_entry cmd_clear_history_entry = { 53 1.5 christos .name = "clear-history", 54 1.5 christos .alias = "clearhist", 55 1.5 christos 56 1.11 wiz .args = { "Ht:", 0, 0, NULL }, 57 1.11 wiz .usage = "[-H] " CMD_TARGET_PANE_USAGE, 58 1.5 christos 59 1.6 christos .target = { 't', CMD_FIND_PANE, 0 }, 60 1.5 christos 61 1.5 christos .flags = CMD_AFTERHOOK, 62 1.5 christos .exec = cmd_capture_pane_exec 63 1.5 christos }; 64 1.5 christos 65 1.5 christos static char * 66 1.2 christos cmd_capture_pane_append(char *buf, size_t *len, char *line, size_t linelen) 67 1.2 christos { 68 1.3 christos buf = xrealloc(buf, *len + linelen + 1); 69 1.2 christos memcpy(buf + *len, line, linelen); 70 1.2 christos *len += linelen; 71 1.2 christos return (buf); 72 1.2 christos } 73 1.2 christos 74 1.5 christos static char * 75 1.2 christos cmd_capture_pane_pending(struct args *args, struct window_pane *wp, 76 1.2 christos size_t *len) 77 1.2 christos { 78 1.3 christos struct evbuffer *pending; 79 1.3 christos char *buf, *line, tmp[5]; 80 1.3 christos size_t linelen; 81 1.3 christos u_int i; 82 1.2 christos 83 1.9 christos pending = input_pending(wp->ictx); 84 1.3 christos if (pending == NULL) 85 1.2 christos return (xstrdup("")); 86 1.2 christos 87 1.3 christos line = (char *)EVBUFFER_DATA(pending); 88 1.3 christos linelen = EVBUFFER_LENGTH(pending); 89 1.2 christos 90 1.2 christos buf = xstrdup(""); 91 1.2 christos if (args_has(args, 'C')) { 92 1.2 christos for (i = 0; i < linelen; i++) { 93 1.5 christos if (line[i] >= ' ' && line[i] != '\\') { 94 1.2 christos tmp[0] = line[i]; 95 1.2 christos tmp[1] = '\0'; 96 1.2 christos } else 97 1.3 christos xsnprintf(tmp, sizeof tmp, "\\%03hho", line[i]); 98 1.2 christos buf = cmd_capture_pane_append(buf, len, tmp, 99 1.2 christos strlen(tmp)); 100 1.2 christos } 101 1.2 christos } else 102 1.2 christos buf = cmd_capture_pane_append(buf, len, line, linelen); 103 1.2 christos return (buf); 104 1.2 christos } 105 1.2 christos 106 1.5 christos static char * 107 1.5 christos cmd_capture_pane_history(struct args *args, struct cmdq_item *item, 108 1.2 christos struct window_pane *wp, size_t *len) 109 1.1 jmmv { 110 1.12 wiz struct grid *gd; 111 1.12 wiz const struct grid_line *gl; 112 1.12 wiz struct screen *s; 113 1.12 wiz struct grid_cell *gc = NULL; 114 1.12 wiz struct window_mode_entry *wme; 115 1.12 wiz int n, join_lines, flags = 0; 116 1.12 wiz u_int i, sx, top, bottom, tmp; 117 1.12 wiz char *cause, *buf, *line; 118 1.12 wiz const char *Sflag, *Eflag; 119 1.12 wiz size_t linelen; 120 1.2 christos 121 1.2 christos sx = screen_size_x(&wp->base); 122 1.2 christos if (args_has(args, 'a')) { 123 1.9 christos gd = wp->base.saved_grid; 124 1.2 christos if (gd == NULL) { 125 1.2 christos if (!args_has(args, 'q')) { 126 1.5 christos cmdq_error(item, "no alternate screen"); 127 1.2 christos return (NULL); 128 1.2 christos } 129 1.2 christos return (xstrdup("")); 130 1.2 christos } 131 1.12 wiz s = &wp->base; 132 1.12 wiz } else if (args_has(args, 'M')) { 133 1.12 wiz wme = TAILQ_FIRST(&wp->modes); 134 1.12 wiz if (wme != NULL && wme->mode->get_screen != NULL) { 135 1.12 wiz s = wme->mode->get_screen (wme); 136 1.12 wiz gd = s->grid; 137 1.12 wiz } else { 138 1.12 wiz s = &wp->base; 139 1.12 wiz gd = wp->base.grid; 140 1.12 wiz } 141 1.12 wiz } else { 142 1.12 wiz s = &wp->base; 143 1.2 christos gd = wp->base.grid; 144 1.12 wiz } 145 1.2 christos 146 1.3 christos Sflag = args_get(args, 'S'); 147 1.3 christos if (Sflag != NULL && strcmp(Sflag, "-") == 0) 148 1.2 christos top = 0; 149 1.3 christos else { 150 1.11 wiz n = args_strtonum_and_expand(args, 'S', INT_MIN, SHRT_MAX, 151 1.11 wiz item, &cause); 152 1.3 christos if (cause != NULL) { 153 1.3 christos top = gd->hsize; 154 1.3 christos free(cause); 155 1.3 christos } else if (n < 0 && (u_int) -n > gd->hsize) 156 1.3 christos top = 0; 157 1.3 christos else 158 1.3 christos top = gd->hsize + n; 159 1.3 christos if (top > gd->hsize + gd->sy - 1) 160 1.3 christos top = gd->hsize + gd->sy - 1; 161 1.3 christos } 162 1.2 christos 163 1.3 christos Eflag = args_get(args, 'E'); 164 1.3 christos if (Eflag != NULL && strcmp(Eflag, "-") == 0) 165 1.2 christos bottom = gd->hsize + gd->sy - 1; 166 1.3 christos else { 167 1.11 wiz n = args_strtonum_and_expand(args, 'E', INT_MIN, SHRT_MAX, 168 1.11 wiz item, &cause); 169 1.3 christos if (cause != NULL) { 170 1.3 christos bottom = gd->hsize + gd->sy - 1; 171 1.3 christos free(cause); 172 1.3 christos } else if (n < 0 && (u_int) -n > gd->hsize) 173 1.3 christos bottom = 0; 174 1.3 christos else 175 1.3 christos bottom = gd->hsize + n; 176 1.3 christos if (bottom > gd->hsize + gd->sy - 1) 177 1.3 christos bottom = gd->hsize + gd->sy - 1; 178 1.3 christos } 179 1.2 christos 180 1.2 christos if (bottom < top) { 181 1.2 christos tmp = bottom; 182 1.2 christos bottom = top; 183 1.2 christos top = tmp; 184 1.2 christos } 185 1.2 christos 186 1.2 christos join_lines = args_has(args, 'J'); 187 1.11 wiz if (args_has(args, 'e')) 188 1.11 wiz flags |= GRID_STRING_WITH_SEQUENCES; 189 1.11 wiz if (args_has(args, 'C')) 190 1.11 wiz flags |= GRID_STRING_ESCAPE_SEQUENCES; 191 1.11 wiz if (!join_lines && !args_has(args, 'T')) 192 1.11 wiz flags |= GRID_STRING_EMPTY_CELLS; 193 1.11 wiz if (!join_lines && !args_has(args, 'N')) 194 1.11 wiz flags |= GRID_STRING_TRIM_SPACES; 195 1.1 jmmv 196 1.1 jmmv buf = NULL; 197 1.2 christos for (i = top; i <= bottom; i++) { 198 1.12 wiz line = grid_string_cells(gd, 0, i, sx, &gc, flags, s); 199 1.2 christos linelen = strlen(line); 200 1.2 christos 201 1.2 christos buf = cmd_capture_pane_append(buf, len, line, linelen); 202 1.2 christos 203 1.2 christos gl = grid_peek_line(gd, i); 204 1.2 christos if (!join_lines || !(gl->flags & GRID_LINE_WRAPPED)) 205 1.2 christos buf[(*len)++] = '\n'; 206 1.2 christos 207 1.2 christos free(line); 208 1.2 christos } 209 1.2 christos return (buf); 210 1.2 christos } 211 1.2 christos 212 1.5 christos static enum cmd_retval 213 1.5 christos cmd_capture_pane_exec(struct cmd *self, struct cmdq_item *item) 214 1.2 christos { 215 1.9 christos struct args *args = cmd_get_args(self); 216 1.9 christos struct client *c = cmdq_get_client(item); 217 1.9 christos struct window_pane *wp = cmdq_get_target(item)->wp; 218 1.2 christos char *buf, *cause; 219 1.3 christos const char *bufname; 220 1.2 christos size_t len; 221 1.1 jmmv 222 1.9 christos if (cmd_get_entry(self) == &cmd_clear_history_entry) { 223 1.7 christos window_pane_reset_mode_all(wp); 224 1.5 christos grid_clear_history(wp->base.grid); 225 1.11 wiz if (args_has(args, 'H')) 226 1.11 wiz screen_reset_hyperlinks(wp->screen); 227 1.5 christos return (CMD_RETURN_NORMAL); 228 1.5 christos } 229 1.5 christos 230 1.2 christos len = 0; 231 1.2 christos if (args_has(args, 'P')) 232 1.2 christos buf = cmd_capture_pane_pending(args, wp, &len); 233 1.2 christos else 234 1.5 christos buf = cmd_capture_pane_history(args, item, wp, &len); 235 1.2 christos if (buf == NULL) 236 1.2 christos return (CMD_RETURN_ERROR); 237 1.2 christos 238 1.2 christos if (args_has(args, 'p')) { 239 1.9 christos if (len > 0 && buf[len - 1] == '\n') 240 1.9 christos len--; 241 1.9 christos if (c->flags & CLIENT_CONTROL) 242 1.9 christos control_write(c, "%.*s", (int)len, buf); 243 1.9 christos else { 244 1.9 christos if (!file_can_print(c)) { 245 1.9 christos cmdq_error(item, "can't write to client"); 246 1.9 christos free(buf); 247 1.9 christos return (CMD_RETURN_ERROR); 248 1.9 christos } 249 1.9 christos file_print_buffer(c, buf, len); 250 1.9 christos file_print(c, "\n"); 251 1.2 christos } 252 1.12 wiz free(buf); 253 1.2 christos } else { 254 1.3 christos bufname = NULL; 255 1.3 christos if (args_has(args, 'b')) 256 1.3 christos bufname = args_get(args, 'b'); 257 1.2 christos 258 1.3 christos if (paste_set(buf, len, bufname, &cause) != 0) { 259 1.5 christos cmdq_error(item, "%s", cause); 260 1.2 christos free(cause); 261 1.2 christos free(buf); 262 1.2 christos return (CMD_RETURN_ERROR); 263 1.2 christos } 264 1.1 jmmv } 265 1.1 jmmv 266 1.2 christos return (CMD_RETURN_NORMAL); 267 1.1 jmmv } 268