Add support for named buffers. If you don't name a buffer, things work
authornicm <nicm@openbsd.org>
Tue, 13 May 2014 07:34:35 +0000 (07:34 +0000)
committernicm <nicm@openbsd.org>
Tue, 13 May 2014 07:34:35 +0000 (07:34 +0000)
much as before - buffers are automatically named "buffer0000",
"buffer0001" and so on and ordered as a stack. Buffers can be named
explicitly when creating ("loadb -b foo" etc) or renamed ("setb -b
buffer0000 -n foo"). If buffers are named explicitly, they are not
deleted when buffer-limit is reached. Diff from J Raynor.

13 files changed:
usr.bin/tmux/cmd-capture-pane.c
usr.bin/tmux/cmd-choose-buffer.c
usr.bin/tmux/cmd-delete-buffer.c
usr.bin/tmux/cmd-list-buffers.c
usr.bin/tmux/cmd-load-buffer.c
usr.bin/tmux/cmd-paste-buffer.c
usr.bin/tmux/cmd-save-buffer.c
usr.bin/tmux/cmd-set-buffer.c
usr.bin/tmux/format.c
usr.bin/tmux/paste.c
usr.bin/tmux/tmux.1
usr.bin/tmux/tmux.h
usr.bin/tmux/window-copy.c

index 68f17aa..17913ba 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-capture-pane.c,v 1.26 2014/04/24 09:14:43 nicm Exp $ */
+/* $OpenBSD: cmd-capture-pane.c,v 1.27 2014/05/13 07:34:35 nicm Exp $ */
 
 /*
  * Copyright (c) 2009 Jonathan Alvarado <radobobo@users.sourceforge.net>
@@ -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);
                }
        }
index f1327c7..bd269d6 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-choose-buffer.c,v 1.17 2014/04/24 09:14:43 nicm Exp $ */
+/* $OpenBSD: cmd-choose-buffer.c,v 1.18 2014/05/13 07:34:35 nicm Exp $ */
 
 /*
  * Copyright (c) 2010 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -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);
 
index f5e4e70..d60897a 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-delete-buffer.c,v 1.11 2014/04/24 09:14:43 nicm Exp $ */
+/* $OpenBSD: cmd-delete-buffer.c,v 1.12 2014/05/13 07:34:35 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -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);
        }
 
index dc86bc7..a43e32b 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-list-buffers.c,v 1.20 2014/04/24 09:14:43 nicm Exp $ */
+/* $OpenBSD: cmd-list-buffers.c,v 1.21 2014/05/13 07:34:35 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -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);
index 32ba813..99dba8b 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-load-buffer.c,v 1.28 2014/04/24 09:14:43 nicm Exp $ */
+/* $OpenBSD: cmd-load-buffer.c,v 1.29 2014/05/13 07:34:35 nicm Exp $ */
 
 /*
  * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -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);
+                   (void*)bufname, &cause);
                if (error != 0) {
                        cmdq_error(cmdq, "%s: %s", path, cause);
                        free(cause);
@@ -117,14 +106,10 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
 
        fclose(f);
 
-       limit = options_get_number(&global_options, "buffer-limit");
-       if (buffer == -1) {
-               paste_add(pdata, psize, limit);
-               return (CMD_RETURN_NORMAL);
-       }
-       if (paste_replace(buffer, pdata, psize) != 0) {
-               cmdq_error(cmdq, "no buffer %d", buffer);
+       if (paste_set(pdata, psize, bufname, &cause) != 0) {
+               cmdq_error(cmdq, "%s", cause);
                free(pdata);
+               free(cause);
                return (CMD_RETURN_ERROR);
        }
 
@@ -140,10 +125,9 @@ error:
 void
 cmd_load_buffer_callback(struct client *c, int closed, void *data)
 {
-       int     *buffer = data;
-       char    *pdata;
-       size_t   psize;
-       u_int    limit;
+       const char      *bufname = data;
+       char            *pdata, *cause;
+       size_t           psize;
 
        if (!closed)
                return;
@@ -154,26 +138,21 @@ cmd_load_buffer_callback(struct client *c, int closed, void *data)
                return;
 
        psize = EVBUFFER_LENGTH(c->stdin_data);
-       if (psize == 0 || (pdata = malloc(psize + 1)) == NULL) {
-               free(data);
+       if (psize == 0 || (pdata = malloc(psize + 1)) == NULL)
                goto out;
-       }
+
        memcpy(pdata, EVBUFFER_DATA(c->stdin_data), psize);
        pdata[psize] = '\0';
        evbuffer_drain(c->stdin_data, psize);
 
-       limit = options_get_number(&global_options, "buffer-limit");
-       if (*buffer == -1)
-               paste_add(pdata, psize, limit);
-       else if (paste_replace(*buffer, pdata, psize) != 0) {
+       if (paste_set(pdata, psize, bufname, &cause) != 0) {
                /* No context so can't use server_client_msg_error. */
-               evbuffer_add_printf(c->stderr_data, "no buffer %d\n", *buffer);
+               evbuffer_add_printf(c->stderr_data, "%s", cause);
                server_push_stderr(c);
                free(pdata);
+               free(cause);
        }
 
