Add sorting (-O flag) and a custom format (-F) to list-keys, from Dane

Jensen in GitHub issue 4845.
This commit is contained in:
nicm
2026-02-24 08:20:52 +00:00
parent 9316476a73
commit 09bd686327
7 changed files with 439 additions and 313 deletions

View File

@@ -28,6 +28,7 @@ SRCS= alerts.c \
cmd-kill-window.c \ cmd-kill-window.c \
cmd-list-buffers.c \ cmd-list-buffers.c \
cmd-list-clients.c \ cmd-list-clients.c \
cmd-list-commands.c \
cmd-list-keys.c \ cmd-list-keys.c \
cmd-list-panes.c \ cmd-list-panes.c \
cmd-list-sessions.c \ cmd-list-sessions.c \

107
cmd-list-commands.c Normal file
View File

@@ -0,0 +1,107 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* List all commands.
*/
#define LIST_COMMANDS_TEMPLATE \
"#{command_list_name}" \
"#{?command_list_alias, (#{command_list_alias}),} " \
"#{command_list_usage}"
static enum cmd_retval cmd_list_commands(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_list_commands_entry = {
.name = "list-commands",
.alias = "lscm",
.args = { "F:", 0, 1, NULL },
.usage = "[-F format] [command]",
.flags = CMD_STARTSERVER|CMD_AFTERHOOK,
.exec = cmd_list_commands
};
static void
cmd_list_single_command(const struct cmd_entry *entry, struct format_tree *ft,
const char *template, struct cmdq_item *item)
{
const char *s;
char *line;
format_add(ft, "command_list_name", "%s", entry->name);
if (entry->alias != NULL)
s = entry->alias;
else
s = "";
format_add(ft, "command_list_alias", "%s", s);
if (entry->usage != NULL)
s = entry->usage;
else
s = "";
format_add(ft, "command_list_usage", "%s", s);
line = format_expand(ft, template);
if (*line != '\0')
cmdq_print(item, "%s", line);
free(line);
}
static enum cmd_retval
cmd_list_commands(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
const struct cmd_entry **entryp;
const struct cmd_entry *entry;
struct format_tree *ft;
const char *template, *command;
char *cause;
if ((template = args_get(args, 'F')) == NULL)
template = LIST_COMMANDS_TEMPLATE;
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
format_defaults(ft, NULL, NULL, NULL, NULL);
command = args_string(args, 0);
if (command == NULL) {
for (entryp = cmd_table; *entryp != NULL; entryp++)
cmd_list_single_command(*entryp, ft, template, item);
} else {
entry = cmd_find(command, &cause);
if (entry != NULL)
cmd_list_single_command(entry, ft, template, item);
else {
cmdq_error(item, "%s", cause);
free(cause);
format_free(ft);
return (CMD_RETURN_ERROR);
}
}
format_free(ft);
return (CMD_RETURN_NORMAL);
}

View File

@@ -27,122 +27,140 @@
* List key bindings. * List key bindings.
*/ */
static enum cmd_retval cmd_list_keys_exec(struct cmd *, struct cmdq_item *); #define LIST_KEYS_TEMPLATE \
"#{?notes_only," \
"#{key_prefix} " \
"#{p|#{key_string_width}:key_string} " \
"#{?key_note,#{key_note},#{key_command}}" \
"," \
"bind-key #{?key_has_repeat,#{?key_repeat,-r, },} " \
"-T #{p|#{key_table_width}:key_table} " \
"#{p|#{key_string_width}:key_string} " \
"#{key_command}}"
static enum cmd_retval cmd_list_keys_commands(struct cmd *, static enum cmd_retval cmd_list_keys_exec(struct cmd *, struct cmdq_item *);
struct cmdq_item *);
const struct cmd_entry cmd_list_keys_entry = { const struct cmd_entry cmd_list_keys_entry = {
.name = "list-keys", .name = "list-keys",
.alias = "lsk", .alias = "lsk",
.args = { "1aNP:T:", 0, 1, NULL }, .args = { "1aF:NO:P:rT:", 0, 1, NULL },
.usage = "[-1aN] [-P prefix-string] [-T key-table] [key]", .usage = "[-1aNr] [-F format] [-O order] [-P prefix-string]"
"[-T key-table] [key]",
.flags = CMD_STARTSERVER|CMD_AFTERHOOK, .flags = CMD_STARTSERVER|CMD_AFTERHOOK,
.exec = cmd_list_keys_exec .exec = cmd_list_keys_exec
}; };
const struct cmd_entry cmd_list_commands_entry = { static char *
.name = "list-commands", cmd_list_keys_get_prefix(struct args *args)
.alias = "lscm", {
key_code prefix;
.args = { "F:", 0, 1, NULL }, if (args_has(args, 'P'))
.usage = "[-F format] [command]", return (xstrdup(args_get(args, 'P')));
.flags = CMD_STARTSERVER|CMD_AFTERHOOK, prefix = options_get_number(global_s_options, "prefix");
.exec = cmd_list_keys_exec if (prefix == KEYC_NONE)
}; return (xstrdup(""));
return (xstrdup(key_string_lookup_key(prefix, 0)));
}
static u_int static u_int
cmd_list_keys_get_width(const char *tablename, key_code only) cmd_list_keys_get_width(struct key_binding **l, u_int n)
{ {
struct key_table *table; u_int i, width, keywidth = 0;
struct key_binding *bd;
u_int width, keywidth = 0;
table = key_bindings_get_table(tablename, 0); for (i = 0; i < n; i++) {
if (table == NULL) width = utf8_cstrwidth(key_string_lookup_key(l[i]->key, 0));
return (0);
bd = key_bindings_first(table);
while (bd != NULL) {
if ((only != KEYC_UNKNOWN && bd->key != only) ||
KEYC_IS_MOUSE(bd->key) ||
bd->note == NULL ||
*bd->note == '\0') {
bd = key_bindings_next(table, bd);
continue;
}
width = utf8_cstrwidth(key_string_lookup_key(bd->key, 0));
if (width > keywidth) if (width > keywidth)
keywidth = width; keywidth = width;
bd = key_bindings_next(table, bd);
} }
return (keywidth); return (keywidth);
} }
static int static u_int
cmd_list_keys_print_notes(struct cmdq_item *item, struct args *args, cmd_list_keys_get_table_width(struct key_binding **l, u_int n)
const char *tablename, u_int keywidth, key_code only, const char *prefix)
{ {
struct client *tc = cmdq_get_target_client(item); u_int i, width, tablewidth = 0;
struct key_table *table;
struct key_binding *bd;
const char *key;
char *tmp, *note;
int found = 0;
table = key_bindings_get_table(tablename, 0); for (i = 0; i < n; i++) {
if (table == NULL) width = utf8_cstrwidth(l[i]->tablename);
return (0); if (width > tablewidth)
bd = key_bindings_first(table); tablewidth = width;
while (bd != NULL) {
if ((only != KEYC_UNKNOWN && bd->key != only) ||
KEYC_IS_MOUSE(bd->key) ||
((bd->note == NULL || *bd->note == '\0') &&
!args_has(args, 'a'))) {
bd = key_bindings_next(table, bd);
continue;
} }
found = 1; return (tablewidth);
key = key_string_lookup_key(bd->key, 0);
if (bd->note == NULL || *bd->note == '\0')
note = cmd_list_print(bd->cmdlist,
CMD_LIST_PRINT_ESCAPED|CMD_LIST_PRINT_NO_GROUPS);
else
note = xstrdup(bd->note);
tmp = utf8_padcstr(key, keywidth + 1);
if (args_has(args, '1') && tc != NULL) {
status_message_set(tc, -1, 1, 0, 0, "%s%s%s", prefix,
tmp, note);
} else
cmdq_print(item, "%s%s%s", prefix, tmp, note);
free(tmp);
free(note);
if (args_has(args, '1'))
break;
bd = key_bindings_next(table, bd);
}
return (found);
} }
static char * static struct key_binding **
cmd_list_keys_get_prefix(struct args *args, key_code *prefix) cmd_get_root_and_prefix(u_int *n, struct sort_criteria *sort_crit)
{ {
char *s; const char *tables[] = { "prefix", "root" };
struct key_table *t;
struct key_binding **lt;
u_int i, ltsz, len = 0, offset = 0;
static struct key_binding **l = NULL;
static u_int lsz = 0;
*prefix = options_get_number(global_s_options, "prefix"); for (i = 0; i < nitems(tables); i++) {
if (!args_has(args, 'P')) { t = key_bindings_get_table(tables[i], 0);
if (*prefix != KEYC_NONE) lt = sort_get_key_bindings_table(t, &ltsz, sort_crit);
xasprintf(&s, "%s ", key_string_lookup_key(*prefix, 0)); len += ltsz;
if (lsz <= len) {
lsz = len + 100;
l = xreallocarray(l, lsz, sizeof *l);
}
memcpy(l + offset, lt, ltsz * sizeof *l);
offset += ltsz;
}
*n = len;
return (l);
}
static void
cmd_filter_key_list(int filter_notes, int filter_key, key_code only,
struct key_binding **l, u_int *n)
{
key_code key;
u_int i, j = 0;
for (i = 0; i < *n; i++) {
key = l[i]->key & (KEYC_MASK_KEY|KEYC_MASK_MODIFIERS);
if (filter_key && only != key)
continue;
if (filter_notes && l[i]->note == NULL)
continue;
l[j++] = l[i];
}
*n = j;
}
static void
cmd_format_add_key_binding(struct format_tree *ft,
const struct key_binding *bd, const char *prefix)
{
const char *s;
if (bd->flags & KEY_BINDING_REPEAT)
format_add(ft, "key_repeat", "1");
else else
s = xstrdup(""); format_add(ft, "key_repeat", "0");
} else
s = xstrdup(args_get(args, 'P')); if (bd->note != NULL)
return (s); format_add(ft, "key_note", "%s", bd->note);
else
format_add(ft, "key_note", "%s", "");
format_add(ft, "key_prefix", "%s", prefix);
format_add(ft, "key_table", "%s", bd->tablename);
s = key_string_lookup_key(bd->key, 0);
format_add(ft, "key_string", "%s", s);
s = cmd_list_print(bd->cmdlist,
CMD_LIST_PRINT_ESCAPED|CMD_LIST_PRINT_NO_GROUPS);
format_add(ft, "key_command", "%s", s);
} }
static enum cmd_retval static enum cmd_retval
@@ -150,16 +168,16 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = cmd_get_args(self);
struct client *tc = cmdq_get_target_client(item); struct client *tc = cmdq_get_target_client(item);
struct key_table *table; struct format_tree *ft;
struct key_binding *bd; struct key_table *table = NULL;
const char *tablename, *r, *keystr; struct key_binding **l;
char *key, *cp, *tmp, *start, *empty; key_code only = KEYC_UNKNOWN;
key_code prefix, only = KEYC_UNKNOWN; const char *template, *tablename, *keystr;
int repeat, width, tablewidth, keywidth, found = 0; char *line;
size_t tmpsize, tmpused, cplen; char *prefix = NULL;
u_int i, n;
if (cmd_get_entry(self) == &cmd_list_commands_entry) int single, notes_only, filter_notes, filter_key;
return (cmd_list_keys_commands(self, item)); struct sort_criteria sort_crit;
if ((keystr = args_string(args, 0)) != NULL) { if ((keystr = args_string(args, 0)) != NULL) {
only = key_string_lookup_string(keystr); only = key_string_lookup_string(keystr);
@@ -170,219 +188,60 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
only &= (KEYC_MASK_KEY|KEYC_MASK_MODIFIERS); only &= (KEYC_MASK_KEY|KEYC_MASK_MODIFIERS);
} }
tablename = args_get(args, 'T'); sort_crit.order = sort_order_from_string(args_get(args, 'O'));
if (tablename != NULL && key_bindings_get_table(tablename, 0) == NULL) { sort_crit.reversed = args_has(args, 'r');
prefix = cmd_list_keys_get_prefix(args);
single = args_has(args, '1');
notes_only = args_has(args, 'N');
if ((tablename = args_get(args, 'T')) != NULL) {
table = key_bindings_get_table(tablename, 0);
if (table == NULL) {
cmdq_error(item, "table %s doesn't exist", tablename); cmdq_error(item, "table %s doesn't exist", tablename);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (args_has(args, 'N')) {
if (tablename == NULL) {
start = cmd_list_keys_get_prefix(args, &prefix);
keywidth = cmd_list_keys_get_width("root", only);
if (prefix != KEYC_NONE) {
width = cmd_list_keys_get_width("prefix", only);
if (width == 0)
prefix = KEYC_NONE;
else if (width > keywidth)
keywidth = width;
} }
empty = utf8_padcstr("", utf8_cstrwidth(start));
found = cmd_list_keys_print_notes(item, args, "root", if ((template = args_get(args, 'F')) == NULL)
keywidth, only, empty); template = LIST_KEYS_TEMPLATE;
if (prefix != KEYC_NONE) {
if (cmd_list_keys_print_notes(item, args, if (table)
"prefix", keywidth, only, start)) l = sort_get_key_bindings_table(table, &n, &sort_crit);
found = 1; else if (notes_only)
} l = cmd_get_root_and_prefix(&n, &sort_crit);
free(empty);
} else {
if (args_has(args, 'P'))
start = xstrdup(args_get(args, 'P'));
else else
start = xstrdup(""); l = sort_get_key_bindings(&n, &sort_crit);
keywidth = cmd_list_keys_get_width(tablename, only);
found = cmd_list_keys_print_notes(item, args, tablename,
keywidth, only, start);
} filter_notes = notes_only && !args_has(args, 'a');
free(start); filter_key = only != KEYC_UNKNOWN;
goto out; if (filter_notes || filter_key)
} cmd_filter_key_list(filter_notes, filter_key, only, l, &n);
if (single)
repeat = 0; n = 1;
tablewidth = keywidth = 0;
table = key_bindings_first_table();
while (table != NULL) {
if (tablename != NULL && strcmp(table->name, tablename) != 0) {
table = key_bindings_next_table(table);
continue;
}
bd = key_bindings_first(table);
while (bd != NULL) {
if (only != KEYC_UNKNOWN && bd->key != only) {
bd = key_bindings_next(table, bd);
continue;
}
key = args_escape(key_string_lookup_key(bd->key, 0));
if (bd->flags & KEY_BINDING_REPEAT)
repeat = 1;
width = utf8_cstrwidth(table->name);
if (width > tablewidth)
tablewidth = width;
width = utf8_cstrwidth(key);
if (width > keywidth)
keywidth = width;
free(key);
bd = key_bindings_next(table, bd);
}
table = key_bindings_next_table(table);
}
tmpsize = 256;
tmp = xmalloc(tmpsize);
table = key_bindings_first_table();
while (table != NULL) {
if (tablename != NULL && strcmp(table->name, tablename) != 0) {
table = key_bindings_next_table(table);
continue;
}
bd = key_bindings_first(table);
while (bd != NULL) {
if (only != KEYC_UNKNOWN && bd->key != only) {
bd = key_bindings_next(table, bd);
continue;
}
found = 1;
key = args_escape(key_string_lookup_key(bd->key, 0));
if (!repeat)
r = "";
else if (bd->flags & KEY_BINDING_REPEAT)
r = "-r ";
else
r = " ";
tmpused = xsnprintf(tmp, tmpsize, "%s-T ", r);
cp = utf8_padcstr(table->name, tablewidth);
cplen = strlen(cp) + 1;
while (tmpused + cplen + 1 >= tmpsize) {
tmpsize *= 2;
tmp = xrealloc(tmp, tmpsize);
}
strlcat(tmp, cp, tmpsize);
tmpused = strlcat(tmp, " ", tmpsize);
free(cp);
cp = utf8_padcstr(key, keywidth);
cplen = strlen(cp) + 1;
while (tmpused + cplen + 1 >= tmpsize) {
tmpsize *= 2;
tmp = xrealloc(tmp, tmpsize);
}
strlcat(tmp, cp, tmpsize);
tmpused = strlcat(tmp, " ", tmpsize);
free(cp);
cp = cmd_list_print(bd->cmdlist,
CMD_LIST_PRINT_ESCAPED|CMD_LIST_PRINT_NO_GROUPS);
cplen = strlen(cp);
while (tmpused + cplen + 1 >= tmpsize) {
tmpsize *= 2;
tmp = xrealloc(tmp, tmpsize);
}
strlcat(tmp, cp, tmpsize);
free(cp);
if (args_has(args, '1') && tc != NULL) {
status_message_set(tc, -1, 1, 0, 0,
"bind-key %s", tmp);
} else
cmdq_print(item, "bind-key %s", tmp);
free(key);
if (args_has(args, '1'))
break;
bd = key_bindings_next(table, bd);
}
table = key_bindings_next_table(table);
}
free(tmp);
out:
if (only != KEYC_UNKNOWN && !found) {
cmdq_error(item, "unknown key: %s", args_string(args, 0));
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
}
static void
cmd_list_single_command(const struct cmd_entry *entry, struct format_tree *ft,
const char *template, struct cmdq_item *item)
{
const char *s;
char *line;
format_add(ft, "command_list_name", "%s", entry->name);
if (entry->alias != NULL)
s = entry->alias;
else
s = "";
format_add(ft, "command_list_alias", "%s", s);
if (entry->usage != NULL)
s = entry->usage;
else
s = "";
format_add(ft, "command_list_usage", "%s", s);
line = format_expand(ft, template);
if (*line != '\0')
cmdq_print(item, "%s", line);
free(line);
}
static enum cmd_retval
cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
const struct cmd_entry **entryp;
const struct cmd_entry *entry;
struct format_tree *ft;
const char *template, *command;
char *cause;
if ((template = args_get(args, 'F')) == NULL) {
template = "#{command_list_name}"
"#{?command_list_alias, (#{command_list_alias}),} "
"#{command_list_usage}";
}
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0); ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
format_defaults(ft, NULL, NULL, NULL, NULL); format_defaults(ft, NULL, NULL, NULL, NULL);
format_add(ft, "notes_only", "%d", notes_only);
format_add(ft, "key_has_repeat", "%d", key_bindings_has_repeat(l, n));
format_add(ft, "key_string_width", "%u", cmd_list_keys_get_width(l, n));
format_add(ft, "key_table_width", "%u",
cmd_list_keys_get_table_width(l, n));
for (i = 0; i < n; i++) {
cmd_format_add_key_binding(ft, l[i], prefix);
command = args_string(args, 0); line = format_expand(ft, template);
if (command == NULL) { if ((single && tc != NULL) || n == 1)
for (entryp = cmd_table; *entryp != NULL; entryp++) status_message_set(tc, -1, 1, 0, 0, "%s", line);
cmd_list_single_command(*entryp, ft, template, item); else if (*line != '\0')
} else { cmdq_print(item, "%s", line);
entry = cmd_find(command, &cause); free(line);
if (entry != NULL)
cmd_list_single_command(entry, ft, template, item);
else {
cmdq_error(item, "%s", cause);
free(cause);
format_free(ft);
return (CMD_RETURN_ERROR);
}
}
if (single)
break;
}
format_free(ft); format_free(ft);
free(prefix);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -215,6 +215,7 @@ key_bindings_add(const char *name, key_code key, const char *note, int repeat,
bd = xcalloc(1, sizeof *bd); bd = xcalloc(1, sizeof *bd);
bd->key = (key & ~KEYC_MASK_FLAGS); bd->key = (key & ~KEYC_MASK_FLAGS);
bd->tablename = table->name;
if (note != NULL) if (note != NULL)
bd->note = xstrdup(note); bd->note = xstrdup(note);
RB_INSERT(key_bindings, &table->key_bindings, bd); RB_INSERT(key_bindings, &table->key_bindings, bd);
@@ -702,3 +703,15 @@ key_bindings_dispatch(struct key_binding *bd, struct cmdq_item *item,
new_item = cmdq_append(c, new_item); new_item = cmdq_append(c, new_item);
return (new_item); return (new_item);
} }
int
key_bindings_has_repeat(struct key_binding **l, u_int n)
{
u_int i;
for (i = 0; i < n; i++) {
if (l[i]->flags & KEY_BINDING_REPEAT)
return (1);
}
return (0);
}

101
sort.c
View File

@@ -72,6 +72,7 @@ sort_buffer_cmp(const void *a0, const void *b0)
break; break;
case SORT_ACTIVITY: case SORT_ACTIVITY:
case SORT_INDEX: case SORT_INDEX:
case SORT_MODIFIER:
case SORT_ORDER: case SORT_ORDER:
case SORT_END: case SORT_END:
break; break;
@@ -117,6 +118,7 @@ sort_client_cmp(const void *a0, const void *b0)
result = 1; result = 1;
break; break;
case SORT_INDEX: case SORT_INDEX:
case SORT_MODIFIER:
case SORT_ORDER: case SORT_ORDER:
case SORT_END: case SORT_END:
break; break;
@@ -167,6 +169,7 @@ sort_session_cmp(const void *a0, const void *b0)
case SORT_NAME: case SORT_NAME:
result = strcmp(sa->name, sb->name); result = strcmp(sa->name, sb->name);
break; break;
case SORT_MODIFIER:
case SORT_ORDER: case SORT_ORDER:
case SORT_SIZE: case SORT_SIZE:
case SORT_END: case SORT_END:
@@ -208,6 +211,7 @@ sort_pane_cmp(const void *a0, const void *b0)
case SORT_NAME: case SORT_NAME:
result = strcmp(a->screen->title, b->screen->title); result = strcmp(a->screen->title, b->screen->title);
break; break;
case SORT_MODIFIER:
case SORT_ORDER: case SORT_ORDER:
case SORT_END: case SORT_END:
break; break;
@@ -263,6 +267,7 @@ sort_winlink_cmp(const void *a0, const void *b0)
case SORT_SIZE: case SORT_SIZE:
result = wa->sx * wa->sy - wb->sx * wb->sy; result = wa->sx * wa->sy - wb->sx * wb->sy;
break; break;
case SORT_MODIFIER:
case SORT_ORDER: case SORT_ORDER:
case SORT_END: case SORT_END:
break; break;
@@ -276,6 +281,41 @@ sort_winlink_cmp(const void *a0, const void *b0)
return (result); return (result);
} }
static int
sort_key_binding_cmp(const void *a0, const void *b0)
{
struct sort_criteria *sort_crit = sort_criteria;
const struct key_binding *a = *(struct key_binding **)a0;
const struct key_binding *b = *(struct key_binding **)b0;
int result = 0;
switch (sort_crit->order) {
case SORT_INDEX:
result = a->key - b->key;
break;
case SORT_MODIFIER:
result = (a->key & KEYC_MASK_MODIFIERS) -
(b->key & KEYC_MASK_MODIFIERS);
break;
case SORT_NAME:
result = strcasecmp(a->tablename, b->tablename) == 0;
break;
case SORT_ACTIVITY:
case SORT_CREATION:
case SORT_ORDER:
case SORT_SIZE:
case SORT_END:
break;
}
if (result == 0)
result = strcasecmp(a->tablename, b->tablename) == 0;
if (sort_crit->reversed)
result = -result;
return (result);
}
void void
sort_next_order(struct sort_criteria *sort_crit) sort_next_order(struct sort_criteria *sort_crit)
{ {
@@ -306,8 +346,11 @@ sort_order_from_string(const char* order)
return (SORT_ACTIVITY); return (SORT_ACTIVITY);
if (strcasecmp(order, "creation") == 0) if (strcasecmp(order, "creation") == 0)
return (SORT_CREATION); return (SORT_CREATION);
if (strcasecmp(order, "index") == 0) if (strcasecmp(order, "index") == 0 ||
strcasecmp(order, "key") == 0)
return (SORT_INDEX); return (SORT_INDEX);
if (strcasecmp(order, "modifier") == 0)
return (SORT_MODIFIER);
if (strcasecmp(order, "name") == 0 || if (strcasecmp(order, "name") == 0 ||
strcasecmp(order, "title") == 0) strcasecmp(order, "title") == 0)
return (SORT_NAME); return (SORT_NAME);
@@ -328,6 +371,8 @@ sort_order_to_string(enum sort_order order)
return "creation"; return "creation";
if (order == SORT_INDEX) if (order == SORT_INDEX)
return "index"; return "index";
if (order == SORT_MODIFIER)
return "modifier";
if (order == SORT_NAME) if (order == SORT_NAME)
return "name"; return "name";
if (order == SORT_ORDER) if (order == SORT_ORDER)
@@ -548,3 +593,57 @@ sort_get_winlinks_session(struct session *s, u_int *n,
return (l); return (l);
} }
struct key_binding **
sort_get_key_bindings(u_int *n, struct sort_criteria *sort_crit)
{
struct key_table *table;
struct key_binding *bd;
u_int i = 0;
static struct key_binding **l = NULL;
static u_int lsz = 0;
table = key_bindings_first_table();
while (table != NULL) {
bd = key_bindings_first(table);
while (bd != NULL) {
if (lsz <= i) {
lsz += 100;
l = xreallocarray(l, lsz, sizeof *l);
}
l[i++] = bd;
bd = key_bindings_next(table, bd);
}
table = key_bindings_next_table(table);
}
sort_qsort(l, i, sizeof *l, sort_key_binding_cmp, sort_crit);
*n = i;
return (l);
}
struct key_binding **
sort_get_key_bindings_table(struct key_table *table, u_int *n,
struct sort_criteria *sort_crit)
{
struct key_binding *bd;
u_int i = 0;
static struct key_binding **l = NULL;
static u_int lsz = 0;
bd = key_bindings_first(table);
while (bd != NULL) {
if (lsz <= i) {
lsz += 100;
l = xreallocarray(l, lsz, sizeof *l);
}
l[i++] = bd;
bd = key_bindings_next(table, bd);
}
sort_qsort(l, i, sizeof *l, sort_key_binding_cmp, sort_crit);
*n = i;
return (l);
}

58
tmux.1
View File

@@ -2245,6 +2245,18 @@ Same as
.Ic scroll-down .Ic scroll-down
but also exit copy mode if the cursor reaches the bottom. but also exit copy mode if the cursor reaches the bottom.
.It Xo .It Xo
.It Xo
.Ic scroll-exit-on
.Xc
Turn on exiting copy mode when scrolling to the end of the buffer.
.It Xo
.Ic scroll-exit-off
.Xc
Turn off exiting copy mode when scrolling to the end of the buffer.
.It Xo
.Ic scroll-exit-toggle
.Xc
Toggle exiting copy mode when scrolling to the end of the buffer.
.Ic scroll-middle .Ic scroll-middle
(vi: z) (vi: z)
.Xc .Xc
@@ -3825,24 +3837,45 @@ To view the default bindings and possible commands, see the
command. command.
.Tg lsk .Tg lsk
.It Xo Ic list-keys .It Xo Ic list-keys
.Op Fl 1aN .Op Fl 1aNr
.Op Fl F Ar format
.Op Fl O Ar sort-order
.Op Fl P Ar prefix-string .Op Fl P Ar prefix-string
.Op Fl T Ar key-table .Op Fl T Ar key-table
.Op Ar key .Op Ar key
.Xc .Xc
.D1 Pq alias: Ic lsk .D1 Pq alias: Ic lsk
List key bindings. List key bindings.
There are two forms: the default lists keys as .Fl F
specifies the format of each line.
See the
.Sx FORMATS
section.
.Fl T
specifies a
.Ar key-table
to list from.
.Fl 1
lists only the first matching key.
.Fl O
specifies the sort order: one of
.Ql key ,
.Ql modifier ,
.Ql name
(table name).
.Fl r
reverses the sort order.
.Pp
If no
.Ar format
is given, there are two forms: the default lists keys as
.Ic bind-key .Ic bind-key
commands; commands;
.Fl N .Fl N
lists only keys with attached notes and shows only the key and note for each lists only keys with attached notes and shows only the key and note for each
key. key.
.Pp .Pp
With the default form, all key tables are listed by default. With the default form, all key tables are listed unless specified otherwise.
.Fl T
lists only keys in
.Ar key-table .
.Pp .Pp
With the With the
.Fl N .Fl N
@@ -3855,9 +3888,7 @@ key tables are listed by default;
also lists only keys in also lists only keys in
.Ar key-table . .Ar key-table .
.Fl P .Fl P
specifies a prefix to print before each key and specifies a prefix to print before each key.
.Fl 1
lists only the first matching key.
.Fl a .Fl a
lists the command for keys that do not have a note rather than skipping them. lists the command for keys that do not have a note rather than skipping them.
.Tg send .Tg send
@@ -6234,6 +6265,15 @@ The following variables are available, where appropriate:
.It Li "host" Ta "#H" Ta "Hostname of local host" .It Li "host" Ta "#H" Ta "Hostname of local host"
.It Li "host_short" Ta "#h" Ta "Hostname of local host (no domain name)" .It Li "host_short" Ta "#h" Ta "Hostname of local host (no domain name)"
.It Li "insert_flag" Ta "" Ta "Pane insert flag" .It Li "insert_flag" Ta "" Ta "Pane insert flag"
.It Li "key_string" Ta "" Ta "String representation of the key binding"
.It Li "key_repeat" Ta "" Ta "1 if key binding is repeatable"
.It Li "key_note" Ta "" Ta "Note of the key binding"
.It Li "key_prefix" Ta "" Ta "Global key prefix"
.It Li "key_table" Ta "" Ta "Table name of the key binding"
.It Li "key_command" Ta "" Ta "Command of the key binding"
.It Li "key_has_repeat" Ta "" Ta "1 if list contain a repeatable key"
.It Li "key_string_width" Ta "" Ta "Maximum key_string width in list"
.It Li "key_table_width" Ta "" Ta "Maximum key_table width in list"
.It Li "keypad_cursor_flag" Ta "" Ta "Pane keypad cursor flag" .It Li "keypad_cursor_flag" Ta "" Ta "Pane keypad cursor flag"
.It Li "keypad_flag" Ta "" Ta "Pane keypad flag" .It Li "keypad_flag" Ta "" Ta "Pane keypad flag"
.It Li "last_window_index" Ta "" Ta "Index of last window in session" .It Li "last_window_index" Ta "" Ta "Index of last window in session"

7
tmux.h
View File

@@ -2111,6 +2111,7 @@ struct key_binding {
key_code key; key_code key;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
const char *note; const char *note;
const char *tablename;
int flags; int flags;
#define KEY_BINDING_REPEAT 0x1 #define KEY_BINDING_REPEAT 0x1
@@ -2249,6 +2250,7 @@ enum sort_order {
SORT_ACTIVITY, SORT_ACTIVITY,
SORT_CREATION, SORT_CREATION,
SORT_INDEX, SORT_INDEX,
SORT_MODIFIER,
SORT_NAME, SORT_NAME,
SORT_ORDER, SORT_ORDER,
SORT_SIZE, SORT_SIZE,
@@ -2347,6 +2349,10 @@ struct window_pane **sort_get_panes_window(struct window *, u_int *,
struct winlink **sort_get_winlinks(u_int *, struct sort_criteria *); struct winlink **sort_get_winlinks(u_int *, struct sort_criteria *);
struct winlink **sort_get_winlinks_session(struct session *, u_int *, struct winlink **sort_get_winlinks_session(struct session *, u_int *,
struct sort_criteria *); struct sort_criteria *);
struct key_binding **sort_get_key_bindings(u_int *,
struct sort_criteria *);
struct key_binding **sort_get_key_bindings_table(struct key_table *,
u_int *, struct sort_criteria *);
/* format.c */ /* format.c */
#define FORMAT_STATUS 0x1 #define FORMAT_STATUS 0x1
@@ -2849,6 +2855,7 @@ void key_bindings_reset(const char *, key_code);
void key_bindings_remove_table(const char *); void key_bindings_remove_table(const char *);
void key_bindings_reset_table(const char *); void key_bindings_reset_table(const char *);
void key_bindings_init(void); void key_bindings_init(void);
int key_bindings_has_repeat(struct key_binding **, u_int);
struct cmdq_item *key_bindings_dispatch(struct key_binding *, struct cmdq_item *key_bindings_dispatch(struct key_binding *,
struct cmdq_item *, struct client *, struct key_event *, struct cmdq_item *, struct client *, struct key_event *,
struct cmd_find_state *); struct cmd_find_state *);