I kept passing in global_buffers since that's what the existing code did, and I thought there might be a reason (planned future functionality?), so I kept it. But it makes sense to not pass it in if you don't expect other paste_stores. But why not do the same with buffer-limit? paste_add can look it up instead of having every call to paste_set look it up first and pass it in.
I thought you might object to having non-printable characters or long buffer names because it might mess up the display in list-buffer and choose-buffer. But I'll remove both restrictions if that's not a valid concern. > I renamed the compare funcs and make some other minor tweaks but didn't > change the sticky/unsticky bits. > > Why do you limit the buffer names to 16 characters? 16 characters is too > short, but why limit them at all? > > Also not certain about limiting them to printables, seems like that will > stop people using UTF-8 in buffer names. > > > Index: cmd-capture-pane.c > =================================================================== > RCS file: /cvs/src/usr.bin/tmux/cmd-capture-pane.c,v > retrieving revision 1.26 > diff -u -p -r1.26 cmd-capture-pane.c > --- cmd-capture-pane.c 24 Apr 2014 09:14:43 -0000 1.26 > +++ cmd-capture-pane.c 24 Apr 2014 09:44:42 -0000 > @@ -38,7 +38,7 @@ char *cmd_capture_pane_history(struct a > const struct cmd_entry cmd_capture_pane_entry = { > "capture-pane", "capturep", > "ab:CeE:JpPqS:t:", 0, 0, > - "[-aCeJpPq] [-b buffer-index] [-E end-line] [-S start-line]" > + "[-aCeJpPq] " CMD_BUFFER_USAGE " [-E end-line] [-S start-line]" > CMD_TARGET_PANE_USAGE, > 0, > NULL, > @@ -165,7 +165,7 @@ cmd_capture_pane_exec(struct cmd *self, > struct client *c; > struct window_pane *wp; > char *buf, *cause; > - int buffer; > + const char *bufname; > u_int limit; > size_t len; > > @@ -193,22 +193,15 @@ cmd_capture_pane_exec(struct cmd *self, > 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, limit, bufname, &cause) != 0) { > + cmdq_error(cmdq, "%s", cause); > free(buf); > + free(cause); > return (CMD_RETURN_ERROR); > } > } > Index: cmd-choose-buffer.c > =================================================================== > RCS file: /cvs/src/usr.bin/tmux/cmd-choose-buffer.c,v > retrieving revision 1.17 > diff -u -p -r1.17 cmd-choose-buffer.c > --- cmd-choose-buffer.c 24 Apr 2014 09:14:43 -0000 1.17 > +++ cmd-choose-buffer.c 24 Apr 2014 09:44:42 -0000 > @@ -75,19 +75,20 @@ cmd_choose_buffer_exec(struct cmd *self, > 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: cmd-command-prompt.c > =================================================================== > RCS file: /cvs/src/usr.bin/tmux/cmd-command-prompt.c,v > retrieving revision 1.27 > diff -u -p -r1.27 cmd-command-prompt.c > --- cmd-command-prompt.c 10 Oct 2013 12:00:19 -0000 1.27 > +++ cmd-command-prompt.c 24 Apr 2014 09:44:42 -0000 > @@ -76,6 +76,9 @@ cmd_command_prompt_key_binding(struct cm > 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; > Index: cmd-delete-buffer.c > =================================================================== > RCS file: /cvs/src/usr.bin/tmux/cmd-delete-buffer.c,v > retrieving revision 1.11 > diff -u -p -r1.11 cmd-delete-buffer.c > --- cmd-delete-buffer.c 24 Apr 2014 09:14:43 -0000 1.11 > +++ cmd-delete-buffer.c 24 Apr 2014 09:44:42 -0000 > @@ -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: cmd-list-buffers.c > =================================================================== > RCS file: /cvs/src/usr.bin/tmux/cmd-list-buffers.c,v > retrieving revision 1.20 > diff -u -p -r1.20 cmd-list-buffers.c > --- cmd-list-buffers.c 24 Apr 2014 09:14:43 -0000 1.20 > +++ cmd-list-buffers.c 24 Apr 2014 09:44:43 -0000 > @@ -44,17 +44,15 @@ cmd_list_buffers_exec(unused struct cmd > 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: cmd-load-buffer.c > =================================================================== > RCS file: /cvs/src/usr.bin/tmux/cmd-load-buffer.c,v > retrieving revision 1.28 > diff -u -p -r1.28 cmd-load-buffer.c > --- cmd-load-buffer.c 24 Apr 2014 09:14:43 -0000 1.28 > +++ cmd-load-buffer.c 24 Apr 2014 09:44:43 -0000 > @@ -50,30 +50,20 @@ cmd_load_buffer_exec(struct cmd *self, s > 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; > + int ch, error, 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); > - } > - } > + bufname = NULL; > + if (args_has(args, 'b')) > + bufname = args_get(args, 'b'); > > path = args->argv[0]; > if (strcmp(path, "-") == 0) { > - buffer_ptr = xmalloc(sizeof *buffer_ptr); > - *buffer_ptr = buffer; > - > error = server_set_stdin_callback(c, cmd_load_buffer_callback, > - buffer_ptr, &cause); > + bufname, &cause); > if (error != 0) { > cmdq_error(cmdq, "%s: %s", path, cause); > free(cause); > @@ -118,13 +108,10 @@ cmd_load_buffer_exec(struct cmd *self, s > 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, limit, bufname, &cause) != 0) { > + cmdq_error(cmdq, "%s", cause); > free(pdata); > + free(cause); > return (CMD_RETURN_ERROR); > } > > @@ -140,10 +127,10 @@ error: > void > cmd_load_buffer_callback(struct client *c, int closed, void *data) > { > - int *buffer = data; > - char *pdata; > - size_t psize; > - u_int limit; > + char *pdata, *cause; > + const char *bufname = data; > + size_t psize; > + u_int limit; > > if (!closed) > return; > @@ -154,25 +141,21 @@ cmd_load_buffer_callback(struct client * > 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, limit, bufname, &cause) != 0) { > /* No context so can't use server_client_msg_error. */ > - evbuffer_add_printf(c->stderr_data, "no buffer %d\n", > *buffer); > + evbuffer_add_printf(c->stderr_data, "%s", cause); > server_push_stderr(c); > free(pdata); > + free(cause); > } > - > - free(data); > > out: > cmdq_continue(c->cmdq); > Index: cmd-paste-buffer.c > =================================================================== > RCS file: /cvs/src/usr.bin/tmux/cmd-paste-buffer.c,v > retrieving revision 1.24 > diff -u -p -r1.24 cmd-paste-buffer.c > --- cmd-paste-buffer.c 24 Apr 2014 09:14:43 -0000 1.24 > +++ cmd-paste-buffer.c 24 Apr 2014 09:44:43 -0000 > @@ -36,7 +36,7 @@ void cmd_paste_buffer_filter(struct wind > 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 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, > > /* 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: cmd-save-buffer.c > =================================================================== > RCS file: /cvs/src/usr.bin/tmux/cmd-save-buffer.c,v > retrieving revision 1.24 > diff -u -p -r1.24 cmd-save-buffer.c > --- cmd-save-buffer.c 24 Apr 2014 09:14:43 -0000 1.24 > +++ cmd-save-buffer.c 24 Apr 2014 09:44:43 -0000 > @@ -59,10 +59,10 @@ cmd_save_buffer_exec(struct cmd *self, s > 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, s > 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: cmd-set-buffer.c > =================================================================== > RCS file: /cvs/src/usr.bin/tmux/cmd-set-buffer.c,v > retrieving revision 1.17 > diff -u -p -r1.17 cmd-set-buffer.c > --- cmd-set-buffer.c 24 Apr 2014 09:14:43 -0000 1.17 > +++ cmd-set-buffer.c 24 Apr 2014 09:44:43 -0000 > @@ -31,8 +31,8 @@ enum cmd_retval cmd_set_buffer_exec(str > > const struct cmd_entry cmd_set_buffer_entry = { > "set-buffer", "setb", > - "ab:", 1, 1, > - "[-a] " CMD_BUFFER_USAGE " data", > + "ab:n:su", 0, 1, > + "[-asu] [-n new_buffer_name] " CMD_BUFFER_USAGE " data", > 0, > NULL, > cmd_set_buffer_exec > @@ -45,36 +45,104 @@ cmd_set_buffer_exec(struct cmd *self, st > struct paste_buffer *pb; > u_int limit; > char *pdata, *cause; > + u_char sticky; > + const char *bufname; > size_t psize, newsize; > - int buffer; > > + bufname = NULL; > limit = options_get_number(&global_options, "buffer-limit"); > > - psize = 0; > - pdata = NULL; > > - pb = NULL; > - buffer = -1; > + if (args_has(args, 'n')) { > + if (args_has(args, 's') || args_has(args, 'u')) { > + cmdq_error(cmdq, "specify only 1 of n, s, or u > flags"); > + return (CMD_RETURN_ERROR); > + } > > - if ((newsize = strlen(args->argv[0])) == 0) > - return (CMD_RETURN_NORMAL); > + if (args->argc > 0) { > + cmdq_error(cmdq, "don't provide data with n flag"); > + return (CMD_RETURN_ERROR); > + } > > - if (args_has(args, 'b')) { > - buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); > - if (cause != NULL) { > - cmdq_error(cmdq, "buffer %s", cause); > + if (args_has(args, 'b')) > + bufname = args_get(args, 'b'); > + > + if (bufname == NULL) { > + pb = paste_get_top(); > + 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); > } > - pb = paste_get_index(buffer); > + > + return (CMD_RETURN_NORMAL); > + } > + > + if (args_has(args, 's') && args_has(args, 'u')) { > + cmdq_error(cmdq, "specify only 1 of s or u flags"); > + return (CMD_RETURN_ERROR); > + } > + > + if (args_has(args, 's') || args_has(args, 'u')) { > + sticky = 0; > + if (args_has(args, 's')) > + sticky = 1; > + > + if (args->argc > 0) { > + cmdq_error(cmdq, "don't provide data with s or u > flags"); > + return (CMD_RETURN_ERROR); > + } > + > + if (args_has(args, 'b')) > + bufname = args_get(args, 'b'); > + > + if (bufname == NULL) > + pb = paste_get_top(); > + else > + pb = paste_get_name(bufname); > + > if (pb == NULL) { > - cmdq_error(cmdq, "no buffer %d", buffer); > + if (bufname == NULL) > + bufname = ""; > + cmdq_error(cmdq, "no buffer %s", bufname); > return (CMD_RETURN_ERROR); > } > + > + if (sticky == 0) > + paste_make_unsticky(pb->name, limit); > + else > + paste_make_sticky(pb->name); > + > + return (CMD_RETURN_NORMAL); > + } > + > + if (args->argc != 1) { > + cmdq_error(cmdq, "no data specified"); > + return (CMD_RETURN_ERROR); > + } > + > + psize = 0; > + pdata = NULL; > + > + pb = NULL; > + > + if ((newsize = strlen(args->argv[0])) == 0) > + return (CMD_RETURN_NORMAL); > + > + if (args_has(args, 'b')) { > + bufname = args_get(args, 'b'); > + pb = paste_get_name(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 +155,12 @@ cmd_set_buffer_exec(struct cmd *self, st > 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, limit, bufname, &cause) != 0) { > + cmdq_error(cmdq, "%s", cause); > + free(pdata); > + free(cause); > + return (CMD_RETURN_ERROR); > + } > > return (CMD_RETURN_NORMAL); > } > Index: format.c > =================================================================== > RCS file: /cvs/src/usr.bin/tmux/format.c,v > retrieving revision 1.44 > diff -u -p -r1.44 format.c > --- format.c 17 Apr 2014 15:37:55 -0000 1.44 > +++ format.c 24 Apr 2014 09:44:43 -0000 > @@ -608,6 +608,9 @@ format_paste_buffer(struct format_tree * > 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); > Index: key-bindings.c > =================================================================== > RCS file: /cvs/src/usr.bin/tmux/key-bindings.c,v > retrieving revision 1.40 > diff -u -p -r1.40 key-bindings.c > --- key-bindings.c 17 Apr 2014 07:55:43 -0000 1.40 > +++ key-bindings.c 24 Apr 2014 09:44:43 -0000 > @@ -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 }, > Index: mode-key.c > =================================================================== > RCS file: /cvs/src/usr.bin/tmux/mode-key.c,v > retrieving revision 1.58 > diff -u -p -r1.58 mode-key.c > --- mode-key.c 31 Mar 2014 21:39:31 -0000 1.58 > +++ mode-key.c 24 Apr 2014 09:44:43 -0000 > @@ -51,6 +51,7 @@ const struct mode_key_cmdstr mode_key_cm > { 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_cm > { 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_ > { '\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_ch > /* 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 }, > Index: paste.c > =================================================================== > RCS file: /cvs/src/usr.bin/tmux/paste.c,v > retrieving revision 1.18 > diff -u -p -r1.18 paste.c > --- paste.c 24 Apr 2014 09:14:43 -0000 1.18 > +++ paste.c 24 Apr 2014 09:44:43 -0000 > @@ -19,6 +19,7 @@ > #include <sys/types.h> > #include <sys/time.h> > > +#include <ctype.h> > #include <stdlib.h> > #include <string.h> > #include <vis.h> > @@ -30,124 +31,300 @@ > * 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; > + > +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); > > -/* 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 *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 (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); > + 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) > { > struct paste_buffer *pb; > + u_int 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); > + 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) > +{ > + const char *c; > + struct paste_buffer *pb; > + > + *cause = NULL; > + > + if (oldname == NULL || *oldname == '\0') { > + *cause = xstrdup("no buffer"); > + return (-1); > + } > + > + if (newname == NULL || *newname == '\0') { > + *cause = xstrdup("new name is empty"); > + return (-1); > + } > + > + if ((pb = paste_get_name(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); > + } > + > + if (strlen(newname) > 16) { > + *cause = xstrdup("buffer name too long"); > + return (-1); > + } > + > + for (c = newname; *c != '\0'; c++) { > + if (!isprint(*c) || isspace(*c)) { > + *cause = xstrdup("bad characters in buffer name"); > + return (-1); > + } > + } > + > + RB_REMOVE(paste_name_tree, &paste_by_name, pb); > + free(pb->name); > + > + pb->name = xstrdup(newname); > + 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, u_int limit, const char *name, char > **cause) > { > struct paste_buffer *pb; > + const char *c; > + > + if (cause != NULL) > + *cause = NULL; > > if (size == 0) { > free(data); > return (0); > } > > - if (idx >= ARRAY_LENGTH(&paste_buffers)) > + if (name == NULL) { > + paste_add(data, size, limit); > + return (0); > + } > + > + > + 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 = ARRAY_ITEM(&paste_buffers, idx); > - free(pb->data); > + if (strlen(name) > 16) { > + if (cause != NULL) > + *cause = xstrdup("buffer name too long"); > + return (-1); > + } > + for (c = name; *c != '\0'; c++) { > + if (!isprint(*c) || isspace(*c)) { > + if (cause != NULL) > + *cause = xstrdup("invalid 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); > +} > + > +/* Set paste buffer sticky. */ > +void > +paste_make_sticky(const char *name) > +{ > + struct paste_buffer *pb; > + > + if ((pb = paste_get_name(name)) == NULL) > + return; > + > + if (pb->sticky == 1) > + return; > + > + RB_REMOVE(paste_time_tree, &paste_by_time, pb); > + paste_num_unsticky--; > + > + pb->sticky = 1; > +} > + > +/* Set paste buffer unsticky. */ > +void > +paste_make_unsticky(const char *name, u_int limit) > +{ > + struct paste_buffer *pb, *tmppb; > + u_int next_crtime; > + > + if ((pb = paste_get_name(name)) == NULL) > + return; > + > + if (pb->sticky == 0) > + return; > + > + while (paste_num_unsticky >= limit) { > + tmppb = RB_MIN(paste_time_tree, &paste_by_time); > + paste_free_name(tmppb->name); > + } > + > + next_crtime = 0; > + if (paste_num_unsticky > 0) { > + tmppb = RB_MAX(paste_time_tree, &paste_by_time); > + next_crtime = tmppb->crtime + 1; > + } > + > + pb->sticky = 0; > + pb->crtime = next_crtime; > + > + RB_INSERT(paste_time_tree, &paste_by_time, pb); > + paste_num_unsticky++; > } > > /* Convert start of buffer into a nice string. */ > Index: tmux.h > =================================================================== > RCS file: /cvs/src/usr.bin/tmux/tmux.h,v > retrieving revision 1.457 > diff -u -p -r1.457 tmux.h > --- tmux.h 24 Apr 2014 09:14:43 -0000 1.457 > +++ tmux.h 24 Apr 2014 09:44:43 -0000 > @@ -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 \ > @@ -499,6 +500,7 @@ enum mode_key_cmd { > MODEKEYEDIT_DELETEWORD, > MODEKEYEDIT_ENDOFLINE, > MODEKEYEDIT_ENTER, > + MODEKEYEDIT_ENTERAPPEND, > MODEKEYEDIT_HISTORYDOWN, > MODEKEYEDIT_HISTORYUP, > MODEKEYEDIT_NEXTSPACE, > @@ -582,6 +584,7 @@ enum mode_key_cmd { > MODEKEYCOPY_SEARCHREVERSE, > MODEKEYCOPY_SEARCHUP, > MODEKEYCOPY_SELECTLINE, > + MODEKEYCOPY_STARTNAMEDBUFFER, > MODEKEYCOPY_STARTNUMBERPREFIX, > MODEKEYCOPY_STARTOFLINE, > MODEKEYCOPY_STARTSELECTION, > @@ -1035,7 +1038,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. */ > @@ -1496,7 +1505,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; > @@ -1708,14 +1717,17 @@ 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); > +int paste_free_name(const char *); > void paste_add(char *, size_t, u_int); > -int paste_replace(u_int, char *, size_t); > +int paste_rename(const char *, const char *, char **); > +int paste_set(char *, size_t, u_int, const char *, char **); > char *paste_make_sample(struct paste_buffer *, int); > +void paste_make_sticky(const char *); > +void paste_make_unsticky(const char *, u_int); > void paste_send_pane(struct paste_buffer *, struct window_pane *, > const char *, int); > > Index: window-copy.c > =================================================================== > RCS file: /cvs/src/usr.bin/tmux/window-copy.c,v > retrieving revision 1.107 > diff -u -p -r1.107 window-copy.c > --- window-copy.c 24 Apr 2014 09:14:43 -0000 1.107 > +++ window-copy.c 24 Apr 2014 09:44:43 -0000 > @@ -54,11 +54,12 @@ void window_copy_update_cursor(struct wi > 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_mod > > 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, > 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, > 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, > 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, > 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, > 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 > 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 > } > data->numprefix = -1; > return (1); > + case MODEKEYEDIT_ENTERAPPEND: > + switch (data->inputtype) { > + case WINDOW_COPY_NAMEDBUFFER: > + window_copy_append_selection(wp, data->inputstr); > + *data->inputstr = '\0'; > + window_pane_reset_mode(wp); > + return (0); > + default: > + break; > + } > + break; > case MODEKEY_OTHER: > if (key < 32 || key > 126) > break; > @@ -918,7 +942,7 @@ reset_mode: > s->mode &= ~MODE_MOUSE_BUTTON; > s->mode |= MODE_MOUSE_STANDARD; > if (sess != NULL) { > - window_copy_copy_selection(wp, -1); > + window_copy_copy_selection(wp, NULL); > window_pane_reset_mode(wp); > } > } > @@ -1452,10 +1476,11 @@ window_copy_get_selection(struct window_ > } > > void > -window_copy_copy_buffer(struct window_pane *wp, int idx, void *buf, size_t > len) > +window_copy_copy_buffer(struct window_pane *wp, const char *bufname, void > *buf, > + size_t len) > { > - u_int limit; > - struct screen_write_ctx ctx; > + u_int limit; > + struct screen_write_ctx ctx; > > if (options_get_number(&global_options, "set-clipboard")) { > screen_write_start(&ctx, wp, NULL); > @@ -1463,16 +1488,16 @@ window_copy_copy_buffer(struct window_pa > 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) > + limit = options_get_number(&global_options, "buffer-limit"); > + if (paste_set(buf, len, limit, bufname, NULL) != 0) > free(buf); > + > + return; > } > > void > -window_copy_copy_pipe( > - struct window_pane *wp, struct session *sess, int idx, const char *arg) > +window_copy_copy_pipe(struct window_pane *wp, struct session *sess, > + const char *bufname, const char *arg) > { > void *buf; > size_t len; > @@ -1486,11 +1511,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 +1524,17 @@ window_copy_copy_selection(struct window > if (buf == NULL) > return; > > - window_copy_copy_buffer(wp, idx, buf, len); > + window_copy_copy_buffer(wp, bufname, buf, len); > } > > void > -window_copy_append_selection(struct window_pane *wp, int idx) > +window_copy_append_selection(struct window_pane *wp, const char *bufname) > { > - char *buf; > - struct paste_buffer *pb; > - size_t len; > - u_int limit; > - struct screen_write_ctx ctx; > + char *buf; > + struct paste_buffer *pb; > + size_t len; > + u_int limit; > + struct screen_write_ctx ctx; > > buf = window_copy_get_selection(wp, &len); > if (buf == NULL) > @@ -1521,24 +1546,20 @@ window_copy_append_selection(struct wind > 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); > + limit = options_get_number(&global_options, "buffer-limit"); > + 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, limit, bufname, NULL) != 0) > free(buf); > } > ------------------------------------------------------------------------------ Start Your Social Network Today - Download eXo Platform Build your Enterprise Intranet with eXo Platform Software Java Based Open Source Intranet - Social, Extensible, Cloud Ready Get Started Now And Turn Your Intranet Into A Collaboration Platform http://p.sf.net/sfu/ExoPlatform _______________________________________________ tmux-users mailing list tmux-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/tmux-users