-       free(data);
-
 out:
        cmdq_continue(c->cmdq);
 }
index fbb0790..088c949 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-paste-buffer.c,v 1.24 2014/04/24 09:14:43 nicm Exp $ */
+/* $OpenBSD: cmd-paste-buffer.c,v 1.25 2014/05/13 07:34:35 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -36,7 +36,7 @@ void  cmd_paste_buffer_filter(struct window_pane *,
 const struct cmd_entry cmd_paste_buffer_entry = {
        "paste-buffer", "pasteb",
        "db:prs:t:", 0, 0,
-       "[-dpr] [-s separator] [-b buffer-index] " CMD_TARGET_PANE_USAGE,
+       "[-dpr] [-s separator] " CMD_BUFFER_USAGE " " CMD_TARGET_PANE_USAGE,
        0,
        NULL,
        cmd_paste_buffer_exec
@@ -49,31 +49,22 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
        struct window_pane      *wp;
        struct session          *s;
        struct paste_buffer     *pb;
-       const char              *sepstr;
-       char                    *cause;
-       int                      buffer;
+       const char              *sepstr, *bufname;
        int                      pflag;
 
        if (cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp) == NULL)
                return (CMD_RETURN_ERROR);
 
-       if (!args_has(args, 'b'))
-               buffer = -1;
-       else {
-               buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
-               if (cause != NULL) {
-                       cmdq_error(cmdq, "buffer %s", cause);
-                       free(cause);
-                       return (CMD_RETURN_ERROR);
-               }
-       }
+       bufname = NULL;
+       if (args_has(args, 'b'))
+               bufname = args_get(args, 'b');
 
-       if (buffer == -1)
+       if (bufname == NULL)
                pb = paste_get_top();
        else {
-               pb = paste_get_index(buffer);
+               pb = paste_get_name(bufname);
                if (pb == NULL) {
-                       cmdq_error(cmdq, "no buffer %d", buffer);
+                       cmdq_error(cmdq, "no buffer %s", bufname);
                        return (CMD_RETURN_ERROR);
                }
        }
@@ -92,10 +83,10 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
 
        /* Delete the buffer if -d. */
        if (args_has(args, 'd')) {
-               if (buffer == -1)
+               if (bufname == NULL)
                        paste_free_top();
                else
-                       paste_free_index(buffer);
+                       paste_free_name(bufname);
        }
 
        return (CMD_RETURN_NORMAL);
