Permit shortcut keys in buffer, client, tree modes to be configured with
authornicm <nicm@openbsd.org>
Mon, 12 Apr 2021 06:50:25 +0000 (06:50 +0000)
committernicm <nicm@openbsd.org>
Mon, 12 Apr 2021 06:50:25 +0000 (06:50 +0000)
a format; the default remains the line number. GitHub issue 2636.

usr.bin/tmux/cmd-choose-tree.c
usr.bin/tmux/format.c
usr.bin/tmux/mode-tree.c
usr.bin/tmux/tmux.1
usr.bin/tmux/tmux.h
usr.bin/tmux/window-buffer.c
usr.bin/tmux/window-client.c
usr.bin/tmux/window-customize.c
usr.bin/tmux/window-tree.c

index 61f9d68..a03ef1f 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-choose-tree.c,v 1.47 2020/05/16 16:02:24 nicm Exp $ */
+/* $OpenBSD: cmd-choose-tree.c,v 1.48 2021/04/12 06:50:25 nicm Exp $ */
 
 /*
  * Copyright (c) 2012 Thomas Adam <thomas@xteddy.org>
@@ -30,9 +30,9 @@ const struct cmd_entry cmd_choose_tree_entry = {
        .name = "choose-tree",
        .alias = NULL,
 
-       .args = { "F:Gf:NO:rst:wZ", 0, 1 },
-       .usage = "[-GNrswZ] [-F format] [-f filter] [-O sort-order] "
-                CMD_TARGET_PANE_USAGE " [template]",
+       .args = { "F:f:GK:NO:rst:wZ", 0, 1 },
+       .usage = "[-GNrswZ] [-F format] [-f filter] [-K key-format] "
+                "[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
 
        .target = { 't', CMD_FIND_PANE, 0 },
 
@@ -44,9 +44,9 @@ const struct cmd_entry cmd_choose_client_entry = {
        .name = "choose-client",
        .alias = NULL,
 
-       .args = { "F:f:NO:rt:Z", 0, 1 },
-       .usage = "[-NrZ] [-F format] [-f filter] [-O sort-order] "
-                CMD_TARGET_PANE_USAGE " [template]",
+       .args = { "F:f:K:NO:rt:Z", 0, 1 },
+       .usage = "[-NrZ] [-F format] [-f filter] [-K key-format] "
+                "[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
 
        .target = { 't', CMD_FIND_PANE, 0 },
 
@@ -58,9 +58,9 @@ const struct cmd_entry cmd_choose_buffer_entry = {
        .name = "choose-buffer",
        .alias = NULL,
 
-       .args = { "F:f:NO:rt:Z", 0, 1 },
-       .usage = "[-NrZ] [-F format] [-f filter] [-O sort-order] "
-                CMD_TARGET_PANE_USAGE " [template]",
+       .args = { "F:f:K:NO:rt:Z", 0, 1 },
+       .usage = "[-NrZ] [-F format] [-f filter] [-K key-format] "
+                "[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
 
        .target = { 't', CMD_FIND_PANE, 0 },
 
index 93e6538..107fca7 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: format.c,v 1.282 2021/03/11 07:08:18 nicm Exp $ */
+/* $OpenBSD: format.c,v 1.283 2021/04/12 06:50:25 nicm Exp $ */
 
 /*
  * Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -100,6 +100,7 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2)
 #define FORMAT_QUOTE_STYLE 0x2000
 #define FORMAT_WINDOW_NAME 0x4000
 #define FORMAT_SESSION_NAME 0x8000
+#define FORMAT_CHARACTER 0x10000
 
 /* Limit on recursion. */
 #define FORMAT_LOOP_LIMIT 10
@@ -3522,7 +3523,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
 
        /*
         * Modifiers are a ; separated list of the forms:
-        *      l,m,C,b,d,n,t,w,q,E,T,S,W,P,<,>
+        *      l,m,C,a,b,d,n,t,w,q,E,T,S,W,P,<,>
         *      =a
         *      =/a
         *      =/a/
@@ -3539,7 +3540,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
                        cp++;
 
                /* Check single character modifiers with no arguments. */
