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. On Thu, Apr 24, 2014 at 07:37:19PM -0500, J Raynor wrote: > I've attached a new patch. It's the patch you just recently sent with > the following modifications: > > 1. buffer-limit isn't passed to paste_set. paste_add is the only > paste function that needs it now, and it'll look it up itself. > 2. The length and character restrictions for buffer names have been removed. > 3. The -s and -u flags to setb have been removed. > 4. I've removed the paste_make_sticky and paste_make_unsticky > functions. They were no longer needed. Nothing can now cause a > buffer to go from sticky to unsticky, and the only time a buffer > changes from unsticky to sticky is during a rename, and the code to do > that was short enough to stick on the end of the rename function. > 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..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 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.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