index d5bd640..8803aa9 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-save-buffer.c,v 1.24 2014/04/24 09:14:43 nicm Exp $ */
+/* $OpenBSD: cmd-save-buffer.c,v 1.25 2014/05/13 07:34:35 nicm Exp $ */
 
 /*
  * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -59,10 +59,10 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
        struct client           *c = cmdq->client;
        struct session          *s;
        struct paste_buffer     *pb;
-       const char              *path;
-       char                    *cause, *start, *end, *msg;
+       const char              *path, *bufname;
+       char                    *start, *end, *msg;
        size_t                   size, used, msglen;
-       int                      cwd, fd, buffer;
+       int                      cwd, fd;
        FILE                    *f;
 
        if (!args_has(args, 'b')) {
@@ -71,16 +71,10 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
                        return (CMD_RETURN_ERROR);
                }
        } else {
-               buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
-               if (cause != NULL) {
-                       cmdq_error(cmdq, "buffer %s", cause);
-                       free(cause);
-                       return (CMD_RETURN_ERROR);
-               }
-
-               pb = paste_get_index(buffer);
+               bufname = args_get(args, 'b');
+               pb = paste_get_name(bufname);
                if (pb == NULL) {
-                       cmdq_error(cmdq, "no buffer %d", buffer);
+                       cmdq_error(cmdq, "no buffer %s", bufname);
                        return (CMD_RETURN_ERROR);
                }
        }
index ca8250c..e807278 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-set-buffer.c,v 1.17 2014/04/24 09:14:43 nicm Exp $ */
+/* $OpenBSD: cmd-set-buffer.c,v 1.18 2014/05/13 07:34:35 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -31,8 +31,8 @@ enum cmd_retval        cmd_set_buffer_exec(struct cmd *, struct cmd_q *);
 
 const struct cmd_entry cmd_set_buffer_entry = {
        "set-buffer", "setb",
-       "ab:", 1, 1,
-       "[-a] " CMD_BUFFER_USAGE " data",
+       "ab:n:", 0, 1,
+       "[-a] " CMD_BUFFER_USAGE " [-n new-buffer-name] data",
        0,
        NULL,
        cmd_set_buffer_exec
@@ -43,38 +43,59 @@ cmd_set_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
 {
        struct args             *args = self->args;
        struct paste_buffer     *pb;
-       u_int                    limit;
        char                    *pdata, *cause;
+       const char              *bufname;
        size_t                   psize, newsize;
-       int                      buffer;
 
-       limit = options_get_number(&global_options, "buffer-limit");
+       bufname = NULL;
+
+       if (args_has(args, 'n')) {
+               if (args->argc > 0) {
+                       cmdq_error(cmdq, "don't provide data with n flag");
+                       return (CMD_RETURN_ERROR);
+               }
+
+               if (args_has(args, 'b'))
+                       bufname = args_get(args, 'b');
+
+               if (bufname == NULL) {
+                       pb = paste_get_top();
+                       if (pb == NULL) {
+                               cmdq_error(cmdq, "no buffer");
+                               return (CMD_RETURN_ERROR);
+                       }
+                       bufname = pb->name;
+               }
+
+               if (paste_rename(bufname, args_get(args, 'n'), &cause) != 0) {
+                       cmdq_error(cmdq, "%s", cause);
+                       free(cause);
+                       return (CMD_RETURN_ERROR);
+               }
+
+               return (CMD_RETURN_NORMAL);
+       }
+
+       if (args->argc != 1) {
+               cmdq_error(cmdq, "no data specified");
+               return (CMD_RETURN_ERROR);
+       }
 
        psize = 0;
        pdata = NULL;
 
        pb = NULL;
-       buffer = -1;
 
        if ((newsize = strlen(args->argv[0])) == 0)
                return (CMD_RETURN_NORMAL);
 
        if (args_has(args, 'b')) {
-               buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
-               if (cause != NULL) {
-                       cmdq_error(cmdq, "buffer %s", cause);
-                       free(cause);
-                       return (CMD_RETURN_ERROR);
-               }
-               pb = paste_get_index(buffer);
-               if (pb == NULL) {
-                       cmdq_error(cmdq, "no buffer %d", buffer);
-                       return (CMD_RETURN_ERROR);
-               }
+               bufname = args_get(args, 'b');
+               pb = paste_get_name(bufname);
        } else if (args_has(args, 'a')) {
                pb = paste_get_top();
                if (pb != NULL)
-                       buffer = 0;
+                       bufname = pb->name;
        }
 
        if (args_has(args, 'a') && pb != NULL) {
@@ -87,10 +108,12 @@ cmd_set_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
        memcpy(pdata + psize, args->argv[0], newsize);
        psize += newsize;
 
-       if (buffer == -1)
-               paste_add(pdata, psize, limit);
-       else
-               paste_replace(buffer, pdata, psize);
+       if (paste_set(pdata, psize, bufname, &cause) != 0) {
+               cmdq_error(cmdq, "%s", cause);
+               free(pdata);
+               free(cause);
+               return (CMD_RETURN_ERROR);
+       }
 
        return (CMD_RETURN_NORMAL);
 }
index 55e0c47..a1dee99 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: format.c,v 1.44 2014/04/17 15:37:55 nicm Exp $ */
+/* $OpenBSD: format.c,v 1.45 2014/05/13 07:34:35 nicm Exp $ */
 
 /*
  * Copyright (c) 2011 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -608,6 +608,7 @@ format_paste_buffer(struct format_tree *ft, struct paste_buffer *pb,
        char    *s;
 
        format_add(ft, "buffer_size", "%zu", pb->size);
+       format_add(ft, "buffer_name", "%s", pb->name);
 
        s = paste_make_sample(pb, utf8flag);
        format_add(ft, "buffer_sample", "%s", s);
index 0390ebf..1f9626f 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: paste.c,v 1.18 2014/04/24 09:14:43 nicm Exp $ */
+/* $OpenBSD: paste.c,v 1.19 2014/05/13 07:34:35 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
 #include "tmux.h"
 
 /*
- * Stack of paste buffers. Note that paste buffer data is not necessarily a C
+ * Set of paste buffers. Note that paste buffer data is not necessarily a C
  * string!
  */
 
-ARRAY_DECL(, struct paste_buffer *) paste_buffers =  ARRAY_INITIALIZER;
+u_int  paste_next_index;
+u_int  paste_next_order;
+u_int  paste_num_automatic;
+RB_HEAD(paste_name_tree, paste_buffer) paste_by_name;
+RB_HEAD(paste_time_tree, paste_buffer) paste_by_time;
 
