I've attached a new patch for named buffers.  There's no longer a
paste stack.  There's a name-tree which stores all the buffers, and a
time-tree which just stores unsticky buffers.  The time-tree only
needs to store unsticky buffers since they're the only ones which can
be aged away.

I was going to use an actual time value for the time-tree, but there
can be duplicate times if you setb quickly, which could happen in a
script, and that would screw things up.  But there's no need to store
a time value.  We just need something that shows relative age, so I
made the crtime field a u_int, and new unsticky buffers have it set 1
higher than the current highest.

There is no most-recent-buffer pointer, which you mentioned before.
Since there's a time-tree, RB_MAX will retrieve the most recent
unsticky buffer, so I saw no need to track it separately.

I've added -s and -u flags to setb to make a buffer sticky or unsticky.

I've also added -n to rename a buffer.  For example:  setb -n newname -b oldname

I've kept the following features from the original patch:

> When in copy mode, pressing the double-quote character allows you to
> enter a buffer name.  Once you've made a selection, typing "myBuf and
> then hitting Enter will save your selection to the buffer named myBuf.
>  You can hit Ctrl-a instead of Enter to append.  Both of these key
> bindings are only set by default in vi mode.

> I added the ability to do prefix-P to more quickly enter a buffer name
> for pasting.
diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c
index e157e3c..2defab0 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,7 +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;
+	const char		*bufname;
 	u_int			 limit;
 	size_t			 len;
 
