diff options
Diffstat (limited to 'paste.c')
-rw-r--r-- | paste.c | 245 |
1 files changed, 184 insertions, 61 deletions
@@ -1,4 +1,4 @@ -/* $Id$ */ +/* $OpenBSD$ */ /* * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> @@ -25,159 +25,282 @@ #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! */ -/* Return each item of the stack in turn. */ -struct paste_buffer * -paste_walk_stack(struct paste_stack *ps, u_int *idx) +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; + +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(ps, *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(struct paste_stack *ps) +paste_walk(struct paste_buffer *pb) { - if (ARRAY_LENGTH(ps) == 0) - return (NULL); - return (ARRAY_FIRST(ps)); + 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(struct paste_stack *ps, u_int idx) +paste_get_top(void) { - if (idx >= ARRAY_LENGTH(ps)) + struct paste_buffer *pb; + + pb = RB_MIN(paste_time_tree, &paste_by_time); + if (pb == NULL) return (NULL); - return (ARRAY_ITEM(ps, idx)); + return (pb); } -/* Free the top item on the stack. */ +/* Free the most recent buffer. */ int -paste_free_top(struct paste_stack *ps) +paste_free_top(void) { struct paste_buffer *pb; - if (ARRAY_LENGTH(ps) == 0) + pb = paste_get_top(); + if (pb == NULL) return (-1); + return (paste_free_name(pb->name)); +} - pb = ARRAY_FIRST(ps); - ARRAY_REMOVE(ps, 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(struct paste_stack *ps, 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(ps)) + pbfind.name = (char *)name; + pb = RB_FIND(paste_name_tree, &paste_by_name, &pbfind); + if (pb == NULL) return (-1); - pb = ARRAY_ITEM(ps, idx); - ARRAY_REMOVE(ps, 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(struct paste_stack *ps, 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(ps) >= limit) { - pb = ARRAY_LAST(ps); - free(pb->data); - free(pb); - ARRAY_TRUNC(ps, 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(ps, 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, *pb_new; + + 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); + } + + pb_new = paste_get_name(newname); + if (pb_new != NULL) { + if (cause != NULL) + xasprintf(cause, "buffer %s already exists", newname); + 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(struct paste_stack *ps, 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(ps)) + if (*name == '\0') { + if (cause != NULL) + *cause = xstrdup("empty buffer name"); return (-1); + } - pb = ARRAY_ITEM(ps, 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); } -/* Convert a buffer into a visible string. */ +/* Convert start of buffer into a nice string. */ char * -paste_print(struct paste_buffer *pb, size_t width) +paste_make_sample(struct paste_buffer *pb, int utf8flag) { - char *buf; - size_t len, used; - - if (width < 3) - width = 3; - buf = xmalloc(width * 4 + 1); + char *buf; + size_t len, used; + const int flags = VIS_OCTAL|VIS_TAB|VIS_NL; + const size_t width = 200; len = pb->size; if (len > width) len = width; + buf = xreallocarray(NULL, len, 4 + 4); - used = strvisx(buf, pb->data, len, VIS_OCTAL|VIS_TAB|VIS_NL); + if (utf8flag) + used = utf8_strvis(buf, pb->data, len, flags); + else + used = strvisx(buf, pb->data, len, flags); if (pb->size > width || used > width) - strlcpy(buf + width - 3, "...", 4); - + strlcpy(buf + width, "...", 4); return (buf); } /* Paste into a window pane, filtering '\n' according to separator. */ void -paste_send_pane (struct paste_buffer *pb, struct window_pane *wp, +paste_send_pane(struct paste_buffer *pb, struct window_pane *wp, const char *sep, int bracket) { const char *data = pb->data, *end = data + pb->size, *lf; size_t seplen; - if (bracket) + if (wp->flags & PANE_INPUTOFF) + return; + + if (bracket && (wp->screen->mode & MODE_BRACKETPASTE)) bufferevent_write(wp->event, "\033[200~", 6); seplen = strlen(sep); @@ -191,6 +314,6 @@ paste_send_pane (struct paste_buffer *pb, struct window_pane *wp, if (end != data) bufferevent_write(wp->event, data, end - data); - if (bracket) + if (bracket && (wp->screen->mode & MODE_BRACKETPASTE)) bufferevent_write(wp->event, "\033[201~", 6); } |