mirror of
https://github.com/tmux/tmux.git
synced 2025-01-07 16:28:48 +00:00
Add support for named buffers. If you don't name a buffer, things work
much as before - buffers are automatically named "buffer0000", "buffer0001" and so on and ordered as a stack. Buffers can be named explicitly when creating ("loadb -b foo" etc) or renamed ("setb -b buffer0000 -n foo"). If buffers are named explicitly, they are not deleted when buffer-limit is reached. Diff from J Raynor.
This commit is contained in:
parent
f4ffaf5a7f
commit
3dbacbb62b
@ -38,7 +38,7 @@ char *cmd_capture_pane_history(struct args *, struct cmd_q *,
|
|||||||
const struct cmd_entry cmd_capture_pane_entry = {
|
const struct cmd_entry cmd_capture_pane_entry = {
|
||||||
"capture-pane", "capturep",
|
"capture-pane", "capturep",
|
||||||
"ab:CeE:JpPqS:t:", 0, 0,
|
"ab:CeE:JpPqS:t:", 0, 0,
|
||||||
"[-aCeJpPq] [-b buffer-index] [-E end-line] [-S start-line]"
|
"[-aCeJpPq] " CMD_BUFFER_USAGE " [-E end-line] [-S start-line]"
|
||||||
CMD_TARGET_PANE_USAGE,
|
CMD_TARGET_PANE_USAGE,
|
||||||
0,
|
0,
|
||||||
NULL,
|
NULL,
|
||||||
@ -165,8 +165,7 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
struct client *c;
|
struct client *c;
|
||||||
struct window_pane *wp;
|
struct window_pane *wp;
|
||||||
char *buf, *cause;
|
char *buf, *cause;
|
||||||
int buffer;
|
const char *bufname;
|
||||||
u_int limit;
|
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL)
|
if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL)
|
||||||
@ -192,25 +191,17 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
evbuffer_add(c->stdout_data, "\n", 1);
|
evbuffer_add(c->stdout_data, "\n", 1);
|
||||||
server_push_stdout(c);
|
server_push_stdout(c);
|
||||||
} else {
|
} else {
|
||||||
limit = options_get_number(&global_options, "buffer-limit");
|
|
||||||
if (!args_has(args, 'b')) {
|
|
||||||
paste_add(buf, len, limit);
|
|
||||||
return (CMD_RETURN_NORMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
|
bufname = NULL;
|
||||||
if (cause != NULL) {
|
if (args_has(args, 'b'))
|
||||||
cmdq_error(cmdq, "buffer %s", cause);
|
bufname = args_get(args, 'b');
|
||||||
|
|
||||||
|
if (paste_set(buf, len, bufname, &cause) != 0) {
|
||||||
|
cmdq_error(cmdq, "%s", cause);
|
||||||
free(buf);
|
free(buf);
|
||||||
free(cause);
|
free(cause);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (paste_replace(buffer, buf, len) != 0) {
|
|
||||||
cmdq_error(cmdq, "no buffer %d", buffer);
|
|
||||||
free(buf);
|
|
||||||
return (CMD_RETURN_ERROR);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
|
@ -75,19 +75,20 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
action = xstrdup("paste-buffer -b '%%'");
|
action = xstrdup("paste-buffer -b '%%'");
|
||||||
|
|
||||||
idx = 0;
|
idx = 0;
|
||||||
while ((pb = paste_walk_stack(&idx)) != NULL) {
|
pb = NULL;
|
||||||
|
while ((pb = paste_walk(pb)) != NULL) {
|
||||||
cdata = window_choose_data_create(TREE_OTHER, c, c->session);
|
cdata = window_choose_data_create(TREE_OTHER, c, c->session);
|
||||||
cdata->idx = idx - 1;
|
cdata->idx = idx;
|
||||||
|
|
||||||
cdata->ft_template = xstrdup(template);
|
cdata->ft_template = xstrdup(template);
|
||||||
format_add(cdata->ft, "line", "%u", idx - 1);
|
|
||||||
format_paste_buffer(cdata->ft, pb, utf8flag);
|
format_paste_buffer(cdata->ft, pb, utf8flag);
|
||||||
|
|
||||||
xasprintf(&action_data, "%u", idx - 1);
|
xasprintf(&action_data, "%s", pb->name);
|
||||||
cdata->command = cmd_template_replace(action, action_data, 1);
|
cdata->command = cmd_template_replace(action, action_data, 1);
|
||||||
free(action_data);
|
free(action_data);
|
||||||
|
|
||||||
window_choose_add(wl->window->active, cdata);
|
window_choose_add(wl->window->active, cdata);
|
||||||
|
idx++;
|
||||||
}
|
}
|
||||||
free(action);
|
free(action);
|
||||||
|
|
||||||
|
@ -41,23 +41,16 @@ enum cmd_retval
|
|||||||
cmd_delete_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
|
cmd_delete_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
|
||||||
{
|
{
|
||||||
struct args *args = self->args;
|
struct args *args = self->args;
|
||||||
char *cause;
|
const char *bufname;
|
||||||
int buffer;
|
|
||||||
|
|
||||||
if (!args_has(args, 'b')) {
|
if (!args_has(args, 'b')) {
|
||||||
paste_free_top();
|
paste_free_top();
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
bufname = args_get(args, 'b');
|
||||||
|
|
||||||
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
|
if (paste_free_name(bufname) != 0) {
|
||||||
if (cause != NULL) {
|
cmdq_error(cmdq, "no buffer %s", bufname);
|
||||||
cmdq_error(cmdq, "buffer %s", cause);
|
|
||||||
free(cause);
|
|
||||||
return (CMD_RETURN_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (paste_free_index(buffer) != 0) {
|
|
||||||
cmdq_error(cmdq, "no buffer %d", buffer);
|
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,17 +44,15 @@ cmd_list_buffers_exec(unused struct cmd *self, struct cmd_q *cmdq)
|
|||||||
struct args *args = self->args;
|
struct args *args = self->args;
|
||||||
struct paste_buffer *pb;
|
struct paste_buffer *pb;
|
||||||
struct format_tree *ft;
|
struct format_tree *ft;
|
||||||
u_int idx;
|
|
||||||
char *line;
|
char *line;
|
||||||
const char *template;
|
const char *template;
|
||||||
|
|
||||||
if ((template = args_get(args, 'F')) == NULL)
|
if ((template = args_get(args, 'F')) == NULL)
|
||||||
template = LIST_BUFFERS_TEMPLATE;
|
template = LIST_BUFFERS_TEMPLATE;
|
||||||
|
|
||||||
idx = 0;
|
pb = NULL;
|
||||||
while ((pb = paste_walk_stack(&idx)) != NULL) {
|
while ((pb = paste_walk(pb)) != NULL) {
|
||||||
ft = format_create();
|
ft = format_create();
|
||||||
format_add(ft, "line", "%u", idx - 1);
|
|
||||||
format_paste_buffer(ft, pb, 0);
|
format_paste_buffer(ft, pb, 0);
|
||||||
|
|
||||||
line = format_expand(ft, template);
|
line = format_expand(ft, template);
|
||||||
|
@ -50,30 +50,19 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
struct client *c = cmdq->client;
|
struct client *c = cmdq->client;
|
||||||
struct session *s;
|
struct session *s;
|
||||||
FILE *f;
|
FILE *f;
|
||||||
const char *path;
|
const char *path, *bufname;
|
||||||
char *pdata, *new_pdata, *cause;
|
char *pdata, *new_pdata, *cause;
|
||||||
size_t psize;
|
size_t psize;
|
||||||
u_int limit;
|
int ch, error, cwd, fd;
|
||||||
int ch, error, buffer, *buffer_ptr, cwd, fd;
|
|
||||||
|
|
||||||
if (!args_has(args, 'b'))
|
bufname = NULL;
|
||||||
buffer = -1;
|
if (args_has(args, 'b'))
|
||||||
else {
|
bufname = args_get(args, 'b');
|
||||||
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
|
|
||||||
if (cause != NULL) {
|
|
||||||
cmdq_error(cmdq, "buffer %s", cause);
|
|
||||||
free(cause);
|
|
||||||
return (CMD_RETURN_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
path = args->argv[0];
|
path = args->argv[0];
|
||||||
if (strcmp(path, "-") == 0) {
|
if (strcmp(path, "-") == 0) {
|
||||||
buffer_ptr = xmalloc(sizeof *buffer_ptr);
|
|
||||||
*buffer_ptr = buffer;
|
|
||||||
|
|
||||||
error = server_set_stdin_callback(c, cmd_load_buffer_callback,
|
error = server_set_stdin_callback(c, cmd_load_buffer_callback,
|
||||||
buffer_ptr, &cause);
|
(void*)bufname, &cause);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
cmdq_error(cmdq, "%s: %s", path, cause);
|
cmdq_error(cmdq, "%s: %s", path, cause);
|
||||||
free(cause);
|
free(cause);
|
||||||
@ -117,14 +106,10 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
limit = options_get_number(&global_options, "buffer-limit");
|
if (paste_set(pdata, psize, bufname, &cause) != 0) {
|
||||||
if (buffer == -1) {
|
cmdq_error(cmdq, "%s", cause);
|
||||||
paste_add(pdata, psize, limit);
|
|
||||||
return (CMD_RETURN_NORMAL);
|
|
||||||
}
|
|
||||||
if (paste_replace(buffer, pdata, psize) != 0) {
|
|
||||||
cmdq_error(cmdq, "no buffer %d", buffer);
|
|
||||||
free(pdata);
|
free(pdata);
|
||||||
|
free(cause);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,10 +125,9 @@ error:
|
|||||||
void
|
void
|
||||||
cmd_load_buffer_callback(struct client *c, int closed, void *data)
|
cmd_load_buffer_callback(struct client *c, int closed, void *data)
|
||||||
{
|
{
|
||||||
int *buffer = data;
|
const char *bufname = data;
|
||||||
char *pdata;
|
char *pdata, *cause;
|
||||||
size_t psize;
|
size_t psize;
|
||||||
u_int limit;
|
|
||||||
|
|
||||||
if (!closed)
|
if (!closed)
|
||||||
return;
|
return;
|
||||||
@ -154,26 +138,21 @@ cmd_load_buffer_callback(struct client *c, int closed, void *data)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
psize = EVBUFFER_LENGTH(c->stdin_data);
|
psize = EVBUFFER_LENGTH(c->stdin_data);
|
||||||
if (psize == 0 || (pdata = malloc(psize + 1)) == NULL) {
|
if (psize == 0 || (pdata = malloc(psize + 1)) == NULL)
|
||||||
free(data);
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
|
||||||
memcpy(pdata, EVBUFFER_DATA(c->stdin_data), psize);
|
memcpy(pdata, EVBUFFER_DATA(c->stdin_data), psize);
|
||||||
pdata[psize] = '\0';
|
pdata[psize] = '\0';
|
||||||
evbuffer_drain(c->stdin_data, psize);
|
evbuffer_drain(c->stdin_data, psize);
|
||||||
|
|
||||||
limit = options_get_number(&global_options, "buffer-limit");
|
if (paste_set(pdata, psize, bufname, &cause) != 0) {
|
||||||
if (*buffer == -1)
|
|
||||||
paste_add(pdata, psize, limit);
|
|
||||||
else if (paste_replace(*buffer, pdata, psize) != 0) {
|
|
||||||
/* No context so can't use server_client_msg_error. */
|
/* No context so can't use server_client_msg_error. */
|
||||||
evbuffer_add_printf(c->stderr_data, "no buffer %d\n", *buffer);
|
evbuffer_add_printf(c->stderr_data, "%s", cause);
|
||||||
server_push_stderr(c);
|
server_push_stderr(c);
|
||||||
free(pdata);
|
free(pdata);
|
||||||
|
free(cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(data);
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
cmdq_continue(c->cmdq);
|
cmdq_continue(c->cmdq);
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ void cmd_paste_buffer_filter(struct window_pane *,
|
|||||||
const struct cmd_entry cmd_paste_buffer_entry = {
|
const struct cmd_entry cmd_paste_buffer_entry = {
|
||||||
"paste-buffer", "pasteb",
|
"paste-buffer", "pasteb",
|
||||||
"db:prs:t:", 0, 0,
|
"db:prs:t:", 0, 0,
|
||||||
"[-dpr] [-s separator] [-b buffer-index] " CMD_TARGET_PANE_USAGE,
|
"[-dpr] [-s separator] " CMD_BUFFER_USAGE " " CMD_TARGET_PANE_USAGE,
|
||||||
0,
|
0,
|
||||||
NULL,
|
NULL,
|
||||||
cmd_paste_buffer_exec
|
cmd_paste_buffer_exec
|
||||||
@ -49,31 +49,22 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
struct window_pane *wp;
|
struct window_pane *wp;
|
||||||
struct session *s;
|
struct session *s;
|
||||||
struct paste_buffer *pb;
|
struct paste_buffer *pb;
|
||||||
const char *sepstr;
|
const char *sepstr, *bufname;
|
||||||
char *cause;
|
|
||||||
int buffer;
|
|
||||||
int pflag;
|
int pflag;
|
||||||
|
|
||||||
if (cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp) == NULL)
|
if (cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp) == NULL)
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
|
|
||||||
if (!args_has(args, 'b'))
|
bufname = NULL;
|
||||||
buffer = -1;
|
if (args_has(args, 'b'))
|
||||||
else {
|
bufname = args_get(args, 'b');
|
||||||
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
|
|
||||||
if (cause != NULL) {
|
|
||||||
cmdq_error(cmdq, "buffer %s", cause);
|
|
||||||
free(cause);
|
|
||||||
return (CMD_RETURN_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buffer == -1)
|
if (bufname == NULL)
|
||||||
pb = paste_get_top();
|
pb = paste_get_top();
|
||||||
else {
|
else {
|
||||||
pb = paste_get_index(buffer);
|
pb = paste_get_name(bufname);
|
||||||
if (pb == NULL) {
|
if (pb == NULL) {
|
||||||
cmdq_error(cmdq, "no buffer %d", buffer);
|
cmdq_error(cmdq, "no buffer %s", bufname);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,10 +83,10 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
|
|
||||||
/* Delete the buffer if -d. */
|
/* Delete the buffer if -d. */
|
||||||
if (args_has(args, 'd')) {
|
if (args_has(args, 'd')) {
|
||||||
if (buffer == -1)
|
if (bufname == NULL)
|
||||||
paste_free_top();
|
paste_free_top();
|
||||||
else
|
else
|
||||||
paste_free_index(buffer);
|
paste_free_name(bufname);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
|
@ -59,10 +59,10 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
struct client *c = cmdq->client;
|
struct client *c = cmdq->client;
|
||||||
struct session *s;
|
struct session *s;
|
||||||
struct paste_buffer *pb;
|
struct paste_buffer *pb;
|
||||||
const char *path;
|
const char *path, *bufname;
|
||||||
char *cause, *start, *end, *msg;
|
char *start, *end, *msg;
|
||||||
size_t size, used, msglen;
|
size_t size, used, msglen;
|
||||||
int cwd, fd, buffer;
|
int cwd, fd;
|
||||||
FILE *f;
|
FILE *f;
|
||||||
|
|
||||||
if (!args_has(args, 'b')) {
|
if (!args_has(args, 'b')) {
|
||||||
@ -71,16 +71,10 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
|
bufname = args_get(args, 'b');
|
||||||
if (cause != NULL) {
|
pb = paste_get_name(bufname);
|
||||||
cmdq_error(cmdq, "buffer %s", cause);
|
|
||||||
free(cause);
|
|
||||||
return (CMD_RETURN_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
pb = paste_get_index(buffer);
|
|
||||||
if (pb == NULL) {
|
if (pb == NULL) {
|
||||||
cmdq_error(cmdq, "no buffer %d", buffer);
|
cmdq_error(cmdq, "no buffer %s", bufname);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,8 +31,8 @@ enum cmd_retval cmd_set_buffer_exec(struct cmd *, struct cmd_q *);
|
|||||||
|
|
||||||
const struct cmd_entry cmd_set_buffer_entry = {
|
const struct cmd_entry cmd_set_buffer_entry = {
|
||||||
"set-buffer", "setb",
|
"set-buffer", "setb",
|
||||||
"ab:", 1, 1,
|
"ab:n:", 0, 1,
|
||||||
"[-a] " CMD_BUFFER_USAGE " data",
|
"[-a] " CMD_BUFFER_USAGE " [-n new-buffer-name] data",
|
||||||
0,
|
0,
|
||||||
NULL,
|
NULL,
|
||||||
cmd_set_buffer_exec
|
cmd_set_buffer_exec
|
||||||
@ -43,38 +43,59 @@ cmd_set_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
{
|
{
|
||||||
struct args *args = self->args;
|
struct args *args = self->args;
|
||||||
struct paste_buffer *pb;
|
struct paste_buffer *pb;
|
||||||
u_int limit;
|
|
||||||
char *pdata, *cause;
|
char *pdata, *cause;
|
||||||
|
const char *bufname;
|
||||||
size_t psize, newsize;
|
size_t psize, newsize;
|
||||||
int buffer;
|
|
||||||
|
|
||||||
limit = options_get_number(&global_options, "buffer-limit");
|
bufname = NULL;
|
||||||
|
|
||||||
|
if (args_has(args, 'n')) {
|
||||||
|
if (args->argc > 0) {
|
||||||
|
cmdq_error(cmdq, "don't provide data with n flag");
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args_has(args, 'b'))
|
||||||
|
bufname = args_get(args, 'b');
|
||||||
|
|
||||||
|
if (bufname == NULL) {
|
||||||
|
pb = paste_get_top();
|
||||||
|
if (pb == NULL) {
|
||||||
|
cmdq_error(cmdq, "no buffer");
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
bufname = pb->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (paste_rename(bufname, args_get(args, 'n'), &cause) != 0) {
|
||||||
|
cmdq_error(cmdq, "%s", cause);
|
||||||
|
free(cause);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args->argc != 1) {
|
||||||
|
cmdq_error(cmdq, "no data specified");
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
psize = 0;
|
psize = 0;
|
||||||
pdata = NULL;
|
pdata = NULL;
|
||||||
|
|
||||||
pb = NULL;
|
pb = NULL;
|
||||||
buffer = -1;
|
|
||||||
|
|
||||||
if ((newsize = strlen(args->argv[0])) == 0)
|
if ((newsize = strlen(args->argv[0])) == 0)
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
|
|
||||||
if (args_has(args, 'b')) {
|
if (args_has(args, 'b')) {
|
||||||
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
|
bufname = args_get(args, 'b');
|
||||||
if (cause != NULL) {
|
pb = paste_get_name(bufname);
|
||||||
cmdq_error(cmdq, "buffer %s", cause);
|
|
||||||
free(cause);
|
|
||||||
return (CMD_RETURN_ERROR);
|
|
||||||
}
|
|
||||||
pb = paste_get_index(buffer);
|
|
||||||
if (pb == NULL) {
|
|
||||||
cmdq_error(cmdq, "no buffer %d", buffer);
|
|
||||||
return (CMD_RETURN_ERROR);
|
|
||||||
}
|
|
||||||
} else if (args_has(args, 'a')) {
|
} else if (args_has(args, 'a')) {
|
||||||
pb = paste_get_top();
|
pb = paste_get_top();
|
||||||
if (pb != NULL)
|
if (pb != NULL)
|
||||||
buffer = 0;
|
bufname = pb->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args_has(args, 'a') && pb != NULL) {
|
if (args_has(args, 'a') && pb != NULL) {
|
||||||
@ -87,10 +108,12 @@ cmd_set_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
memcpy(pdata + psize, args->argv[0], newsize);
|
memcpy(pdata + psize, args->argv[0], newsize);
|
||||||
psize += newsize;
|
psize += newsize;
|
||||||
|
|
||||||
if (buffer == -1)
|
if (paste_set(pdata, psize, bufname, &cause) != 0) {
|
||||||
paste_add(pdata, psize, limit);
|
cmdq_error(cmdq, "%s", cause);
|
||||||
else
|
free(pdata);
|
||||||
paste_replace(buffer, pdata, psize);
|
free(cause);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
1
format.c
1
format.c
@ -608,6 +608,7 @@ format_paste_buffer(struct format_tree *ft, struct paste_buffer *pb,
|
|||||||
char *s;
|
char *s;
|
||||||
|
|
||||||
format_add(ft, "buffer_size", "%zu", pb->size);
|
format_add(ft, "buffer_size", "%zu", pb->size);
|
||||||
|
format_add(ft, "buffer_name", "%s", pb->name);
|
||||||
|
|
||||||
s = paste_make_sample(pb, utf8flag);
|
s = paste_make_sample(pb, utf8flag);
|
||||||
format_add(ft, "buffer_sample", "%s", s);
|
format_add(ft, "buffer_sample", "%s", s);
|
||||||
|
218
paste.c
218
paste.c
@ -26,127 +26,237 @@
|
|||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Stack of paste buffers. Note that paste buffer data is not necessarily a C
|
* Set of paste buffers. Note that paste buffer data is not necessarily a C
|
||||||
* string!
|
* string!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ARRAY_DECL(, struct paste_buffer *) paste_buffers = ARRAY_INITIALIZER;
|
u_int paste_next_index;
|
||||||
|
u_int paste_next_order;
|
||||||
|
u_int paste_num_automatic;
|
||||||
|
RB_HEAD(paste_name_tree, paste_buffer) paste_by_name;
|
||||||
|
RB_HEAD(paste_time_tree, paste_buffer) paste_by_time;
|
||||||
|
|
||||||
/* Return each item of the stack in turn. */
|
int paste_cmp_names(const struct paste_buffer *, const struct paste_buffer *);
|
||||||
struct paste_buffer *
|
RB_PROTOTYPE(paste_name_tree, paste_buffer, name_entry, paste_cmp_names);
|
||||||
paste_walk_stack(u_int *idx)
|
RB_GENERATE(paste_name_tree, paste_buffer, name_entry, paste_cmp_names);
|
||||||
|
|
||||||
|
int paste_cmp_times(const struct paste_buffer *, const struct paste_buffer *);
|
||||||
|
RB_PROTOTYPE(paste_time_tree, paste_buffer, time_entry, paste_cmp_times);
|
||||||
|
RB_GENERATE(paste_time_tree, paste_buffer, time_entry, paste_cmp_times);
|
||||||
|
|
||||||
|
int
|
||||||
|
paste_cmp_names(const struct paste_buffer *a, const struct paste_buffer *b)
|
||||||
{
|
{
|
||||||
struct paste_buffer *pb;
|
return (strcmp(a->name, b->name));
|
||||||
|
|
||||||
pb = paste_get_index(*idx);
|
|
||||||
(*idx)++;
|
|
||||||
return (pb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the top item on the stack. */
|
int
|
||||||
|
paste_cmp_times(const struct paste_buffer *a, const struct paste_buffer *b)
|
||||||
|
{
|
||||||
|
if (a->order > b->order)
|
||||||
|
return (-1);
|
||||||
|
if (a->order < b->order)
|
||||||
|
return (1);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Walk paste buffers by name. */
|
||||||
|
struct paste_buffer *
|
||||||
|
paste_walk(struct paste_buffer *pb)
|
||||||
|
{
|
||||||
|
if (pb == NULL)
|
||||||
|
return (RB_MIN(paste_time_tree, &paste_by_time));
|
||||||
|
return (RB_NEXT(paste_time_tree, &paste_by_time, pb));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the most recent automatic buffer */
|
||||||
struct paste_buffer *
|
struct paste_buffer *
|
||||||
paste_get_top(void)
|
paste_get_top(void)
|
||||||
{
|
{
|
||||||
if (ARRAY_LENGTH(&paste_buffers) == 0)
|
struct paste_buffer *pb;
|
||||||
|
|
||||||
|
pb = RB_MIN(paste_time_tree, &paste_by_time);
|
||||||
|
if (pb == NULL)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
return (ARRAY_FIRST(&paste_buffers));
|
return (pb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get an item by its index. */
|
/* Free the most recent buffer */
|
||||||
struct paste_buffer *
|
|
||||||
paste_get_index(u_int idx)
|
|
||||||
{
|
|
||||||
if (idx >= ARRAY_LENGTH(&paste_buffers))
|
|
||||||
return (NULL);
|
|
||||||
return (ARRAY_ITEM(&paste_buffers, idx));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Free the top item on the stack. */
|
|
||||||
int
|
int
|
||||||
paste_free_top(void)
|
paste_free_top(void)
|
||||||
{
|
{
|
||||||
struct paste_buffer *pb;
|
struct paste_buffer *pb;
|
||||||
|
|
||||||
if (ARRAY_LENGTH(&paste_buffers) == 0)
|
pb = paste_get_top();
|
||||||
|
if (pb == NULL)
|
||||||
return (-1);
|
return (-1);
|
||||||
|
return (paste_free_name(pb->name));
|
||||||
pb = ARRAY_FIRST(&paste_buffers);
|
|
||||||
ARRAY_REMOVE(&paste_buffers, 0);
|
|
||||||
|
|
||||||
free(pb->data);
|
|
||||||
free(pb);
|
|
||||||
|
|
||||||
return (0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free an item by index. */
|
/* Get a paste buffer by name. */
|
||||||
int
|
struct paste_buffer *
|
||||||
paste_free_index(u_int idx)
|
paste_get_name(const char *name)
|
||||||
{
|
{
|
||||||
struct paste_buffer *pb;
|
struct paste_buffer pbfind;
|
||||||
|
|
||||||
if (idx >= ARRAY_LENGTH(&paste_buffers))
|
if (name == NULL || *name == '\0')
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
pbfind.name = (char*)name;
|
||||||
|
return (RB_FIND(paste_name_tree, &paste_by_name, &pbfind));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free a paste buffer by name. */
|
||||||
|
int
|
||||||
|
paste_free_name(const char *name)
|
||||||
|
{
|
||||||
|
struct paste_buffer *pb, pbfind;
|
||||||
|
|
||||||
|
if (name == NULL || *name == '\0')
|
||||||
return (-1);
|
return (-1);
|
||||||
|
|
||||||
pb = ARRAY_ITEM(&paste_buffers, idx);
|
pbfind.name = (char*)name;
|
||||||
ARRAY_REMOVE(&paste_buffers, idx);
|
pb = RB_FIND(paste_name_tree, &paste_by_name, &pbfind);
|
||||||
|
if (pb == NULL)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
RB_REMOVE(paste_name_tree, &paste_by_name, pb);
|
||||||
|
RB_REMOVE(paste_time_tree, &paste_by_time, pb);
|
||||||
|
if (pb->automatic)
|
||||||
|
paste_num_automatic--;
|
||||||
|
|
||||||
free(pb->data);
|
free(pb->data);
|
||||||
|
free(pb->name);
|
||||||
free(pb);
|
free(pb);
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add an item onto the top of the stack, freeing the bottom if at limit. Note
|
* Add an automatic buffer, freeing the oldest automatic item if at limit. Note
|
||||||
* that the caller is responsible for allocating data.
|
* that the caller is responsible for allocating data.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
paste_add(char *data, size_t size, u_int limit)
|
paste_add(char *data, size_t size)
|
||||||
{
|
{
|
||||||
struct paste_buffer *pb;
|
struct paste_buffer *pb, *pb1;
|
||||||
|
u_int limit;
|
||||||
|
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
while (ARRAY_LENGTH(&paste_buffers) >= limit) {
|
limit = options_get_number(&global_options, "buffer-limit");
|
||||||
pb = ARRAY_LAST(&paste_buffers);
|
RB_FOREACH_REVERSE_SAFE(pb, paste_time_tree, &paste_by_time, pb1) {
|
||||||
free(pb->data);
|
if (paste_num_automatic < limit)
|
||||||
free(pb);
|
break;
|
||||||
ARRAY_TRUNC(&paste_buffers, 1);
|
if (pb->automatic)
|
||||||
|
paste_free_name(pb->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
pb = xmalloc(sizeof *pb);
|
pb = xmalloc(sizeof *pb);
|
||||||
ARRAY_INSERT(&paste_buffers, 0, pb);
|
|
||||||
|
pb->name = NULL;
|
||||||
|
do {
|
||||||
|
free(pb->name);
|
||||||
|
xasprintf(&pb->name, "buffer%04u", paste_next_index);
|
||||||
|
paste_next_index++;
|
||||||
|
} while (paste_get_name(pb->name) != NULL);
|
||||||
|
|
||||||
pb->data = data;
|
pb->data = data;
|
||||||
pb->size = size;
|
pb->size = size;
|
||||||
|
|
||||||
|
pb->automatic = 1;
|
||||||
|
paste_num_automatic++;
|
||||||
|
|
||||||
|
pb->order = paste_next_order++;
|
||||||
|
RB_INSERT(paste_name_tree, &paste_by_name, pb);
|
||||||
|
RB_INSERT(paste_time_tree, &paste_by_time, pb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Rename a paste buffer. */
|
||||||
|
int
|
||||||
|
paste_rename(const char *oldname, const char *newname, char **cause)
|
||||||
|
{
|
||||||
|
struct paste_buffer *pb;
|
||||||
|
|
||||||
|
if (cause != NULL)
|
||||||
|
*cause = NULL;
|
||||||
|
|
||||||
|
if (oldname == NULL || *oldname == '\0') {
|
||||||
|
if (cause != NULL)
|
||||||
|
*cause = xstrdup("no buffer");
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
if (newname == NULL || *newname == '\0') {
|
||||||
|
if (cause != NULL)
|
||||||
|
*cause = xstrdup("new name is empty");
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pb = paste_get_name(oldname);
|
||||||
|
if (pb == NULL) {
|
||||||
|
if (cause != NULL)
|
||||||
|
xasprintf(cause, "no buffer %s", oldname);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
RB_REMOVE(paste_name_tree, &paste_by_name, pb);
|
||||||
|
|
||||||
|
free(pb->name);
|
||||||
|
pb->name = xstrdup(newname);
|
||||||
|
|
||||||
|
if (pb->automatic)
|
||||||
|
paste_num_automatic--;
|
||||||
|
pb->automatic = 0;
|
||||||
|
|
||||||
|
RB_INSERT(paste_name_tree, &paste_by_name, pb);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Replace an item on the stack. Note that the caller is responsible for
|
* Add or replace an item in the store. Note that the caller is responsible for
|
||||||
* allocating data.
|
* allocating data.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
paste_replace(u_int idx, char *data, size_t size)
|
paste_set(char *data, size_t size, const char *name, char **cause)
|
||||||
{
|
{
|
||||||
struct paste_buffer *pb;
|
struct paste_buffer *pb;
|
||||||
|
|
||||||
|
if (cause != NULL)
|
||||||
|
*cause = NULL;
|
||||||
|
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
free(data);
|
free(data);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
if (name == NULL) {
|
||||||
|
paste_add(data, size);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
if (idx >= ARRAY_LENGTH(&paste_buffers))
|
if (*name == '\0') {
|
||||||
|
if (cause != NULL)
|
||||||
|
*cause = xstrdup("empty buffer name");
|
||||||
return (-1);
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
pb = ARRAY_ITEM(&paste_buffers, idx);
|
pb = paste_get_name(name);
|
||||||
free(pb->data);
|
if (pb != NULL)
|
||||||
|
paste_free_name(name);
|
||||||
|
|
||||||
|
pb = xmalloc(sizeof *pb);
|
||||||
|
|
||||||
|
pb->name = xstrdup(name);
|
||||||
|
|
||||||
pb->data = data;
|
pb->data = data;
|
||||||
pb->size = size;
|
pb->size = size;
|
||||||
|
|
||||||
|
pb->automatic = 0;
|
||||||
|
pb->order = paste_next_order++;
|
||||||
|
|
||||||
|
RB_INSERT(paste_name_tree, &paste_by_name, pb);
|
||||||
|
RB_INSERT(paste_time_tree, &paste_by_time, pb);
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
63
tmux.1
63
tmux.1
@ -930,9 +930,6 @@ in emacs mode, and
|
|||||||
.Ql 10w
|
.Ql 10w
|
||||||
in vi.
|
in vi.
|
||||||
.Pp
|
.Pp
|
||||||
When copying the selection, the repeat count indicates the buffer index to
|
|
||||||
replace, if used.
|
|
||||||
.Pp
|
|
||||||
Mode key bindings are defined in a set of named tables:
|
Mode key bindings are defined in a set of named tables:
|
||||||
.Em vi-edit
|
.Em vi-edit
|
||||||
and
|
and
|
||||||
@ -1090,7 +1087,7 @@ but a different format may be specified with
|
|||||||
.Fl F .
|
.Fl F .
|
||||||
.It Xo Ic capture-pane
|
.It Xo Ic capture-pane
|
||||||
.Op Fl aepPq
|
.Op Fl aepPq
|
||||||
.Op Fl b Ar buffer-index
|
.Op Fl b Ar buffer-name
|
||||||
.Op Fl E Ar end-line
|
.Op Fl E Ar end-line
|
||||||
.Op Fl S Ar start-line
|
.Op Fl S Ar start-line
|
||||||
.Op Fl t Ar target-pane
|
.Op Fl t Ar target-pane
|
||||||
@ -3366,19 +3363,40 @@ is given, otherwise the active pane for the session attached to
|
|||||||
.El
|
.El
|
||||||
.Sh BUFFERS
|
.Sh BUFFERS
|
||||||
.Nm
|
.Nm
|
||||||
maintains a stack of
|
maintains a set of named
|
||||||
.Em paste buffers .
|
.Em paste buffers .
|
||||||
Up to the value of the
|
Each buffer may be either explicitly or automatically named.
|
||||||
|
Explicitly named buffers are named when created with the
|
||||||
|
.Ic set-buffer
|
||||||
|
or
|
||||||
|
.Ic load-buffer
|
||||||
|
commands, or by renaming an automatically named buffer with
|
||||||
|
.Ic set-buffer
|
||||||
|
.Fl n .
|
||||||
|
Automatically named buffers are given a name such as
|
||||||
|
.Ql buffer0001 ,
|
||||||
|
.Ql buffer0002
|
||||||
|
and so on.
|
||||||
|
When the
|
||||||
.Ic buffer-limit
|
.Ic buffer-limit
|
||||||
option are kept; when a new buffer is added, the buffer at the bottom of the
|
option is reached, the oldest automatically named buffer is deleted.
|
||||||
stack is removed.
|
Explicitly named are not subject to
|
||||||
|
.Ic buffer-limit
|
||||||
|
and may be deleted with
|
||||||
|
.Ic delete-buffer
|
||||||
|
command.
|
||||||
|
.Pp
|
||||||
Buffers may be added using
|
Buffers may be added using
|
||||||
.Ic copy-mode
|
.Ic copy-mode
|
||||||
or the
|
or the
|
||||||
.Ic set-buffer
|
.Ic set-buffer
|
||||||
command, and pasted into a window using the
|
and
|
||||||
|
.Ic load-buffer
|
||||||
|
commands, and pasted into a window using the
|
||||||
.Ic paste-buffer
|
.Ic paste-buffer
|
||||||
command.
|
command.
|
||||||
|
If a buffer command is used and no buffer is specified, the most
|
||||||
|
recently added automatically named buffer is assumed.
|
||||||
.Pp
|
.Pp
|
||||||
A configurable history buffer is also maintained for each window.
|
A configurable history buffer is also maintained for each window.
|
||||||
By default, up to 2000 lines are kept; this can be altered with the
|
By default, up to 2000 lines are kept; this can be altered with the
|
||||||
@ -3399,7 +3417,7 @@ Put a window into buffer choice mode, where a buffer may be chosen
|
|||||||
interactively from a list.
|
interactively from a list.
|
||||||
After a buffer is selected,
|
After a buffer is selected,
|
||||||
.Ql %%
|
.Ql %%
|
||||||
is replaced by the buffer index in
|
is replaced by the buffer name in
|
||||||
.Ar template
|
.Ar template
|
||||||
and the result executed as a command.
|
and the result executed as a command.
|
||||||
If
|
If
|
||||||
@ -3414,11 +3432,11 @@ This command works only if at least one client is attached.
|
|||||||
.It Ic clear-history Op Fl t Ar target-pane
|
.It Ic clear-history Op Fl t Ar target-pane
|
||||||
.D1 (alias: Ic clearhist )
|
.D1 (alias: Ic clearhist )
|
||||||
Remove and free the history for the specified pane.
|
Remove and free the history for the specified pane.
|
||||||
.It Ic delete-buffer Op Fl b Ar buffer-index
|
.It Ic delete-buffer Op Fl b Ar buffer-name
|
||||||
.D1 (alias: Ic deleteb )
|
.D1 (alias: Ic deleteb )
|
||||||
Delete the buffer at
|
Delete the buffer named
|
||||||
.Ar buffer-index ,
|
.Ar buffer-name ,
|
||||||
or the top buffer if not specified.
|
or the most recently added automatically named buffer if not specified.
|
||||||
.It Xo Ic list-buffers
|
.It Xo Ic list-buffers
|
||||||
.Op Fl F Ar format
|
.Op Fl F Ar format
|
||||||
.Xc
|
.Xc
|
||||||
@ -3430,7 +3448,7 @@ flag, see the
|
|||||||
.Sx FORMATS
|
.Sx FORMATS
|
||||||
section.
|
section.
|
||||||
.It Xo Ic load-buffer
|
.It Xo Ic load-buffer
|
||||||
.Op Fl b Ar buffer-index
|
.Op Fl b Ar buffer-name
|
||||||
.Ar path
|
.Ar path
|
||||||
.Xc
|
.Xc
|
||||||
.D1 (alias: Ic loadb )
|
.D1 (alias: Ic loadb )
|
||||||
@ -3438,7 +3456,7 @@ Load the contents of the specified paste buffer from
|
|||||||
.Ar path .
|
.Ar path .
|
||||||
.It Xo Ic paste-buffer
|
.It Xo Ic paste-buffer
|
||||||
.Op Fl dpr
|
.Op Fl dpr
|
||||||
.Op Fl b Ar buffer-index
|
.Op Fl b Ar buffer-name
|
||||||
.Op Fl s Ar separator
|
.Op Fl s Ar separator
|
||||||
.Op Fl t Ar target-pane
|
.Op Fl t Ar target-pane
|
||||||
.Xc
|
.Xc
|
||||||
@ -3447,7 +3465,7 @@ Insert the contents of a paste buffer into the specified pane.
|
|||||||
If not specified, paste into the current one.
|
If not specified, paste into the current one.
|
||||||
With
|
With
|
||||||
.Fl d ,
|
.Fl d ,
|
||||||
also delete the paste buffer from the stack.
|
also delete the paste buffer.
|
||||||
When output, any linefeed (LF) characters in the paste buffer are replaced with
|
When output, any linefeed (LF) characters in the paste buffer are replaced with
|
||||||
a separator, by default carriage return (CR).
|
a separator, by default carriage return (CR).
|
||||||
A custom separator may be specified using the
|
A custom separator may be specified using the
|
||||||
@ -3462,7 +3480,7 @@ is specified, paste bracket control codes are inserted around the
|
|||||||
buffer if the application has requested bracketed paste mode.
|
buffer if the application has requested bracketed paste mode.
|
||||||
.It Xo Ic save-buffer
|
.It Xo Ic save-buffer
|
||||||
.Op Fl a
|
.Op Fl a
|
||||||
.Op Fl b Ar buffer-index
|
.Op Fl b Ar buffer-name
|
||||||
.Ar path
|
.Ar path
|
||||||
.Xc
|
.Xc
|
||||||
.D1 (alias: Ic saveb )
|
.D1 (alias: Ic saveb )
|
||||||
@ -3473,7 +3491,8 @@ The
|
|||||||
option appends to rather than overwriting the file.
|
option appends to rather than overwriting the file.
|
||||||
.It Xo Ic set-buffer
|
.It Xo Ic set-buffer
|
||||||
.Op Fl a
|
.Op Fl a
|
||||||
.Op Fl b Ar buffer-index
|
.Op Fl b Ar buffer-name
|
||||||
|
.Op Fl n Ar new-buffer-name
|
||||||
.Ar data
|
.Ar data
|
||||||
.Xc
|
.Xc
|
||||||
.D1 (alias: Ic setb )
|
.D1 (alias: Ic setb )
|
||||||
@ -3482,8 +3501,12 @@ Set the contents of the specified buffer to
|
|||||||
The
|
The
|
||||||
.Fl a
|
.Fl a
|
||||||
option appends to rather than overwriting the buffer.
|
option appends to rather than overwriting the buffer.
|
||||||
|
The
|
||||||
|
.Fl n
|
||||||
|
option renames the buffer to
|
||||||
|
.Ar new-buffer-name .
|
||||||
.It Xo Ic show-buffer
|
.It Xo Ic show-buffer
|
||||||
.Op Fl b Ar buffer-index
|
.Op Fl b Ar buffer-name
|
||||||
.Xc
|
.Xc
|
||||||
.D1 (alias: Ic showb )
|
.D1 (alias: Ic showb )
|
||||||
Display the contents of the specified buffer.
|
Display the contents of the specified buffer.
|
||||||
|
25
tmux.h
25
tmux.h
@ -85,7 +85,7 @@ extern char **environ;
|
|||||||
|
|
||||||
/* Default template for choose-buffer. */
|
/* Default template for choose-buffer. */
|
||||||
#define CHOOSE_BUFFER_TEMPLATE \
|
#define CHOOSE_BUFFER_TEMPLATE \
|
||||||
"#{line}: #{buffer_size} bytes: #{buffer_sample}"
|
"#{buffer_name}: #{buffer_size} bytes: #{buffer_sample}"
|
||||||
|
|
||||||
/* Default template for choose-client. */
|
/* Default template for choose-client. */
|
||||||
#define CHOOSE_CLIENT_TEMPLATE \
|
#define CHOOSE_CLIENT_TEMPLATE \
|
||||||
@ -118,7 +118,8 @@ extern char **environ;
|
|||||||
|
|
||||||
/* Default template for list-buffers. */
|
/* Default template for list-buffers. */
|
||||||
#define LIST_BUFFERS_TEMPLATE \
|
#define LIST_BUFFERS_TEMPLATE \
|
||||||
"#{line}: #{buffer_size} bytes: \"#{buffer_sample}\""
|
"#{buffer_name}: #{buffer_size} bytes: " \
|
||||||
|
"\"#{buffer_sample}\""
|
||||||
|
|
||||||
/* Default template for list-clients. */
|
/* Default template for list-clients. */
|
||||||
#define LIST_CLIENTS_TEMPLATE \
|
#define LIST_CLIENTS_TEMPLATE \
|
||||||
@ -1036,6 +1037,13 @@ struct layout_cell {
|
|||||||
struct paste_buffer {
|
struct paste_buffer {
|
||||||
char *data;
|
char *data;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|
||||||
|
char *name;
|
||||||
|
int automatic;
|
||||||
|
u_int order;
|
||||||
|
|
||||||
|
RB_ENTRY(paste_buffer) name_entry;
|
||||||
|
RB_ENTRY(paste_buffer) time_entry;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Environment variable. */
|
/* Environment variable. */
|
||||||
@ -1499,7 +1507,7 @@ RB_HEAD(format_tree, format_entry);
|
|||||||
#define CMD_SRCDST_WINDOW_USAGE "[-s src-window] [-t dst-window]"
|
#define CMD_SRCDST_WINDOW_USAGE "[-s src-window] [-t dst-window]"
|
||||||
#define CMD_SRCDST_SESSION_USAGE "[-s src-session] [-t dst-session]"
|
#define CMD_SRCDST_SESSION_USAGE "[-s src-session] [-t dst-session]"
|
||||||
#define CMD_SRCDST_CLIENT_USAGE "[-s src-client] [-t dst-client]"
|
#define CMD_SRCDST_CLIENT_USAGE "[-s src-client] [-t dst-client]"
|
||||||
#define CMD_BUFFER_USAGE "[-b buffer-index]"
|
#define CMD_BUFFER_USAGE "[-b buffer-name]"
|
||||||
|
|
||||||
/* tmux.c */
|
/* tmux.c */
|
||||||
extern struct options global_options;
|
extern struct options global_options;
|
||||||
@ -1711,13 +1719,14 @@ void tty_keys_free(struct tty *);
|
|||||||
int tty_keys_next(struct tty *);
|
int tty_keys_next(struct tty *);
|
||||||
|
|
||||||
/* paste.c */
|
/* paste.c */
|
||||||
struct paste_buffer *paste_walk_stack(u_int *);
|
struct paste_buffer *paste_walk(struct paste_buffer *);
|
||||||
struct paste_buffer *paste_get_top(void);
|
struct paste_buffer *paste_get_top(void);
|
||||||
struct paste_buffer *paste_get_index(u_int);
|
struct paste_buffer *paste_get_name(const char *);
|
||||||
int paste_free_top(void);
|
int paste_free_top(void);
|
||||||
int paste_free_index(u_int);
|
int paste_free_name(const char *);
|
||||||
void paste_add(char *, size_t, u_int);
|
void paste_add(char *, size_t);
|
||||||
int paste_replace(u_int, char *, size_t);
|
int paste_rename(const char *, const char *, char **);
|
||||||
|
int paste_set(char *, size_t, const char *, char **);
|
||||||
char *paste_make_sample(struct paste_buffer *, int);
|
char *paste_make_sample(struct paste_buffer *, int);
|
||||||
void paste_send_pane(struct paste_buffer *, struct window_pane *,
|
void paste_send_pane(struct paste_buffer *, struct window_pane *,
|
||||||
const char *, int);
|
const char *, int);
|
||||||
|
@ -54,11 +54,12 @@ 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);
|
int window_copy_update_selection(struct window_pane *, int);
|
||||||
void *window_copy_get_selection(struct window_pane *, size_t *);
|
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_buffer(struct window_pane *, const char *, void *,
|
||||||
void window_copy_copy_pipe(
|
size_t);
|
||||||
struct window_pane *, struct session *, int, const char *);
|
void window_copy_copy_pipe(struct window_pane *, struct session *,
|
||||||
void window_copy_copy_selection(struct window_pane *, int);
|
const char *, const char *);
|
||||||
void window_copy_append_selection(struct window_pane *, int);
|
void window_copy_copy_selection(struct window_pane *, const char *);
|
||||||
|
void window_copy_append_selection(struct window_pane *, const char *);
|
||||||
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(
|
||||||
struct window_pane *, char **, size_t *, u_int, u_int, u_int);
|
struct window_pane *, char **, size_t *, u_int, u_int, u_int);
|
||||||
@ -417,7 +418,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
|
|||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case MODEKEYCOPY_APPENDSELECTION:
|
case MODEKEYCOPY_APPENDSELECTION:
|
||||||
if (sess != NULL) {
|
if (sess != NULL) {
|
||||||
window_copy_append_selection(wp, data->numprefix);
|
window_copy_append_selection(wp, NULL);
|
||||||
window_pane_reset_mode(wp);
|
window_pane_reset_mode(wp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -543,7 +544,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
|
|||||||
if (sess != NULL &&
|
if (sess != NULL &&
|
||||||
(cmd == MODEKEYCOPY_COPYLINE ||
|
(cmd == MODEKEYCOPY_COPYLINE ||
|
||||||
cmd == MODEKEYCOPY_COPYENDOFLINE)) {
|
cmd == MODEKEYCOPY_COPYENDOFLINE)) {
|
||||||
window_copy_copy_selection(wp, -1);
|
window_copy_copy_selection(wp, NULL);
|
||||||
window_pane_reset_mode(wp);
|
window_pane_reset_mode(wp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -554,14 +555,14 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
|
|||||||
break;
|
break;
|
||||||
case MODEKEYCOPY_COPYPIPE:
|
case MODEKEYCOPY_COPYPIPE:
|
||||||
if (sess != NULL) {
|
if (sess != NULL) {
|
||||||
window_copy_copy_pipe(wp, sess, data->numprefix, arg);
|
window_copy_copy_pipe(wp, sess, NULL, arg);
|
||||||
window_pane_reset_mode(wp);
|
window_pane_reset_mode(wp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
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, NULL);
|
||||||
window_pane_reset_mode(wp);
|
window_pane_reset_mode(wp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -918,7 +919,7 @@ reset_mode:
|
|||||||
s->mode &= ~MODE_MOUSE_BUTTON;
|
s->mode &= ~MODE_MOUSE_BUTTON;
|
||||||
s->mode |= MODE_MOUSE_STANDARD;
|
s->mode |= MODE_MOUSE_STANDARD;
|
||||||
if (sess != NULL) {
|
if (sess != NULL) {
|
||||||
window_copy_copy_selection(wp, -1);
|
window_copy_copy_selection(wp, NULL);
|
||||||
window_pane_reset_mode(wp);
|
window_pane_reset_mode(wp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1452,9 +1453,9 @@ window_copy_get_selection(struct window_pane *wp, size_t *len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
window_copy_copy_buffer(struct window_pane *wp, int idx, void *buf, size_t len)
|
window_copy_copy_buffer(struct window_pane *wp, const char *bufname, void *buf,
|
||||||
|
size_t len)
|
||||||
{
|
{
|
||||||
u_int limit;
|
|
||||||
struct screen_write_ctx ctx;
|
struct screen_write_ctx ctx;
|
||||||
|
|
||||||
if (options_get_number(&global_options, "set-clipboard")) {
|
if (options_get_number(&global_options, "set-clipboard")) {
|
||||||
@ -1463,16 +1464,13 @@ window_copy_copy_buffer(struct window_pane *wp, int idx, void *buf, size_t len)
|
|||||||
screen_write_stop(&ctx);
|
screen_write_stop(&ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (idx == -1) {
|
if (paste_set(buf, len, bufname, NULL) != 0)
|
||||||
limit = options_get_number(&global_options, "buffer-limit");
|
|
||||||
paste_add(buf, len, limit);
|
|
||||||
} else if (paste_replace(idx, buf, len) != 0)
|
|
||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
window_copy_copy_pipe(
|
window_copy_copy_pipe(struct window_pane *wp, struct session *sess,
|
||||||
struct window_pane *wp, struct session *sess, int idx, const char *arg)
|
const char *bufname, const char *arg)
|
||||||
{
|
{
|
||||||
void *buf;
|
void *buf;
|
||||||
size_t len;
|
size_t len;
|
||||||
@ -1486,11 +1484,11 @@ window_copy_copy_pipe(
|
|||||||
job = job_run(arg, sess, NULL, NULL, NULL);
|
job = job_run(arg, sess, NULL, NULL, NULL);
|
||||||
bufferevent_write(job->event, buf, len);
|
bufferevent_write(job->event, buf, len);
|
||||||
|
|
||||||
window_copy_copy_buffer(wp, idx, buf, len);
|
window_copy_copy_buffer(wp, bufname, buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
window_copy_copy_selection(struct window_pane *wp, int idx)
|
window_copy_copy_selection(struct window_pane *wp, const char *bufname)
|
||||||
{
|
{
|
||||||
void* buf;
|
void* buf;
|
||||||
size_t len;
|
size_t len;
|
||||||
@ -1499,17 +1497,16 @@ window_copy_copy_selection(struct window_pane *wp, int idx)
|
|||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
window_copy_copy_buffer(wp, idx, buf, len);
|
window_copy_copy_buffer(wp, bufname, buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
window_copy_append_selection(struct window_pane *wp, int idx)
|
window_copy_append_selection(struct window_pane *wp, const char *bufname)
|
||||||
{
|
{
|
||||||
char *buf;
|
char *buf;
|
||||||
struct paste_buffer *pb;
|
struct paste_buffer *pb;
|
||||||
size_t len;
|
size_t len;
|
||||||
u_int limit;
|
struct screen_write_ctx ctx;
|
||||||
struct screen_write_ctx ctx;
|
|
||||||
|
|
||||||
buf = window_copy_get_selection(wp, &len);
|
buf = window_copy_get_selection(wp, &len);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
@ -1521,24 +1518,19 @@ window_copy_append_selection(struct window_pane *wp, int idx)
|
|||||||
screen_write_stop(&ctx);
|
screen_write_stop(&ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (idx == -1)
|
if (bufname == NULL || *bufname == '\0') {
|
||||||
idx = 0;
|
pb = paste_get_top();
|
||||||
|
if (pb != NULL)
|
||||||
if (idx == 0 && paste_get_top() == NULL) {
|
bufname = pb->name;
|
||||||
limit = options_get_number(&global_options, "buffer-limit");
|
} else
|
||||||
paste_add(buf, len, limit);
|
pb = paste_get_name(bufname);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pb = paste_get_index(idx);
|
|
||||||
if (pb != NULL) {
|
if (pb != NULL) {
|
||||||
buf = xrealloc(buf, 1, len + pb->size);
|
buf = xrealloc(buf, 1, len + pb->size);
|
||||||
memmove(buf + pb->size, buf, len);
|
memmove(buf + pb->size, buf, len);
|
||||||
memcpy(buf, pb->data, pb->size);
|
memcpy(buf, pb->data, pb->size);
|
||||||
len += pb->size;
|
len += pb->size;
|
||||||
}
|
}
|
||||||
|
if (paste_set(buf, len, bufname, NULL) != 0)
|
||||||
if (paste_replace(idx, buf, len) != 0)
|
|
||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user