-/* Return each item of the stack in turn. */
-struct paste_buffer *
-paste_walk_stack(u_int *idx)
+int paste_cmp_names(const struct paste_buffer *, const struct paste_buffer *);
+RB_PROTOTYPE(paste_name_tree, paste_buffer, name_entry, paste_cmp_names);
+RB_GENERATE(paste_name_tree, paste_buffer, name_entry, paste_cmp_names);
+
+int paste_cmp_times(const struct paste_buffer *, const struct paste_buffer *);
+RB_PROTOTYPE(paste_time_tree, paste_buffer, time_entry, paste_cmp_times);
+RB_GENERATE(paste_time_tree, paste_buffer, time_entry, paste_cmp_times);
+
+int
+paste_cmp_names(const struct paste_buffer *a, const struct paste_buffer *b)
 {
-       struct paste_buffer     *pb;
+       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)
+{
+       if (a->order > b->order)
+               return (-1);
+       if (a->order < b->order)
+               return (1);
+       return (0);
 }
 
-/* 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_time_tree, &paste_by_time));
+       return (RB_NEXT(paste_time_tree, &paste_by_time, pb));
 }
 
-/* Get an item by its index. */
+/* Get the most recent automatic buffer */
 struct paste_buffer *
-paste_get_index(u_int idx)
+paste_get_top(void)
 {
-       if (idx >= ARRAY_LENGTH(&paste_buffers))
+       struct paste_buffer     *pb;
+
+       pb = RB_MIN(paste_time_tree, &paste_by_time);
+       if (pb == NULL)
                return (NULL);
-       return (ARRAY_ITEM(&paste_buffers, idx));
+       return (pb);
 }
 
-/* Free the top item on the stack. */
+/* Free the most recent buffer */
 int
 paste_free_top(void)
 {
        struct paste_buffer     *pb;
 
-       if (ARRAY_LENGTH(&paste_buffers) == 0)
+       pb = paste_get_top();
+       if (pb == NULL)
                return (-1);
+       return (paste_free_name(pb->name));
+}
 
-       pb = ARRAY_FIRST(&paste_buffers);
-       ARRAY_REMOVE(&paste_buffers, 0);
+/* Get a paste buffer by name. */
+struct paste_buffer *
+paste_get_name(const char *name)
+{
+       struct paste_buffer     pbfind;
 
-       free(pb->data);
-       free(pb);
+       if (name == NULL || *name == '\0')
+               return (NULL);
 
-       return (0);
+       pbfind.name = (char*)name;
+       return (RB_FIND(paste_name_tree, &paste_by_name, &pbfind));
 }
 
-/* Free an item by index. */
+/* Free a paste buffer 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 (name == NULL || *name == '\0')
+               return (-1);
 
-       if (idx >= ARRAY_LENGTH(&paste_buffers))
+       pbfind.name = (char*)name;
+       pb = RB_FIND(paste_name_tree, &paste_by_name, &pbfind);
+       if (pb == NULL)
                return (-1);
 
-       pb = ARRAY_ITEM(&paste_buffers, idx);
-       ARRAY_REMOVE(&paste_buffers, idx);
+       RB_REMOVE(paste_name_tree, &paste_by_name, pb);
+       RB_REMOVE(paste_time_tree, &paste_by_time, pb);
+       if (pb->automatic)
+               paste_num_automatic--;
 
        free(pb->data);
+       free(pb->name);
        free(pb);
-
        return (0);
 }
 
 /*
- * Add an item onto the top of the stack, freeing the bottom if at limit. Note
+ * Add an automatic buffer, freeing the oldest automatic item if at limit. Note
  * that the caller is responsible for allocating data.
  */
 void
