diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c index e4d97f44..0b9b3926 100644 --- a/cmd-paste-buffer.c +++ b/cmd-paste-buffer.c @@ -18,7 +18,9 @@ #include +#include #include +#include #include "tmux.h" @@ -26,27 +28,109 @@ * Paste paste buffer if present. */ +struct cmd_paste_buffer_data { + char *target; + int buffer; + + int flag_delete; + char *sepstr; +}; + +void cmd_paste_buffer_init(struct cmd *, int); +int cmd_paste_buffer_parse(struct cmd *, int, char **, char **); int cmd_paste_buffer_exec(struct cmd *, struct cmd_ctx *); -void cmd_paste_buffer_lf2cr(struct window_pane *, const char *, size_t); +void cmd_paste_buffer_filter( + struct window_pane *, const char *, size_t, char *); +void cmd_paste_buffer_free(struct cmd *); +size_t cmd_paste_buffer_print(struct cmd *, char *, size_t); const struct cmd_entry cmd_paste_buffer_entry = { "paste-buffer", "pasteb", - "[-dr] " CMD_BUFFER_PANE_USAGE, - 0, "dr", - cmd_buffer_init, - cmd_buffer_parse, + "[-dr] [-s separator] [-b buffer-index] [-t target-window]", + 0, "", + cmd_paste_buffer_init, + cmd_paste_buffer_parse, cmd_paste_buffer_exec, - cmd_buffer_free, - cmd_buffer_print + cmd_paste_buffer_free, + cmd_paste_buffer_print }; +/* ARGSUSED */ +void +cmd_paste_buffer_init(struct cmd *self, unused int arg) +{ + struct cmd_paste_buffer_data *data; + + self->data = data = xmalloc(sizeof *data); + data->target = NULL; + data->buffer = -1; + data->flag_delete = 0; + data->sepstr = xstrdup("\r"); +} + +int +cmd_paste_buffer_parse(struct cmd *self, int argc, char **argv, char **cause) +{ + struct cmd_paste_buffer_data *data; + int opt, n; + const char *errstr; + + cmd_paste_buffer_init(self, 0); + data = self->data; + + while ((opt = getopt(argc, argv, "b:ds:t:r")) != -1) { + switch (opt) { + case 'b': + if (data->buffer == -1) { + n = strtonum(optarg, 0, INT_MAX, &errstr); + if (errstr != NULL) { + xasprintf(cause, "buffer %s", errstr); + goto error; + } + data->buffer = n; + } + break; + case 'd': + data->flag_delete = 1; + break; + case 's': + if (data->sepstr != NULL) + xfree(data->sepstr); + data->sepstr = xstrdup(optarg); + break; + case 't': + if (data->target == NULL) + data->target = xstrdup(optarg); + break; + case 'r': + if (data->sepstr != NULL) + xfree(data->sepstr); + data->sepstr = xstrdup("\n"); + break; + default: + goto usage; + } + } + argc -= optind; + argv += optind; + + return (0); + +usage: + xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); + +error: + self->entry->free(self); + return (-1); +} + int cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_buffer_data *data = self->data; - struct window_pane *wp; - struct session *s; - struct paste_buffer *pb; + struct cmd_paste_buffer_data *data = self->data; + struct window_pane *wp; + struct session *s; + struct paste_buffer *pb; if (cmd_find_pane(ctx, data->target, &s, &wp) == NULL) return (-1); @@ -60,16 +144,11 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) } } - if (pb != NULL) { - /* -r means raw data without LF->CR conversion. */ - if (cmd_check_flag(data->chflags, 'r')) - bufferevent_write(wp->event, pb->data, pb->size); - else - cmd_paste_buffer_lf2cr(wp, pb->data, pb->size); - } + if (pb != NULL) + cmd_paste_buffer_filter(wp, pb->data, pb->size, data->sepstr); /* Delete the buffer if -d. */ - if (cmd_check_flag(data->chflags, 'd')) { + if (data->flag_delete) { if (data->buffer == -1) paste_free_top(&s->buffers); else @@ -79,20 +158,66 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) return (0); } -/* Add bytes to a buffer but change every '\n' to '\r'. */ +/* Add bytes to a buffer and filter '\n' according to separator. */ void -cmd_paste_buffer_lf2cr(struct window_pane *wp, const char *data, size_t size) +cmd_paste_buffer_filter( + struct window_pane *wp, const char *data, size_t size, char *sep) { const char *end = data + size; const char *lf; + size_t seplen; + seplen = strlen(sep); while ((lf = memchr(data, '\n', end - data)) != NULL) { if (lf != data) bufferevent_write(wp->event, data, lf - data); - bufferevent_write(wp->event, "\r", 1); + bufferevent_write(wp->event, sep, seplen); data = lf + 1; } if (end != data) bufferevent_write(wp->event, data, end - data); } + +void +cmd_paste_buffer_free(struct cmd *self) +{ + struct cmd_paste_buffer_data *data = self->data; + + if (data->target != NULL) + xfree(data->target); + if (data->sepstr != NULL) + xfree(data->sepstr); + xfree(data); +} + +size_t +cmd_paste_buffer_print(struct cmd *self, char *buf, size_t len) +{ + struct cmd_paste_buffer_data *data = self->data; + size_t off = 0; + char tmp[BUFSIZ]; + int r_flag; + + r_flag = 0; + if (data->sepstr != NULL) + r_flag = (data->sepstr[0] == '\n' && data->sepstr[1] == '\0'); + + off += xsnprintf(buf, len, "%s", self->entry->name); + if (data == NULL) + return (off); + if (off < len && data->flag_delete) + off += xsnprintf(buf + off, len - off, " -d"); + if (off < len && r_flag) + off += xsnprintf(buf + off, len - off, " -r"); + if (off < len && data->buffer != -1) + off += xsnprintf(buf + off, len - off, " -b %d", data->buffer); + if (off < len && data->sepstr != NULL && !r_flag) { + strnvis( + tmp, data->sepstr, sizeof tmp, VIS_OCTAL|VIS_TAB|VIS_NL); + off += cmd_prarg(buf + off, len - off, " -s ", tmp); + } + if (off < len && data->target != NULL) + off += cmd_prarg(buf + off, len - off, " -t ", data->target); + return (off); +} diff --git a/tmux.1 b/tmux.1 index 132a58ea..8d123b25 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2387,6 +2387,7 @@ Load the contents of the specified paste buffer from .It Xo Ic paste-buffer .Op Fl dr .Op Fl b Ar buffer-index +.Op Fl s Ar separator .Op Fl t Ar target-pane .Xc .D1 (alias: Ic pasteb ) @@ -2396,10 +2397,13 @@ With .Fl d , also delete the paste buffer from the stack. When output, any linefeed (LF) characters in the paste buffer are replaced with -carriage returns (CR). -This translation may be disabled with the -.Fl r +a separator, by default carriage return (CR). +A custom separator may be specified using the +.Fl s flag. +The +.Fl r +flag means to do no replacement (equivalent to a separator of LF). .It Xo Ic save-buffer .Op Fl a .Op Fl b Ar buffer-index