-               if (strchr("lbdnwETSWP<>", cp[0]) != NULL &&
+               if (strchr("labdnwETSWP<>", cp[0]) != NULL &&
                    format_is_end(cp[1])) {
                        format_add_modifier(&list, count, cp, 1, NULL, 0);
                        cp++;
@@ -3956,7 +3957,7 @@ format_replace_expression(struct format_modifier *mexp,
                mright = (long long)mright;
        }
        format_log(es, "expression left side is: %.*f", prec, mleft);
-       format_log(es, "expression right side is:  %.*f", prec, mright);
+       format_log(es, "expression right side is: %.*f", prec, mright);
 
        switch (operator) {
        case ADD:
@@ -4016,10 +4017,10 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
 {
        struct format_tree               *ft = es->ft;
        struct window_pane               *wp = ft->wp;
-       const char                       *errptr, *copy, *cp, *marker = NULL;
+       const char                       *errstr, *copy, *cp, *marker = NULL;
        const char                       *time_format = NULL;
        char                             *copy0, *condition, *found, *new;
-       char                             *value, *left, *right;
+       char                             *value, *left, *right, c;
        size_t                            valuelen;
        int                               modifiers = 0, limit = 0, width = 0;
        int                               j;
@@ -4063,8 +4064,8 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
                                if (fm->argc < 1)
                                        break;
                                limit = strtonum(fm->argv[0], INT_MIN, INT_MAX,
-                                   &errptr);
-                               if (errptr != NULL)
+                                   &errstr);
+                               if (errstr != NULL)
                                        limit = 0;
                                if (fm->argc >= 2 && fm->argv[1] != NULL)
                                        marker = fm->argv[1];
@@ -4073,8 +4074,8 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
                                if (fm->argc < 1)
                                        break;
                                width = strtonum(fm->argv[0], INT_MIN, INT_MAX,
-                                   &errptr);
-                               if (errptr != NULL)
+                                   &errstr);
+                               if (errstr != NULL)
                                        width = 0;
                                break;
                        case 'w':
@@ -4088,6 +4089,9 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
                        case 'l':
                                modifiers |= FORMAT_LITERAL;
                                break;
+                       case 'a':
+                               modifiers |= FORMAT_CHARACTER;
+                               break;
                        case 'b':
                                modifiers |= FORMAT_BASENAME;
                                break;
@@ -4154,6 +4158,18 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
                goto done;
        }
 
+       /* Is this a character? */
+       if (modifiers & FORMAT_CHARACTER) {
+               new = format_expand1(es, copy);
+               c = strtonum(new, 32, 126, &errstr);
+               if (errstr != NULL)
+                       value = xstrdup("");
+               else
+                       xasprintf(&value, "%c", c);
+               free (new);
+               goto done;
+       }
+
        /* Is this a loop, comparison or condition? */
        if (modifiers & FORMAT_SESSIONS) {
                value = format_loop_sessions(es, copy);
index f696c05..1d1bee6 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: mode-tree.c,v 1.51 2020/07/27 08:03:10 nicm Exp $ */
+/* $OpenBSD: mode-tree.c,v 1.52 2021/04/12 06:50:25 nicm Exp $ */
 
 /*
  * Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -46,6 +46,7 @@ struct mode_tree_data {
        mode_tree_search_cb       searchcb;
        mode_tree_menu_cb         menucb;
        mode_tree_height_cb       heightcb;
+       mode_tree_key_cb          keycb;
 
        struct mode_tree_list     children;
        struct mode_tree_list     saved;
@@ -74,6 +75,10 @@ struct mode_tree_item {
        void                            *itemdata;
        u_int                            line;
 
+       key_code                         key;
+       const char                      *keystr;
+       size_t                           keylen;
+
        uint64_t                         tag;
        const char                      *name;
        const char                      *text;
@@ -135,6 +140,7 @@ mode_tree_free_item(struct mode_tree_item *mti)
 
        free((void *)mti->name);
        free((void *)mti->text);
+       free((void *)mti->keystr);
 
        free(mti);
 }
@@ -193,6 +199,26 @@ mode_tree_build_lines(struct mode_tree_data *mtd,
                        flat = 0;
                if (mti->expanded)
                        mode_tree_build_lines(mtd, &mti->children, depth + 1);
+
+               if (mtd->keycb != NULL) {
+                       mti->key = mtd->keycb(mtd->modedata, mti->itemdata,
+                           mti->line);
+                       if (mti->key == KEYC_UNKNOWN)
+                               mti->key = KEYC_NONE;
+               } else if (mti->line < 10)
+                       mti->key = '0' + mti->line;
+               else if (mti->line < 36)
+                       mti->key = KEYC_META|('a' + mti->line - 10);
+               else
+                       mti->key = KEYC_NONE;
+               if (mti->key != KEYC_NONE) {
+                       mti->keystr = xstrdup(key_string_lookup_key(mti->key,
+                           0));
+                       mti->keylen = strlen(mti->keystr);
+               } else {
+                       mti->keystr = NULL;
+                       mti->keylen = 0;
+               }
        }
        TAILQ_FOREACH(mti, mtl, entry) {
                for (i = 0; i < mtd->line_size; i++) {
@@ -363,7 +389,7 @@ struct mode_tree_data *
 mode_tree_start(struct window_pane *wp, struct args *args,
     mode_tree_build_cb buildcb, mode_tree_draw_cb drawcb,
     mode_tree_search_cb searchcb, mode_tree_menu_cb menucb,
-    mode_tree_height_cb heightcb, void *modedata,
+    mode_tree_height_cb heightcb, mode_tree_key_cb keycb, void *modedata,
     const struct menu_item *menu, const char **sort_list, u_int sort_size,
     struct screen **s)
 {
@@ -402,6 +428,7 @@ mode_tree_start(struct window_pane *wp, struct args *args,
        mtd->searchcb = searchcb;
        mtd->menucb = menucb;
        mtd->heightcb = heightcb;
+       mtd->keycb = keycb;
 
        TAILQ_INIT(&mtd->children);
 
@@ -596,10 +623,10 @@ mode_tree_draw(struct mode_tree_data *mtd)
        struct screen_write_ctx  ctx;
        struct grid_cell         gc0, gc;
        u_int                    w, h, i, j, sy, box_x, box_y, width;
-       char                    *text, *start, key[7];
+       char                    *text, *start, *key;
        const char              *tag, *symbol;
        size_t                   size, n;
-       int                      keylen;
+       int                      keylen, pad;
 
        if (mtd->line_size == 0)
                return;
@@ -614,28 +641,30 @@ mode_tree_draw(struct mode_tree_data *mtd)
        screen_write_start(&ctx, s);
        screen_write_clearscreen(&ctx, 8);
 
-       if (mtd->line_size > 10)
-               keylen = 6;
-       else
-               keylen = 4;
+       keylen = 0;
+       for (i = 0; i < mtd->line_size; i++) {
+               mti = mtd->line_list[i].item;
+               if (mti->key == KEYC_NONE)
+                       continue;
+               if ((int)mti->keylen + 3 > keylen)
+                       keylen = mti->keylen + 3;
+       }
 
        for (i = 0; i < mtd->line_size; i++) {
                if (i < mtd->offset)
                        continue;
                if (i > mtd->offset + h - 1)
                        break;
-
                line = &mtd->line_list[i];
                mti = line->item;
 
                screen_write_cursormove(&ctx, 0, i - mtd->offset, 0);
 
-               if (i < 10)
-                       snprintf(key, sizeof key, "(%c)  ", '0' + i);
-               else if (i < 36)
-                       snprintf(key, sizeof key, "(M-%c)", 'a' + (i - 10));
+               pad = keylen - 2 - mti->keylen;
+               if (mti->key != KEYC_NONE)
+                       xasprintf(&key, "(%s)%*s", mti->keystr, pad, "");
                else
-                       *key = '\0';
+                       key = xstrdup("");
 
                if (line->flat)
                        symbol = "";
@@ -698,6 +727,7 @@ mode_tree_draw(struct mode_tree_data *mtd)
                        }
                }
                free(text);
+               free(key);
 
                if (mti->tagged) {
                        gc.attr ^= GRID_ATTR_BRIGHT;
@@ -951,7 +981,6 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
        struct mode_tree_item   *current, *parent, *mti;
        u_int                    i, x, y;
        int                      choice;
-       key_code                 tmp;
 
        if (KEYC_IS_MOUSE(*key) && m != NULL) {
                if (cmd_mouse_at(mtd->wp, m, &x, &y, 0) != 0) {
@@ -993,12 +1022,11 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
        current = line->item;
 
        choice = -1;
-       if (*key >= '0' && *key <= '9')
-               choice = (*key) - '0';
-       else if (((*key) & KEYC_MASK_MODIFIERS) == KEYC_META) {
-               tmp = (*key) & KEYC_MASK_KEY;
-               if (tmp >= 'a' && tmp <= 'z')
-                       choice = 10 + (tmp - 'a');
+       for (i = 0; i < mtd->line_size; i++) {
+               if (*key == mtd->line_list[i].item->key) {
+                       choice = i;
+                       break;
+               }
        }
        if (choice != -1) {
                if ((u_int)choice > mtd->line_size - 1) {
index 455b2f6..930cbf4 100644 (file)
@@ -1,4 +1,4 @@
-.\" $OpenBSD: tmux.1,v 1.832 2021/04/07 12:50:12 nicm Exp $
+.\" $OpenBSD: tmux.1,v 1.833 2021/04/12 06:50:25 nicm Exp $
 .\"
 .\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
 .\"
@@ -14,7 +14,7 @@
 .\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 .\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: April 7 2021 $
+.Dd $Mdocdate: April 12 2021 $
 .Dt TMUX 1
 .Os
 .Sh NAME
@@ -1985,12 +1985,17 @@ The default is to capture only the visible contents of the pane.
 .Op Fl NrZ
 .Op Fl F Ar format
 .Op Fl f Ar filter
+.Op Fl K Ar key-format
 .Op Fl O Ar sort-order
 .Op Fl t Ar target-pane
 .Op Ar template
 .Xc
 Put a pane into client mode, allowing a client to be selected interactively from
 a list.
+Each client is shown on one line.
+A shortcut key is shown on the left in brackets allowing for immediate choice,
+or the list may be navigated and an item chosen or otherwise manipulated using
+the keys below.
 .Fl Z
 zooms the pane.
 The following keys may be used in client mode:
@@ -2040,7 +2045,9 @@ specifies an initial filter: the filter is a format - if it evaluates to zero,
 the item in the list is not shown, otherwise it is shown.
 If a filter would lead to an empty list, it is ignored.
 .Fl F
-specifies the format for each item in the list.
+specifies the format for each item in the list and
+.Fl K
+a format for each shortcut key; both are evaluated once for each line.
 .Fl N
 starts without the preview.
 This command works only if at least one client is attached.
@@ -2049,12 +2056,17 @@ This command works only if at least one client is attached.
 .Op Fl GNrswZ
 .Op Fl F Ar format
 .Op Fl f Ar filter
+.Op Fl K Ar key-format
 .Op Fl O Ar sort-order
 .Op Fl t Ar target-pane
 .Op Ar template
 .Xc
 Put a pane into tree mode, where a session, window or pane may be chosen
-interactively from a list.
+interactively from a tree.
+Each session, window or pane is shown on one line.
+A shortcut key is shown on the left in brackets allowing for immediate choice,
+or the tree may be navigated and an item chosen or otherwise manipulated using
+the keys below.
 .Fl s
 starts with sessions collapsed and
 .Fl w
@@ -2113,7 +2125,9 @@ specifies an initial filter: the filter is a format - if it evaluates to zero,
 the item in the list is not shown, otherwise it is shown.
 If a filter would lead to an empty list, it is ignored.
 .Fl F
-specifies the format for each item in the tree.
+specifies the format for each item in the tree and
+.Fl K
+a format for each shortcut key; both are evaluated once for each line.
 .Fl N
 starts without the preview.
 .Fl G
@@ -4663,6 +4677,11 @@ For example,
 multiplies 5.5 by 3 for a result with four decimal places and
 .Ql #{e|%%:7,3}
 returns the modulus of 7 and 3.
+.Ql a
+replaces a numeric argument by its ASCII equivalent, so
+.Ql #{a:98}
+results in
+.Ql b .
 .Pp
 A limit may be placed on the length of the resultant string by prefixing it
 by an
@@ -5681,12 +5700,17 @@ The buffer commands are as follows:
 .Op Fl NZr
 .Op Fl F Ar format
 .Op Fl f Ar filter
+.Op Fl K Ar key-format
 .Op Fl O Ar sort-order
 .Op Fl t Ar target-pane
 .Op Ar template
 .Xc
 Put a pane into buffer mode, where a buffer may be chosen interactively from
 a list.
+Each buffer is shown on one line.
+A shortcut key is shown on the left in brackets allowing for immediate choice,
+or the list may be navigated and an item chosen or otherwise manipulated using
+the keys below.
 .Fl Z
 zooms the pane.
 The following keys may be used in buffer mode:
@@ -5734,7 +5758,9 @@ specifies an initial filter: the filter is a format - if it evaluates to zero,
 the item in the list is not shown, otherwise it is shown.
 If a filter would lead to an empty list, it is ignored.
 .Fl F
-specifies the format for each item in the list.
+specifies the format for each item in the list and
+.Fl K
+a format for each shortcut key; both are evaluated once for each line.
 .Fl N
 starts without the preview.
 This command works only if at least one client is attached.
index b873244..8cb3179 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmux.h,v 1.1101 2021/04/05 08:43:48 nicm Exp $ */
+/* $OpenBSD: tmux.h,v 1.1102 2021/04/12 06:50:25 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -2855,6 +2855,7 @@ typedef void (*mode_tree_draw_cb)(void *, void *, struct screen_write_ctx *,
 typedef int (*mode_tree_search_cb)(void *, void *, const char *);
 typedef void (*mode_tree_menu_cb)(void *, struct client *, key_code);
 typedef u_int (*mode_tree_height_cb)(void *, u_int);
+typedef key_code (*mode_tree_key_cb)(void *, void *, u_int);
 typedef void (*mode_tree_each_cb)(void *, void *, struct client *, key_code);
 u_int   mode_tree_count_tagged(struct mode_tree_data *);
 void   *mode_tree_get_current(struct mode_tree_data *);
@@ -2869,7 +2870,7 @@ void       mode_tree_up(struct mode_tree_data *, int);
 void    mode_tree_down(struct mode_tree_data *, int);
 struct mode_tree_data *mode_tree_start(struct window_pane *, struct args *,
             mode_tree_build_cb, mode_tree_draw_cb, mode_tree_search_cb,
-            mode_tree_menu_cb, mode_tree_height_cb, void *,
+            mode_tree_menu_cb, mode_tree_height_cb, mode_tree_key_cb, void *,
             const struct menu_item *, const char **, u_int, struct screen **);
 void    mode_tree_zoom(struct mode_tree_data *, struct args *);
 void    mode_tree_build(struct mode_tree_data *);
index f353693..23574f1 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: window-buffer.c,v 1.32 2020/12/03 07:12:12 nicm Exp $ */
+/* $OpenBSD: window-buffer.c,v 1.33 2021/04/12 06:50:25 nicm Exp $ */
 
 /*
  * Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -41,6 +41,17 @@ static void           window_buffer_key(struct window_mode_entry *,
 #define WINDOW_BUFFER_DEFAULT_FORMAT \
        "#{t/p:buffer_created}: #{buffer_sample}"
 
+#define WINDOW_BUFFER_DEFAULT_KEY_FORMAT \
+       "#{?#{e|<:#{line},10}," \
+               "#{line}" \
+       "," \
+               "#{?#{e|<:#{line},36}," \
+                       "M-#{a:#{e|+:97,#{e|-:#{line},10}}}" \
+               "," \
+                       "" \
+               "}" \
+       "}"
+
 static const struct menu_item window_buffer_menu_items[] = {
        { "Paste", 'p', NULL },
        { "Paste Tagged", 'P', NULL },
@@ -93,6 +104,7 @@ struct window_buffer_modedata {
        struct mode_tree_data            *data;
        char                             *command;
        char                             *format;
+       char                             *key_format;
 
        struct window_buffer_itemdata   **item_list;
        u_int                             item_size;
@@ -232,7 +244,8 @@ window_buffer_draw(__unused void *modedata, void *itemdata,
                while (end != pdata + psize && *end != '\n')
                        end++;
                buf = xreallocarray(buf, 4, end - start + 1);
-               utf8_strvis(buf, start, end - start, VIS_OCTAL|VIS_CSTYLE|VIS_TAB);
+               utf8_strvis(buf, start, end - start,
+                   VIS_OCTAL|VIS_CSTYLE|VIS_TAB);
                if (*buf != '\0') {
                        screen_write_cursormove(ctx, cx, cy + i, 0);
                        screen_write_nputs(ctx, sx, &grid_default_cell, "%s",
@@ -275,6 +288,41 @@ window_buffer_menu(void *modedata, struct client *c, key_code key)
        window_buffer_key(wme, c, NULL, NULL, key, NULL);
 }
 
+static key_code
+window_buffer_get_key(void *modedata, void *itemdata, u_int line)
+{
+       struct window_buffer_modedata   *data = modedata;
+       struct window_buffer_itemdata   *item = itemdata;
+       struct format_tree              *ft;
+       struct session                  *s;
+       struct winlink                  *wl;
+       struct window_pane              *wp;
+       struct paste_buffer             *pb;
+       char                            *expanded;
+       key_code                         key;
+
+       if (cmd_find_valid_state(&data->fs)) {
+               s = data->fs.s;
+               wl = data->fs.wl;
+               wp = data->fs.wp;
+       }
+       pb = paste_get_name(item->name);
+       if (pb == NULL)
+               return KEYC_NONE;
+
+       ft = format_create(NULL, NULL, FORMAT_NONE, 0);
+       format_defaults(ft, NULL, NULL, 0, NULL);
+       format_defaults(ft, NULL, s, wl, wp);
+       format_defaults_paste_buffer(ft, pb);
+       format_add(ft, "line", "%u", line);
+
+       expanded = format_expand(ft, data->key_format);
+       key = key_string_lookup_string(expanded);
+       free(expanded);
+       format_free(ft);
+       return key;
+}
+
 static struct screen *
 window_buffer_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
     struct args *args)
@@ -291,6 +339,10 @@ window_buffer_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
                data->format = xstrdup(WINDOW_BUFFER_DEFAULT_FORMAT);
        else
                data->format = xstrdup(args_get(args, 'F'));
+       if (args == NULL || !args_has(args, 'K'))
+               data->key_format = xstrdup(WINDOW_BUFFER_DEFAULT_KEY_FORMAT);
+       else
+               data->key_format = xstrdup(args_get(args, 'K'));
        if (args == NULL || args->argc == 0)
                data->command = xstrdup(WINDOW_BUFFER_DEFAULT_COMMAND);
        else
@@ -298,8 +350,8 @@ window_buffer_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
 
        data->data = mode_tree_start(wp, args, window_buffer_build,
            window_buffer_draw, window_buffer_search, window_buffer_menu, NULL,
-           data, window_buffer_menu_items, window_buffer_sort_list,
-           nitems(window_buffer_sort_list), &s);
+           window_buffer_get_key, data, window_buffer_menu_items,
+           window_buffer_sort_list, nitems(window_buffer_sort_list), &s);
        mode_tree_zoom(data->data, args);
 
        mode_tree_build(data->data);
@@ -324,6 +376,7 @@ window_buffer_free(struct window_mode_entry *wme)
        free(data->item_list);
 
        free(data->format);
+       free(data->key_format);
        free(data->command);
 
        free(data);
index 9a3b8dd..fa0ebda 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: window-client.c,v 1.30 2020/12/03 07:12:12 nicm Exp $ */
+/* $OpenBSD: window-client.c,v 1.31 2021/04/12 06:50:25 nicm Exp $ */
 
 /*
  * Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -40,6 +40,17 @@ static void           window_client_key(struct window_mode_entry *,
 #define WINDOW_CLIENT_DEFAULT_FORMAT \
        "#{t/p:client_activity}: session #{session_name}"
 
+#define WINDOW_CLIENT_DEFAULT_KEY_FORMAT \
+       "#{?#{e|<:#{line},10}," \
+               "#{line}" \
+       "," \
+               "#{?#{e|<:#{line},36}," \
+                       "M-#{a:#{e|+:97,#{e|-:#{line},10}}}" \
+               "," \
+                       "" \
+               "}" \
+       "}"
+
 static const struct menu_item window_client_menu_items[] = {
        { "Detach", 'd', NULL },
        { "Detach Tagged", 'D', NULL },
@@ -87,6 +98,7 @@ struct window_client_modedata {
 
        struct mode_tree_data            *data;
        char                             *format;
+       char                             *key_format;
        char                             *command;
 
        struct window_client_itemdata   **item_list;
@@ -252,6 +264,26 @@ window_client_menu(void *modedata, struct client *c, key_code key)
        window_client_key(wme, c, NULL, NULL, key, NULL);
 }
 
+static key_code
+window_client_get_key(void *modedata, void *itemdata, u_int line)
+{
+       struct window_client_modedata   *data = modedata;
+       struct window_client_itemdata   *item = itemdata;
+       struct format_tree              *ft;
+       char                            *expanded;
+       key_code                         key;
+
+       ft = format_create(NULL, NULL, FORMAT_NONE, 0);
+       format_defaults(ft, item->c, NULL, 0, NULL);
+       format_add(ft, "line", "%u", line);
+
+       expanded = format_expand(ft, data->key_format);
+       key = key_string_lookup_string(expanded);
+       free(expanded);
+       format_free(ft);
+       return key;
+}
+
 static struct screen *
 window_client_init(struct window_mode_entry *wme,
     __unused struct cmd_find_state *fs, struct args *args)
@@ -267,15 +299,19 @@ window_client_init(struct window_mode_entry *wme,
                data->format = xstrdup(WINDOW_CLIENT_DEFAULT_FORMAT);
        else
                data->format = xstrdup(args_get(args, 'F'));
+       if (args == NULL || !args_has(args, 'K'))
+               data->key_format = xstrdup(WINDOW_CLIENT_DEFAULT_KEY_FORMAT);
+       else
+               data->key_format = xstrdup(args_get(args, 'K'));
        if (args == NULL || args->argc == 0)
                data->command = xstrdup(WINDOW_CLIENT_DEFAULT_COMMAND);
        else
                data->command = xstrdup(args->argv[0]);
 
        data->data = mode_tree_start(wp, args, window_client_build,
-           window_client_draw, NULL, window_client_menu, NULL, data,
-           window_client_menu_items, window_client_sort_list,
-           nitems(window_client_sort_list), &s);
+           window_client_draw, NULL, window_client_menu, NULL,
+           window_client_get_key, data, window_client_menu_items,
+           window_client_sort_list, nitems(window_client_sort_list), &s);
        mode_tree_zoom(data->data, args);
 
        mode_tree_build(data->data);
@@ -300,6 +336,7 @@ window_client_free(struct window_mode_entry *wme)
        free(data->item_list);
 
        free(data->format);
+       free(data->key_format);
        free(data->command);
 
        free(data);
index f354013..6e09bc5 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: window-customize.c,v 1.8 2021/01/18 11:14:24 nicm Exp $ */
+/* $OpenBSD: window-customize.c,v 1.9 2021/04/12 06:50:25 nicm Exp $ */
 
 /*
  * Copyright (c) 2020 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -890,8 +890,8 @@ window_customize_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
 
        data->data = mode_tree_start(wp, args, window_customize_build,
            window_customize_draw, NULL, window_customize_menu,
-           window_customize_height, data, window_customize_menu_items, NULL, 0,
-           &s);
+           window_customize_height, NULL, data, window_customize_menu_items,
+           NULL, 0, &s);
        mode_tree_zoom(data->data, args);
 
        mode_tree_build(data->data);
index 760da78..c60fede 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: window-tree.c,v 1.53 2020/12/03 07:12:12 nicm Exp $ */
+/* $OpenBSD: window-tree.c,v 1.54 2021/04/12 06:50:25 nicm Exp $ */
 
 /*
  * Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -56,6 +56,17 @@ static void           window_tree_key(struct window_mode_entry *,
                "}" \
        "}"
 
+#define WINDOW_TREE_DEFAULT_KEY_FORMAT \
+       "#{?#{e|<:#{line},10}," \
+               "#{line}" \
+       "," \
+               "#{?#{e|<:#{line},36}," \
+                       "M-#{a:#{e|+:97,#{e|-:#{line},10}}}" \
+               "," \
+                       "" \
+               "}" \
+       "}"
+
 static const struct menu_item window_tree_menu_items[] = {
        { "Select", '\r', NULL },
        { "Expand", KEYC_RIGHT, NULL },
@@ -117,6 +128,7 @@ struct window_tree_modedata {
 
        struct mode_tree_data            *data;
        char                             *format;
+       char                             *key_format;
        char                             *command;
        int                               squash_groups;
 
@@ -856,6 +868,35 @@ window_tree_menu(void *modedata, struct client *c, key_code key)
        window_tree_key(wme, c, NULL, NULL, key, NULL);
 }
 
+static key_code
+window_tree_get_key(void *modedata, void *itemdata, u_int line)
+{
+       struct window_tree_modedata     *data = modedata;
+       struct window_tree_itemdata     *item = itemdata;
+       struct format_tree              *ft;
+       struct session                  *s;
+       struct winlink                  *wl;
+       struct window_pane              *wp;
+       char                            *expanded;
+       key_code                         key;
+
+       ft = format_create(NULL, NULL, FORMAT_NONE, 0);
+       window_tree_pull_item(item, &s, &wl, &wp);
+       if (item->type == WINDOW_TREE_SESSION)
+               format_defaults(ft, NULL, s, NULL, NULL);
+       else if (item->type == WINDOW_TREE_WINDOW)
+               format_defaults(ft, NULL, s, wl, NULL);
+       else
+               format_defaults(ft, NULL, s, wl, wp);
+       format_add(ft, "line", "%u", line);
+
+       expanded = format_expand(ft, data->key_format);
+       key = key_string_lookup_string(expanded);
+       free(expanded);
+       format_free(ft);
+       return key;
+}
+
 static struct screen *
 window_tree_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
     struct args *args)
@@ -880,6 +921,10 @@ window_tree_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
                data->format = xstrdup(WINDOW_TREE_DEFAULT_FORMAT);
        else
                data->format = xstrdup(args_get(args, 'F'));
+       if (args == NULL || !args_has(args, 'K'))
+               data->key_format = xstrdup(WINDOW_TREE_DEFAULT_KEY_FORMAT);
+       else
+               data->key_format = xstrdup(args_get(args, 'K'));
        if (args == NULL || args->argc == 0)
                data->command = xstrdup(WINDOW_TREE_DEFAULT_COMMAND);
        else
@@ -887,9 +932,9 @@ window_tree_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
        data->squash_groups = !args_has(args, 'G');
 
        data->data = mode_tree_start(wp, args, window_tree_build,
-           window_tree_draw, window_tree_search, window_tree_menu, NULL, data,
-           window_tree_menu_items, window_tree_sort_list,
-           nitems(window_tree_sort_list), &s);
+           window_tree_draw, window_tree_search, window_tree_menu, NULL,
+           window_tree_get_key, data, window_tree_menu_items,
+           window_tree_sort_list, nitems(window_tree_sort_list), &s);
        mode_tree_zoom(data->data, args);
 
        mode_tree_build(data->data);
@@ -913,6 +958,7 @@ window_tree_destroy(struct window_tree_modedata *data)
        free(data->item_list);
 
        free(data->format);
+       free(data->key_format);
        free(data->command);
 
        free(data);