From 438eed14c004e26e3bffee5f80e95daf56d8e510 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 12 Apr 2021 06:50:25 +0000 Subject: [PATCH] Permit shortcut keys in buffer, client, tree modes to be configured with a format; the default remains the line number. GitHub issue 2636. --- usr.bin/tmux/cmd-choose-tree.c | 20 +++++----- usr.bin/tmux/format.c | 36 ++++++++++++----- usr.bin/tmux/mode-tree.c | 70 +++++++++++++++++++++++---------- usr.bin/tmux/tmux.1 | 38 +++++++++++++++--- usr.bin/tmux/tmux.h | 5 ++- usr.bin/tmux/window-buffer.c | 61 ++++++++++++++++++++++++++-- usr.bin/tmux/window-client.c | 45 +++++++++++++++++++-- usr.bin/tmux/window-customize.c | 6 +-- usr.bin/tmux/window-tree.c | 54 +++++++++++++++++++++++-- 9 files changed, 271 insertions(+), 64 deletions(-) diff --git a/usr.bin/tmux/cmd-choose-tree.c b/usr.bin/tmux/cmd-choose-tree.c index 61f9d68f5d0..a03ef1f48d3 100644 --- a/usr.bin/tmux/cmd-choose-tree.c +++ b/usr.bin/tmux/cmd-choose-tree.c @@ -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 @@ -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 }, diff --git a/usr.bin/tmux/format.c b/usr.bin/tmux/format.c index 93e653826f3..107fca71c2e 100644 --- a/usr.bin/tmux/format.c +++ b/usr.bin/tmux/format.c @@ -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 @@ -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); diff --git a/usr.bin/tmux/mode-tree.c b/usr.bin/tmux/mode-tree.c index f696c05e2a0..1d1bee611f5 100644 --- a/usr.bin/tmux/mode-tree.c +++ b/usr.bin/tmux/mode-tree.c @@ -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 @@ -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) { diff --git a/usr.bin/tmux/tmux.1 b/usr.bin/tmux/tmux.1 index 455b2f67a20..930cbf4e2a1 100644 --- a/usr.bin/tmux/tmux.1 +++ b/usr.bin/tmux/tmux.1 @@ -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 .\" @@ -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. diff --git a/usr.bin/tmux/tmux.h b/usr.bin/tmux/tmux.h index b87324452ba..8cb31798b03 100644 --- a/usr.bin/tmux/tmux.h +++ b/usr.bin/tmux/tmux.h @@ -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 @@ -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 *); diff --git a/usr.bin/tmux/window-buffer.c b/usr.bin/tmux/window-buffer.c index f353693fcec..23574f18576 100644 --- a/usr.bin/tmux/window-buffer.c +++ b/usr.bin/tmux/window-buffer.c @@ -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 @@ -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); diff --git a/usr.bin/tmux/window-client.c b/usr.bin/tmux/window-client.c index 9a3b8dd3d93..fa0ebdaa606 100644 --- a/usr.bin/tmux/window-client.c +++ b/usr.bin/tmux/window-client.c @@ -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 @@ -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); diff --git a/usr.bin/tmux/window-customize.c b/usr.bin/tmux/window-customize.c index f354013b3ed..6e09bc54883 100644 --- a/usr.bin/tmux/window-customize.c +++ b/usr.bin/tmux/window-customize.c @@ -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 @@ -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); diff --git a/usr.bin/tmux/window-tree.c b/usr.bin/tmux/window-tree.c index 760da789d47..c60fedeb44a 100644 --- a/usr.bin/tmux/window-tree.c +++ b/usr.bin/tmux/window-tree.c @@ -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 @@ -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); -- 2.20.1