diff --git a/cmd-bind-key.c b/cmd-bind-key.c index 28e94e26..2a7b482a 100644 --- a/cmd-bind-key.c +++ b/cmd-bind-key.c @@ -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); } diff --git a/cmd-list-keys.c b/cmd-list-keys.c index 51eeb674..3cb35f21 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -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 ? "\"": ""); } } diff --git a/mode-key.c b/mode-key.c index 86367ada..94115ebb 100644 --- a/mode-key.c +++ b/mode-key.c @@ -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); } } diff --git a/status.c b/status.c index 4083f2a5..3a315f49 100644 --- a/status.c +++ b/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--; diff --git a/tmux.1 b/tmux.1 index c1380ffd..fcca0924 100644 --- a/tmux.1 +++ b/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. diff --git a/tmux.h b/tmux.h index 8b3d4e14..f5691e91 100644 --- a/tmux.h +++ b/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); diff --git a/window-choose.c b/window-choose.c index eb526ec4..366c65d3 100644 --- a/window-choose.c +++ b/window-choose.c @@ -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) diff --git a/window-copy.c b/window-copy.c index be759d8b..2228b38a 100644 --- a/window-copy.c +++ b/window-copy.c @@ -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