Add copy-pipe mode command to copy selection and also pipe to a command.

This commit is contained in:
Nicholas Marriott 2013-02-19 17:49:53 +00:00
parent 5a5e285be8
commit c3859d1df1
8 changed files with 118 additions and 34 deletions

View File

@ -46,7 +46,7 @@ enum cmd_retval
cmd_bind_key_check(struct args *args) cmd_bind_key_check(struct args *args)
{ {
if (args_has(args, 't')) { if (args_has(args, 't')) {
if (args->argc != 2) if (args->argc != 2 && args->argc != 3)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} else { } else {
if (args->argc < 2) 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; const struct mode_key_table *mtab;
struct mode_key_binding *mbind, mtmp; struct mode_key_binding *mbind, mtmp;
enum mode_key_cmd cmd; enum mode_key_cmd cmd;
const char *arg;
tablename = args_get(args, 't'); tablename = args_get(args, 't');
if ((mtab = mode_key_findtable(tablename)) == NULL) { 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); 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.key = key;
mtmp.mode = !!args_has(args, 'c'); mtmp.mode = !!args_has(args, 'c');
if ((mbind = RB_FIND(mode_key_tree, mtab->tree, &mtmp)) != NULL) { if ((mbind = RB_FIND(mode_key_tree, mtab->tree, &mtmp)) == NULL) {
mbind->cmd = cmd; mbind = xmalloc(sizeof *mbind);
return (CMD_RETURN_NORMAL); 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; mbind->cmd = cmd;
RB_INSERT(mode_key_tree, mtab->tree, mbind); mbind->arg = arg != NULL ? xstrdup(arg) : NULL;
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@ -138,9 +138,12 @@ cmd_list_keys_table(struct cmd *self, struct cmd_ctx *ctx)
mode = "c"; mode = "c";
cmdstr = mode_key_tostring(mtab->cmdstr, mbind->cmd); cmdstr = mode_key_tostring(mtab->cmdstr, mbind->cmd);
if (cmdstr != NULL) { 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' ? " " : "", 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 ? "\"": "");
} }
} }

View File

@ -99,6 +99,7 @@ const struct mode_key_cmdstr mode_key_cmdstr_copy[] = {
{ MODEKEYCOPY_BOTTOMLINE, "bottom-line" }, { MODEKEYCOPY_BOTTOMLINE, "bottom-line" },
{ MODEKEYCOPY_CANCEL, "cancel" }, { MODEKEYCOPY_CANCEL, "cancel" },
{ MODEKEYCOPY_CLEARSELECTION, "clear-selection" }, { MODEKEYCOPY_CLEARSELECTION, "clear-selection" },
{ MODEKEYCOPY_COPYPIPE, "copy-pipe" },
{ MODEKEYCOPY_COPYLINE, "copy-line" }, { MODEKEYCOPY_COPYLINE, "copy-line" },
{ MODEKEYCOPY_COPYENDOFLINE, "copy-end-of-line" }, { MODEKEYCOPY_COPYENDOFLINE, "copy-end-of-line" },
{ MODEKEYCOPY_COPYSELECTION, "copy-selection" }, { MODEKEYCOPY_COPYSELECTION, "copy-selection" },
@ -513,6 +514,7 @@ mode_key_init_trees(void)
mbind->key = ment->key; mbind->key = ment->key;
mbind->mode = ment->mode; mbind->mode = ment->mode;
mbind->cmd = ment->cmd; mbind->cmd = ment->cmd;
mbind->arg = NULL;
RB_INSERT(mode_key_tree, mtab->tree, mbind); 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 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; 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; mdata->mode = 1 - mdata->mode;
/* FALLTHROUGH */ /* FALLTHROUGH */
default: default:
if (arg != NULL)
*arg = mbind->arg;
return (mbind->cmd); return (mbind->cmd);
} }
} }

View File

