Enhance paste-buffer to allow lines to be separated by any string, from

Andrea Barisani.
pull/1/head
Nicholas Marriott 2010-05-19 22:28:14 +00:00
parent d91127958d
commit 0ed727a012
2 changed files with 154 additions and 25 deletions

View File

@ -18,7 +18,9 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <vis.h>
#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);
}

10
tmux.1
View File

@ -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