-paste_add(char *data, size_t size, u_int limit)
+paste_add(char *data, size_t size)
 {
-       struct paste_buffer     *pb;
+       struct paste_buffer     *pb, *pb1;
+       u_int                    limit;
 
        if (size == 0)
                return;
 
-       while (ARRAY_LENGTH(&paste_buffers) >= limit) {
-               pb = ARRAY_LAST(&paste_buffers);
-               free(pb->data);
-               free(pb);
-               ARRAY_TRUNC(&paste_buffers, 1);
+       limit = options_get_number(&global_options, "buffer-limit");
+       RB_FOREACH_REVERSE_SAFE(pb, paste_time_tree, &paste_by_time, pb1) {
+               if (paste_num_automatic < limit)
+                       break;
+               if (pb->automatic)
+                       paste_free_name(pb->name);
        }
 
        pb = xmalloc(sizeof *pb);
-       ARRAY_INSERT(&paste_buffers, 0, pb);
+
+       pb->name = NULL;
+       do {
+               free(pb->name);
+               xasprintf(&pb->name, "buffer%04u", paste_next_index);
+               paste_next_index++;
+       } while (paste_get_name(pb->name) != NULL);
 
        pb->data = data;
        pb->size = size;
+
+       pb->automatic = 1;
+       paste_num_automatic++;
+
+       pb->order = paste_next_order++;
+       RB_INSERT(paste_name_tree, &paste_by_name, pb);
+       RB_INSERT(paste_time_tree, &paste_by_time, pb);
 }
 
+/* Rename a paste buffer. */
+int
+paste_rename(const char *oldname, const char *newname, char **cause)
+{
+       struct paste_buffer     *pb;
+
+       if (cause != NULL)
+               *cause = NULL;
+
+       if (oldname == NULL || *oldname == '\0') {
+               if (cause != NULL)
+                       *cause = xstrdup("no buffer");
+               return (-1);
+       }
+       if (newname == NULL || *newname == '\0') {
+               if (cause != NULL)
+                       *cause = xstrdup("new name is empty");
+               return (-1);
+       }
+
+       pb = paste_get_name(oldname);
+       if (pb == NULL) {
+               if (cause != NULL)
+                   xasprintf(cause, "no buffer %s", oldname);
+               return (-1);
+       }
+
+       RB_REMOVE(paste_name_tree, &paste_by_name, pb);
+
+       free(pb->name);
+       pb->name = xstrdup(newname);
+
+       if (pb->automatic)
+               paste_num_automatic--;
+       pb->automatic = 0;
+
+       RB_INSERT(paste_name_tree, &paste_by_name, pb);
+
+       return (0);
+}
 
 /*
- * Replace an item on the stack. Note that the caller is responsible for
+ * Add or replace an item in the store. Note that the caller is responsible for
  * allocating data.
  */
 int
-paste_replace(u_int idx, char *data, size_t size)
+paste_set(char *data, size_t size, const char *name, char **cause)
 {
        struct paste_buffer     *pb;
 
+       if (cause != NULL)
+               *cause = NULL;
+
        if (size == 0) {
                free(data);
                return (0);
        }
+       if (name == NULL) {
+               paste_add(data, size);
+               return (0);
+       }
 
-       if (idx >= ARRAY_LENGTH(&paste_buffers))
+       if (*name == '\0') {
+               if (cause != NULL)
+                       *cause = xstrdup("empty buffer name");
                return (-1);
+       }
 
-       pb = ARRAY_ITEM(&paste_buffers, idx);
-       free(pb->data);
+       pb = paste_get_name(name);
+       if (pb != NULL)
+               paste_free_name(name);
+
+       pb = xmalloc(sizeof *pb);
+
+       pb->name = xstrdup(name);
 
        pb->data = data;
        pb->size = size;
 
+       pb->automatic = 0;
+       pb->order = paste_next_order++;
+
+       RB_INSERT(paste_name_tree, &paste_by_name, pb);
+       RB_INSERT(paste_time_tree, &paste_by_time, pb);
+
        return (0);
 }
 
index 3d2187d..e20f848 100644 (file)
@@ -1,4 +1,4 @@
-.\" $OpenBSD: tmux.1,v 1.391 2014/04/17 15:48:02 nicm Exp $
+.\" $OpenBSD: tmux.1,v 1.392 2014/05/13 07:34:35 nicm Exp $
 .\"
 .\" Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
 .\"
@@ -14,7 +14,7 @@
 .\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 .\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: April 17 2014 $
+.Dd $Mdocdate: May 13 2014 $
 .Dt TMUX 1
 .Os
 .Sh NAME
@@ -930,9 +930,6 @@ in emacs mode, and
 .Ql 10w
 in vi.
 .Pp
-When copying the selection, the repeat count indicates the buffer index to
-replace, if used.
-.Pp
 Mode key bindings are defined in a set of named tables:
 .Em vi-edit
 and
@@ -1090,7 +1087,7 @@ but a different format may be specified with
 .Fl F .
 .It Xo Ic capture-pane
 .Op Fl aepPq
-.Op Fl b Ar buffer-index
+.Op Fl b Ar buffer-name
 .Op Fl E Ar end-line
 .Op Fl S Ar start-line
 .Op Fl t Ar target-pane
@@ -3366,19 +3363,40 @@ is given, otherwise the active pane for the session attached to
 .El
 .Sh BUFFERS
 .Nm
-maintains a stack of
+maintains a set of named
 .Em paste buffers .
-Up to the value of the
+Each buffer may be either explicitly or automatically named.
+Explicitly named buffers are named when created with the
+.Ic set-buffer
+or
+.Ic load-buffer
+commands, or by renaming an automatically named buffer with
+.Ic set-buffer
+.Fl n .
+Automatically named buffers are given a name such as
+.Ql buffer0001 ,
+.Ql buffer0002
+and so on.
+When the
+.Ic buffer-limit
+option is reached, the oldest automatically named buffer is deleted.
+Explicitly named are not subject to
 .Ic buffer-limit
-option are kept; when a new buffer is added, the buffer at the bottom of the
-stack is removed.
+and may be deleted with
+.Ic delete-buffer
+command.
+.Pp
 Buffers may be added using
 .Ic copy-mode
 or the
 .Ic set-buffer
-command, and pasted into a window using the
+and
+.Ic load-buffer
+commands, and pasted into a window using the
 .Ic paste-buffer
 command.
+If a buffer command is used and no buffer is specified, the most
+recently added automatically named buffer is assumed.
 .Pp
 A configurable history buffer is also maintained for each window.
 By default, up to 2000 lines are kept; this can be altered with the
@@ -3399,7 +3417,7 @@ Put a window into buffer choice mode, where a buffer may be chosen
 interactively from a list.
 After a buffer is selected,
 .Ql %%
-is replaced by the buffer index in
+is replaced by the buffer name in
 .Ar template
 and the result executed as a command.
 If
@@ -3414,11 +3432,11 @@ This command works only if at least one client is attached.
 .It Ic clear-history Op Fl t Ar target-pane
 .D1 (alias: Ic clearhist )
 Remove and free the history for the specified pane.
-.It Ic delete-buffer Op Fl b Ar buffer-index
+.It Ic delete-buffer Op Fl b Ar buffer-name
 .D1 (alias: Ic deleteb )
-Delete the buffer at
-.Ar buffer-index ,
-or the top buffer if not specified.
+Delete the buffer named
+.Ar buffer-name ,
+or the most recently added automatically named buffer if not specified.
 .It Xo Ic list-buffers
 .Op Fl F Ar format
 .Xc
@@ -3430,7 +3448,7 @@ flag, see the
 .Sx FORMATS
 section.
 .It Xo Ic load-buffer
-.Op Fl b Ar buffer-index
+.Op Fl b Ar buffer-name
 .Ar path
 .Xc
 .D1 (alias: Ic loadb )
@@ -3438,7 +3456,7 @@ Load the contents of the specified paste buffer from
 .Ar path .
 .It Xo Ic paste-buffer
 .Op Fl dpr
-.Op Fl b Ar buffer-index
+.Op Fl b Ar buffer-name
 .Op Fl s Ar separator
 .Op Fl t Ar target-pane
 .Xc
@@ -3447,7 +3465,7 @@ Insert the contents of a paste buffer into the specified pane.
 If not specified, paste into the current one.
 With
 .Fl d ,
-also delete the paste buffer from the stack.
+also delete the paste buffer.
 When output, any linefeed (LF) characters in the paste buffer are replaced with
 a separator, by default carriage return (CR).
 A custom separator may be specified using the
@@ -3462,7 +3480,7 @@ is specified, paste bracket control codes are inserted around the
 buffer if the application has requested bracketed paste mode.
 .It Xo Ic save-buffer
 .Op Fl a
-.Op Fl b Ar buffer-index
+.Op Fl b Ar buffer-name
 .Ar path
 .Xc
 .D1 (alias: Ic saveb )
@@ -3473,7 +3491,8 @@ The
 option appends to rather than overwriting the file.
 .It Xo Ic set-buffer
 .Op Fl a
-.Op Fl b Ar buffer-index
+.Op Fl b Ar buffer-name
+.Op Fl n Ar new-buffer-name
 .Ar data
 .Xc
 .D1 (alias: Ic setb )
@@ -3482,8 +3501,12 @@ Set the contents of the specified buffer to
 The
 .Fl a
 option appends to rather than overwriting the buffer.
+The
+.Fl n
+option renames the buffer to
+.Ar new-buffer-name .
 .It Xo Ic show-buffer
-.Op Fl b Ar buffer-index
+.Op Fl b Ar buffer-name
 .Xc
 .D1 (alias: Ic showb )
 Display the contents of the specified buffer.
index 6534eaf..ea09031 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmux.h,v 1.460 2014/05/09 09:11:24 nicm Exp $ */
+/* $OpenBSD: tmux.h,v 1.461 2014/05/13 07:34:35 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -85,7 +85,7 @@ extern char   **environ;
 
 /* Default template for choose-buffer. */
 #define CHOOSE_BUFFER_TEMPLATE                                 \
-       "#{line}: #{buffer_size} bytes: #{buffer_sample}"
+       "#{buffer_name}: #{buffer_size} bytes: #{buffer_sample}"
 
 /* Default template for choose-client. */
 #define CHOOSE_CLIENT_TEMPLATE                                 \
@@ -118,7 +118,8 @@ extern char   **environ;
 
 /* Default template for list-buffers. */
 #define LIST_BUFFERS_TEMPLATE                                  \
-       "#{line}: #{buffer_size} bytes: \"#{buffer_sample}\""
+       "#{buffer_name}: #{buffer_size} bytes: "                \
+       "\"#{buffer_sample}\""
 
 /* Default template for list-clients. */
 #define LIST_CLIENTS_TEMPLATE                                  \
@@ -1036,6 +1037,13 @@ struct layout_cell {
 struct paste_buffer {
        char            *data;
        size_t           size;
+
+       char            *name;
+       int              automatic;
+       u_int            order;
+
+       RB_ENTRY(paste_buffer) name_entry;
+       RB_ENTRY(paste_buffer) time_entry;
 };
 
 /* Environment variable. */
@@ -1499,7 +1507,7 @@ RB_HEAD(format_tree, format_entry);
 #define CMD_SRCDST_WINDOW_USAGE "[-s src-window] [-t dst-window]"
 #define CMD_SRCDST_SESSION_USAGE "[-s src-session] [-t dst-session]"
 #define CMD_SRCDST_CLIENT_USAGE "[-s src-client] [-t dst-client]"
-#define CMD_BUFFER_USAGE "[-b buffer-index]"
+#define CMD_BUFFER_USAGE "[-b buffer-name]"
 
 /* tmux.c */
 extern struct options global_options;
@@ -1711,13 +1719,14 @@ void    tty_keys_free(struct tty *);
 int    tty_keys_next(struct tty *);
 
 /* paste.c */
-struct paste_buffer *paste_walk_stack(u_int *);
+struct paste_buffer *paste_walk(struct paste_buffer *);
 struct paste_buffer *paste_get_top(void);
-struct paste_buffer *paste_get_index(u_int);
+struct paste_buffer *paste_get_name(const char *);
 int             paste_free_top(void);
-int             paste_free_index(u_int);
-void            paste_add(char *, size_t, u_int);
-int             paste_replace(u_int, char *, size_t);
+int             paste_free_name(const char *);
+void            paste_add(char *, size_t);
+int             paste_rename(const char *, const char *, char **);
+int             paste_set(char *, size_t, const char *, char **);
 char           *paste_make_sample(struct paste_buffer *, int);
 void            paste_send_pane(struct paste_buffer *, struct window_pane *,
                     const char *, int);
index daa32b8..73f931c 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: window-copy.c,v 1.107 2014/04/24 09:14:43 nicm Exp $ */
+/* $OpenBSD: window-copy.c,v 1.108 2014/05/13 07:34:35 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -54,11 +54,12 @@ void        window_copy_update_cursor(struct window_pane *, u_int, u_int);
 void   window_copy_start_selection(struct window_pane *);
 int    window_copy_update_selection(struct window_pane *, int);
 void   *window_copy_get_selection(struct window_pane *, size_t *);
-void   window_copy_copy_buffer(struct window_pane *, int, void *, size_t);
-void   window_copy_copy_pipe(
-           struct window_pane *, struct session *, int, const char *);
-void   window_copy_copy_selection(struct window_pane *, int);
-void   window_copy_append_selection(struct window_pane *, int);
+void   window_copy_copy_buffer(struct window_pane *, const char *, void *,
+           size_t);
+void   window_copy_copy_pipe(struct window_pane *, struct session *,
+           const char *, const char *);
+void   window_copy_copy_selection(struct window_pane *, const char *);
+void   window_copy_append_selection(struct window_pane *, const char *);
 void   window_copy_clear_selection(struct window_pane *);
 void   window_copy_copy_line(
            struct window_pane *, char **, size_t *, u_int, u_int, u_int);
@@ -417,7 +418,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
        switch (cmd) {
        case MODEKEYCOPY_APPENDSELECTION:
                if (sess != NULL) {
-                       window_copy_append_selection(wp, data->numprefix);
+                       window_copy_append_selection(wp, NULL);
                        window_pane_reset_mode(wp);
                        return;
                }
@@ -543,7 +544,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
                if (sess != NULL &&
                    (cmd == MODEKEYCOPY_COPYLINE ||
                    cmd == MODEKEYCOPY_COPYENDOFLINE)) {
-                       window_copy_copy_selection(wp, -1);
+                       window_copy_copy_selection(wp, NULL);
                        window_pane_reset_mode(wp);
                        return;
                }
@@ -554,14 +555,14 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
                break;
        case MODEKEYCOPY_COPYPIPE:
                if (sess != NULL) {
-                       window_copy_copy_pipe(wp, sess, data->numprefix, arg);
+                       window_copy_copy_pipe(wp, sess, NULL, arg);
                        window_pane_reset_mode(wp);
                        return;
                }
                break;
        case MODEKEYCOPY_COPYSELECTION:
                if (sess != NULL) {
-                       window_copy_copy_selection(wp, data->numprefix);
+                       window_copy_copy_selection(wp, NULL);
                        window_pane_reset_mode(wp);
                        return;
                }
@@ -918,7 +919,7 @@ reset_mode:
        s->mode &= ~MODE_MOUSE_BUTTON;
        s->mode |= MODE_MOUSE_STANDARD;
        if (sess != NULL) {
-               window_copy_copy_selection(wp, -1);
+               window_copy_copy_selection(wp, NULL);
                window_pane_reset_mode(wp);
        }
 }
@@ -1452,9 +1453,9 @@ window_copy_get_selection(struct window_pane *wp, size_t *len)
 }
 
 void
-window_copy_copy_buffer(struct window_pane *wp, int idx, void *buf, size_t len)
+window_copy_copy_buffer(struct window_pane *wp, const char *bufname, void *buf,
+    size_t len)
 {
-       u_int                   limit;
        struct screen_write_ctx ctx;
 
        if (options_get_number(&global_options, "set-clipboard")) {
@@ -1463,16 +1464,13 @@ window_copy_copy_buffer(struct window_pane *wp, int idx, void *buf, size_t len)
                screen_write_stop(&ctx);
        }
 
-       if (idx == -1) {
-               limit = options_get_number(&global_options, "buffer-limit");
-               paste_add(buf, len, limit);
-       } else if (paste_replace(idx, buf, len) != 0)
+       if (paste_set(buf, len, bufname, NULL) != 0)
                free(buf);
 }
 
 void
-window_copy_copy_pipe(
-    struct window_pane *wp, struct session *sess, int idx, const char *arg)
+window_copy_copy_pipe(struct window_pane *wp, struct session *sess,
+    const char *bufname, const char *arg)
 {
        void            *buf;
        size_t           len;
@@ -1486,11 +1484,11 @@ window_copy_copy_pipe(
        job = job_run(arg, sess, NULL, NULL, NULL);
        bufferevent_write(job->event, buf, len);
 
-       window_copy_copy_buffer(wp, idx, buf, len);
+       window_copy_copy_buffer(wp, bufname, buf, len);
 }
 
 void
-window_copy_copy_selection(struct window_pane *wp, int idx)
+window_copy_copy_selection(struct window_pane *wp, const char *bufname)
 {
        void*   buf;
        size_t  len;
@@ -1499,17 +1497,16 @@ window_copy_copy_selection(struct window_pane *wp, int idx)
        if (buf == NULL)
                return;
 
-       window_copy_copy_buffer(wp, idx, buf, len);
+       window_copy_copy_buffer(wp, bufname, buf, len);
 }
 
 void
-window_copy_append_selection(struct window_pane *wp, int idx)
+window_copy_append_selection(struct window_pane *wp, const char *bufname)
 {
-       char                    *buf;
-       struct paste_buffer     *pb;
-       size_t                   len;
-       u_int                    limit;
-       struct screen_write_ctx  ctx;
+       char                            *buf;
+       struct paste_buffer             *pb;
+       size_t                           len;
+       struct screen_write_ctx          ctx;
 
        buf = window_copy_get_selection(wp, &len);
        if (buf == NULL)
@@ -1521,24 +1518,19 @@ window_copy_append_selection(struct window_pane *wp, int idx)
                screen_write_stop(&ctx);
        }
 
-       if (idx == -1)
-               idx = 0;
-
-       if (idx == 0 && paste_get_top() == NULL) {
-               limit = options_get_number(&global_options, "buffer-limit");
-               paste_add(buf, len, limit);
-               return;
-       }
-
-       pb = paste_get_index(idx);
+       if (bufname == NULL || *bufname == '\0') {
+               pb = paste_get_top();
+               if (pb != NULL)
+                       bufname = pb->name;
+       } else
+               pb = paste_get_name(bufname);
        if (pb != NULL) {
                buf = xrealloc(buf, 1, len + pb->size);
                memmove(buf + pb->size, buf, len);
                memcpy(buf, pb->data, pb->size);
                len += pb->size;
        }
-
-       if (paste_replace(idx, buf, len) != 0)
+       if (paste_set(buf, len, bufname, NULL) != 0)
                free(buf);
 }