@@ -193,24 +193,17 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_q *cmdq)
 		server_push_stdout(c);
 	} else {
 		limit = options_get_number(&global_options, "buffer-limit");
-		if (!args_has(args, 'b')) {
-			paste_add(&global_buffers, buf, len, limit);
-			return (CMD_RETURN_NORMAL);
-		}
+		bufname = NULL;
+		if (args_has(args, 'b'))
+			bufname = args_get(args, 'b');
 
-		buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
-		if (cause != NULL) {
-			cmdq_error(cmdq, "buffer %s", cause);
+		if (paste_set(
+		    &global_buffers, buf, len, limit, bufname, &cause) != 0) {
+			cmdq_error(cmdq, "%s", cause);
 			free(buf);
 			free(cause);
 			return (CMD_RETURN_ERROR);
 		}
-
-		if (paste_replace(&global_buffers, buffer, buf, len) != 0) {
-			cmdq_error(cmdq, "no buffer %d", buffer);
-			free(buf);
-			return (CMD_RETURN_ERROR);
-		}
 	}
 
 	return (CMD_RETURN_NORMAL);
diff --git a/cmd-choose-buffer.c b/cmd-choose-buffer.c
index 64edc84..9532f0a 100644
--- a/cmd-choose-buffer.c
+++ b/cmd-choose-buffer.c
@@ -75,19 +75,19 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
 		action = xstrdup("paste-buffer -b '%%'");
 
 	idx = 0;
-	while ((pb = paste_walk_stack(&global_buffers, &idx)) != NULL) {
+	RB_FOREACH(pb, paste_name_tree, &global_buffers.name_tree) {
 		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 b8f55db..436ec25 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(&global_buffers);
 		return (CMD_RETURN_NORMAL);
 	}
 
-	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(&global_buffers, buffer) != 0) {
-		cmdq_error(cmdq, "no buffer %d", buffer);
+	bufname = args_get(args, 'b');
+	if (paste_free_name(&global_buffers, 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 53f6598..8bc4fcb 100644
--- a/cmd-list-buffers.c
+++ b/cmd-list-buffers.c
@@ -44,17 +44,14 @@ 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(&global_buffers, &idx)) != NULL) {
+	RB_FOREACH(pb, paste_name_tree, &global_buffers.name_tree) {
 		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 2cb01b9..3ea6589 100644
--- a/cmd-load-buffer.c
+++ b/cmd-load-buffer.c
@@ -50,30 +50,20 @@ 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);
@@ -118,13 +108,12 @@ 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(&global_buffers, pdata, psize, limit);
-		return (CMD_RETURN_NORMAL);
-	}
-	if (paste_replace(&global_buffers, buffer, pdata, psize) != 0) {
-		cmdq_error(cmdq, "no buffer %d", buffer);
+
+	if(paste_set(
+	    &global_buffers, pdata, psize, limit, bufname, &cause) != 0) {
+		cmdq_error(cmdq, "%s", cause);
 		free(pdata);
+		free(cause);
 		return (CMD_RETURN_ERROR);
 	}
 
@@ -140,10 +129,10 @@ 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;
+	u_int		 limit;
 
 	if (!closed)
 		return;
@@ -154,26 +143,24 @@ 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(&global_buffers, pdata, psize, limit);
-	else if (paste_replace(&global_buffers, *buffer, pdata, psize) != 0) {
+
+	if (paste_set(&global_buffers,
+	    pdata, psize, limit, 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 5305b7e..af0c1f0 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(&global_buffers);
 	else {
-		pb = paste_get_index(&global_buffers, buffer);
+		pb = paste_get_name(&global_buffers, 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(&global_buffers);
 		else
-			paste_free_index(&global_buffers, buffer);
+			paste_free_name(&global_buffers, bufname);
 	}
 
 	return (CMD_RETURN_NORMAL);
diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c
index f08f80c..0ce0238 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(&global_buffers, buffer);
+		bufname = args_get(args, 'b');
+		pb = paste_get_name(&global_buffers, 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 e7f9b95..61895f9 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:su", 0, 1,
+	"[-asu] [-n new_buffer_name] " CMD_BUFFER_USAGE " data",
 	0,
 	NULL,
 	cmd_set_buffer_exec
@@ -45,36 +45,105 @@ cmd_set_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
 	struct paste_buffer	*pb;
 	u_int			 limit;
 	char			*pdata, *cause;
+	u_char			sticky;
+	const char		*bufname;
 	size_t			 psize, newsize;
-	int			 buffer;
 
+	bufname = NULL;
 	limit = options_get_number(&global_options, "buffer-limit");
 
-	psize = 0;
-	pdata = NULL;
 
-	pb = NULL;
-	buffer = -1;
+	if (args_has(args, 'n')) {
+		if (args_has(args, 's') || args_has(args, 'u')) {
+			cmdq_error(cmdq, "specify only 1 of n, s, or u flags");
+			return (CMD_RETURN_ERROR);
+		}
 
-	if ((newsize = strlen(args->argv[0])) == 0)
-		return (CMD_RETURN_NORMAL);
+		if (args->argc > 0) {
+			cmdq_error(cmdq, "don't provide data with n flag");
+			return (CMD_RETURN_ERROR);
+		}
 
-	if (args_has(args, 'b')) {
-		buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
-		if (cause != NULL) {
-			cmdq_error(cmdq, "buffer %s", cause);
+		if (args_has(args, 'b'))
+			bufname = args_get(args, 'b');
+
+		if (bufname == NULL) {
+			pb = paste_get_top(&global_buffers);
+			if (pb == NULL) {
+				cmdq_error(cmdq, "no buffer");
+				return (CMD_RETURN_ERROR);
+			}
+			bufname = pb->name;
+		}
+
+		if (paste_rename(&global_buffers,
+		    bufname, args_get(args, 'n'), &cause) != 0) {
+			cmdq_error(cmdq, "%s", cause);
 			free(cause);
 			return (CMD_RETURN_ERROR);
 		}
-		pb = paste_get_index(&global_buffers, buffer);
+
+		return (CMD_RETURN_NORMAL);
+	}
+
+	if (args_has(args, 's') && args_has(args, 'u')) {
+		cmdq_error(cmdq, "specify only 1 of s or u flags");
+		return (CMD_RETURN_ERROR);
+	}
+
+	if (args_has(args, 's') || args_has(args, 'u')) {
+		sticky = 0;
+		if (args_has(args, 's'))
+			sticky = 1;
+
+		if (args->argc > 0) {
+			cmdq_error(cmdq, "don't provide data with s or u flags");
+			return (CMD_RETURN_ERROR);
+		}
+
+		if (args_has(args, 'b'))
+			bufname = args_get(args, 'b');
+
+		if (bufname == NULL)
+			pb = paste_get_top(&global_buffers);
+		else
+			pb = paste_get_name(&global_buffers, bufname);
+
 		if (pb == NULL) {
-			cmdq_error(cmdq, "no buffer %d", buffer);
+			if (bufname == NULL)
+				bufname = "";
+			cmdq_error(cmdq, "no buffer %s", bufname);
 			return (CMD_RETURN_ERROR);
 		}
+
+		if (sticky == 0)
+			paste_make_unsticky(&global_buffers, pb->name, limit);
+		else
+			paste_make_sticky(&global_buffers, pb->name);
+
+		return (CMD_RETURN_NORMAL);
+	}
+
+	if (args->argc != 1) {
+		cmdq_error(cmdq, "no data specified");
+		return (CMD_RETURN_ERROR);
+	}
+
+	psize = 0;
+	pdata = NULL;
+
+	pb = NULL;
+
+	if ((newsize = strlen(args->argv[0])) == 0)
+		return (CMD_RETURN_NORMAL);
+
+	if (args_has(args, 'b')) {
+		bufname = args_get(args, 'b');
+		pb = paste_get_name(&global_buffers, bufname);
 	} else if (args_has(args, 'a')) {
 		pb = paste_get_top(&global_buffers);
 		if (pb != NULL)
-			buffer = 0;
+			bufname = pb->name;
 	}
 
 	if (args_has(args, 'a') && pb != NULL) {
@@ -87,10 +156,13 @@ 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(&global_buffers, pdata, psize, limit);
-	else
-		paste_replace(&global_buffers, buffer, pdata, psize);
+	if (paste_set(&global_buffers,
+	    pdata, psize, limit, 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..6bef9ab 100644
--- a/format.c
+++ b/format.c
@@ -610,6 +610,9 @@ 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);
+	format_add(ft, "buffer_stickiness", "%c",
+	    pb->sticky == 0 ? 'U' : 'S');
 
 	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 00f37b9..e4875c0 100644
--- a/paste.c
+++ b/paste.c
@@ -21,6 +21,7 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
 
 #include "tmux.h"
 
@@ -29,124 +30,104 @@
  * string!
  */
 
-/* Return each item of the stack in turn. */
-struct paste_buffer *
-paste_walk_stack(struct paste_stack *ps, u_int *idx)
-{
-	struct paste_buffer	*pb;
+int compare_buffer_names(const struct paste_buffer *, const struct paste_buffer *);
+int compare_buffer_times(const struct paste_buffer *, const struct paste_buffer *);
 
-	pb = paste_get_index(ps, *idx);
-	(*idx)++;
-	return (pb);
-}
+RB_GENERATE(paste_name_tree, paste_buffer, name_entry, compare_buffer_names);
+RB_GENERATE(paste_time_tree, paste_buffer, time_entry, compare_buffer_times);
 
-/* Get the top item on the stack. */
-struct paste_buffer *
-paste_get_top(struct paste_stack *ps)
-{
-	if (ARRAY_LENGTH(ps) == 0)
-		return (NULL);
-	return (ARRAY_FIRST(ps));
-}
 
-/* Get an item by its index. */
+/* Get the most recent unsticky buffer */
 struct paste_buffer *
-paste_get_index(struct paste_stack *ps, u_int idx)
+paste_get_top(struct paste_store *ps)
 {
-	if (idx >= ARRAY_LENGTH(ps))
-		return (NULL);
-	return (ARRAY_ITEM(ps, idx));
+	return (RB_MAX(paste_time_tree, &ps->time_tree));
 }
 
-/* Free the top item on the stack. */
+/* Free the most recent unsticky buffer */
 int
-paste_free_top(struct paste_stack *ps)
+paste_free_top(struct paste_store *ps)
 {
 	struct paste_buffer	*pb;
 
-	if (ARRAY_LENGTH(ps) == 0)
+	pb = paste_get_top(ps);
+	if (pb == NULL)
 		return (-1);
 
-	pb = ARRAY_FIRST(ps);
-	ARRAY_REMOVE(ps, 0);
-
-	free(pb->data);
-	free(pb);
-
-	return (0);
+	return (paste_free_name(ps, pb->name));
 }
 
-/* Free an item by index. */
+/* Free an item by name. */
 int
-paste_free_index(struct paste_stack *ps, u_int idx)
+paste_free_name(struct paste_store *ps, const char *name)
 {
-	struct paste_buffer	*pb;
+	struct paste_buffer	*pb, pbfind;
 
-	if (idx >= ARRAY_LENGTH(ps))
+	if (name == NULL || *name == '\0')
 		return (-1);
 
-	pb = ARRAY_ITEM(ps, idx);
-	ARRAY_REMOVE(ps, idx);
+	pbfind.name = name;
+	pb = RB_FIND(paste_name_tree, &ps->name_tree, &pbfind);
+
+	if (pb == NULL)
+		return (-1);
+
+	RB_REMOVE(paste_name_tree, &ps->name_tree, pb);
+	if (pb->sticky == 0) {
+		RB_REMOVE(paste_time_tree, &ps->time_tree, pb);
+		ps->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(struct paste_stack *ps, char *data, size_t size, u_int limit)
+paste_add(struct paste_store *ps, char *data, size_t size, u_int limit)
 {
 	struct paste_buffer	*pb;
+	u_int			 next_crtime;
 
 	if (size == 0)
 		return;
 
-	while (ARRAY_LENGTH(ps) >= limit) {
-		pb = ARRAY_LAST(ps);
-		free(pb->data);
-		free(pb);
-		ARRAY_TRUNC(ps, 1);
+	while (ps->num_unsticky >= limit) {
+		pb = RB_MIN(paste_time_tree, &ps->time_tree);
+		paste_free_name(ps, pb->name);
 	}
 
-	pb = xmalloc(sizeof *pb);
-	ARRAY_INSERT(ps, 0, pb);
-
-	pb->data = data;
-	pb->size = size;
-}
-
-
-/*
- * Replace an item on the stack. Note that the caller is responsible for
- * allocating data.
- */
-int
-paste_replace(struct paste_stack *ps, u_int idx, char *data, size_t size)
-{
-	struct paste_buffer	*pb;
-
-	if (size == 0) {
-		free(data);
-		return (0);
+	next_crtime = 0;
+	if (ps->num_unsticky > 0) {
+		pb = RB_MAX(paste_time_tree, &ps->time_tree);
+		next_crtime = pb->crtime + 1;
 	}
 
-	if (idx >= ARRAY_LENGTH(ps))
-		return (-1);
-
-	pb = ARRAY_ITEM(ps, idx);
-	free(pb->data);
+	pb = xmalloc(sizeof *pb);
+	pb->name = NULL;
+	do {
+		free(pb->name);
+		xasprintf(&pb->name, "buffer%04u", ps->unsticky_idx);
+		ps->unsticky_idx++;
+	} while (paste_get_name(ps, pb->name) != NULL);
 
 	pb->data = data;
 	pb->size = size;
+	pb->sticky = 0;
+	pb->crtime = next_crtime;
+
+	RB_INSERT(paste_name_tree, &ps->name_tree, pb);
+	RB_INSERT(paste_time_tree, &ps->time_tree, pb);
+	ps->num_unsticky++;
 
-	return (0);
 }
 
+
 /* Convert start of buffer into a nice string. */
 char *
 paste_make_sample(struct paste_buffer *pb, int utf8flag)
@@ -195,3 +176,194 @@ paste_send_pane(struct paste_buffer *pb, struct window_pane *wp,
 	if (bracket)
 		bufferevent_write(wp->event, "\033[201~", 6);
 }
+
+int
+compare_buffer_names(const struct paste_buffer *a,
+    const struct paste_buffer *b)
+{
+	return (strcmp(a->name, b->name));
+}
+
+
+int
+compare_buffer_times(const struct paste_buffer *a,
+    const struct paste_buffer *b)
+{
+	return (a->crtime < b->crtime ? -1 : a->crtime > b->crtime);
+}
+
+/* Get an item by its name. */
+struct paste_buffer *
+paste_get_name(struct paste_store *ps, const char *name)
+{
+	struct paste_buffer	pbfind;
+
+	if (name == NULL || *name == '\0')
+		return (NULL);
+
+	pbfind.name = name;
+	return (RB_FIND(paste_name_tree, &ps->name_tree, &pbfind));
+}
+
+int
+paste_rename(struct paste_store *ps, const char *oldname,
+    const char *newname, char **cause)
+{
+	const char		*c;
+	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(ps, oldname)) == NULL) {
+		xasprintf(cause, "no buffer %s", oldname);
+		return (-1);
+	}
+
+	if (paste_get_name(ps, newname) != NULL) {
+		*cause = xstrdup("buffer with new name already exists");
+		return (-1);
+	}
+
+	if (strlen(newname) > 16) {
+		*cause = xstrdup("buffer name too long");
+		return (-1);
+	}
+
+	for (c = newname; *c != '\0'; c++) {
+		if (!isprint(*c) || isspace(*c)) {
+			*cause = xstrdup("bad characters in buffer name");
+			return (-1);
+		}
+	}
+
+	RB_REMOVE(paste_name_tree, &ps->name_tree, pb);
+	free(pb->name);
+
+	pb->name = xstrdup(newname);
+	RB_INSERT(paste_name_tree, &ps->name_tree, pb);
+	return (0);
+}
+
+/*
+ * Add or Replace an item in the store. Note that the caller is responsible for
+ * allocating data.
+ */
+int
+paste_set(struct paste_store *ps,  char *data, size_t size, u_int limit,
+    const char *name, char **cause)
+{
+	struct paste_buffer	*pb;
+	const char		*c;
+
+
+	if (cause != NULL)
+		*cause = NULL;
+
+	if (size == 0) {
+		free(data);
+		return (0);
+	}
+
+	if (name == NULL) {
+		paste_add(ps, data, size, limit);
+		return (0);
+	}
+
+
+	pb = paste_get_name(ps, 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);
+	}
+
+	if (strlen(name) > 16) {
+		if (cause != NULL)
+			*cause = xstrdup("buffer name too long");
+		return (-1);
+	}
+
+	for (c = name; *c != '\0'; c++) {
+		if (!isprint(*c) || isspace(*c)) {
+			if (cause != NULL)
+				*cause = xstrdup("bad characters in 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, &ps->name_tree, pb);
+
+	return (0);
+}
+
+void
+paste_make_sticky(struct paste_store *ps, const char *name)
+{
+	struct paste_buffer *pb;
+
+	if ((pb = paste_get_name(ps, name)) == NULL)
+		return;
+
+	if (pb->sticky == 1)
+		return;
+
+	RB_REMOVE(paste_time_tree, &ps->time_tree, pb);
+	ps->num_unsticky--;
+
+	pb->sticky = 1;
+}
+
+void
+paste_make_unsticky(struct paste_store *ps, const char *name, u_int limit)
+{
+	struct paste_buffer	*pb, *tmppb;
+	u_int			 next_crtime;
+
+	if ((pb = paste_get_name(ps, name)) == NULL)
+		return;
+
+	if (pb->sticky == 0)
+		return;
+
+	while (ps->num_unsticky >= limit) {
+		tmppb = RB_MIN(paste_time_tree, &ps->time_tree);
+		paste_free_name(ps, tmppb->name);
+	}
+
+	next_crtime = 0;
+	if (ps->num_unsticky > 0) {
+		tmppb = RB_MAX(paste_time_tree, &ps->time_tree);
+		next_crtime = tmppb->crtime + 1;
+	}
+
+	pb->sticky = 0;
+	pb->crtime = next_crtime;
+
+	RB_INSERT(paste_time_tree, &ps->time_tree, pb);
+	ps->num_unsticky++;
+}
diff --git a/server.c b/server.c
index c8bc7ed..60717f6 100644
--- a/server.c
+++ b/server.c
@@ -50,7 +50,7 @@ int		 server_shutdown;
 struct event	 server_ev_accept;
 struct event	 server_ev_second;
 
-struct paste_stack global_buffers;
+struct paste_store global_buffers;
 
 int		 server_create_socket(void);
 void		 server_loop(void);
@@ -146,7 +146,10 @@ server_start(int lockfd, char *lockfile)
 	RB_INIT(&sessions);
 	RB_INIT(&dead_sessions);
 	TAILQ_INIT(&session_groups);
-	ARRAY_INIT(&global_buffers);
+	global_buffers.unsticky_idx = 0;
+	global_buffers.num_unsticky = 0;
+	RB_INIT(&global_buffers.name_tree);
+	RB_INIT(&global_buffers.time_tree);
 	mode_key_init_trees();
 	key_bindings_init();
 	utf8_build();
diff --git a/tmux.h b/tmux.h
index 6f29126..9f89a09 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,9 +1035,21 @@ 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;
+};
+
+struct paste_store {
+	u_int		unsticky_idx, num_unsticky;
+	RB_HEAD(paste_name_tree, paste_buffer) name_tree;
+	RB_HEAD(paste_time_tree, paste_buffer) time_tree;
+
 };
-ARRAY_DECL(paste_stack, struct paste_buffer *);
 
 /* Environment variable. */
 struct environ_entry {
@@ -1494,7 +1509,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;
@@ -1706,14 +1721,20 @@ void	tty_keys_free(struct tty *);
 int	tty_keys_next(struct tty *);
 
 /* paste.c */
-struct paste_buffer *paste_walk_stack(struct paste_stack *, u_int *);
-struct paste_buffer *paste_get_top(struct paste_stack *);
-struct paste_buffer *paste_get_index(struct paste_stack *, u_int);
-int		 paste_free_top(struct paste_stack *);
-int		 paste_free_index(struct paste_stack *, u_int);
-void		 paste_add(struct paste_stack *, char *, size_t, u_int);
-int		 paste_replace(struct paste_stack *, u_int, char *, size_t);
+RB_PROTOTYPE(paste_name_tree, paste_buffer, name_entry, compare_buffer_names);
+RB_PROTOTYPE(paste_time_tree, paste_buffer, time_entry, compare_buffer_times);
+struct paste_buffer *paste_get_top(struct paste_store *);
+struct paste_buffer *paste_get_name(struct paste_store *, const char *);
+int		 paste_free_top(struct paste_store *);
+int		 paste_free_name(struct paste_store *, const char *);
+void		 paste_add(struct paste_store *, char *, size_t, u_int);
+int		paste_rename(struct paste_store *, const char *,
+		     const char *, char **);
+int		 paste_set(struct paste_store *, char *, size_t, u_int,
+		     const char *, char **);
 char		*paste_make_sample(struct paste_buffer *, int);
+void		 paste_make_sticky(struct paste_store *, const char *);
+void		 paste_make_unsticky(struct paste_store *, const char *, u_int);
 void		 paste_send_pane(struct paste_buffer *, struct window_pane *,
 		     const char *, int);
 
@@ -1883,7 +1904,7 @@ const char *key_string_lookup_key(int);
 /* server.c */
 extern struct clients clients;
 extern struct clients dead_clients;
-extern struct paste_stack global_buffers;
+extern struct paste_store global_buffers;
 int	 server_start(int, char *);
 void	 server_update_socket(void);
 void	 server_add_accept(int);
diff --git a/window-copy.c b/window-copy.c
index afa6d4d..4d8505c 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,11 @@ 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;
+	u_int				 limit;
+	struct screen_write_ctx		 ctx;
 
 	if (options_get_number(&global_options, "set-clipboard")) {
 		screen_write_start(&ctx, wp, NULL);
@@ -1463,16 +1488,18 @@ 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(&global_buffers, buf, len, limit);
-	} else if (paste_replace(&global_buffers, idx, buf, len) != 0)
+	limit = options_get_number(&global_options, "buffer-limit");
+
+	if (paste_set(
+	    &global_buffers, buf, len, limit, 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 +1513,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 +1526,17 @@ 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;
+	u_int				 limit;
+	struct screen_write_ctx		 ctx;
 
 	buf = window_copy_get_selection(wp, &len);
 	if (buf == NULL)
@@ -1521,16 +1548,17 @@ window_copy_append_selection(struct window_pane *wp, int idx)
 		screen_write_stop(&ctx);
 	}
 
-	if (idx == -1)
-		idx = 0;
+	limit = options_get_number(&global_options, "buffer-limit");
 
-	if (idx == 0 && paste_get_top(&global_buffers) == NULL) {
-		limit = options_get_number(&global_options, "buffer-limit");
-		paste_add(&global_buffers, buf, len, limit);
-		return;
+	if (bufname == NULL || *bufname == '\0') {
+		pb = paste_get_top(&global_buffers);
+		if (pb != NULL)
+			bufname = pb->name;
+	} else {
+		pb = paste_get_name(&global_buffers, bufname);
 	}
 
-	pb = paste_get_index(&global_buffers, idx);
+
 	if (pb != NULL) {
 		buf = xrealloc(buf, 1, len + pb->size);
 		memmove(buf + pb->size, buf, len);
@@ -1538,7 +1566,8 @@ window_copy_append_selection(struct window_pane *wp, int idx)
 		len += pb->size;
 	}
 
-	if (paste_replace(&global_buffers, idx, buf, len) != 0)
+	if (paste_set(
+	    &global_buffers, buf, len, limit, bufname, NULL) != 0)
 		free(buf);
 }
 
------------------------------------------------------------------------------
Start Your Social Network Today - Download eXo Platform
Build your Enterprise Intranet with eXo Platform Software
Java Based Open Source Intranet - Social, Extensible, Cloud Ready
Get Started Now And Turn Your Intranet Into A Collaboration Platform
http://p.sf.net/sfu/ExoPlatform
_______________________________________________
tmux-users mailing list
tmux-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/tmux-users

Reply via email to