I've attached a new patch which drops the buffer_stickiness format and
includes changes to the man page.


On Thu, May 1, 2014 at 5:33 PM, Nicholas Marriott
<nicholas.marri...@gmail.com> wrote:
> Hi
>
> This looks good thanks, but I'd lose the buffer_stickiness format and just add
> buffer_name.
>
> (Even if we want it flag formats should be 0 or 1 so that the #{?,}
> conditional works.)
>
> Also this is going to need some manpage changes.
>
diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c
index 4961463..bbaf70c 100644
--- a/cmd-capture-pane.c
+++ b/cmd-capture-pane.c
@@ -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,23 +191,15 @@ 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);
-			free(buf);
-			free(cause);
-			return (CMD_RETURN_ERROR);
-		}
+		bufname = NULL;
+		if (args_has(args, 'b'))
+			bufname = args_get(args, 'b');
 
-		if (paste_replace(buffer, buf, len) != 0) {
-			cmdq_error(cmdq, "no buffer %d", buffer);
+		if (paste_set(buf, len, bufname, &cause) != 0) {
+			cmdq_error(cmdq, "%s", cause);
 			free(buf);
+			free(cause);
 			return (CMD_RETURN_ERROR);
 		}
 	}
diff --git a/cmd-choose-buffer.c b/cmd-choose-buffer.c
index 18d2834..6b146fa 100644
--- a/cmd-choose-buffer.c
+++ b/cmd-choose-buffer.c
@@ -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);
 
diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c
index 759d578..0acecc5 100644
--- a/cmd-command-prompt.c
+++ b/cmd-command-prompt.c
@@ -76,6 +76,9 @@ cmd_command_prompt_key_binding(struct cmd *self, int key)
 		self->args = args_create(1, "select-window -t ':%%'");
 		args_set(self->args, 'p', "index");
 		break;
+	case 'P':
+		self->args = args_create(1, "paste-buffer -b '%%'");
+		break;
 	default:
 		self->args = args_create(0);
 		break;
diff --git a/cmd-delete-buffer.c b/cmd-delete-buffer.c
index e05fe09..9957de6 100644
--- a/cmd-delete-buffer.c
+++ b/cmd-delete-buffer.c
@@ -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);
 	}
 
diff --git a/cmd-list-buffers.c b/cmd-list-buffers.c
index f3987dd..c5a6e32 100644
--- a/cmd-list-buffers.c
+++ b/cmd-list-buffers.c
@@ -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);
diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c
index 16ff40d..5bc5247 100644
--- a/cmd-load-buffer.c
+++ b/cmd-load-buffer.c
@@ -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;
-
-	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);
-		}
-	}
+	int		 ch, error, cwd, fd;
+
+	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);
+		    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;
+	char		*pdata, *cause;
+	const char	*bufname = data;
+	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);
 }
diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c
index 4bc2cfd..f6c9d0a 100644
--- a/cmd-paste-buffer.c
+++ b/cmd-paste-buffer.c
@@ -35,7 +35,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
@@ -48,31 +48,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);
 		}
 	}
@@ -91,10 +82,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);
diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c
index b5ca62e..8dd52c9 100644
--- a/cmd-save-buffer.c
+++ b/cmd-save-buffer.c
@@ -58,10 +58,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')) {
@@ -70,16 +70,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);
 		}
 	}
diff --git a/cmd-set-buffer.c b/cmd-set-buffer.c
index b0fc3fe..9b8057d 100644
--- a/cmd-set-buffer.c
+++ b/cmd-set-buffer.c
@@ -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] [-n new_buffer_name] " CMD_BUFFER_USAGE " 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);
 }
diff --git a/format.c b/format.c
index 6f988b9..1f17b96 100644
--- a/format.c
+++ b/format.c
@@ -610,6 +610,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);
diff --git a/key-bindings.c b/key-bindings.c
index f725508..6a7d14c 100644
--- a/key-bindings.c
+++ b/key-bindings.c
@@ -130,6 +130,7 @@ key_bindings_init(void)
 		{ '?', 			  0, &cmd_list_keys_entry },
 		{ 'D',			  0, &cmd_choose_client_entry },
 		{ 'L',			  0, &cmd_switch_client_entry },
+		{ 'P',			  0, &cmd_command_prompt_entry },
 		{ '[', 			  0, &cmd_copy_mode_entry },
 		{ '\'',			  0, &cmd_command_prompt_entry },
 		{ '\002', /* C-b */	  0, &cmd_send_prefix_entry },
