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:
nicm 2014-05-13 07:34:35 +00:00
parent f4ffaf5a7f
commit 3dbacbb62b
13 changed files with 353 additions and 248 deletions

View File

@ -38,7 +38,7 @@ char *cmd_capture_pane_history(struct args *, struct cmd_q *,
const struct cmd_entry cmd_capture_pane_entry = {
"capture-pane", "capturep",
"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,
0,
NULL,
@ -165,8 +165,7 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_q *cmdq)
struct client *c;
struct window_pane *wp;
char *buf, *cause;
int buffer;
u_int limit;
const char *bufname;
size_t len;
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);
server_push_stdout(c);
} 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);
if (cause != NULL) {
cmdq_error(cmdq, "buffer %s", cause);
bufname = NULL;
if (args_has(args, 'b'))
bufname = args_get(args, 'b');
if (paste_set(buf, len, bufname, &cause) != 0) {
cmdq_error(cmdq, "%s", cause);
free(buf);
free(cause);
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);

View File

@ -75,19 +75,20 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
action = xstrdup("paste-buffer -b '%%'");
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->idx = idx - 1;
cdata->idx = idx;
cdata->ft_template = xstrdup(template);
format_add(cdata->ft, "line", "%u", idx - 1);
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);
free(action_data);
window_choose_add(wl->window->active, cdata);
idx++;
}
free(action);

View File

