Home | History | Annotate | Line # | Download | only in dist
      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