diff --git a/mode-key.c b/mode-key.c
index 57be2d8..b9ad8e4 100644
--- a/mode-key.c
+++ b/mode-key.c
@@ -51,6 +51,7 @@ const struct mode_key_cmdstr mode_key_cmdstr_edit[] = {
 	{ MODEKEYEDIT_DELETEWORD, "delete-word" },
 	{ MODEKEYEDIT_ENDOFLINE, "end-of-line" },
 	{ MODEKEYEDIT_ENTER, "enter" },
+	{ MODEKEYEDIT_ENTERAPPEND, "enter-append" },
 	{ MODEKEYEDIT_HISTORYDOWN, "history-down" },
 	{ MODEKEYEDIT_HISTORYUP, "history-up" },
 	{ MODEKEYEDIT_NEXTSPACE, "next-space" },
@@ -141,6 +142,7 @@ const struct mode_key_cmdstr mode_key_cmdstr_copy[] = {
 	{ MODEKEYCOPY_SEARCHREVERSE, "search-reverse" },
 	{ MODEKEYCOPY_SEARCHUP, "search-backward" },
 	{ MODEKEYCOPY_SELECTLINE, "select-line" },
+	{ MODEKEYCOPY_STARTNAMEDBUFFER, "start-named-buffer" },
 	{ MODEKEYCOPY_STARTNUMBERPREFIX, "start-number-prefix" },
 	{ MODEKEYCOPY_STARTOFLINE, "start-of-line" },
 	{ MODEKEYCOPY_STARTSELECTION, "begin-selection" },
@@ -160,6 +162,7 @@ const struct mode_key_entry mode_key_vi_edit[] = {
 	{ '\033' /* Escape */,	    0, MODEKEYEDIT_SWITCHMODE },
 	{ '\n',			    0, MODEKEYEDIT_ENTER },
 	{ '\r',			    0, MODEKEYEDIT_ENTER },
+	{ '\001' /* C-a */,	    0, MODEKEYEDIT_ENTERAPPEND },
 	{ KEYC_BSPACE,		    0, MODEKEYEDIT_BACKSPACE },
 	{ KEYC_DC,		    0, MODEKEYEDIT_DELETE },
 	{ KEYC_DOWN,		    0, MODEKEYEDIT_HISTORYDOWN },
@@ -257,6 +260,7 @@ struct mode_key_tree mode_key_tree_vi_choice;
 /* vi copy mode keys. */
 const struct mode_key_entry mode_key_vi_copy[] = {
 	{ ' ',			    0, MODEKEYCOPY_STARTSELECTION },
+	{ '"',			    0, MODEKEYCOPY_STARTNAMEDBUFFER },
 	{ '$',			    0, MODEKEYCOPY_ENDOFLINE },
 	{ ',',			    0, MODEKEYCOPY_JUMPREVERSE },
 	{ ';',			    0, MODEKEYCOPY_JUMPAGAIN },
diff --git a/paste.c b/paste.c
index 0f29b6b..74c30eb 100644
--- a/paste.c
+++ b/paste.c
@@ -19,6 +19,7 @@
 #include <sys/types.h>
 #include <sys/time.h>
 
+#include <ctype.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -29,122 +30,229 @@
  * string!
  */
 
-ARRAY_DECL(, struct paste_buffer *) paste_buffers =  ARRAY_INITIALIZER;
+u_int	paste_unsticky_idx;
+u_int	paste_num_unsticky;
+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;
+	return (strcmp(a->name, b->name));
+}
 
-	pb = paste_get_index(*idx);
-	(*idx)++;
-	return (pb);
+int
+paste_cmp_times(const struct paste_buffer *a, const struct paste_buffer *b)
+{
+	return (a->crtime < b->crtime ? -1 : a->crtime > b->crtime);
 }
 
-/* Get the top item on the stack. */
+/* Walk paste buffers by name. */
 struct paste_buffer *
-paste_get_top(void)
+paste_walk(struct paste_buffer *pb)
 {
-	if (ARRAY_LENGTH(&paste_buffers) == 0)
-		return (NULL);
-	return (ARRAY_FIRST(&paste_buffers));
+	if (pb == NULL)
+		return (RB_MIN(paste_name_tree, &paste_by_name));
+	return (RB_NEXT(paste_name_tree, &paste_by_name, pb));
 }
 
-/* Get an item by its index. */
+/* Get the most recent unsticky buffer */
 struct paste_buffer *
-paste_get_index(u_int idx)
+paste_get_top(void)
 {
-	if (idx >= ARRAY_LENGTH(&paste_buffers))
-		return (NULL);
-	return (ARRAY_ITEM(&paste_buffers, idx));
+	return (RB_MAX(paste_time_tree, &paste_by_time));
 }
 
-/* Free the top item on the stack. */
+/* Free the most recent unsticky 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. */
+/* Free an item by name. */
 int
-paste_free_index(u_int idx)
+paste_free_name(const char *name)
 {
-	struct paste_buffer	*pb;
+	struct paste_buffer	*pb, pbfind;
 
-	if (idx >= ARRAY_LENGTH(&paste_buffers))
+	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);
+	if (pb->sticky == 0) {
+		RB_REMOVE(paste_time_tree, &paste_by_time, pb);
+		paste_num_unsticky--;
+	}
 
 	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 unsticky buffer, freeing the oldest unsticky 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;
+	u_int			 limit, next_crtime;
 
 	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");
+	while (paste_num_unsticky >= limit) {
+		pb = RB_MIN(paste_time_tree, &paste_by_time);
+		paste_free_name(pb->name);
+	}
+
+	next_crtime = 0;
+	if (paste_num_unsticky > 0) {
+		pb = RB_MAX(paste_time_tree, &paste_by_time);
+		next_crtime = pb->crtime + 1;
 	}
 
 	pb = xmalloc(sizeof *pb);
-	ARRAY_INSERT(&paste_buffers, 0, pb);
+	pb->name = NULL;
+	do {
+		free(pb->name);
+		xasprintf(&pb->name, "buffer%04u", paste_unsticky_idx);
+		paste_unsticky_idx++;
+	} while (paste_get_name(pb->name) != NULL);
 
 	pb->data = data;
 	pb->size = size;
+	pb->sticky = 0;
+	pb->crtime = next_crtime;
+
+	RB_INSERT(paste_name_tree, &paste_by_name, pb);
+	RB_INSERT(paste_time_tree, &paste_by_time, pb);
+	paste_num_unsticky++;
 }
 
+/* Get an item by its name. */
+struct paste_buffer *
+paste_get_name(const char *name)
+{
+	struct paste_buffer	pbfind;
+
+	if (name == NULL || *name == '\0')
+		return (NULL);
+
+	pbfind.name = (char*)name;
+	return (RB_FIND(paste_name_tree, &paste_by_name, &pbfind));
+}
+
+/* Rename a paste buffer. */
+int
+paste_rename(const char *oldname, const char *newname, char **cause)
+{
+	struct paste_buffer	*pb;
+
+	*cause = NULL;
+
+	if (oldname == NULL || *oldname == '\0') {
+		*cause = xstrdup("no buffer");
+		return (-1);
+	}
+
+	if (newname == NULL || *newname == '\0') {
+		*cause = xstrdup("new name is empty");
+		return (-1);
+	}
+
+	if ((pb = paste_get_name(oldname)) == NULL) {
+		xasprintf(cause, "no buffer %s", oldname);
+		return (-1);
+	}
+
+	if (paste_get_name(newname) != NULL) {
+		*cause = xstrdup("buffer with new name already exists");
+		return (-1);
+	}
+
+	RB_REMOVE(paste_name_tree, &paste_by_name, pb);
+	free(pb->name);
+
+	pb->name = xstrdup(newname);
+	RB_INSERT(paste_name_tree, &paste_by_name, pb);
+
+	if (pb->sticky == 0) {
+		RB_REMOVE(paste_time_tree, &paste_by_time, pb);
+		paste_num_unsticky--;
+		pb->sticky = 1;
+	}
+
+	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 (idx >= ARRAY_LENGTH(&paste_buffers))
-		return (-1);
+	if (name == NULL) {
+		paste_add(data, size);
+		return (0);
+	}
 
-	pb = ARRAY_ITEM(&paste_buffers, idx);
-	free(pb->data);
 
+	pb = paste_get_name(name);
+
+	if (pb != NULL) {
+		free(pb->data);
+		pb->data = data;
+		pb->size = size;
+		return (0);
+	}
+
+	if (*name == '\0') {
+		if (cause != NULL)
+			*cause = xstrdup("empty buffer name");
+		return (-1);
+	}
+
+	pb = xmalloc(sizeof *pb);
 	pb->data = data;
 	pb->size = size;
+	pb->name = xstrdup(name);
+	pb->sticky = 1;
+
+	RB_INSERT(paste_name_tree, &paste_by_name, pb);
 
 	return (0);
 }
diff --git a/tmux.1 b/tmux.1
index c05eacf..5cfe518 100644
--- a/tmux.1
+++ b/tmux.1
@@ -271,6 +271,8 @@ Choose which buffer to paste interactively from a list.
 List all key bindings.
 .It D
 Choose a client to detach.
+.It P
+Prompt for a buffer-name to paste.
 .It \&[
 Enter copy mode to copy text or view the history.
 .It \&]
@@ -852,7 +854,9 @@ The following keys are supported as appropriate for the mode:
 .Bl -column "FunctionXXXXXXXXXXXXXXXXX" "viXXXXXXXXXX" "emacs" -offset indent
 .It Sy "Function" Ta Sy "vi" Ta Sy "emacs"
 .It Li "Append selection" Ta "A" Ta ""
+.It Li "Append to named buffer" Ta "C-a" Ta ""
 .It Li "Back to indentation" Ta "^" Ta "M-m"
+.It Li "Begin enter name of buffer" Ta \&" Ta ""
 .It Li "Bottom of history" Ta "G" Ta "M-<"
 .It Li "Clear selection" Ta "Escape" Ta "C-g"
 .It Li "Copy selection" Ta "Enter" Ta "M-w"
@@ -934,9 +938,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
@@ -1094,7 +1095,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
@@ -3371,19 +3372,32 @@ is given, otherwise the active pane for the session attached to
 .El
 .Sh BUFFERS
 .Nm
-maintains a stack of
-.Em paste buffers .
-Up to the value of the
+maintains a list of
+.Em paste buffers ,
+with each buffer having a name.  If a buffer name is not specified at the time
+the buffer is created, the buffer is automatically given a name of the form
+bufferXXXX, where XXXX is a number.  The first such buffer would be buffer0000,
+the 2nd buffer0001, etc.  Up to the value of the
+.Ic buffer-limit
+option auto-named buffers are kept; when a new auto-named buffer is added,
+the oldest is removed.
+.Pp
+Buffers that are explicitly given a name when they are created are not subject
+to the
+.Ic buffer-limit .
+There can be an unlimited number of such buffers, and they must be explicitly
+deleted.  If an auto-named buffer is renamed, it ceases to be subject to the
 .Ic buffer-limit
-option are kept; when a new buffer is added, the buffer at the bottom of the
-stack is removed.
+setting, and must be explicitly deleted.
+.Pp
 Buffers may be added using
 .Ic copy-mode
 or the
 .Ic set-buffer
 command, and pasted into a window using the
 .Ic paste-buffer
-command.
+command.  If a buffer command is entered and no buffer is specified, the most
+recently added auto-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
@@ -3404,7 +3418,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
@@ -3419,11 +3433,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 auto-named buffer if not specified.
 .It Xo Ic list-buffers
 .Op Fl F Ar format
 .Xc
@@ -3435,7 +3449,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 )
@@ -3443,7 +3457,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
@@ -3452,7 +3466,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
@@ -3467,7 +3481,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 )
@@ -3478,7 +3492,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 )
@@ -3486,9 +3501,17 @@ Set the contents of the specified buffer to
 .Ar data .
 The
 .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 .
