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

Reply via email to