1c9ad075bSchristos /* $OpenBSD$ */ 2c9ad075bSchristos 3c9ad075bSchristos /* 4c9ad075bSchristos * Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com> 5c9ad075bSchristos * 6c9ad075bSchristos * Permission to use, copy, modify, and distribute this software for any 7c9ad075bSchristos * purpose with or without fee is hereby granted, provided that the above 8c9ad075bSchristos * copyright notice and this permission notice appear in all copies. 9c9ad075bSchristos * 10c9ad075bSchristos * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11c9ad075bSchristos * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12c9ad075bSchristos * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13c9ad075bSchristos * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14c9ad075bSchristos * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15c9ad075bSchristos * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16c9ad075bSchristos * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17c9ad075bSchristos */ 18c9ad075bSchristos 19c9ad075bSchristos #include <sys/types.h> 20c9ad075bSchristos 21e271dbb8Schristos #include <stdio.h> 22c9ad075bSchristos #include <stdlib.h> 23c9ad075bSchristos #include <string.h> 24c9ad075bSchristos #include <time.h> 25e271dbb8Schristos #include <unistd.h> 26c9ad075bSchristos 27c9ad075bSchristos #include "tmux.h" 28c9ad075bSchristos 290a274e86Schristos static struct screen *window_buffer_init(struct window_mode_entry *, 30c9ad075bSchristos struct cmd_find_state *, struct args *); 310a274e86Schristos static void window_buffer_free(struct window_mode_entry *); 320a274e86Schristos static void window_buffer_resize(struct window_mode_entry *, u_int, 33c9ad075bSchristos u_int); 34e271dbb8Schristos static void window_buffer_update(struct window_mode_entry *); 350a274e86Schristos static void window_buffer_key(struct window_mode_entry *, 360a274e86Schristos struct client *, struct session *, 370a274e86Schristos struct winlink *, key_code, struct mouse_event *); 38c9ad075bSchristos 39*890b6d91Swiz #define WINDOW_BUFFER_DEFAULT_COMMAND "paste-buffer -p -b '%%'" 40c9ad075bSchristos 41c9ad075bSchristos #define WINDOW_BUFFER_DEFAULT_FORMAT \ 42e271dbb8Schristos "#{t/p:buffer_created}: #{buffer_sample}" 43e271dbb8Schristos 44e271dbb8Schristos #define WINDOW_BUFFER_DEFAULT_KEY_FORMAT \ 45e271dbb8Schristos "#{?#{e|<:#{line},10}," \ 46e271dbb8Schristos "#{line}" \ 47e271dbb8Schristos "," \ 48e271dbb8Schristos "#{?#{e|<:#{line},36}," \ 49e271dbb8Schristos "M-#{a:#{e|+:97,#{e|-:#{line},10}}}" \ 50e271dbb8Schristos "," \ 51e271dbb8Schristos "" \ 52e271dbb8Schristos "}" \ 53e271dbb8Schristos "}" 54c9ad075bSchristos 5530744affSchristos static const struct menu_item window_buffer_menu_items[] = { 5630744affSchristos { "Paste", 'p', NULL }, 5730744affSchristos { "Paste Tagged", 'P', NULL }, 5830744affSchristos { "", KEYC_NONE, NULL }, 5930744affSchristos { "Tag", 't', NULL }, 6030744affSchristos { "Tag All", '\024', NULL }, 6130744affSchristos { "Tag None", 'T', NULL }, 6230744affSchristos { "", KEYC_NONE, NULL }, 6330744affSchristos { "Delete", 'd', NULL }, 6430744affSchristos { "Delete Tagged", 'D', NULL }, 6530744affSchristos { "", KEYC_NONE, NULL }, 6630744affSchristos { "Cancel", 'q', NULL }, 6730744affSchristos 6830744affSchristos { NULL, KEYC_NONE, NULL } 6930744affSchristos }; 7030744affSchristos 71c9ad075bSchristos const struct window_mode window_buffer_mode = { 72c9ad075bSchristos .name = "buffer-mode", 730a274e86Schristos .default_format = WINDOW_BUFFER_DEFAULT_FORMAT, 74c9ad075bSchristos 75c9ad075bSchristos .init = window_buffer_init, 76c9ad075bSchristos .free = window_buffer_free, 77c9ad075bSchristos .resize = window_buffer_resize, 78e271dbb8Schristos .update = window_buffer_update, 79c9ad075bSchristos .key = window_buffer_key, 80c9ad075bSchristos }; 81c9ad075bSchristos 82c9ad075bSchristos enum window_buffer_sort_type { 83c9ad075bSchristos WINDOW_BUFFER_BY_TIME, 84c9ad075bSchristos WINDOW_BUFFER_BY_NAME, 85c9ad075bSchristos WINDOW_BUFFER_BY_SIZE, 86c9ad075bSchristos }; 87c9ad075bSchristos static const char *window_buffer_sort_list[] = { 88c9ad075bSchristos "time", 89c9ad075bSchristos "name", 90c9ad075bSchristos "size" 91c9ad075bSchristos }; 9268e6ba84Schristos static struct mode_tree_sort_criteria *window_buffer_sort; 93c9ad075bSchristos 94c9ad075bSchristos struct window_buffer_itemdata { 95c9ad075bSchristos const char *name; 96c9ad075bSchristos u_int order; 97c9ad075bSchristos size_t size; 98c9ad075bSchristos }; 99c9ad075bSchristos 100c9ad075bSchristos struct window_buffer_modedata { 10130744affSchristos struct window_pane *wp; 10230744affSchristos struct cmd_find_state fs; 10330744affSchristos 104c9ad075bSchristos struct mode_tree_data *data; 105c9ad075bSchristos char *command; 106c9ad075bSchristos char *format; 107e271dbb8Schristos char *key_format; 108c9ad075bSchristos 109c9ad075bSchristos struct window_buffer_itemdata **item_list; 110c9ad075bSchristos u_int item_size; 111c9ad075bSchristos }; 112c9ad075bSchristos 113e271dbb8Schristos struct window_buffer_editdata { 114e271dbb8Schristos u_int wp_id; 115e271dbb8Schristos char *name; 116e271dbb8Schristos struct paste_buffer *pb; 117e271dbb8Schristos }; 118e271dbb8Schristos 119c9ad075bSchristos static struct window_buffer_itemdata * 120c9ad075bSchristos window_buffer_add_item(struct window_buffer_modedata *data) 121c9ad075bSchristos { 122c9ad075bSchristos struct window_buffer_itemdata *item; 123c9ad075bSchristos 124c9ad075bSchristos data->item_list = xreallocarray(data->item_list, data->item_size + 1, 125c9ad075bSchristos sizeof *data->item_list); 126c9ad075bSchristos item = data->item_list[data->item_size++] = xcalloc(1, sizeof *item); 127c9ad075bSchristos return (item); 128c9ad075bSchristos } 129c9ad075bSchristos 130c9ad075bSchristos static void 131c9ad075bSchristos window_buffer_free_item(struct window_buffer_itemdata *item) 132c9ad075bSchristos { 133fe99a117Schristos free(__UNCONST(item->name)); 134c9ad075bSchristos free(item); 135c9ad075bSchristos } 136c9ad075bSchristos 137c9ad075bSchristos static int 13868e6ba84Schristos window_buffer_cmp(const void *a0, const void *b0) 139c9ad075bSchristos { 140c9ad075bSchristos const struct window_buffer_itemdata *const *a = a0; 141c9ad075bSchristos const struct window_buffer_itemdata *const *b = b0; 14268e6ba84Schristos int result = 0; 143c9ad075bSchristos 14468e6ba84Schristos if (window_buffer_sort->field == WINDOW_BUFFER_BY_TIME) 14568e6ba84Schristos result = (*b)->order - (*a)->order; 14668e6ba84Schristos else if (window_buffer_sort->field == WINDOW_BUFFER_BY_SIZE) 14768e6ba84Schristos result = (*b)->size - (*a)->size; 148c9ad075bSchristos 14968e6ba84Schristos /* Use WINDOW_BUFFER_BY_NAME as default order and tie breaker. */ 15068e6ba84Schristos if (result == 0) 15168e6ba84Schristos result = strcmp((*a)->name, (*b)->name); 152c9ad075bSchristos 15368e6ba84Schristos if (window_buffer_sort->reversed) 15468e6ba84Schristos result = -result; 15568e6ba84Schristos return (result); 156c9ad075bSchristos } 157c9ad075bSchristos 158c9ad075bSchristos static void 15968e6ba84Schristos window_buffer_build(void *modedata, struct mode_tree_sort_criteria *sort_crit, 16068e6ba84Schristos __unused uint64_t *tag, const char *filter) 161c9ad075bSchristos { 162c9ad075bSchristos struct window_buffer_modedata *data = modedata; 163c9ad075bSchristos struct window_buffer_itemdata *item; 164c9ad075bSchristos u_int i; 165c9ad075bSchristos struct paste_buffer *pb; 166c9ad075bSchristos char *text, *cp; 167c9ad075bSchristos struct format_tree *ft; 16830744affSchristos struct session *s = NULL; 16930744affSchristos struct winlink *wl = NULL; 17030744affSchristos struct window_pane *wp = NULL; 171c9ad075bSchristos 172c9ad075bSchristos for (i = 0; i < data->item_size; i++) 173c9ad075bSchristos window_buffer_free_item(data->item_list[i]); 174c9ad075bSchristos free(data->item_list); 175c9ad075bSchristos data->item_list = NULL; 176c9ad075bSchristos data->item_size = 0; 177c9ad075bSchristos 178c9ad075bSchristos pb = NULL; 179c9ad075bSchristos while ((pb = paste_walk(pb)) != NULL) { 180c9ad075bSchristos item = window_buffer_add_item(data); 181c9ad075bSchristos item->name = xstrdup(paste_buffer_name(pb)); 182c9ad075bSchristos paste_buffer_data(pb, &item->size); 183c9ad075bSchristos item->order = paste_buffer_order(pb); 184c9ad075bSchristos } 185c9ad075bSchristos 18668e6ba84Schristos window_buffer_sort = sort_crit; 187c9ad075bSchristos qsort(data->item_list, data->item_size, sizeof *data->item_list, 18868e6ba84Schristos window_buffer_cmp); 189c9ad075bSchristos 19030744affSchristos if (cmd_find_valid_state(&data->fs)) { 19130744affSchristos s = data->fs.s; 19230744affSchristos wl = data->fs.wl; 19330744affSchristos wp = data->fs.wp; 19430744affSchristos } 19530744affSchristos 196c9ad075bSchristos for (i = 0; i < data->item_size; i++) { 197c9ad075bSchristos item = data->item_list[i]; 198c9ad075bSchristos 199c9ad075bSchristos pb = paste_get_name(item->name); 200c9ad075bSchristos if (pb == NULL) 201c9ad075bSchristos continue; 202c9ad075bSchristos ft = format_create(NULL, NULL, FORMAT_NONE, 0); 20330744affSchristos format_defaults(ft, NULL, s, wl, wp); 204c9ad075bSchristos format_defaults_paste_buffer(ft, pb); 205c9ad075bSchristos 206c9ad075bSchristos if (filter != NULL) { 207c9ad075bSchristos cp = format_expand(ft, filter); 208c9ad075bSchristos if (!format_true(cp)) { 209c9ad075bSchristos free(cp); 210c9ad075bSchristos format_free(ft); 211c9ad075bSchristos continue; 212c9ad075bSchristos } 213c9ad075bSchristos free(cp); 214c9ad075bSchristos } 215c9ad075bSchristos 216c9ad075bSchristos text = format_expand(ft, data->format); 217c9ad075bSchristos mode_tree_add(data->data, NULL, item, item->order, item->name, 218c9ad075bSchristos text, -1); 219c9ad075bSchristos free(text); 220c9ad075bSchristos 221c9ad075bSchristos format_free(ft); 222c9ad075bSchristos } 223c9ad075bSchristos 224c9ad075bSchristos } 225c9ad075bSchristos 226c7e17de0Schristos static void 227c7e17de0Schristos window_buffer_draw(__unused void *modedata, void *itemdata, 228c7e17de0Schristos struct screen_write_ctx *ctx, u_int sx, u_int sy) 229c9ad075bSchristos { 230c9ad075bSchristos struct window_buffer_itemdata *item = itemdata; 231c9ad075bSchristos struct paste_buffer *pb; 23268e6ba84Schristos const char *pdata, *start, *end; 23368e6ba84Schristos char *buf = NULL; 23468e6ba84Schristos size_t psize; 235c7e17de0Schristos u_int i, cx = ctx->s->cx, cy = ctx->s->cy; 236c9ad075bSchristos 237c9ad075bSchristos pb = paste_get_name(item->name); 238c9ad075bSchristos if (pb == NULL) 239c7e17de0Schristos return; 240c9ad075bSchristos 241c9ad075bSchristos pdata = end = paste_buffer_data(pb, &psize); 242c9ad075bSchristos for (i = 0; i < sy; i++) { 24368e6ba84Schristos start = end; 24468e6ba84Schristos while (end != pdata + psize && *end != '\n') 245c9ad075bSchristos end++; 24668e6ba84Schristos buf = xreallocarray(buf, 4, end - start + 1); 247e271dbb8Schristos utf8_strvis(buf, start, end - start, 248e271dbb8Schristos VIS_OCTAL|VIS_CSTYLE|VIS_TAB); 24968e6ba84Schristos if (*buf != '\0') { 2500a274e86Schristos screen_write_cursormove(ctx, cx, cy + i, 0); 25168e6ba84Schristos screen_write_nputs(ctx, sx, &grid_default_cell, "%s", 25268e6ba84Schristos buf); 253c9ad075bSchristos } 254c9ad075bSchristos 255c9ad075bSchristos if (end == pdata + psize) 256c9ad075bSchristos break; 257c9ad075bSchristos end++; 258c9ad075bSchristos } 25968e6ba84Schristos free(buf); 260c9ad075bSchristos } 261c9ad075bSchristos 262c9ad075bSchristos static int 263c9ad075bSchristos window_buffer_search(__unused void *modedata, void *itemdata, const char *ss) 264c9ad075bSchristos { 265c9ad075bSchristos struct window_buffer_itemdata *item = itemdata; 266c9ad075bSchristos struct paste_buffer *pb; 267c9ad075bSchristos const char *bufdata; 268c9ad075bSchristos size_t bufsize; 269c9ad075bSchristos 270c9ad075bSchristos if ((pb = paste_get_name(item->name)) == NULL) 271c9ad075bSchristos return (0); 272c9ad075bSchristos if (strstr(item->name, ss) != NULL) 273c9ad075bSchristos return (1); 274c9ad075bSchristos bufdata = paste_buffer_data(pb, &bufsize); 275c9ad075bSchristos return (memmem(bufdata, bufsize, ss, strlen(ss)) != NULL); 276c9ad075bSchristos } 277c9ad075bSchristos 27830744affSchristos static void 27930744affSchristos window_buffer_menu(void *modedata, struct client *c, key_code key) 28030744affSchristos { 28130744affSchristos struct window_buffer_modedata *data = modedata; 28230744affSchristos struct window_pane *wp = data->wp; 28330744affSchristos struct window_mode_entry *wme; 28430744affSchristos 28530744affSchristos wme = TAILQ_FIRST(&wp->modes); 28630744affSchristos if (wme == NULL || wme->data != modedata) 28730744affSchristos return; 28830744affSchristos window_buffer_key(wme, c, NULL, NULL, key, NULL); 28930744affSchristos } 29030744affSchristos 291e271dbb8Schristos static key_code 292e271dbb8Schristos window_buffer_get_key(void *modedata, void *itemdata, u_int line) 293e271dbb8Schristos { 294e271dbb8Schristos struct window_buffer_modedata *data = modedata; 295e271dbb8Schristos struct window_buffer_itemdata *item = itemdata; 296e271dbb8Schristos struct format_tree *ft; 29759b94b2cSchristos struct session *s = NULL; 29859b94b2cSchristos struct winlink *wl = NULL; 299e271dbb8Schristos struct window_pane *wp = NULL; 300e271dbb8Schristos struct paste_buffer *pb; 301e271dbb8Schristos char *expanded; 302e271dbb8Schristos key_code key; 303e271dbb8Schristos 304e271dbb8Schristos if (cmd_find_valid_state(&data->fs)) { 305e271dbb8Schristos s = data->fs.s; 306e271dbb8Schristos wl = data->fs.wl; 307e271dbb8Schristos wp = data->fs.wp; 308e271dbb8Schristos } 309e271dbb8Schristos pb = paste_get_name(item->name); 310e271dbb8Schristos if (pb == NULL) 31146548964Swiz return (KEYC_NONE); 312e271dbb8Schristos 313e271dbb8Schristos ft = format_create(NULL, NULL, FORMAT_NONE, 0); 314e271dbb8Schristos format_defaults(ft, NULL, NULL, 0, NULL); 315e271dbb8Schristos if (wp != NULL) 316e271dbb8Schristos format_defaults(ft, NULL, s, wl, wp); 317e271dbb8Schristos format_defaults_paste_buffer(ft, pb); 318e271dbb8Schristos format_add(ft, "line", "%u", line); 319e271dbb8Schristos 320e271dbb8Schristos expanded = format_expand(ft, data->key_format); 321e271dbb8Schristos key = key_string_lookup_string(expanded); 322e271dbb8Schristos free(expanded); 323e271dbb8Schristos format_free(ft); 32446548964Swiz return (key); 325e271dbb8Schristos } 326e271dbb8Schristos 327c9ad075bSchristos static struct screen * 32830744affSchristos window_buffer_init(struct window_mode_entry *wme, struct cmd_find_state *fs, 32930744affSchristos struct args *args) 330c9ad075bSchristos { 3310a274e86Schristos struct window_pane *wp = wme->wp; 332c9ad075bSchristos struct window_buffer_modedata *data; 333c9ad075bSchristos struct screen *s; 334c9ad075bSchristos 3350a274e86Schristos wme->data = data = xcalloc(1, sizeof *data); 33630744affSchristos data->wp = wp; 33730744affSchristos cmd_find_copy_state(&data->fs, fs); 338c9ad075bSchristos 339c9ad075bSchristos if (args == NULL || !args_has(args, 'F')) 340c9ad075bSchristos data->format = xstrdup(WINDOW_BUFFER_DEFAULT_FORMAT); 341c9ad075bSchristos else 342c9ad075bSchristos data->format = xstrdup(args_get(args, 'F')); 343e271dbb8Schristos if (args == NULL || !args_has(args, 'K')) 344e271dbb8Schristos data->key_format = xstrdup(WINDOW_BUFFER_DEFAULT_KEY_FORMAT); 345e271dbb8Schristos else 346e271dbb8Schristos data->key_format = xstrdup(args_get(args, 'K')); 34746548964Swiz if (args == NULL || args_count(args) == 0) 348c9ad075bSchristos data->command = xstrdup(WINDOW_BUFFER_DEFAULT_COMMAND); 349c9ad075bSchristos else 35046548964Swiz data->command = xstrdup(args_string(args, 0)); 351c9ad075bSchristos 352c9ad075bSchristos data->data = mode_tree_start(wp, args, window_buffer_build, 353e271dbb8Schristos window_buffer_draw, window_buffer_search, window_buffer_menu, NULL, 354e271dbb8Schristos window_buffer_get_key, data, window_buffer_menu_items, 355e271dbb8Schristos window_buffer_sort_list, nitems(window_buffer_sort_list), &s); 356c7e17de0Schristos mode_tree_zoom(data->data, args); 357c9ad075bSchristos 358c9ad075bSchristos mode_tree_build(data->data); 359c9ad075bSchristos mode_tree_draw(data->data); 360c9ad075bSchristos 361c9ad075bSchristos return (s); 362c9ad075bSchristos } 363c9ad075bSchristos 364c9ad075bSchristos static void 3650a274e86Schristos window_buffer_free(struct window_mode_entry *wme) 366c9ad075bSchristos { 3670a274e86Schristos struct window_buffer_modedata *data = wme->data; 368c9ad075bSchristos u_int i; 369c9ad075bSchristos 370c9ad075bSchristos if (data == NULL) 371c9ad075bSchristos return; 372c9ad075bSchristos 373c9ad075bSchristos mode_tree_free(data->data); 374c9ad075bSchristos 375c9ad075bSchristos for (i = 0; i < data->item_size; i++) 376c9ad075bSchristos window_buffer_free_item(data->item_list[i]); 377c9ad075bSchristos free(data->item_list); 378c9ad075bSchristos 379c9ad075bSchristos free(data->format); 380e271dbb8Schristos free(data->key_format); 381c9ad075bSchristos free(data->command); 382c9ad075bSchristos 383c9ad075bSchristos free(data); 384c9ad075bSchristos } 385c9ad075bSchristos 386c9ad075bSchristos static void 3870a274e86Schristos window_buffer_resize(struct window_mode_entry *wme, u_int sx, u_int sy) 388c9ad075bSchristos { 3890a274e86Schristos struct window_buffer_modedata *data = wme->data; 390c9ad075bSchristos 391c9ad075bSchristos mode_tree_resize(data->data, sx, sy); 392c9ad075bSchristos } 393c9ad075bSchristos 394c9ad075bSchristos static void 395e271dbb8Schristos window_buffer_update(struct window_mode_entry *wme) 396e271dbb8Schristos { 397e271dbb8Schristos struct window_buffer_modedata *data = wme->data; 398e271dbb8Schristos 399e271dbb8Schristos mode_tree_build(data->data); 400e271dbb8Schristos mode_tree_draw(data->data); 401e271dbb8Schristos data->wp->flags |= PANE_REDRAW; 402e271dbb8Schristos } 403e271dbb8Schristos 404e271dbb8Schristos static void 405c7e17de0Schristos window_buffer_do_delete(void *modedata, void *itemdata, 406c7e17de0Schristos __unused struct client *c, __unused key_code key) 407c9ad075bSchristos { 408c9ad075bSchristos struct window_buffer_modedata *data = modedata; 409c9ad075bSchristos struct window_buffer_itemdata *item = itemdata; 410c9ad075bSchristos struct paste_buffer *pb; 411c9ad075bSchristos 412*890b6d91Swiz if (item == mode_tree_get_current(data->data) && 413*890b6d91Swiz !mode_tree_down(data->data, 0)) { 414*890b6d91Swiz /* 415*890b6d91Swiz *If we were unable to select the item further down we are at 416*890b6d91Swiz * the end of the list. Move one element up instead, to make 417*890b6d91Swiz * sure that we preserve a valid selection or we risk having 418*890b6d91Swiz * the tree build logic reset it to the first item. 419*890b6d91Swiz */ 420*890b6d91Swiz mode_tree_up(data->data, 0); 421*890b6d91Swiz } 422*890b6d91Swiz 423c9ad075bSchristos if ((pb = paste_get_name(item->name)) != NULL) 424c9ad075bSchristos paste_free(pb); 425c9ad075bSchristos } 426c9ad075bSchristos 427c9ad075bSchristos static void 428c7e17de0Schristos window_buffer_do_paste(void *modedata, void *itemdata, struct client *c, 429c7e17de0Schristos __unused key_code key) 430c7e17de0Schristos { 431c7e17de0Schristos struct window_buffer_modedata *data = modedata; 432c7e17de0Schristos struct window_buffer_itemdata *item = itemdata; 433c7e17de0Schristos 434e271dbb8Schristos if (paste_get_name(item->name) != NULL) 435c7e17de0Schristos mode_tree_run_command(c, NULL, data->command, item->name); 436c7e17de0Schristos } 437c7e17de0Schristos 438c7e17de0Schristos static void 439e271dbb8Schristos window_buffer_finish_edit(struct window_buffer_editdata *ed) 440e271dbb8Schristos { 441e271dbb8Schristos free(ed->name); 442e271dbb8Schristos free(ed); 443e271dbb8Schristos } 444e271dbb8Schristos 445e271dbb8Schristos static void 446e271dbb8Schristos window_buffer_edit_close_cb(char *buf, size_t len, void *arg) 447e271dbb8Schristos { 448e271dbb8Schristos struct window_buffer_editdata *ed = arg; 449e271dbb8Schristos size_t oldlen; 450e271dbb8Schristos const char *oldbuf; 451e271dbb8Schristos struct paste_buffer *pb; 452e271dbb8Schristos struct window_pane *wp; 453e271dbb8Schristos struct window_buffer_modedata *data; 454e271dbb8Schristos struct window_mode_entry *wme; 455e271dbb8Schristos 456e271dbb8Schristos if (buf == NULL || len == 0) { 457e271dbb8Schristos window_buffer_finish_edit(ed); 458e271dbb8Schristos return; 459e271dbb8Schristos } 460e271dbb8Schristos 461e271dbb8Schristos pb = paste_get_name(ed->name); 462e271dbb8Schristos if (pb == NULL || pb != ed->pb) { 463e271dbb8Schristos window_buffer_finish_edit(ed); 464e271dbb8Schristos return; 465e271dbb8Schristos } 466e271dbb8Schristos 467e271dbb8Schristos oldbuf = paste_buffer_data(pb, &oldlen); 468e271dbb8Schristos if (oldlen != '\0' && 469e271dbb8Schristos oldbuf[oldlen - 1] != '\n' && 470e271dbb8Schristos buf[len - 1] == '\n') 471e271dbb8Schristos len--; 472e271dbb8Schristos if (len != 0) 473e271dbb8Schristos paste_replace(pb, buf, len); 474e271dbb8Schristos 475e271dbb8Schristos wp = window_pane_find_by_id(ed->wp_id); 476e271dbb8Schristos if (wp != NULL) { 477e271dbb8Schristos wme = TAILQ_FIRST(&wp->modes); 478e271dbb8Schristos if (wme->mode == &window_buffer_mode) { 479e271dbb8Schristos data = wme->data; 480e271dbb8Schristos mode_tree_build(data->data); 481e271dbb8Schristos mode_tree_draw(data->data); 482e271dbb8Schristos } 483e271dbb8Schristos wp->flags |= PANE_REDRAW; 484e271dbb8Schristos } 485e271dbb8Schristos window_buffer_finish_edit(ed); 486e271dbb8Schristos } 487e271dbb8Schristos 488e271dbb8Schristos static void 489e271dbb8Schristos window_buffer_start_edit(struct window_buffer_modedata *data, 490e271dbb8Schristos struct window_buffer_itemdata *item, struct client *c) 491e271dbb8Schristos { 492e271dbb8Schristos struct paste_buffer *pb; 493e271dbb8Schristos const char *buf; 494e271dbb8Schristos size_t len; 495e271dbb8Schristos struct window_buffer_editdata *ed; 496e271dbb8Schristos 497e271dbb8Schristos if ((pb = paste_get_name(item->name)) == NULL) 498e271dbb8Schristos return; 499e271dbb8Schristos buf = paste_buffer_data(pb, &len); 500e271dbb8Schristos 501e271dbb8Schristos ed = xcalloc(1, sizeof *ed); 502e271dbb8Schristos ed->wp_id = data->wp->id; 503e271dbb8Schristos ed->name = xstrdup(paste_buffer_name(pb)); 504e271dbb8Schristos ed->pb = pb; 505e271dbb8Schristos 506e271dbb8Schristos if (popup_editor(c, buf, len, window_buffer_edit_close_cb, ed) != 0) 507e271dbb8Schristos window_buffer_finish_edit(ed); 508e271dbb8Schristos } 509e271dbb8Schristos 510e271dbb8Schristos static void 5110a274e86Schristos window_buffer_key(struct window_mode_entry *wme, struct client *c, 5120a274e86Schristos __unused struct session *s, __unused struct winlink *wl, key_code key, 5130a274e86Schristos struct mouse_event *m) 514c9ad075bSchristos { 5150a274e86Schristos struct window_pane *wp = wme->wp; 5160a274e86Schristos struct window_buffer_modedata *data = wme->data; 517c7e17de0Schristos struct mode_tree_data *mtd = data->data; 518c9ad075bSchristos struct window_buffer_itemdata *item; 519c9ad075bSchristos int finished; 520c9ad075bSchristos 521*890b6d91Swiz if (paste_is_empty()) { 522f844e94eSwiz finished = 1; 523f844e94eSwiz goto out; 524f844e94eSwiz } 525f844e94eSwiz 526c7e17de0Schristos finished = mode_tree_key(mtd, c, &key, m, NULL, NULL); 527c9ad075bSchristos switch (key) { 528e271dbb8Schristos case 'e': 529e271dbb8Schristos item = mode_tree_get_current(mtd); 530e271dbb8Schristos window_buffer_start_edit(data, item, c); 531e271dbb8Schristos break; 532c9ad075bSchristos case 'd': 533c7e17de0Schristos item = mode_tree_get_current(mtd); 534c7e17de0Schristos window_buffer_do_delete(data, item, c, key); 535c7e17de0Schristos mode_tree_build(mtd); 536c9ad075bSchristos break; 537c9ad075bSchristos case 'D': 538c7e17de0Schristos mode_tree_each_tagged(mtd, window_buffer_do_delete, c, key, 0); 539c7e17de0Schristos mode_tree_build(mtd); 540c9ad075bSchristos break; 541c7e17de0Schristos case 'P': 542c7e17de0Schristos mode_tree_each_tagged(mtd, window_buffer_do_paste, c, key, 0); 543c7e17de0Schristos finished = 1; 544c7e17de0Schristos break; 545c7e17de0Schristos case 'p': 546c9ad075bSchristos case '\r': 547c7e17de0Schristos item = mode_tree_get_current(mtd); 548c7e17de0Schristos window_buffer_do_paste(data, item, c, key); 549c7e17de0Schristos finished = 1; 550c7e17de0Schristos break; 551c9ad075bSchristos } 552f844e94eSwiz 553f844e94eSwiz out: 554*890b6d91Swiz if (finished || paste_is_empty()) 555c9ad075bSchristos window_pane_reset_mode(wp); 556c9ad075bSchristos else { 557c7e17de0Schristos mode_tree_draw(mtd); 558c9ad075bSchristos wp->flags |= PANE_REDRAW; 559c9ad075bSchristos } 560c9ad075bSchristos } 561