+Do not specify
+.Ar data
+with the
+.Fl n
+flag.
 .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.
diff --git a/tmux.h b/tmux.h
index fde94af..fa1c7b3 100644
--- a/tmux.h
+++ b/tmux.h
@@ -82,7 +82,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					\
@@ -115,7 +115,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					\
@@ -496,6 +497,7 @@ enum mode_key_cmd {
 	MODEKEYEDIT_DELETEWORD,
 	MODEKEYEDIT_ENDOFLINE,
 	MODEKEYEDIT_ENTER,
+	MODEKEYEDIT_ENTERAPPEND,
 	MODEKEYEDIT_HISTORYDOWN,
 	MODEKEYEDIT_HISTORYUP,
 	MODEKEYEDIT_NEXTSPACE,
@@ -579,6 +581,7 @@ enum mode_key_cmd {
 	MODEKEYCOPY_SEARCHREVERSE,
 	MODEKEYCOPY_SEARCHUP,
 	MODEKEYCOPY_SELECTLINE,
+	MODEKEYCOPY_STARTNAMEDBUFFER,
 	MODEKEYCOPY_STARTNUMBERPREFIX,
 	MODEKEYCOPY_STARTOFLINE,
 	MODEKEYCOPY_STARTSELECTION,
@@ -1032,7 +1035,13 @@ struct layout_cell {
 /* Paste buffer. */
 struct paste_buffer {
 	char		*data;
+	char		*name;
+	u_char		 sticky;
 	size_t		 size;
+	u_int		 crtime;
+
+	RB_ENTRY(paste_buffer) name_entry;
+	RB_ENTRY(paste_buffer) time_entry;
 };
 
 /* Environment variable. */
@@ -1493,7 +1502,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;
@@ -1705,13 +1714,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);
diff --git a/window-copy.c b/window-copy.c
index 508001d..38364d3 100644
--- a/window-copy.c
+++ b/window-copy.c
@@ -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_buffer(
+	    struct window_pane *, const char *, 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);
+	    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);
@@ -94,6 +95,7 @@ const struct window_mode window_copy_mode = {
 
 enum window_copy_input_type {
 	WINDOW_COPY_OFF,
+	WINDOW_COPY_NAMEDBUFFER,
 	WINDOW_COPY_NUMERICPREFIX,
 	WINDOW_COPY_SEARCHUP,
 	WINDOW_COPY_SEARCHDOWN,
@@ -417,7 +419,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 +545,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 +556,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;
 		}
@@ -676,6 +678,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
 		case WINDOW_COPY_JUMPBACK:
 		case WINDOW_COPY_JUMPTOFORWARD:
 		case WINDOW_COPY_JUMPTOBACK:
+		case WINDOW_COPY_NAMEDBUFFER:
 		case WINDOW_COPY_NUMERICPREFIX:
 			break;
 		case WINDOW_COPY_SEARCHUP:
@@ -711,6 +714,11 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
 		data->inputprompt = "Goto Line";
 		*data->inputstr = '\0';
 		goto input_on;
+	case MODEKEYCOPY_STARTNAMEDBUFFER:
+		data->inputtype = WINDOW_COPY_NAMEDBUFFER;
+		data->inputprompt = "Buffer";
+		*data->inputstr = '\0';
+		goto input_on;
 	case MODEKEYCOPY_STARTNUMBERPREFIX:
 		key &= KEYC_MASK_KEY;
 		if (key >= '0' && key <= '9') {
@@ -814,6 +822,11 @@ window_copy_key_input(struct window_pane *wp, int key)
 			data->searchtype = data->inputtype;
 			data->searchstr = xstrdup(data->inputstr);
 			break;
+		case WINDOW_COPY_NAMEDBUFFER:
+			window_copy_copy_selection(wp, data->inputstr);
+			*data->inputstr = '\0';
+			window_pane_reset_mode(wp);
+			return (0);
 		case WINDOW_COPY_GOTOLINE:
 			window_copy_goto_line(wp, data->inputstr);
 			*data->inputstr = '\0';
@@ -821,6 +834,17 @@ window_copy_key_input(struct window_pane *wp, int key)
 		}
 		data->numprefix = -1;
 		return (1);
+	case MODEKEYEDIT_ENTERAPPEND:
+		switch (data->inputtype) {
+		case WINDOW_COPY_NAMEDBUFFER:
+			window_copy_append_selection(wp, data->inputstr);
+			*data->inputstr = '\0';
+			window_pane_reset_mode(wp);
+			return (0);
+		default:
+			break;
+		}
+		break;
 	case MODEKEY_OTHER:
 		if (key < 32 || key > 126)
 			break;
@@ -918,7 +942,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,10 +1476,10 @@ 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;
+	struct screen_write_ctx		 ctx;
 
 	if (options_get_number(&global_options, "set-clipboard")) {
 		screen_write_start(&ctx, wp, NULL);
@@ -1463,16 +1487,15 @@ 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);
+
+	return;
 }
 
 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 +1509,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 +1522,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 +1543,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);
 }
 
------------------------------------------------------------------------------
"Accelerate Dev Cycles with Automated Cross-Browser Testing - For FREE
Instantly run your Selenium tests across 300+ browser/OS combos.  Get 
unparalleled scalability from the best Selenium testing platform available.
Simple to use. Nothing to install. Get started now for free."
http://p.sf.net/sfu/SauceLabs
_______________________________________________
tmux-users mailing list
tmux-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/tmux-users

Reply via email to