mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-03 16:46:18 +00:00 
			
		
		
		
	Add copy-pipe mode command to copy selection and also pipe to a command.
This commit is contained in:
		@@ -46,7 +46,7 @@ enum cmd_retval
 | 
			
		||||
cmd_bind_key_check(struct args *args)
 | 
			
		||||
{
 | 
			
		||||
	if (args_has(args, 't')) {
 | 
			
		||||
		if (args->argc != 2)
 | 
			
		||||
		if (args->argc != 2 && args->argc != 3)
 | 
			
		||||
			return (CMD_RETURN_ERROR);
 | 
			
		||||
	} else {
 | 
			
		||||
		if (args->argc < 2)
 | 
			
		||||
@@ -93,6 +93,7 @@ cmd_bind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key)
 | 
			
		||||
	const struct mode_key_table	*mtab;
 | 
			
		||||
	struct mode_key_binding		*mbind, mtmp;
 | 
			
		||||
	enum mode_key_cmd		 cmd;
 | 
			
		||||
	const char			*arg;
 | 
			
		||||
 | 
			
		||||
	tablename = args_get(args, 't');
 | 
			
		||||
	if ((mtab = mode_key_findtable(tablename)) == NULL) {
 | 
			
		||||
@@ -106,16 +107,29 @@ cmd_bind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key)
 | 
			
		||||
		return (CMD_RETURN_ERROR);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (cmd != MODEKEYCOPY_COPYPIPE) {
 | 
			
		||||
		if (args->argc != 2) {
 | 
			
		||||
			ctx->error(ctx, "no argument allowed");
 | 
			
		||||
			return (CMD_RETURN_ERROR);
 | 
			
		||||
		}
 | 
			
		||||
		arg = NULL;
 | 
			
		||||
	} else {
 | 
			
		||||
		if (args->argc != 3) {
 | 
			
		||||
			ctx->error(ctx, "no argument given");
 | 
			
		||||
			return (CMD_RETURN_ERROR);
 | 
			
		||||
		}
 | 
			
		||||
		arg = args->argv[2];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mtmp.key = key;
 | 
			
		||||
	mtmp.mode = !!args_has(args, 'c');
 | 
			
		||||
	if ((mbind = RB_FIND(mode_key_tree, mtab->tree, &mtmp)) != NULL) {
 | 
			
		||||
		mbind->cmd = cmd;
 | 
			
		||||
		return (CMD_RETURN_NORMAL);
 | 
			
		||||
	if ((mbind = RB_FIND(mode_key_tree, mtab->tree, &mtmp)) == NULL) {
 | 
			
		||||
		mbind = xmalloc(sizeof *mbind);
 | 
			
		||||
		mbind->key = mtmp.key;
 | 
			
		||||
		mbind->mode = mtmp.mode;
 | 
			
		||||
		RB_INSERT(mode_key_tree, mtab->tree, mbind);
 | 
			
		||||
	}
 | 
			
		||||
	mbind = xmalloc(sizeof *mbind);
 | 
			
		||||
	mbind->key = mtmp.key;
 | 
			
		||||
	mbind->mode = mtmp.mode;
 | 
			
		||||
	mbind->cmd = cmd;
 | 
			
		||||
	RB_INSERT(mode_key_tree, mtab->tree, mbind);
 | 
			
		||||
	mbind->arg = arg != NULL ? xstrdup(arg) : NULL;
 | 
			
		||||
	return (CMD_RETURN_NORMAL);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -138,9 +138,12 @@ cmd_list_keys_table(struct cmd *self, struct cmd_ctx *ctx)
 | 
			
		||||
			mode = "c";
 | 
			
		||||
		cmdstr = mode_key_tostring(mtab->cmdstr, mbind->cmd);
 | 
			
		||||
		if (cmdstr != NULL) {
 | 
			
		||||
			ctx->print(ctx, "bind-key -%st %s%s %*s %s",
 | 
			
		||||
			ctx->print(ctx, "bind-key -%st %s%s %*s %s%s%s%s",
 | 
			
		||||
			    mode, any_mode && *mode == '\0' ? " " : "",
 | 
			
		||||
			    mtab->name, (int) width, key, cmdstr);
 | 
			
		||||
			    mtab->name, (int) width, key, cmdstr,
 | 
			
		||||
			    mbind->arg != NULL ? " \"" : "",
 | 
			
		||||
			    mbind->arg != NULL ? mbind->arg : "",
 | 
			
		||||
			    mbind->arg != NULL ? "\"": "");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -99,6 +99,7 @@ const struct mode_key_cmdstr mode_key_cmdstr_copy[] = {
 | 
			
		||||
	{ MODEKEYCOPY_BOTTOMLINE, "bottom-line" },
 | 
			
		||||
	{ MODEKEYCOPY_CANCEL, "cancel" },
 | 
			
		||||
	{ MODEKEYCOPY_CLEARSELECTION, "clear-selection" },
 | 
			
		||||
	{ MODEKEYCOPY_COPYPIPE, "copy-pipe" },
 | 
			
		||||
	{ MODEKEYCOPY_COPYLINE, "copy-line" },
 | 
			
		||||
	{ MODEKEYCOPY_COPYENDOFLINE, "copy-end-of-line" },
 | 
			
		||||
	{ MODEKEYCOPY_COPYSELECTION, "copy-selection" },
 | 
			
		||||
@@ -513,6 +514,7 @@ mode_key_init_trees(void)
 | 
			
		||||
			mbind->key = ment->key;
 | 
			
		||||
			mbind->mode = ment->mode;
 | 
			
		||||
			mbind->cmd = ment->cmd;
 | 
			
		||||
			mbind->arg = NULL;
 | 
			
		||||
			RB_INSERT(mode_key_tree, mtab->tree, mbind);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -526,7 +528,7 @@ mode_key_init(struct mode_key_data *mdata, struct mode_key_tree *mtree)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum mode_key_cmd
 | 
			
		||||
mode_key_lookup(struct mode_key_data *mdata, int key)
 | 
			
		||||
mode_key_lookup(struct mode_key_data *mdata, int key, const char **arg)
 | 
			
		||||
{
 | 
			
		||||
	struct mode_key_binding	*mbind, mtmp;
 | 
			
		||||
 | 
			
		||||
@@ -546,6 +548,8 @@ mode_key_lookup(struct mode_key_data *mdata, int key)
 | 
			
		||||
		mdata->mode = 1 - mdata->mode;
 | 
			
		||||
		/* FALLTHROUGH */
 | 
			
		||||
	default:
 | 
			
		||||
		if (arg != NULL)
 | 
			
		||||
			*arg = mbind->arg;
 | 
			
		||||
		return (mbind->cmd);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								status.c
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								status.c
									
									
									
									
									
								
							@@ -1042,7 +1042,7 @@ status_prompt_key(struct client *c, int key)
 | 
			
		||||
	size_t			 size, n, off, idx;
 | 
			
		||||
 | 
			
		||||
	size = strlen(c->prompt_buffer);
 | 
			
		||||
	switch (mode_key_lookup(&c->prompt_mdata, key)) {
 | 
			
		||||
	switch (mode_key_lookup(&c->prompt_mdata, key, NULL)) {
 | 
			
		||||
	case MODEKEYEDIT_CURSORLEFT:
 | 
			
		||||
		if (c->prompt_index > 0) {
 | 
			
		||||
			c->prompt_index--;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										13
									
								
								tmux.1
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								tmux.1
									
									
									
									
									
								
							@@ -854,7 +854,7 @@ The following keys are supported as appropriate for the mode:
 | 
			
		||||
.It Li "Start of line" Ta "0" Ta "C-a"
 | 
			
		||||
.It Li "Start selection" Ta "Space" Ta "C-Space"
 | 
			
		||||
.It Li "Top of history" Ta "g" Ta "M->"
 | 
			
		||||
.It Li "Transpose chars" Ta "" Ta "C-t"
 | 
			
		||||
.It Li "Transpose characters" Ta "" Ta "C-t"
 | 
			
		||||
.El
 | 
			
		||||
.Pp
 | 
			
		||||
The next and previous word keys use space and the
 | 
			
		||||
@@ -916,6 +916,17 @@ command and keys modified or removed with
 | 
			
		||||
.Ic bind-key
 | 
			
		||||
and
 | 
			
		||||
.Ic unbind-key .
 | 
			
		||||
One command in accepts an argument,
 | 
			
		||||
.Ic copy-pipe ,
 | 
			
		||||
which copies the selection and pipes it to a command.
 | 
			
		||||
For example the following will bind
 | 
			
		||||
.Ql C-q
 | 
			
		||||
to copy the selection into
 | 
			
		||||
.Pa /tmp
 | 
			
		||||
as well as the paste buffer:
 | 
			
		||||
.Bd -literal -offset indent
 | 
			
		||||
bind-key -temacs-copy C-q copy-pipe "cat >/tmp/out"
 | 
			
		||||
.Ed
 | 
			
		||||
.Pp
 | 
			
		||||
The paste buffer key pastes the first line from the top paste buffer on the
 | 
			
		||||
stack.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								tmux.h
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								tmux.h
									
									
									
									
									
								
							@@ -562,6 +562,7 @@ enum mode_key_cmd {
 | 
			
		||||
	MODEKEYCOPY_BOTTOMLINE,
 | 
			
		||||
	MODEKEYCOPY_CANCEL,
 | 
			
		||||
	MODEKEYCOPY_CLEARSELECTION,
 | 
			
		||||
	MODEKEYCOPY_COPYPIPE,
 | 
			
		||||
	MODEKEYCOPY_COPYLINE,
 | 
			
		||||
	MODEKEYCOPY_COPYENDOFLINE,
 | 
			
		||||
	MODEKEYCOPY_COPYSELECTION,
 | 
			
		||||
@@ -628,12 +629,13 @@ struct mode_key_data {
 | 
			
		||||
 | 
			
		||||
/* Binding between a key and a command. */
 | 
			
		||||
struct mode_key_binding {
 | 
			
		||||
	int			key;
 | 
			
		||||
	int				 key;
 | 
			
		||||
 | 
			
		||||
	int			mode;
 | 
			
		||||
	enum mode_key_cmd	cmd;
 | 
			
		||||
	int				 mode;
 | 
			
		||||
	enum mode_key_cmd		 cmd;
 | 
			
		||||
	const char			*arg;
 | 
			
		||||
 | 
			
		||||
	RB_ENTRY(mode_key_binding) entry;
 | 
			
		||||
	RB_ENTRY(mode_key_binding)	 entry;
 | 
			
		||||
};
 | 
			
		||||
RB_HEAD(mode_key_tree, mode_key_binding);
 | 
			
		||||
 | 
			
		||||
@@ -1544,7 +1546,7 @@ enum mode_key_cmd mode_key_fromstring(const struct mode_key_cmdstr *,
 | 
			
		||||
const struct mode_key_table *mode_key_findtable(const char *);
 | 
			
		||||
void	mode_key_init_trees(void);
 | 
			
		||||
void	mode_key_init(struct mode_key_data *, struct mode_key_tree *);
 | 
			
		||||
enum mode_key_cmd mode_key_lookup(struct mode_key_data *, int);
 | 
			
		||||
enum mode_key_cmd mode_key_lookup(struct mode_key_data *, int, const char **);
 | 
			
		||||
 | 
			
		||||
/* notify.c */
 | 
			
		||||
void	notify_enable(void);
 | 
			
		||||
 
 | 
			
		||||
@@ -492,7 +492,7 @@ window_choose_key(struct window_pane *wp, unused struct session *sess, int key)
 | 
			
		||||
	items = ARRAY_LENGTH(&data->list);
 | 
			
		||||
 | 
			
		||||
	if (data->input_type == WINDOW_CHOOSE_GOTO_ITEM) {
 | 
			
		||||
		switch (mode_key_lookup(&data->mdata, key)) {
 | 
			
		||||
		switch (mode_key_lookup(&data->mdata, key, NULL)) {
 | 
			
		||||
		case MODEKEYCHOICE_CANCEL:
 | 
			
		||||
			data->input_type = WINDOW_CHOOSE_NORMAL;
 | 
			
		||||
			window_choose_redraw_screen(wp);
 | 
			
		||||
@@ -523,7 +523,7 @@ window_choose_key(struct window_pane *wp, unused struct session *sess, int key)
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch (mode_key_lookup(&data->mdata, key)) {
 | 
			
		||||
	switch (mode_key_lookup(&data->mdata, key, NULL)) {
 | 
			
		||||
	case MODEKEYCHOICE_CANCEL:
 | 
			
		||||
		window_choose_fire_callback(wp, NULL);
 | 
			
		||||
		break;
 | 
			
		||||
@@ -777,7 +777,7 @@ window_choose_key_index(struct window_choose_mode_data *data, u_int idx)
 | 
			
		||||
	int			mkey;
 | 
			
		||||
 | 
			
		||||
	for (ptr = keys; *ptr != '\0'; ptr++) {
 | 
			
		||||
		mkey = mode_key_lookup(&data->mdata, *ptr);
 | 
			
		||||
		mkey = mode_key_lookup(&data->mdata, *ptr, NULL);
 | 
			
		||||
		if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER)
 | 
			
		||||
			continue;
 | 
			
		||||
		if (idx-- == 0)
 | 
			
		||||
@@ -797,7 +797,7 @@ window_choose_index_key(struct window_choose_mode_data *data, int key)
 | 
			
		||||
	u_int			idx = 0;
 | 
			
		||||
 | 
			
		||||
	for (ptr = keys; *ptr != '\0'; ptr++) {
 | 
			
		||||
		mkey = mode_key_lookup(&data->mdata, *ptr);
 | 
			
		||||
		mkey = mode_key_lookup(&data->mdata, *ptr, NULL);
 | 
			
		||||
		if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER)
 | 
			
		||||
			continue;
 | 
			
		||||
		if (key == *ptr)
 | 
			
		||||
 
 | 
			
		||||
@@ -52,6 +52,9 @@ void	window_copy_goto_line(struct window_pane *, const char *);
 | 
			
		||||
void	window_copy_update_cursor(struct window_pane *, u_int, u_int);
 | 
			
		||||
void	window_copy_start_selection(struct window_pane *);
 | 
			
		||||
int	window_copy_update_selection(struct window_pane *);
 | 
			
		||||
void   *window_copy_get_selection(struct window_pane *, size_t *);
 | 
			
		||||
void	window_copy_copy_buffer(struct window_pane *, int, void *, size_t);
 | 
			
		||||
void	window_copy_copy_pipe(struct window_pane *, int, const char *);
 | 
			
		||||
void	window_copy_copy_selection(struct window_pane *, int);
 | 
			
		||||
void	window_copy_clear_selection(struct window_pane *);
 | 
			
		||||
void	window_copy_copy_line(
 | 
			
		||||
@@ -364,6 +367,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
 | 
			
		||||
	u_int				 n;
 | 
			
		||||
	int				 np, keys;
 | 
			
		||||
	enum mode_key_cmd		 cmd;
 | 
			
		||||
	const char			*arg;
 | 
			
		||||
 | 
			
		||||
	np = data->numprefix;
 | 
			
		||||
	if (np <= 0)
 | 
			
		||||
@@ -405,7 +409,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cmd = mode_key_lookup(&data->mdata, key);
 | 
			
		||||
	cmd = mode_key_lookup(&data->mdata, key, &arg);
 | 
			
		||||
	switch (cmd) {
 | 
			
		||||
	case MODEKEYCOPY_CANCEL:
 | 
			
		||||
		window_pane_reset_mode(wp);
 | 
			
		||||
@@ -533,6 +537,13 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
 | 
			
		||||
		window_copy_clear_selection(wp);
 | 
			
		||||
		window_copy_redraw_screen(wp);
 | 
			
		||||
		break;
 | 
			
		||||
	case MODEKEYCOPY_COPYPIPE:
 | 
			
		||||
		if (sess != NULL) {
 | 
			
		||||
			window_copy_copy_pipe(wp, data->numprefix, arg);
 | 
			
		||||
			window_pane_reset_mode(wp);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	case MODEKEYCOPY_COPYSELECTION:
 | 
			
		||||
		if (sess != NULL) {
 | 
			
		||||
			window_copy_copy_selection(wp, data->numprefix);
 | 
			
		||||
@@ -735,7 +746,7 @@ window_copy_key_input(struct window_pane *wp, int key)
 | 
			
		||||
	size_t				 inputlen;
 | 
			
		||||
	int				 np;
 | 
			
		||||
 | 
			
		||||
	switch (mode_key_lookup(&data->mdata, key)) {
 | 
			
		||||
	switch (mode_key_lookup(&data->mdata, key, NULL)) {
 | 
			
		||||
	case MODEKEYEDIT_CANCEL:
 | 
			
		||||
		data->numprefix = -1;
 | 
			
		||||
		return (-1);
 | 
			
		||||
@@ -1259,19 +1270,19 @@ window_copy_update_selection(struct window_pane *wp)
 | 
			
		||||
	return (1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
window_copy_copy_selection(struct window_pane *wp, int idx)
 | 
			
		||||
void *
 | 
			
		||||
window_copy_get_selection(struct window_pane *wp, size_t *len)
 | 
			
		||||
{
 | 
			
		||||
	struct window_copy_mode_data	*data = wp->modedata;
 | 
			
		||||
	struct screen			*s = &data->screen;
 | 
			
		||||
	char				*buf;
 | 
			
		||||
	size_t				 off;
 | 
			
		||||
	u_int				 i, xx, yy, sx, sy, ex, ey, limit;
 | 
			
		||||
	u_int				 i, xx, yy, sx, sy, ex, ey;
 | 
			
		||||
	u_int				 firstsx, lastex, restex, restsx;
 | 
			
		||||
	int				 keys;
 | 
			
		||||
 | 
			
		||||
	if (!s->sel.flag)
 | 
			
		||||
		return;
 | 
			
		||||
		return (NULL);
 | 
			
		||||
 | 
			
		||||
	buf = xmalloc(1);
 | 
			
		||||
	off = 0;
 | 
			
		||||
@@ -1364,19 +1375,58 @@ window_copy_copy_selection(struct window_pane *wp, int idx)
 | 
			
		||||
	/* Don't bother if no data. */
 | 
			
		||||
	if (off == 0) {
 | 
			
		||||
		free(buf);
 | 
			
		||||
		return;
 | 
			
		||||
		return (NULL);
 | 
			
		||||
	}
 | 
			
		||||
	off--;	/* remove final \n */
 | 
			
		||||
	*len = off - 1;	/* remove final \n */
 | 
			
		||||
	return (buf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
window_copy_copy_buffer(struct window_pane *wp, int idx, void *buf, size_t len)
 | 
			
		||||
{
 | 
			
		||||
	u_int	limit;
 | 
			
		||||
 | 
			
		||||
	if (options_get_number(&global_options, "set-clipboard"))
 | 
			
		||||
		screen_write_setselection(&wp->ictx.ctx, buf, off);
 | 
			
		||||
		screen_write_setselection(&wp->ictx.ctx, buf, len);
 | 
			
		||||
 | 
			
		||||
	/* Add the buffer to the stack. */
 | 
			
		||||
	if (idx == -1) {
 | 
			
		||||
		limit = options_get_number(&global_options, "buffer-limit");
 | 
			
		||||
		paste_add(&global_buffers, buf, off, limit);
 | 
			
		||||
		paste_add(&global_buffers, buf, len, limit);
 | 
			
		||||
	} else
 | 
			
		||||
		paste_replace(&global_buffers, idx, buf, off);
 | 
			
		||||
		paste_replace(&global_buffers, idx, buf, len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
window_copy_copy_pipe(struct window_pane *wp, int idx, const char *arg)
 | 
			
		||||
{
 | 
			
		||||
	void*	buf;
 | 
			
		||||
	size_t	len;
 | 
			
		||||
	FILE*	f;
 | 
			
		||||
 | 
			
		||||
	buf = window_copy_get_selection(wp, &len);
 | 
			
		||||
	if (buf == NULL)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	f = popen(arg, "w");
 | 
			
		||||
	if (f != NULL) {
 | 
			
		||||
		fwrite(buf, 1, len, f);
 | 
			
		||||
		pclose(f);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	window_copy_copy_buffer(wp, idx, buf, len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
window_copy_copy_selection(struct window_pane *wp, int idx)
 | 
			
		||||
{
 | 
			
		||||
	void*	buf;
 | 
			
		||||
	size_t	len;
 | 
			
		||||
 | 
			
		||||
	buf = window_copy_get_selection(wp, &len);
 | 
			
		||||
	if (buf == NULL)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	window_copy_copy_buffer(wp, idx, buf, len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user