"Fossies" - the Fresh Open Source Software Archive

Member "tmux-3.2a/window-buffer.c" (10 Jun 2021, 13762 Bytes) of package /linux/misc/tmux-3.2a.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "window-buffer.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.2_vs_3.2a.

    1 /* $OpenBSD$ */
    2 
    3 /*
    4  * Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
    5  *
    6  * Permission to use, copy, modify, and distribute this software for any
    7  * purpose with or without fee is hereby granted, provided that the above
    8  * copyright notice and this permission notice appear in all copies.
    9  *
   10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   14  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
   15  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
   16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   17  */
   18 
   19 #include <sys/types.h>
   20 
   21 #include <stdio.h>
   22 #include <stdlib.h>
   23 #include <string.h>
   24 #include <time.h>
   25 #include <unistd.h>
   26 
   27 #include "tmux.h"
   28 
   29 static struct screen    *window_buffer_init(struct window_mode_entry *,
   30                  struct cmd_find_state *, struct args *);
   31 static void      window_buffer_free(struct window_mode_entry *);
   32 static void      window_buffer_resize(struct window_mode_entry *, u_int,
   33                  u_int);
   34 static void      window_buffer_update(struct window_mode_entry *);
   35 static void      window_buffer_key(struct window_mode_entry *,
   36                  struct client *, struct session *,
   37                  struct winlink *, key_code, struct mouse_event *);
   38 
   39 #define WINDOW_BUFFER_DEFAULT_COMMAND "paste-buffer -b '%%'"
   40 
   41 #define WINDOW_BUFFER_DEFAULT_FORMAT \
   42     "#{t/p:buffer_created}: #{buffer_sample}"
   43 
   44 #define WINDOW_BUFFER_DEFAULT_KEY_FORMAT \
   45     "#{?#{e|<:#{line},10}," \
   46         "#{line}" \
   47     "," \
   48         "#{?#{e|<:#{line},36}," \
   49                 "M-#{a:#{e|+:97,#{e|-:#{line},10}}}" \
   50         "," \
   51                 "" \
   52         "}" \
   53     "}"
   54 
   55 static const struct menu_item window_buffer_menu_items[] = {
   56     { "Paste", 'p', NULL },
   57     { "Paste Tagged", 'P', NULL },
   58     { "", KEYC_NONE, NULL },
   59     { "Tag", 't', NULL },
   60     { "Tag All", '\024', NULL },
   61     { "Tag None", 'T', NULL },
   62     { "", KEYC_NONE, NULL },
   63     { "Delete", 'd', NULL },
   64     { "Delete Tagged", 'D', NULL },
   65     { "", KEYC_NONE, NULL },
   66     { "Cancel", 'q', NULL },
   67 
   68     { NULL, KEYC_NONE, NULL }
   69 };
   70 
   71 const struct window_mode window_buffer_mode = {
   72     .name = "buffer-mode",
   73     .default_format = WINDOW_BUFFER_DEFAULT_FORMAT,
   74 
   75     .init = window_buffer_init,
   76     .free = window_buffer_free,
   77     .resize = window_buffer_resize,
   78     .update = window_buffer_update,
   79     .key = window_buffer_key,
   80 };
   81 
   82 enum window_buffer_sort_type {
   83     WINDOW_BUFFER_BY_TIME,
   84     WINDOW_BUFFER_BY_NAME,
   85     WINDOW_BUFFER_BY_SIZE,
   86 };
   87 static const char *window_buffer_sort_list[] = {
   88     "time",
   89     "name",
   90     "size"
   91 };
   92 static struct mode_tree_sort_criteria *window_buffer_sort;
   93 
   94 struct window_buffer_itemdata {
   95     const char  *name;
   96     u_int        order;
   97     size_t       size;
   98 };
   99 
  100 struct window_buffer_modedata {
  101     struct window_pane       *wp;
  102     struct cmd_find_state         fs;
  103 
  104     struct mode_tree_data        *data;
  105     char                 *command;
  106     char                 *format;
  107     char                 *key_format;
  108 
  109     struct window_buffer_itemdata   **item_list;
  110     u_int                 item_size;
  111 };
  112 
  113 struct window_buffer_editdata {
  114     u_int            wp_id;
  115     char            *name;
  116     struct paste_buffer *pb;
  117 };
  118 
  119 static struct window_buffer_itemdata *
  120 window_buffer_add_item(struct window_buffer_modedata *data)
  121 {
  122     struct window_buffer_itemdata   *item;
  123 
  124     data->item_list = xreallocarray(data->item_list, data->item_size + 1,
  125         sizeof *data->item_list);
  126     item = data->item_list[data->item_size++] = xcalloc(1, sizeof *item);
  127     return (item);
  128 }
  129 
  130 static void
  131 window_buffer_free_item(struct window_buffer_itemdata *item)
  132 {
  133     free((void *)item->name);
  134     free(item);
  135 }
  136 
  137 static int
  138 window_buffer_cmp(const void *a0, const void *b0)
  139 {
  140     const struct window_buffer_itemdata *const  *a = a0;
  141     const struct window_buffer_itemdata *const  *b = b0;
  142     int                      result = 0;
  143 
  144     if (window_buffer_sort->field == WINDOW_BUFFER_BY_TIME)
  145         result = (*b)->order - (*a)->order;
  146     else if (window_buffer_sort->field == WINDOW_BUFFER_BY_SIZE)
  147         result = (*b)->size - (*a)->size;
  148 
  149     /* Use WINDOW_BUFFER_BY_NAME as default order and tie breaker. */
  150     if (result == 0)
  151         result = strcmp((*a)->name, (*b)->name);
  152 
  153     if (window_buffer_sort->reversed)
  154         result = -result;
  155     return (result);
  156 }
  157 
  158 static void
  159 window_buffer_build(void *modedata, struct mode_tree_sort_criteria *sort_crit,
  160     __unused uint64_t *tag, const char *filter)
  161 {
  162     struct window_buffer_modedata   *data = modedata;
  163     struct window_buffer_itemdata   *item;
  164     u_int                i;
  165     struct paste_buffer     *pb;
  166     char                *text, *cp;
  167     struct format_tree      *ft;
  168     struct session          *s = NULL;
  169     struct winlink          *wl = NULL;
  170     struct window_pane      *wp = NULL;
  171 
  172     for (i = 0; i < data->item_size; i++)
  173         window_buffer_free_item(data->item_list[i]);
  174     free(data->item_list);
  175     data->item_list = NULL;
  176     data->item_size = 0;
  177 
  178     pb = NULL;
  179     while ((pb = paste_walk(pb)) != NULL) {
  180         item = window_buffer_add_item(data);
  181         item->name = xstrdup(paste_buffer_name(pb));
  182         paste_buffer_data(pb, &item->size);
  183         item->order = paste_buffer_order(pb);
  184     }
  185 
  186     window_buffer_sort = sort_crit;
  187     qsort(data->item_list, data->item_size, sizeof *data->item_list,
  188         window_buffer_cmp);
  189 
  190     if (cmd_find_valid_state(&data->fs)) {
  191         s = data->fs.s;
  192         wl = data->fs.wl;
  193         wp = data->fs.wp;
  194     }
  195 
  196     for (i = 0; i < data->item_size; i++) {
  197         item = data->item_list[i];
  198 
  199         pb = paste_get_name(item->name);
  200         if (pb == NULL)
  201             continue;
  202         ft = format_create(NULL, NULL, FORMAT_NONE, 0);
  203         format_defaults(ft, NULL, s, wl, wp);
  204         format_defaults_paste_buffer(ft, pb);
  205 
  206         if (filter != NULL) {
  207             cp = format_expand(ft, filter);
  208             if (!format_true(cp)) {
  209                 free(cp);
  210                 format_free(ft);
  211                 continue;
  212             }
  213             free(cp);
  214         }
  215 
  216         text = format_expand(ft, data->format);
  217         mode_tree_add(data->data, NULL, item, item->order, item->name,
  218             text, -1);
  219         free(text);
  220 
  221         format_free(ft);
  222     }
  223 
  224 }
  225 
  226 static void
  227 window_buffer_draw(__unused void *modedata, void *itemdata,
  228     struct screen_write_ctx *ctx, u_int sx, u_int sy)
  229 {
  230     struct window_buffer_itemdata   *item = itemdata;
  231     struct paste_buffer     *pb;
  232     const char          *pdata, *start, *end;
  233     char                *buf = NULL;
  234     size_t               psize;
  235     u_int                i, cx = ctx->s->cx, cy = ctx->s->cy;
  236 
  237     pb = paste_get_name(item->name);
  238     if (pb == NULL)
  239         return;
  240 
  241     pdata = end = paste_buffer_data(pb, &psize);
  242     for (i = 0; i < sy; i++) {
  243         start = end;
  244         while (end != pdata + psize && *end != '\n')
  245             end++;
  246         buf = xreallocarray(buf, 4, end - start + 1);
  247         utf8_strvis(buf, start, end - start,
  248             VIS_OCTAL|VIS_CSTYLE|VIS_TAB);
  249         if (*buf != '\0') {
  250             screen_write_cursormove(ctx, cx, cy + i, 0);
  251             screen_write_nputs(ctx, sx, &grid_default_cell, "%s",
  252                 buf);
  253         }
  254 
  255         if (end == pdata + psize)
  256             break;
  257         end++;
  258     }
  259     free(buf);
  260 }
  261 
  262 static int
  263 window_buffer_search(__unused void *modedata, void *itemdata, const char *ss)
  264 {
  265     struct window_buffer_itemdata   *item = itemdata;
  266     struct paste_buffer     *pb;
  267     const char          *bufdata;
  268     size_t               bufsize;
  269 
  270     if ((pb = paste_get_name(item->name)) == NULL)
  271         return (0);
  272     if (strstr(item->name, ss) != NULL)
  273         return (1);
  274     bufdata = paste_buffer_data(pb, &bufsize);
  275     return (memmem(bufdata, bufsize, ss, strlen(ss)) != NULL);
  276 }
  277 
  278 static void
  279 window_buffer_menu(void *modedata, struct client *c, key_code key)
  280 {
  281     struct window_buffer_modedata   *data = modedata;
  282     struct window_pane      *wp = data->wp;
  283     struct window_mode_entry    *wme;
  284 
  285     wme = TAILQ_FIRST(&wp->modes);
  286     if (wme == NULL || wme->data != modedata)
  287         return;
  288     window_buffer_key(wme, c, NULL, NULL, key, NULL);
  289 }
  290 
  291 static key_code
  292 window_buffer_get_key(void *modedata, void *itemdata, u_int line)
  293 {
  294     struct window_buffer_modedata   *data = modedata;
  295     struct window_buffer_itemdata   *item = itemdata;
  296     struct format_tree      *ft;
  297     struct session          *s = NULL;
  298     struct winlink          *wl = NULL;
  299     struct window_pane      *wp = NULL;
  300     struct paste_buffer     *pb;
  301     char                *expanded;
  302     key_code             key;
  303 
  304     if (cmd_find_valid_state(&data->fs)) {
  305         s = data->fs.s;
  306         wl = data->fs.wl;
  307         wp = data->fs.wp;
  308     }
  309     pb = paste_get_name(item->name);
  310     if (pb == NULL)
  311         return KEYC_NONE;
  312 
  313     ft = format_create(NULL, NULL, FORMAT_NONE, 0);
  314     format_defaults(ft, NULL, NULL, 0, NULL);
  315     format_defaults(ft, NULL, s, wl, wp);
  316     format_defaults_paste_buffer(ft, pb);
  317     format_add(ft, "line", "%u", line);
  318 
  319     expanded = format_expand(ft, data->key_format);
  320     key = key_string_lookup_string(expanded);
  321     free(expanded);
  322     format_free(ft);
  323     return key;
  324 }
  325 
  326 static struct screen *
  327 window_buffer_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
  328     struct args *args)
  329 {
  330     struct window_pane      *wp = wme->wp;
  331     struct window_buffer_modedata   *data;
  332     struct screen           *s;
  333 
  334     wme->data = data = xcalloc(1, sizeof *data);
  335     data->wp = wp;
  336     cmd_find_copy_state(&data->fs, fs);
  337 
  338     if (args == NULL || !args_has(args, 'F'))
  339         data->format = xstrdup(WINDOW_BUFFER_DEFAULT_FORMAT);
  340     else
  341         data->format = xstrdup(args_get(args, 'F'));
  342     if (args == NULL || !args_has(args, 'K'))
  343         data->key_format = xstrdup(WINDOW_BUFFER_DEFAULT_KEY_FORMAT);
  344     else
  345         data->key_format = xstrdup(args_get(args, 'K'));
  346     if (args == NULL || args->argc == 0)
  347         data->command = xstrdup(WINDOW_BUFFER_DEFAULT_COMMAND);
  348     else
  349         data->command = xstrdup(args->argv[0]);
  350 
  351     data->data = mode_tree_start(wp, args, window_buffer_build,
  352         window_buffer_draw, window_buffer_search, window_buffer_menu, NULL,
  353         window_buffer_get_key, data, window_buffer_menu_items,
  354         window_buffer_sort_list, nitems(window_buffer_sort_list), &s);
  355     mode_tree_zoom(data->data, args);
  356 
  357     mode_tree_build(data->data);
  358     mode_tree_draw(data->data);
  359 
  360     return (s);
  361 }
  362 
  363 static void
  364 window_buffer_free(struct window_mode_entry *wme)
  365 {
  366     struct window_buffer_modedata   *data = wme->data;
  367     u_int                i;
  368 
  369     if (data == NULL)
  370         return;
  371 
  372     mode_tree_free(data->data);
  373 
  374     for (i = 0; i < data->item_size; i++)
  375         window_buffer_free_item(data->item_list[i]);
  376     free(data->item_list);
  377 
  378     free(data->format);
  379     free(data->key_format);
  380     free(data->command);
  381 
  382     free(data);
  383 }
  384 
  385 static void
  386 window_buffer_resize(struct window_mode_entry *wme, u_int sx, u_int sy)
  387 {
  388     struct window_buffer_modedata   *data = wme->data;
  389 
  390     mode_tree_resize(data->data, sx, sy);
  391 }
  392 
  393 static void
  394 window_buffer_update(struct window_mode_entry *wme)
  395 {
  396     struct window_buffer_modedata   *data = wme->data;
  397 
  398     mode_tree_build(data->data);
  399     mode_tree_draw(data->data);
  400     data->wp->flags |= PANE_REDRAW;
  401 }
  402 
  403 static void
  404 window_buffer_do_delete(void *modedata, void *itemdata,
  405     __unused struct client *c, __unused key_code key)
  406 {
  407     struct window_buffer_modedata   *data = modedata;
  408     struct window_buffer_itemdata   *item = itemdata;
  409     struct paste_buffer     *pb;
  410 
  411     if (item == mode_tree_get_current(data->data))
  412         mode_tree_down(data->data, 0);
  413     if ((pb = paste_get_name(item->name)) != NULL)
  414         paste_free(pb);
  415 }
  416 
  417 static void
  418 window_buffer_do_paste(void *modedata, void *itemdata, struct client *c,
  419     __unused key_code key)
  420 {
  421     struct window_buffer_modedata   *data = modedata;
  422     struct window_buffer_itemdata   *item = itemdata;
  423 
  424     if (paste_get_name(item->name) != NULL)
  425         mode_tree_run_command(c, NULL, data->command, item->name);
  426 }
  427 
  428 static void
  429 window_buffer_finish_edit(struct window_buffer_editdata *ed)
  430 {
  431     free(ed->name);
  432     free(ed);
  433 }
  434 
  435 static void
  436 window_buffer_edit_close_cb(char *buf, size_t len, void *arg)
  437 {
  438     struct window_buffer_editdata   *ed = arg;
  439     size_t               oldlen;
  440     const char          *oldbuf;
  441     struct paste_buffer     *pb;
  442     struct window_pane      *wp;
  443     struct window_buffer_modedata   *data;
  444     struct window_mode_entry    *wme;
  445 
  446     if (buf == NULL || len == 0) {
  447         window_buffer_finish_edit(ed);
  448         return;
  449     }
  450 
  451     pb = paste_get_name(ed->name);
  452     if (pb == NULL || pb != ed->pb) {
  453         window_buffer_finish_edit(ed);
  454         return;
  455     }
  456 
  457     oldbuf = paste_buffer_data(pb, &oldlen);
  458     if (oldlen != '\0' &&
  459         oldbuf[oldlen - 1] != '\n' &&
  460         buf[len - 1] == '\n')
  461         len--;
  462     if (len != 0)
  463         paste_replace(pb, buf, len);
  464 
  465     wp = window_pane_find_by_id(ed->wp_id);
  466     if (wp != NULL) {
  467         wme = TAILQ_FIRST(&wp->modes);
  468         if (wme->mode == &window_buffer_mode) {
  469             data = wme->data;
  470             mode_tree_build(data->data);
  471             mode_tree_draw(data->data);
  472         }
  473         wp->flags |= PANE_REDRAW;
  474     }
  475     window_buffer_finish_edit(ed);
  476 }
  477 
  478 static void
  479 window_buffer_start_edit(struct window_buffer_modedata *data,
  480     struct window_buffer_itemdata *item, struct client *c)
  481 {
  482     struct paste_buffer     *pb;
  483     const char          *buf;
  484     size_t               len;
  485     struct window_buffer_editdata   *ed;
  486 
  487     if ((pb = paste_get_name(item->name)) == NULL)
  488         return;
  489     buf = paste_buffer_data(pb, &len);
  490 
  491     ed = xcalloc(1, sizeof *ed);
  492     ed->wp_id = data->wp->id;
  493     ed->name = xstrdup(paste_buffer_name(pb));
  494     ed->pb = pb;
  495 
  496     if (popup_editor(c, buf, len, window_buffer_edit_close_cb, ed) != 0)
  497         window_buffer_finish_edit(ed);
  498 }
  499 
  500 static void
  501 window_buffer_key(struct window_mode_entry *wme, struct client *c,
  502     __unused struct session *s, __unused struct winlink *wl, key_code key,
  503     struct mouse_event *m)
  504 {
  505     struct window_pane      *wp = wme->wp;
  506     struct window_buffer_modedata   *data = wme->data;
  507     struct mode_tree_data       *mtd = data->data;
  508     struct window_buffer_itemdata   *item;
  509     int              finished;
  510 
  511     finished = mode_tree_key(mtd, c, &key, m, NULL, NULL);
  512     switch (key) {
  513     case 'e':
  514         item = mode_tree_get_current(mtd);
  515         window_buffer_start_edit(data, item, c);
  516         break;
  517     case 'd':
  518         item = mode_tree_get_current(mtd);
  519         window_buffer_do_delete(data, item, c, key);
  520         mode_tree_build(mtd);
  521         break;
  522     case 'D':
  523         mode_tree_each_tagged(mtd, window_buffer_do_delete, c, key, 0);
  524         mode_tree_build(mtd);
  525         break;
  526     case 'P':
  527         mode_tree_each_tagged(mtd, window_buffer_do_paste, c, key, 0);
  528         finished = 1;
  529         break;
  530     case 'p':
  531     case '\r':
  532         item = mode_tree_get_current(mtd);
  533         window_buffer_do_paste(data, item, c, key);
  534         finished = 1;
  535         break;
  536     }
  537     if (finished || paste_get_top(NULL) == NULL)
  538         window_pane_reset_mode(wp);
  539     else {
  540         mode_tree_draw(mtd);
  541         wp->flags |= PANE_REDRAW;
  542     }
  543 }