@ -41,23 +41,16 @@ enum cmd_retval
cmd_delete_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
char *cause;
int buffer;
const char *bufname;
if (!args_has(args, 'b')) {
paste_free_top();
return (CMD_RETURN_NORMAL);
}
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 (paste_free_index(buffer) != 0) {
cmdq_error(cmdq, "no buffer %d", buffer);
if (paste_free_name(bufname) != 0) {
cmdq_error(cmdq, "no buffer %s", bufname);
return (CMD_RETURN_ERROR);
}

View File

@ -44,17 +44,15 @@ cmd_list_buffers_exec(unused struct cmd *self, struct cmd_q *cmdq)
struct args *args = self->args;
struct paste_buffer *pb;
struct format_tree *ft;
u_int idx;
char *line;
const char *template;
if ((template = args_get(args, 'F')) == NULL)
template = LIST_BUFFERS_TEMPLATE;
idx = 0;
while ((pb = paste_walk_stack(&idx)) != NULL) {
pb = NULL;
while ((pb = paste_walk(pb)) != NULL) {
ft = format_create();
format_add(ft, "line", "%u", idx - 1);
format_paste_buffer(ft, pb, 0);
line = format_expand(ft, template);

View File

@ -50,30 +50,19 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
struct client *c = cmdq->client;
struct session *s;
FILE *f;
const char *path;
const char *path, *bufname;
char *pdata, *new_pdata, *cause;
size_t psize;
u_int limit;
int ch, error, buffer, *buffer_ptr, cwd, fd;
int ch, error, cwd, fd;
if (!args_has(args, 'b'))
buffer = -1;
else {
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
if (cause != NULL) {
cmdq_error(cmdq, "buffer %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
bufname = NULL;
if (args_has(args, 'b'))
bufname = args_get(args, 'b');
path = args->argv[0];
if (strcmp(path, "-") == 0) {
buffer_ptr = xmalloc(sizeof *buffer_ptr);
*buffer_ptr = buffer;
error = server_set_stdin_callback(c, cmd_load_buffer_callback,
buffer_ptr, &cause);
(void*)bufname, &cause);
if (error != 0) {
cmdq_error(cmdq, "%s: %s", path, cause);
free(cause);
@ -117,14 +106,10 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
fclose(f);
limit = options_get_number(&global_options, "buffer-limit");
if (buffer == -1) {
paste_add(pdata, psize, limit);
return (CMD_RETURN_NORMAL);
}
if (paste_replace(buffer, pdata, psize) != 0) {
cmdq_error(cmdq, "no buffer %d", buffer);
if (paste_set(pdata, psize, bufname, &cause) != 0) {
cmdq_error(cmdq, "%s", cause);
free(pdata);
free(cause);
return (CMD_RETURN_ERROR);
}
@ -140,10 +125,9 @@ error:
void
cmd_load_buffer_callback(struct client *c, int closed, void *data)
{
int *buffer = data;
char *pdata;
size_t psize;
u_int limit;
const char *bufname = data;
char *pdata, *cause;
size_t psize;
if (!closed)
return;
@ -154,26 +138,21 @@ cmd_load_buffer_callback(struct client *c, int closed, void *data)
return;
psize = EVBUFFER_LENGTH(c->stdin_data);
if (psize == 0 || (pdata = malloc(psize + 1)) == NULL) {
free(data);
if (psize == 0 || (pdata = malloc(psize + 1)) == NULL)
goto out;
}
memcpy(pdata, EVBUFFER_DATA(c->stdin_data), psize);
pdata[psize] = '\0';
evbuffer_drain(c->stdin_data, psize);
limit = options_get_number(&global_options, "buffer-limit");
if (*buffer == -1)
paste_add(pdata, psize, limit);
else if (paste_replace(*buffer, pdata, psize) != 0) {
if (paste_set(pdata, psize, bufname, &cause) != 0) {
/* 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);
free(pdata);
free(cause);
}
free(data);
out:
cmdq_continue(c->cmdq);
}

View File

@ -36,7 +36,7 @@ void cmd_paste_buffer_filter(struct window_pane *,
const struct cmd_entry cmd_paste_buffer_entry = {
"paste-buffer", "pasteb",
"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,
NULL,
cmd_paste_buffer_exec
@ -49,31 +49,22 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
struct window_pane *wp;
struct session *s;
struct paste_buffer *pb;
const char *sepstr;
char *cause;
int buffer;
const char *sepstr, *bufname;
int pflag;
if (cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp) == NULL)
return (CMD_RETURN_ERROR);
if (!args_has(args, 'b'))
buffer = -1;
else {
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
if (cause != NULL) {
cmdq_error(cmdq, "buffer %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
bufname = NULL;
if (args_has(args, 'b'))
bufname = args_get(args, 'b');
if (buffer == -1)
if (bufname == NULL)
pb = paste_get_top();
else {
pb = paste_get_index(buffer);
pb = paste_get_name(bufname);
if (pb == NULL) {
cmdq_error(cmdq, "no buffer %d", buffer);
cmdq_error(cmdq, "no buffer %s", bufname);
return (CMD_RETURN_ERROR);
}
}
@ -92,10 +83,10 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
/* Delete the buffer if -d. */
if (args_has(args, 'd')) {
if (buffer == -1)
if (bufname == NULL)
paste_free_top();
else
paste_free_index(buffer);
paste_free_name(bufname);
}
return (CMD_RETURN_NORMAL);

View File

@ -59,10 +59,10 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
struct client *c = cmdq->client;
struct session *s;
struct paste_buffer *pb;
const char *path;
char *cause, *start, *end, *msg;
const char *path, *bufname;
char *start, *end, *msg;
size_t size, used, msglen;
int cwd, fd, buffer;
int cwd, fd;
FILE *f;
if (!args_has(args, 'b')) {
@ -71,16 +71,10 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_ERROR);
}
} else {
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
if (cause != NULL) {
cmdq_error(cmdq, "buffer %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
pb = paste_get_index(buffer);
bufname = args_get(args, 'b');
pb = paste_get_name(bufname);
if (pb == NULL) {
cmdq_error(cmdq, "no buffer %d", buffer);
cmdq_error(cmdq, "no buffer %s", bufname);
return (CMD_RETURN_ERROR);
}
}

View File

@ -31,8 +31,8 @@ enum cmd_retval cmd_set_buffer_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_set_buffer_entry = {
"set-buffer", "setb",
"ab:", 1, 1,
"[-a] " CMD_BUFFER_USAGE " data",
"ab:n:", 0, 1,
"[-a] " CMD_BUFFER_USAGE " [-n new-buffer-name] data",
0,
NULL,
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 paste_buffer *pb;
u_int limit;
char *pdata, *cause;
const char *bufname;
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;
pdata = NULL;
pb = NULL;
buffer = -1;
if ((newsize = strlen(args->argv[0])) == 0)
return (CMD_RETURN_NORMAL);
if (args_has(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);
}
pb = paste_get_index(buffer);
if (pb == NULL) {
cmdq_error(cmdq, "no buffer %d", buffer);
return (CMD_RETURN_ERROR);
}
bufname = args_get(args, 'b');
pb = paste_get_name(bufname);
} else if (args_has(args, 'a')) {
pb = paste_get_top();
if (pb != NULL)
buffer = 0;
bufname = pb->name;
}
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);
psize += newsize;
if (buffer == -1)
paste_add(pdata, psize, limit);
else
paste_replace(buffer, pdata, psize);
if (paste_set(pdata, psize, bufname, &cause) != 0) {
cmdq_error(cmdq, "%s", cause);
free(pdata);
free(cause);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
}

View File

@ -608,6 +608,7 @@ format_paste_buffer(struct format_tree *ft, struct paste_buffer *pb,
char *s;
format_add(ft, "buffer_size", "%zu", pb->size);
format_add(ft, "buffer_name", "%s", pb->name);
s = paste_make_sample(pb, utf8flag);
format_add(ft, "buffer_sample", "%s", s);

218
paste.c
View File

@ -26,127 +26,237 @@
#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!
*/
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. */
struct paste_buffer *
paste_walk_stack(u_int *idx)
int paste_cmp_names(const struct paste_buffer *, const struct paste_buffer *);
RB_PROTOTYPE(paste_name_tree, paste_buffer, name_entry, paste_cmp_names);
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;
pb = paste_get_index(*idx);
(*idx)++;
return (pb);
return (strcmp(a->name, b->name));
}
/* 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 *
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 (ARRAY_FIRST(&paste_buffers));
return (pb);
}
/* Get an item by its index. */
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. */
/* Free the most recent buffer */
int
paste_free_top(void)
{
struct paste_buffer *pb;
if (ARRAY_LENGTH(&paste_buffers) == 0)
pb = paste_get_top();
if (pb == NULL)
return (-1);
pb = ARRAY_FIRST(&paste_buffers);
ARRAY_REMOVE(&paste_buffers, 0);
free(pb->data);
free(pb);
return (0);
return (paste_free_name(pb->name));
}
/* Free an item by index. */
int
paste_free_index(u_int idx)
/* Get a paste buffer by name. */
struct paste_buffer *
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);
pb = ARRAY_ITEM(&paste_buffers, idx);
ARRAY_REMOVE(&paste_buffers, idx);
pbfind.name = (char*)name;
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->name);
free(pb);
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.
*/
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)
return;
while (ARRAY_LENGTH(&paste_buffers) >= limit) {
pb = ARRAY_LAST(&paste_buffers);
free(pb->data);
free(pb);
ARRAY_TRUNC(&paste_buffers, 1);
limit = options_get_number(&global_options, "buffer-limit");
RB_FOREACH_REVERSE_SAFE(pb, paste_time_tree, &paste_by_time, pb1) {
if (paste_num_automatic < limit)
break;
if (pb->automatic)
paste_free_name(pb->name);
}
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->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.
*/
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;
if (cause != NULL)
*cause = NULL;
if (size == 0) {
free(data);
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);
}
pb = ARRAY_ITEM(&paste_buffers, idx);
free(pb->data);
pb = paste_get_name(name);
if (pb != NULL)
paste_free_name(name);
pb = xmalloc(sizeof *pb);
pb->name = xstrdup(name);
pb->data = data;
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);
}

63
tmux.1
View File

@ -930,9 +930,6 @@ in emacs mode, and
.Ql 10w
in vi.
.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:
.Em vi-edit
and
@ -1090,7 +1087,7 @@ but a different format may be specified with
.Fl F .
.It Xo Ic capture-pane
.Op Fl aepPq
.Op Fl b Ar buffer-index
.Op Fl b Ar buffer-name
.Op Fl E Ar end-line
.Op Fl S Ar start-line
.Op Fl t Ar target-pane
@ -3366,19 +3363,40 @@ is given, otherwise the active pane for the session attached to
.El
.Sh BUFFERS
.Nm
maintains a stack of
maintains a set of named
.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
option are kept; when a new buffer is added, the buffer at the bottom of the
stack is removed.
option is reached, the oldest automatically named buffer is deleted.
Explicitly named are not subject to
.Ic buffer-limit
and may be deleted with
.Ic delete-buffer
command.
.Pp
Buffers may be added using
.Ic copy-mode
or the
.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
command.
If a buffer command is used and no buffer is specified, the most
recently added automatically named buffer is assumed.
.Pp
A configurable history buffer is also maintained for each window.
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.
After a buffer is selected,
.Ql %%
is replaced by the buffer index in
is replaced by the buffer name in
.Ar template
and the result executed as a command.
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
.D1 (alias: Ic clearhist )
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 )
Delete the buffer at
.Ar buffer-index ,
or the top buffer if not specified.
Delete the buffer named
.Ar buffer-name ,
or the most recently added automatically named buffer if not specified.
.It Xo Ic list-buffers
.Op Fl F Ar format
.Xc
@ -3430,7 +3448,7 @@ flag, see the
.Sx FORMATS
section.
.It Xo Ic load-buffer
.Op Fl b Ar buffer-index
.Op Fl b Ar buffer-name
.Ar path
.Xc
.D1 (alias: Ic loadb )
@ -3438,7 +3456,7 @@ Load the contents of the specified paste buffer from
.Ar path .
.It Xo Ic paste-buffer
.Op Fl dpr
.Op Fl b Ar buffer-index
.Op Fl b Ar buffer-name
.Op Fl s Ar separator
.Op Fl t Ar target-pane
.Xc
@ -3447,7 +3465,7 @@ Insert the contents of a paste buffer into the specified pane.
If not specified, paste into the current one.
With
.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
a separator, by default carriage return (CR).
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.
.It Xo Ic save-buffer
.Op Fl a
.Op Fl b Ar buffer-index
.Op Fl b Ar buffer-name
.Ar path
.Xc
.D1 (alias: Ic saveb )
@ -3473,7 +3491,8 @@ The
option appends to rather than overwriting the file.
.It Xo Ic set-buffer
.Op Fl a
.Op Fl b Ar buffer-index
.Op Fl b Ar buffer-name
.Op Fl n Ar new-buffer-name
.Ar data
.Xc
.D1 (alias: Ic setb )
@ -3482,8 +3501,12 @@ Set the contents of the specified buffer to
The
.Fl a
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
.Op Fl b Ar buffer-index
.Op Fl b Ar buffer-name
.Xc
.D1 (alias: Ic showb )
Display the contents of the specified buffer.

25
tmux.h
View File

@ -85,7 +85,7 @@ extern char **environ;
/* Default template for choose-buffer. */
#define CHOOSE_BUFFER_TEMPLATE \
"#{line}: #{buffer_size} bytes: #{buffer_sample}"
"#{buffer_name}: #{buffer_size} bytes: #{buffer_sample}"
/* Default template for choose-client. */
#define CHOOSE_CLIENT_TEMPLATE \
@ -118,7 +118,8 @@ extern char **environ;
/* Default template for list-buffers. */
#define LIST_BUFFERS_TEMPLATE \
"#{line}: #{buffer_size} bytes: \"#{buffer_sample}\""
"#{buffer_name}: #{buffer_size} bytes: " \
"\"#{buffer_sample}\""
/* Default template for list-clients. */
#define LIST_CLIENTS_TEMPLATE \
@ -1036,6 +1037,13 @@ struct layout_cell {
struct paste_buffer {
char *data;
size_t size;
char *name;
int automatic;
u_int order;
RB_ENTRY(paste_buffer) name_entry;
RB_ENTRY(paste_buffer) time_entry;
};
/* 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_SESSION_USAGE "[-s src-session] [-t dst-session]"
#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 */
extern struct options global_options;
@ -1711,13 +1719,14 @@ void tty_keys_free(struct tty *);
int tty_keys_next(struct tty *);
/* 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_index(u_int);
struct paste_buffer *paste_get_name(const char *);
int paste_free_top(void);
int paste_free_index(u_int);
void paste_add(char *, size_t, u_int);
int paste_replace(u_int, char *, size_t);
int paste_free_name(const char *);
void paste_add(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);
void paste_send_pane(struct paste_buffer *, struct window_pane *,
const char *, int);

View File

@ -54,11 +54,12 @@ 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 *, int);
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 *, struct session *, int, const char *);
void window_copy_copy_selection(struct window_pane *, int);
void window_copy_append_selection(struct window_pane *, int);
void window_copy_copy_buffer(struct window_pane *, const char *, void *,
size_t);
void window_copy_copy_pipe(struct window_pane *, struct session *,
const char *, const char *);
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_copy_line(
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) {
case MODEKEYCOPY_APPENDSELECTION:
if (sess != NULL) {
window_copy_append_selection(wp, data->numprefix);
window_copy_append_selection(wp, NULL);
window_pane_reset_mode(wp);
return;
}
@ -543,7 +544,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
if (sess != NULL &&
(cmd == MODEKEYCOPY_COPYLINE ||
cmd == MODEKEYCOPY_COPYENDOFLINE)) {
window_copy_copy_selection(wp, -1);
window_copy_copy_selection(wp, NULL);
window_pane_reset_mode(wp);
return;
}
@ -554,14 +555,14 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
break;
case MODEKEYCOPY_COPYPIPE:
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);
return;
}
break;
case MODEKEYCOPY_COPYSELECTION:
if (sess != NULL) {
window_copy_copy_selection(wp, data->numprefix);
window_copy_copy_selection(wp, NULL);
window_pane_reset_mode(wp);
return;
}
@ -918,7 +919,7 @@ reset_mode:
s->mode &= ~MODE_MOUSE_BUTTON;
s->mode |= MODE_MOUSE_STANDARD;
if (sess != NULL) {
window_copy_copy_selection(wp, -1);
window_copy_copy_selection(wp, NULL);
window_pane_reset_mode(wp);
}
}
@ -1452,9 +1453,9 @@ window_copy_get_selection(struct window_pane *wp, size_t *len)
}
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;
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);
}
if (idx == -1) {
limit = options_get_number(&global_options, "buffer-limit");
paste_add(buf, len, limit);
} else if (paste_replace(idx, buf, len) != 0)
if (paste_set(buf, len, bufname, NULL) != 0)
free(buf);
}
void
window_copy_copy_pipe(
struct window_pane *wp, struct session *sess, int idx, const char *arg)
window_copy_copy_pipe(struct window_pane *wp, struct session *sess,
const char *bufname, const char *arg)
{
void *buf;
size_t len;
@ -1486,11 +1484,11 @@ window_copy_copy_pipe(
job = job_run(arg, sess, NULL, NULL, NULL);
bufferevent_write(job->event, buf, len);
window_copy_copy_buffer(wp, idx, buf, len);
window_copy_copy_buffer(wp, bufname, buf, len);
}
void
window_copy_copy_selection(struct window_pane *wp, int idx)
window_copy_copy_selection(struct window_pane *wp, const char *bufname)
{
void* buf;
size_t len;
@ -1499,17 +1497,16 @@ window_copy_copy_selection(struct window_pane *wp, int idx)
if (buf == NULL)
return;
window_copy_copy_buffer(wp, idx, buf, len);
window_copy_copy_buffer(wp, bufname, buf, len);
}
void
window_copy_append_selection(struct window_pane *wp, int idx)
window_copy_append_selection(struct window_pane *wp, const char *bufname)
{
char *buf;
struct paste_buffer *pb;
size_t len;
u_int limit;
struct screen_write_ctx ctx;
char *buf;
struct paste_buffer *pb;
size_t len;
struct screen_write_ctx ctx;
buf = window_copy_get_selection(wp, &len);
if (buf == NULL)
@ -1521,24 +1518,19 @@ window_copy_append_selection(struct window_pane *wp, int idx)
screen_write_stop(&ctx);
}
if (idx == -1)
idx = 0;
if (idx == 0 && paste_get_top() == NULL) {
limit = options_get_number(&global_options, "buffer-limit");
paste_add(buf, len, limit);
return;
}
pb = paste_get_index(idx);
if (bufname == NULL || *bufname == '\0') {
pb = paste_get_top();
if (pb != NULL)
bufname = pb->name;
} else
pb = paste_get_name(bufname);
if (pb != NULL) {
buf = xrealloc(buf, 1, len + pb->size);
memmove(buf + pb->size, buf, len);
memcpy(buf, pb->data, pb->size);
len += pb->size;
}
if (paste_replace(idx, buf, len) != 0)
if (paste_set(buf, len, bufname, NULL) != 0)
free(buf);
}