1*d3278555Snicm /* $OpenBSD: window-buffer.c,v 1.40 2024/08/04 08:53:43 nicm Exp $ */ 2a42faf7dSnicm 3a42faf7dSnicm /* 4a42faf7dSnicm * Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com> 5a42faf7dSnicm * 6a42faf7dSnicm * Permission to use, copy, modify, and distribute this software for any 7a42faf7dSnicm * purpose with or without fee is hereby granted, provided that the above 8a42faf7dSnicm * copyright notice and this permission notice appear in all copies. 9a42faf7dSnicm * 10a42faf7dSnicm * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11a42faf7dSnicm * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12a42faf7dSnicm * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13a42faf7dSnicm * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14a42faf7dSnicm * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15a42faf7dSnicm * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16a42faf7dSnicm * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17a42faf7dSnicm */ 18a42faf7dSnicm 19a42faf7dSnicm #include <sys/types.h> 20a42faf7dSnicm 21a42faf7dSnicm #include <stdlib.h> 22a42faf7dSnicm #include <string.h> 2305835efcSnicm #include <time.h> 24a6c9106fSnicm #include <unistd.h> 25a42faf7dSnicm #include <vis.h> 26a42faf7dSnicm 27a42faf7dSnicm #include "tmux.h" 28a42faf7dSnicm 2930a94f45Snicm static struct screen *window_buffer_init(struct window_mode_entry *, 30a42faf7dSnicm struct cmd_find_state *, struct args *); 3130a94f45Snicm static void window_buffer_free(struct window_mode_entry *); 3230a94f45Snicm static void window_buffer_resize(struct window_mode_entry *, u_int, 33a42faf7dSnicm u_int); 34734f37e4Snicm static void window_buffer_update(struct window_mode_entry *); 3530a94f45Snicm static void window_buffer_key(struct window_mode_entry *, 36bf52409eSnicm struct client *, struct session *, 37bf52409eSnicm struct winlink *, key_code, struct mouse_event *); 38a42faf7dSnicm 392e03ad1fSnicm #define WINDOW_BUFFER_DEFAULT_COMMAND "paste-buffer -p -b '%%'" 40a42faf7dSnicm 41bf38e336Snicm #define WINDOW_BUFFER_DEFAULT_FORMAT \ 426c6f347cSnicm "#{t/p:buffer_created}: #{buffer_sample}" 43bf38e336Snicm 44438eed14Snicm #define WINDOW_BUFFER_DEFAULT_KEY_FORMAT \ 45438eed14Snicm "#{?#{e|<:#{line},10}," \ 46438eed14Snicm "#{line}" \ 47438eed14Snicm "," \ 48438eed14Snicm "#{?#{e|<:#{line},36}," \ 49438eed14Snicm "M-#{a:#{e|+:97,#{e|-:#{line},10}}}" \ 50438eed14Snicm "," \ 51438eed14Snicm "" \ 52438eed14Snicm "}" \ 53438eed14Snicm "}" 54438eed14Snicm 551335341aSnicm static const struct menu_item window_buffer_menu_items[] = { 561335341aSnicm { "Paste", 'p', NULL }, 571335341aSnicm { "Paste Tagged", 'P', NULL }, 581335341aSnicm { "", KEYC_NONE, NULL }, 591335341aSnicm { "Tag", 't', NULL }, 601335341aSnicm { "Tag All", '\024', NULL }, 611335341aSnicm { "Tag None", 'T', NULL }, 621335341aSnicm { "", KEYC_NONE, NULL }, 631335341aSnicm { "Delete", 'd', NULL }, 641335341aSnicm { "Delete Tagged", 'D', NULL }, 651335341aSnicm { "", KEYC_NONE, NULL }, 661335341aSnicm { "Cancel", 'q', NULL }, 671335341aSnicm 681335341aSnicm { NULL, KEYC_NONE, NULL } 691335341aSnicm }; 70f43bc87cSnicm 71a42faf7dSnicm const struct window_mode window_buffer_mode = { 72a42faf7dSnicm .name = "buffer-mode", 7371431f24Snicm .default_format = WINDOW_BUFFER_DEFAULT_FORMAT, 74a42faf7dSnicm 75a42faf7dSnicm .init = window_buffer_init, 76a42faf7dSnicm .free = window_buffer_free, 77a42faf7dSnicm .resize = window_buffer_resize, 78734f37e4Snicm .update = window_buffer_update, 79a42faf7dSnicm .key = window_buffer_key, 80a42faf7dSnicm }; 81a42faf7dSnicm 82a42faf7dSnicm enum window_buffer_sort_type { 83a42faf7dSnicm WINDOW_BUFFER_BY_TIME, 8438801d3eSnicm WINDOW_BUFFER_BY_NAME, 85a42faf7dSnicm WINDOW_BUFFER_BY_SIZE, 86a42faf7dSnicm }; 87a42faf7dSnicm static const char *window_buffer_sort_list[] = { 88a42faf7dSnicm "time", 8938801d3eSnicm "name", 90a42faf7dSnicm "size" 91a42faf7dSnicm }; 923f6f9f7dSnicm static struct mode_tree_sort_criteria *window_buffer_sort; 93a42faf7dSnicm 94a42faf7dSnicm struct window_buffer_itemdata { 95a42faf7dSnicm const char *name; 96a42faf7dSnicm u_int order; 97a42faf7dSnicm size_t size; 98a42faf7dSnicm }; 99a42faf7dSnicm 100a42faf7dSnicm struct window_buffer_modedata { 101f43bc87cSnicm struct window_pane *wp; 10200db7279Snicm struct cmd_find_state fs; 103f43bc87cSnicm 104a42faf7dSnicm struct mode_tree_data *data; 105a42faf7dSnicm char *command; 106bf38e336Snicm char *format; 107438eed14Snicm char *key_format; 108a42faf7dSnicm 109a42faf7dSnicm struct window_buffer_itemdata **item_list; 110a42faf7dSnicm u_int item_size; 111a42faf7dSnicm }; 112a42faf7dSnicm 113a6c9106fSnicm struct window_buffer_editdata { 114a6c9106fSnicm u_int wp_id; 115a6c9106fSnicm char *name; 116a6c9106fSnicm struct paste_buffer *pb; 117a6c9106fSnicm }; 118a6c9106fSnicm 119a42faf7dSnicm static struct window_buffer_itemdata * 120a42faf7dSnicm window_buffer_add_item(struct window_buffer_modedata *data) 121a42faf7dSnicm { 122a42faf7dSnicm struct window_buffer_itemdata *item; 123a42faf7dSnicm 124a42faf7dSnicm data->item_list = xreallocarray(data->item_list, data->item_size + 1, 125a42faf7dSnicm sizeof *data->item_list); 126a42faf7dSnicm item = data->item_list[data->item_size++] = xcalloc(1, sizeof *item); 127a42faf7dSnicm return (item); 128a42faf7dSnicm } 129a42faf7dSnicm 130a42faf7dSnicm static void 131a42faf7dSnicm window_buffer_free_item(struct window_buffer_itemdata *item) 132a42faf7dSnicm { 133a42faf7dSnicm free((void *)item->name); 134a42faf7dSnicm free(item); 135a42faf7dSnicm } 136a42faf7dSnicm 137a42faf7dSnicm static int 1383f6f9f7dSnicm window_buffer_cmp(const void *a0, const void *b0) 139a42faf7dSnicm { 140a42faf7dSnicm const struct window_buffer_itemdata *const *a = a0; 141a42faf7dSnicm const struct window_buffer_itemdata *const *b = b0; 1423f6f9f7dSnicm int result = 0; 143a42faf7dSnicm 1443f6f9f7dSnicm if (window_buffer_sort->field == WINDOW_BUFFER_BY_TIME) 1453f6f9f7dSnicm result = (*b)->order - (*a)->order; 1463f6f9f7dSnicm else if (window_buffer_sort->field == WINDOW_BUFFER_BY_SIZE) 1473f6f9f7dSnicm result = (*b)->size - (*a)->size; 148a42faf7dSnicm 1493f6f9f7dSnicm /* Use WINDOW_BUFFER_BY_NAME as default order and tie breaker. */ 1503f6f9f7dSnicm if (result == 0) 1513f6f9f7dSnicm result = strcmp((*a)->name, (*b)->name); 152a42faf7dSnicm 1533f6f9f7dSnicm if (window_buffer_sort->reversed) 1543f6f9f7dSnicm result = -result; 1553f6f9f7dSnicm return (result); 156a42faf7dSnicm } 157a42faf7dSnicm 158a42faf7dSnicm static void 1593f6f9f7dSnicm window_buffer_build(void *modedata, struct mode_tree_sort_criteria *sort_crit, 1603f6f9f7dSnicm __unused uint64_t *tag, const char *filter) 161a42faf7dSnicm { 162a42faf7dSnicm struct window_buffer_modedata *data = modedata; 163a42faf7dSnicm struct window_buffer_itemdata *item; 164a42faf7dSnicm u_int i; 165a42faf7dSnicm struct paste_buffer *pb; 166bf38e336Snicm char *text, *cp; 167024c311aSnicm struct format_tree *ft; 16800db7279Snicm struct session *s = NULL; 16900db7279Snicm struct winlink *wl = NULL; 17000db7279Snicm struct window_pane *wp = NULL; 171a42faf7dSnicm 172a42faf7dSnicm for (i = 0; i < data->item_size; i++) 173a42faf7dSnicm window_buffer_free_item(data->item_list[i]); 174a42faf7dSnicm free(data->item_list); 175a42faf7dSnicm data->item_list = NULL; 176a42faf7dSnicm data->item_size = 0; 177a42faf7dSnicm 178a42faf7dSnicm pb = NULL; 179a42faf7dSnicm while ((pb = paste_walk(pb)) != NULL) { 180a42faf7dSnicm item = window_buffer_add_item(data); 181a42faf7dSnicm item->name = xstrdup(paste_buffer_name(pb)); 182a42faf7dSnicm paste_buffer_data(pb, &item->size); 183a42faf7dSnicm item->order = paste_buffer_order(pb); 184a42faf7dSnicm } 185a42faf7dSnicm 1863f6f9f7dSnicm window_buffer_sort = sort_crit; 187a42faf7dSnicm qsort(data->item_list, data->item_size, sizeof *data->item_list, 1883f6f9f7dSnicm window_buffer_cmp); 189a42faf7dSnicm 19000db7279Snicm if (cmd_find_valid_state(&data->fs)) { 19100db7279Snicm s = data->fs.s; 19200db7279Snicm wl = data->fs.wl; 19300db7279Snicm wp = data->fs.wp; 19400db7279Snicm } 19500db7279Snicm 196a42faf7dSnicm for (i = 0; i < data->item_size; i++) { 197a42faf7dSnicm item = data->item_list[i]; 198a42faf7dSnicm 199024c311aSnicm pb = paste_get_name(item->name); 200024c311aSnicm if (pb == NULL) 201024c311aSnicm continue; 202024c311aSnicm ft = format_create(NULL, NULL, FORMAT_NONE, 0); 20300db7279Snicm format_defaults(ft, NULL, s, wl, wp); 204024c311aSnicm format_defaults_paste_buffer(ft, pb); 205bf38e336Snicm 206bf38e336Snicm if (filter != NULL) { 207024c311aSnicm cp = format_expand(ft, filter); 208024c311aSnicm if (!format_true(cp)) { 209024c311aSnicm free(cp); 210024c311aSnicm format_free(ft); 211024c311aSnicm continue; 212024c311aSnicm } 213024c311aSnicm free(cp); 214024c311aSnicm } 215024c311aSnicm 216bf38e336Snicm text = format_expand(ft, data->format); 217a42faf7dSnicm mode_tree_add(data->data, NULL, item, item->order, item->name, 218a42faf7dSnicm text, -1); 219a42faf7dSnicm free(text); 220bf38e336Snicm 221bf38e336Snicm format_free(ft); 222a42faf7dSnicm } 223a42faf7dSnicm 224a42faf7dSnicm } 225a42faf7dSnicm 2262b7e51f7Snicm static void 2272b7e51f7Snicm window_buffer_draw(__unused void *modedata, void *itemdata, 2282b7e51f7Snicm struct screen_write_ctx *ctx, u_int sx, u_int sy) 229a42faf7dSnicm { 230a42faf7dSnicm struct window_buffer_itemdata *item = itemdata; 231a42faf7dSnicm struct paste_buffer *pb; 2328917ecadSnicm const char *pdata, *start, *end; 2338917ecadSnicm char *buf = NULL; 234f8ef6c4bSnicm size_t psize; 2352b7e51f7Snicm u_int i, cx = ctx->s->cx, cy = ctx->s->cy; 236a42faf7dSnicm 237a42faf7dSnicm pb = paste_get_name(item->name); 238a42faf7dSnicm if (pb == NULL) 2392b7e51f7Snicm return; 240a42faf7dSnicm 241a42faf7dSnicm pdata = end = paste_buffer_data(pb, &psize); 242a42faf7dSnicm for (i = 0; i < sy; i++) { 2438917ecadSnicm start = end; 2448917ecadSnicm while (end != pdata + psize && *end != '\n') 245a42faf7dSnicm end++; 2468917ecadSnicm buf = xreallocarray(buf, 4, end - start + 1); 247438eed14Snicm utf8_strvis(buf, start, end - start, 248438eed14Snicm VIS_OCTAL|VIS_CSTYLE|VIS_TAB); 2498917ecadSnicm if (*buf != '\0') { 2505c6c7001Snicm screen_write_cursormove(ctx, cx, cy + i, 0); 2518917ecadSnicm screen_write_nputs(ctx, sx, &grid_default_cell, "%s", 2528917ecadSnicm buf); 253a42faf7dSnicm } 254a42faf7dSnicm 255a42faf7dSnicm if (end == pdata + psize) 256a42faf7dSnicm break; 257a42faf7dSnicm end++; 258a42faf7dSnicm } 2598917ecadSnicm free(buf); 260a42faf7dSnicm } 261a42faf7dSnicm 262943a08b1Snicm static int 263943a08b1Snicm window_buffer_search(__unused void *modedata, void *itemdata, const char *ss) 264943a08b1Snicm { 265943a08b1Snicm struct window_buffer_itemdata *item = itemdata; 266943a08b1Snicm struct paste_buffer *pb; 267943a08b1Snicm const char *bufdata; 268943a08b1Snicm size_t bufsize; 269943a08b1Snicm 270943a08b1Snicm if ((pb = paste_get_name(item->name)) == NULL) 271943a08b1Snicm return (0); 272943a08b1Snicm if (strstr(item->name, ss) != NULL) 2730cf33a8dSnicm return (1); 274943a08b1Snicm bufdata = paste_buffer_data(pb, &bufsize); 275943a08b1Snicm return (memmem(bufdata, bufsize, ss, strlen(ss)) != NULL); 276943a08b1Snicm } 277943a08b1Snicm 278f43bc87cSnicm static void 279f43bc87cSnicm window_buffer_menu(void *modedata, struct client *c, key_code key) 280f43bc87cSnicm { 281f43bc87cSnicm struct window_buffer_modedata *data = modedata; 282f43bc87cSnicm struct window_pane *wp = data->wp; 283f43bc87cSnicm struct window_mode_entry *wme; 284f43bc87cSnicm 285f43bc87cSnicm wme = TAILQ_FIRST(&wp->modes); 286f43bc87cSnicm if (wme == NULL || wme->data != modedata) 287f43bc87cSnicm return; 288f43bc87cSnicm window_buffer_key(wme, c, NULL, NULL, key, NULL); 289f43bc87cSnicm } 290f43bc87cSnicm 291438eed14Snicm static key_code 292438eed14Snicm window_buffer_get_key(void *modedata, void *itemdata, u_int line) 293438eed14Snicm { 294438eed14Snicm struct window_buffer_modedata *data = modedata; 295438eed14Snicm struct window_buffer_itemdata *item = itemdata; 296438eed14Snicm struct format_tree *ft; 2972bd728e0Snicm struct session *s = NULL; 2982bd728e0Snicm struct winlink *wl = NULL; 2992bd728e0Snicm struct window_pane *wp = NULL; 300438eed14Snicm struct paste_buffer *pb; 301438eed14Snicm char *expanded; 302438eed14Snicm key_code key; 303438eed14Snicm 304438eed14Snicm if (cmd_find_valid_state(&data->fs)) { 305438eed14Snicm s = data->fs.s; 306438eed14Snicm wl = data->fs.wl; 307438eed14Snicm wp = data->fs.wp; 308438eed14Snicm } 309438eed14Snicm pb = paste_get_name(item->name); 310438eed14Snicm if (pb == NULL) 3113e8355bdSnicm return (KEYC_NONE); 312438eed14Snicm 313438eed14Snicm ft = format_create(NULL, NULL, FORMAT_NONE, 0); 314438eed14Snicm format_defaults(ft, NULL, NULL, 0, NULL); 315438eed14Snicm format_defaults(ft, NULL, s, wl, wp); 316438eed14Snicm format_defaults_paste_buffer(ft, pb); 317438eed14Snicm format_add(ft, "line", "%u", line); 318438eed14Snicm 319438eed14Snicm expanded = format_expand(ft, data->key_format); 320438eed14Snicm key = key_string_lookup_string(expanded); 321438eed14Snicm free(expanded); 322438eed14Snicm format_free(ft); 3233e8355bdSnicm return (key); 324438eed14Snicm } 325438eed14Snicm 326a42faf7dSnicm static struct screen * 32700db7279Snicm window_buffer_init(struct window_mode_entry *wme, struct cmd_find_state *fs, 32800db7279Snicm struct args *args) 329a42faf7dSnicm { 33030a94f45Snicm struct window_pane *wp = wme->wp; 331a42faf7dSnicm struct window_buffer_modedata *data; 332a42faf7dSnicm struct screen *s; 333a42faf7dSnicm 33430a94f45Snicm wme->data = data = xcalloc(1, sizeof *data); 335f43bc87cSnicm data->wp = wp; 33600db7279Snicm cmd_find_copy_state(&data->fs, fs); 337a42faf7dSnicm 338bf38e336Snicm if (args == NULL || !args_has(args, 'F')) 339bf38e336Snicm data->format = xstrdup(WINDOW_BUFFER_DEFAULT_FORMAT); 340bf38e336Snicm else 341bf38e336Snicm data->format = xstrdup(args_get(args, 'F')); 342438eed14Snicm if (args == NULL || !args_has(args, 'K')) 343438eed14Snicm data->key_format = xstrdup(WINDOW_BUFFER_DEFAULT_KEY_FORMAT); 344438eed14Snicm else 345438eed14Snicm data->key_format = xstrdup(args_get(args, 'K')); 3461693b10bSnicm if (args == NULL || args_count(args) == 0) 347a42faf7dSnicm data->command = xstrdup(WINDOW_BUFFER_DEFAULT_COMMAND); 348a42faf7dSnicm else 3491693b10bSnicm data->command = xstrdup(args_string(args, 0)); 350a42faf7dSnicm 351b38aa712Snicm data->data = mode_tree_start(wp, args, window_buffer_build, 35267c16a7cSnicm window_buffer_draw, window_buffer_search, window_buffer_menu, NULL, 353438eed14Snicm window_buffer_get_key, data, window_buffer_menu_items, 354438eed14Snicm window_buffer_sort_list, nitems(window_buffer_sort_list), &s); 3554f5e4c93Snicm mode_tree_zoom(data->data, args); 356a42faf7dSnicm 357a42faf7dSnicm mode_tree_build(data->data); 358a42faf7dSnicm mode_tree_draw(data->data); 359a42faf7dSnicm 360a42faf7dSnicm return (s); 361a42faf7dSnicm } 362a42faf7dSnicm 363a42faf7dSnicm static void 36430a94f45Snicm window_buffer_free(struct window_mode_entry *wme) 365a42faf7dSnicm { 36630a94f45Snicm struct window_buffer_modedata *data = wme->data; 367a42faf7dSnicm u_int i; 368a42faf7dSnicm 369a42faf7dSnicm if (data == NULL) 370a42faf7dSnicm return; 371a42faf7dSnicm 372a42faf7dSnicm mode_tree_free(data->data); 373a42faf7dSnicm 374a42faf7dSnicm for (i = 0; i < data->item_size; i++) 375a42faf7dSnicm window_buffer_free_item(data->item_list[i]); 376a42faf7dSnicm free(data->item_list); 377a42faf7dSnicm 378bf38e336Snicm free(data->format); 379438eed14Snicm free(data->key_format); 380a42faf7dSnicm free(data->command); 381bf38e336Snicm 382a42faf7dSnicm free(data); 383a42faf7dSnicm } 384a42faf7dSnicm 385a42faf7dSnicm static void 38630a94f45Snicm window_buffer_resize(struct window_mode_entry *wme, u_int sx, u_int sy) 387a42faf7dSnicm { 38830a94f45Snicm struct window_buffer_modedata *data = wme->data; 389a42faf7dSnicm 390a42faf7dSnicm mode_tree_resize(data->data, sx, sy); 391a42faf7dSnicm } 392a42faf7dSnicm 393a42faf7dSnicm static void 394734f37e4Snicm window_buffer_update(struct window_mode_entry *wme) 395734f37e4Snicm { 396734f37e4Snicm struct window_buffer_modedata *data = wme->data; 397734f37e4Snicm 398734f37e4Snicm mode_tree_build(data->data); 399734f37e4Snicm mode_tree_draw(data->data); 400734f37e4Snicm data->wp->flags |= PANE_REDRAW; 401734f37e4Snicm } 402734f37e4Snicm 403734f37e4Snicm static void 404d7af2c28Snicm window_buffer_do_delete(void *modedata, void *itemdata, 405d7af2c28Snicm __unused struct client *c, __unused key_code key) 406a42faf7dSnicm { 407a42faf7dSnicm struct window_buffer_modedata *data = modedata; 408a42faf7dSnicm struct window_buffer_itemdata *item = itemdata; 409a42faf7dSnicm struct paste_buffer *pb; 410a42faf7dSnicm 411*d3278555Snicm if (item == mode_tree_get_current(data->data) && 412*d3278555Snicm !mode_tree_down(data->data, 0)) { 413*d3278555Snicm /* 414*d3278555Snicm *If we were unable to select the item further down we are at 415*d3278555Snicm * the end of the list. Move one element up instead, to make 416*d3278555Snicm * sure that we preserve a valid selection or we risk having 417*d3278555Snicm * the tree build logic reset it to the first item. 418*d3278555Snicm */ 419*d3278555Snicm mode_tree_up(data->data, 0); 420*d3278555Snicm } 421*d3278555Snicm 422a42faf7dSnicm if ((pb = paste_get_name(item->name)) != NULL) 423a42faf7dSnicm paste_free(pb); 424a42faf7dSnicm } 425a42faf7dSnicm 426a42faf7dSnicm static void 427d7af2c28Snicm window_buffer_do_paste(void *modedata, void *itemdata, struct client *c, 428d7af2c28Snicm __unused key_code key) 429d7af2c28Snicm { 430d7af2c28Snicm struct window_buffer_modedata *data = modedata; 431d7af2c28Snicm struct window_buffer_itemdata *item = itemdata; 432d7af2c28Snicm 433ba27d7a5Snicm if (paste_get_name(item->name) != NULL) 434d7af2c28Snicm mode_tree_run_command(c, NULL, data->command, item->name); 435d7af2c28Snicm } 436d7af2c28Snicm 437d7af2c28Snicm static void 438a6c9106fSnicm window_buffer_finish_edit(struct window_buffer_editdata *ed) 439a6c9106fSnicm { 440a6c9106fSnicm free(ed->name); 441a6c9106fSnicm free(ed); 442a6c9106fSnicm } 443a6c9106fSnicm 444a6c9106fSnicm static void 445f67736f8Snicm window_buffer_edit_close_cb(char *buf, size_t len, void *arg) 446a6c9106fSnicm { 447a6c9106fSnicm struct window_buffer_editdata *ed = arg; 448a6c9106fSnicm size_t oldlen; 449a6c9106fSnicm const char *oldbuf; 450a6c9106fSnicm struct paste_buffer *pb; 451a6c9106fSnicm struct window_pane *wp; 452a6c9106fSnicm struct window_buffer_modedata *data; 453a6c9106fSnicm struct window_mode_entry *wme; 454a6c9106fSnicm 455f67736f8Snicm if (buf == NULL || len == 0) { 456a6c9106fSnicm window_buffer_finish_edit(ed); 457a6c9106fSnicm return; 458a6c9106fSnicm } 459a6c9106fSnicm 460a6c9106fSnicm pb = paste_get_name(ed->name); 461a6c9106fSnicm if (pb == NULL || pb != ed->pb) { 462a6c9106fSnicm window_buffer_finish_edit(ed); 463a6c9106fSnicm return; 464a6c9106fSnicm } 465a6c9106fSnicm 466a6c9106fSnicm oldbuf = paste_buffer_data(pb, &oldlen); 467a6c9106fSnicm if (oldlen != '\0' && 468a6c9106fSnicm oldbuf[oldlen - 1] != '\n' && 469a6c9106fSnicm buf[len - 1] == '\n') 470a6c9106fSnicm len--; 471a6c9106fSnicm if (len != 0) 472a6c9106fSnicm paste_replace(pb, buf, len); 473a6c9106fSnicm 474a6c9106fSnicm wp = window_pane_find_by_id(ed->wp_id); 475a6c9106fSnicm if (wp != NULL) { 476a6c9106fSnicm wme = TAILQ_FIRST(&wp->modes); 477a6c9106fSnicm if (wme->mode == &window_buffer_mode) { 478a6c9106fSnicm data = wme->data; 479a6c9106fSnicm mode_tree_build(data->data); 480a6c9106fSnicm mode_tree_draw(data->data); 481a6c9106fSnicm } 482a6c9106fSnicm wp->flags |= PANE_REDRAW; 483a6c9106fSnicm } 484a6c9106fSnicm window_buffer_finish_edit(ed); 485a6c9106fSnicm } 486a6c9106fSnicm 487a6c9106fSnicm static void 488a6c9106fSnicm window_buffer_start_edit(struct window_buffer_modedata *data, 489a6c9106fSnicm struct window_buffer_itemdata *item, struct client *c) 490a6c9106fSnicm { 491a6c9106fSnicm struct paste_buffer *pb; 492a6c9106fSnicm const char *buf; 493a6c9106fSnicm size_t len; 494a6c9106fSnicm struct window_buffer_editdata *ed; 495a6c9106fSnicm 496a6c9106fSnicm if ((pb = paste_get_name(item->name)) == NULL) 497a6c9106fSnicm return; 498a6c9106fSnicm buf = paste_buffer_data(pb, &len); 499a6c9106fSnicm 500a6c9106fSnicm ed = xcalloc(1, sizeof *ed); 501a6c9106fSnicm ed->wp_id = data->wp->id; 502a6c9106fSnicm ed->name = xstrdup(paste_buffer_name(pb)); 503a6c9106fSnicm ed->pb = pb; 504a6c9106fSnicm 505f67736f8Snicm if (popup_editor(c, buf, len, window_buffer_edit_close_cb, ed) != 0) 506a6c9106fSnicm window_buffer_finish_edit(ed); 507a6c9106fSnicm } 508a6c9106fSnicm 509a6c9106fSnicm static void 51030a94f45Snicm window_buffer_key(struct window_mode_entry *wme, struct client *c, 511bf52409eSnicm __unused struct session *s, __unused struct winlink *wl, key_code key, 512bf52409eSnicm struct mouse_event *m) 513a42faf7dSnicm { 51430a94f45Snicm struct window_pane *wp = wme->wp; 51530a94f45Snicm struct window_buffer_modedata *data = wme->data; 516d7af2c28Snicm struct mode_tree_data *mtd = data->data; 517a42faf7dSnicm struct window_buffer_itemdata *item; 518a42faf7dSnicm int finished; 519a42faf7dSnicm 52000b011bcSnicm if (paste_is_empty()) { 521ee191f7aSnicm finished = 1; 522ee191f7aSnicm goto out; 523ee191f7aSnicm } 524ee191f7aSnicm 52563c9949dSnicm finished = mode_tree_key(mtd, c, &key, m, NULL, NULL); 526a42faf7dSnicm switch (key) { 527a6c9106fSnicm case 'e': 528a6c9106fSnicm item = mode_tree_get_current(mtd); 529a6c9106fSnicm window_buffer_start_edit(data, item, c); 530a6c9106fSnicm break; 531a42faf7dSnicm case 'd': 532d7af2c28Snicm item = mode_tree_get_current(mtd); 533d7af2c28Snicm window_buffer_do_delete(data, item, c, key); 534d7af2c28Snicm mode_tree_build(mtd); 535a42faf7dSnicm break; 536a42faf7dSnicm case 'D': 537d7af2c28Snicm mode_tree_each_tagged(mtd, window_buffer_do_delete, c, key, 0); 538d7af2c28Snicm mode_tree_build(mtd); 539a42faf7dSnicm break; 540d7af2c28Snicm case 'P': 541d7af2c28Snicm mode_tree_each_tagged(mtd, window_buffer_do_paste, c, key, 0); 542d7af2c28Snicm finished = 1; 543d7af2c28Snicm break; 544d7af2c28Snicm case 'p': 545a42faf7dSnicm case '\r': 546d7af2c28Snicm item = mode_tree_get_current(mtd); 547d7af2c28Snicm window_buffer_do_paste(data, item, c, key); 548d7af2c28Snicm finished = 1; 549d7af2c28Snicm break; 550a42faf7dSnicm } 551ee191f7aSnicm 552ee191f7aSnicm out: 55300b011bcSnicm if (finished || paste_is_empty()) 554a42faf7dSnicm window_pane_reset_mode(wp); 555a42faf7dSnicm else { 556d7af2c28Snicm mode_tree_draw(mtd); 557a42faf7dSnicm wp->flags |= PANE_REDRAW; 558a42faf7dSnicm } 559a42faf7dSnicm } 560