mirror of
https://github.com/tmux/tmux.git
synced 2024-11-07 03:28:48 +00:00
Add copy-pipe mode command to copy selection and also pipe to a command.
This commit is contained in:
parent
5a5e285be8
commit
c3859d1df1
@ -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;
|
|
||||||
return (CMD_RETURN_NORMAL);
|
|
||||||
}
|
|
||||||
mbind = xmalloc(sizeof *mbind);
|
mbind = xmalloc(sizeof *mbind);
|
||||||
mbind->key = mtmp.key;
|
mbind->key = mtmp.key;
|
||||||
mbind->mode = mtmp.mode;
|
mbind->mode = mtmp.mode;
|
||||||
mbind->cmd = cmd;
|
|
||||||
RB_INSERT(mode_key_tree, mtab->tree, mbind);
|
RB_INSERT(mode_key_tree, mtab->tree, mbind);
|
||||||
|
}
|
||||||
|
mbind->cmd = cmd;
|
||||||
|
mbind->arg = arg != NULL ? xstrdup(arg) : NULL;
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
@ -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 ? "\"": "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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_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
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 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.
|
||||||
|
4
tmux.h
4
tmux.h
@ -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,
|
||||||
@ -632,6 +633,7 @@ struct mode_key_binding {
|
|||||||
|
|
||||||
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;
|
||||||
};
|
};
|
||||||
@ -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);
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user