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
[email protected]
https://lists.sourceforge.net/lists/listinfo/tmux-users