@ -1042,7 +1042,7 @@ status_prompt_key(struct client *c, int key)
size_t size, n, off, idx; size_t size, n, off, idx;
size = strlen(c->prompt_buffer); 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: case MODEKEYEDIT_CURSORLEFT:
if (c->prompt_index > 0) { if (c->prompt_index > 0) {
c->prompt_index--; c->prompt_index--;

13
tmux.1
View File

@ -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 of line" Ta "0" Ta "C-a"
.It Li "Start selection" Ta "Space" Ta "C-Space" .It Li "Start selection" Ta "Space" Ta "C-Space"
.It Li "Top of history" Ta "g" Ta "M->" .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 .El
.Pp .Pp
The next and previous word keys use space and the The next and previous word keys use space and the
@ -916,6 +916,17 @@ command and keys modified or removed with
.Ic bind-key .Ic bind-key
and and
.Ic unbind-key . .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 .Pp
The paste buffer key pastes the first line from the top paste buffer on the The paste buffer key pastes the first line from the top paste buffer on the
stack. stack.

12
tmux.h
View File

@ -562,6 +562,7 @@ enum mode_key_cmd {
MODEKEYCOPY_BOTTOMLINE, MODEKEYCOPY_BOTTOMLINE,
MODEKEYCOPY_CANCEL, MODEKEYCOPY_CANCEL,
MODEKEYCOPY_CLEARSELECTION, MODEKEYCOPY_CLEARSELECTION,
MODEKEYCOPY_COPYPIPE,
MODEKEYCOPY_COPYLINE, MODEKEYCOPY_COPYLINE,
MODEKEYCOPY_COPYENDOFLINE, MODEKEYCOPY_COPYENDOFLINE,
MODEKEYCOPY_COPYSELECTION, MODEKEYCOPY_COPYSELECTION,
@ -628,12 +629,13 @@ struct mode_key_data {
/* Binding between a key and a command. */ /* Binding between a key and a command. */
struct mode_key_binding { struct mode_key_binding {
int key; int key;
int mode; int mode;
enum mode_key_cmd cmd; 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); 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 *); const struct mode_key_table *mode_key_findtable(const char *);
void mode_key_init_trees(void); void mode_key_init_trees(void);
void mode_key_init(struct mode_key_data *, struct mode_key_tree *); 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 */ /* notify.c */
void notify_enable(void); void notify_enable(void);

View File

@ -492,7 +492,7 @@ window_choose_key(struct window_pane *wp, unused struct session *sess, int key)
items = ARRAY_LENGTH(&data->list); items = ARRAY_LENGTH(&data->list);
if (data->input_type == WINDOW_CHOOSE_GOTO_ITEM) { 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: case MODEKEYCHOICE_CANCEL:
data->input_type = WINDOW_CHOOSE_NORMAL; data->input_type = WINDOW_CHOOSE_NORMAL;
window_choose_redraw_screen(wp); window_choose_redraw_screen(wp);
@ -523,7 +523,7 @@ window_choose_key(struct window_pane *wp, unused struct session *sess, int key)
return; return;
} }
switch (mode_key_lookup(&data->mdata, key)) { switch (mode_key_lookup(&data->mdata, key, NULL)) {
case MODEKEYCHOICE_CANCEL: case MODEKEYCHOICE_CANCEL:
window_choose_fire_callback(wp, NULL); window_choose_fire_callback(wp, NULL);
break; break;
@ -777,7 +777,7 @@ window_choose_key_index(struct window_choose_mode_data *data, u_int idx)
int mkey; int mkey;
for (ptr = keys; *ptr != '\0'; ptr++) { 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) if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER)
continue; continue;
if (idx-- == 0) if (idx-- == 0)
@ -797,7 +797,7 @@ window_choose_index_key(struct window_choose_mode_data *data, int key)
u_int idx = 0; u_int idx = 0;
for (ptr = keys; *ptr != '\0'; ptr++) { 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) if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER)
continue; continue;
if (key == *ptr) if (key == *ptr)

View File

@ -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_update_cursor(struct window_pane *, u_int, u_int);
void window_copy_start_selection(struct window_pane *); void window_copy_start_selection(struct window_pane *);
int window_copy_update_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_copy_selection(struct window_pane *, int);
void window_copy_clear_selection(struct window_pane *); void window_copy_clear_selection(struct window_pane *);
void window_copy_copy_line( void window_copy_copy_line(
@ -364,6 +367,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
u_int n; u_int n;
int np, keys; int np, keys;
enum mode_key_cmd cmd; enum mode_key_cmd cmd;
const char *arg;
np = data->numprefix; np = data->numprefix;
if (np <= 0) if (np <= 0)
@ -405,7 +409,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
return; return;
} }
cmd = mode_key_lookup(&data->mdata, key); cmd = mode_key_lookup(&data->mdata, key, &arg);
switch (cmd) { switch (cmd) {
case MODEKEYCOPY_CANCEL: case MODEKEYCOPY_CANCEL:
window_pane_reset_mode(wp); 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_clear_selection(wp);
window_copy_redraw_screen(wp); window_copy_redraw_screen(wp);
break; 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: case MODEKEYCOPY_COPYSELECTION:
if (sess != NULL) { if (sess != NULL) {
window_copy_copy_selection(wp, data->numprefix); window_copy_copy_selection(wp, data->numprefix);
@ -735,7 +746,7 @@ window_copy_key_input(struct window_pane *wp, int key)
size_t inputlen; size_t inputlen;
int np; int np;
switch (mode_key_lookup(&data->mdata, key)) { switch (mode_key_lookup(&data->mdata, key, NULL)) {
case MODEKEYEDIT_CANCEL: case MODEKEYEDIT_CANCEL:
data->numprefix = -1; data->numprefix = -1;
return (-1); return (-1);
@ -1259,19 +1270,19 @@ window_copy_update_selection(struct window_pane *wp)
return (1); return (1);
} }
void void *
window_copy_copy_selection(struct window_pane *wp, int idx) window_copy_get_selection(struct window_pane *wp, size_t *len)
{ {
struct window_copy_mode_data *data = wp->modedata; struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen; struct screen *s = &data->screen;
char *buf; char *buf;
size_t off; 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; u_int firstsx, lastex, restex, restsx;
int keys; int keys;
if (!s->sel.flag) if (!s->sel.flag)
return; return (NULL);
buf = xmalloc(1); buf = xmalloc(1);
off = 0; off = 0;
@ -1364,19 +1375,58 @@ window_copy_copy_selection(struct window_pane *wp, int idx)
/* Don't bother if no data. */ /* Don't bother if no data. */
if (off == 0) { if (off == 0) {
free(buf); 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")) 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) { if (idx == -1) {
limit = options_get_number(&global_options, "buffer-limit"); limit = options_get_number(&global_options, "buffer-limit");
paste_add(&global_buffers, buf, off, limit); paste_add(&global_buffers, buf, len, limit);
} else } 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 void