summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornicm <nicm>2021-04-12 06:50:25 +0000
committernicm <nicm>2021-04-12 06:50:25 +0000
commitcd208c9d72df79a34024df6b8eb8f984613de8ef (patch)
tree334af8c27c6b06e00dbf1a61ab769594c1bd58ba
parent73cbe46f8d871b70310735276f34d9c207412587 (diff)
Permit shortcut keys in buffer, client, tree modes to be configured with
a format; the default remains the line number. GitHub issue 2636.
-rw-r--r--cmd-choose-tree.c18
-rw-r--r--format.c34
-rw-r--r--mode-tree.c68
-rw-r--r--tmux.134
-rw-r--r--tmux.h3
-rw-r--r--window-buffer.c59
-rw-r--r--window-client.c43
-rw-r--r--window-customize.c4
-rw-r--r--window-tree.c52
9 files changed, 261 insertions, 54 deletions
diff --git a/cmd-choose-tree.c b/cmd-choose-tree.c
index a58469ac..81209ee3 100644
--- a/cmd-choose-tree.c
+++ b/cmd-choose-tree.c
@@ -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/format.c b/format.c
index 80e72cf0..3a1385b2 100644
--- a/format.c
+++ b/format.c
@@ -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/mode-tree.c b/mode-tree.c
index a47c0c06..c0f85026 100644
--- a/mode-tree.c
+++ b/mode-tree.c
@@ -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/tmux.1 b/tmux.1
index 00b5cd84..74cb5f00 100644
--- a/tmux.1
+++ b/tmux.1
@@ -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/tmux.h b/tmux.h
index 0c7636f8..9160ef92 100644
--- a/tmux.h
+++ b/tmux.h
@@ -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/window-buffer.c b/window-buffer.c
index 4599cbc5..5e4dd699 100644
--- a/window-buffer.c
+++ b/window-buffer.c
@@ -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/window-client.c b/window-client.c
index ec3c646a..db7c6dcc 100644
--- a/window-client.c
+++ b/window-client.c
@@ -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/window-customize.c b/window-customize.c
index a1f191b5..fce002fd 100644
--- a/window-customize.c
+++ b/window-customize.c
@@ -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/window-tree.c b/window-tree.c
index 1498b337..881896e7 100644
--- a/window-tree.c
+++ b/window-tree.c
@@ -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);