Add a customize mode where keys and options may be browsed and changed,

includes adding a brief description of each option. Bound to "C" by
default.
This commit is contained in:
nicm 2020-05-16 16:02:24 +00:00
parent 472d77fd0f
commit d67245c734
22 changed files with 2284 additions and 363 deletions

View File

@ -120,6 +120,7 @@ SRCS= alerts.c \
window-client.c \
window-clock.c \
window-copy.c \
window-customize.c \
window-tree.c \
window.c \
xmalloc.c \

View File

@ -68,6 +68,19 @@ const struct cmd_entry cmd_choose_buffer_entry = {
.exec = cmd_choose_tree_exec
};
const struct cmd_entry cmd_customize_mode_entry = {
.name = "customize-mode",
.alias = NULL,
.args = { "F:f:Nt:Z", 0, 0 },
.usage = "[-NZ] [-F format] [-f filter] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_choose_tree_exec
};
static enum cmd_retval
cmd_choose_tree_exec(struct cmd *self, struct cmdq_item *item)
{
@ -84,7 +97,9 @@ cmd_choose_tree_exec(struct cmd *self, struct cmdq_item *item)
if (server_client_how_many() == 0)
return (CMD_RETURN_NORMAL);
mode = &window_client_mode;
} else
} else if (cmd_get_entry(self) == &cmd_customize_mode_entry)
mode = &window_customize_mode;
else
mode = &window_tree_mode;
window_pane_set_mode(wp, NULL, mode, target, args);

View File

@ -68,7 +68,8 @@ cmd_list_keys_get_width(const char *tablename, key_code only)
while (bd != NULL) {
if ((only != KEYC_UNKNOWN && bd->key != only) ||
KEYC_IS_MOUSE(bd->key) ||
bd->note == NULL) {
bd->note == NULL ||
*bd->note == '\0') {
bd = key_bindings_next(table, bd);
continue;
}
@ -99,14 +100,15 @@ cmd_list_keys_print_notes(struct cmdq_item *item, struct args *args,
while (bd != NULL) {
if ((only != KEYC_UNKNOWN && bd->key != only) ||
KEYC_IS_MOUSE(bd->key) ||
(bd->note == NULL && !args_has(args, 'a'))) {
((bd->note == NULL || *bd->note == '\0') &&
!args_has(args, 'a'))) {
bd = key_bindings_next(table, bd);
continue;
}
found = 1;
key = key_string_lookup_key(bd->key);
if (bd->note == NULL)
if (bd->note == NULL || *bd->note == '\0')
note = cmd_list_print(bd->cmdlist, 1);
else
note = xstrdup(bd->note);

View File

@ -190,7 +190,8 @@ cmd_run_shell_callback(struct job *job)
retcode = WTERMSIG(status);
xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode);
retcode += 128;
}
} else
retcode = 0;
if (msg != NULL)
cmd_run_shell_print(job, msg);
free(msg);

View File

@ -30,15 +30,6 @@
static enum cmd_retval cmd_set_option_exec(struct cmd *, struct cmdq_item *);
static int cmd_set_option_set(struct cmd *, struct cmdq_item *,
struct options *, struct options_entry *, const char *);
static int cmd_set_option_flag(struct cmdq_item *,
const struct options_table_entry *, struct options *,
const char *);
static int cmd_set_option_choice(struct cmdq_item *,
const struct options_table_entry *, struct options *,
const char *);
const struct cmd_entry cmd_set_option_entry = {
.name = "set-option",
.alias = "set",
@ -84,10 +75,6 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
struct args *args = cmd_get_args(self);
int append = args_has(args, 'a');
struct cmd_find_state *target = cmdq_get_target(item);
struct client *loop;
struct session *s = target->s;
struct window *w;
struct window_pane *wp;
struct options *oo;
struct options_entry *parent, *o;
char *name, *argument, *value = NULL, *cause;
@ -138,7 +125,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
parent = options_get(oo, name);
/* Check that array options and indexes match up. */
if (idx != -1 && (*name == '@' || !options_isarray(parent))) {
if (idx != -1 && (*name == '@' || !options_is_array(parent))) {
cmdq_error(item, "not an array: %s", argument);
goto fail;
}
@ -185,10 +172,15 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
goto fail;
}
options_set_string(oo, name, append, "%s", value);
} else if (idx == -1 && !options_isarray(parent)) {
error = cmd_set_option_set(self, item, oo, parent, value);
if (error != 0)
} else if (idx == -1 && !options_is_array(parent)) {
error = options_from_string(oo, options_table_entry(parent),
options_table_entry(parent)->name, value,
args_has(args, 'a'), &cause);
if (error != 0) {
cmdq_error(item, "%s", cause);
free(cause);
goto fail;
}
} else {
if (value == NULL) {
cmdq_error(item, "empty value");
@ -212,51 +204,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
}
}
/* Update timers and so on for various options. */
if (strcmp(name, "automatic-rename") == 0) {
RB_FOREACH(w, windows, &windows) {
if (w->active == NULL)
continue;
if (options_get_number(w->options, "automatic-rename"))
w->active->flags |= PANE_CHANGED;
}
}
if (strcmp(name, "key-table") == 0) {
TAILQ_FOREACH(loop, &clients, entry)
server_client_set_key_table(loop, NULL);
}
if (strcmp(name, "user-keys") == 0) {
TAILQ_FOREACH(loop, &clients, entry) {
if (loop->tty.flags & TTY_OPENED)
tty_keys_build(&loop->tty);
}
}
if (strcmp(name, "status") == 0 ||
strcmp(name, "status-interval") == 0)
status_timer_start_all();
if (strcmp(name, "monitor-silence") == 0)
alerts_reset_all();
if (strcmp(name, "window-style") == 0 ||
strcmp(name, "window-active-style") == 0) {
RB_FOREACH(wp, window_pane_tree, &all_window_panes)
wp->flags |= PANE_STYLECHANGED;
}
if (strcmp(name, "pane-border-status") == 0) {
RB_FOREACH(w, windows, &windows)
layout_fix_panes(w);
}
RB_FOREACH(s, sessions, &sessions)
status_update_cache(s);
/*
* Update sizes and redraw. May not always be necessary but do it
* anyway.
*/
recalculate_sizes();
TAILQ_FOREACH(loop, &clients, entry) {
if (loop->session != NULL)
server_redraw_client(loop);
}
options_push_changes(name);
out:
free(argument);
@ -270,147 +218,3 @@ fail:
free(name);
return (CMD_RETURN_ERROR);
}
static int
cmd_set_option_check_string(const struct options_table_entry *oe,
const char *value, char **cause)
{
struct style sy;
if (strcmp(oe->name, "default-shell") == 0 && !checkshell(value)) {
xasprintf(cause, "not a suitable shell: %s", value);
return (-1);
}
if (oe->pattern != NULL && fnmatch(oe->pattern, value, 0) != 0) {
xasprintf(cause, "value is invalid: %s", value);
return (-1);
}
if ((oe->flags & OPTIONS_TABLE_IS_STYLE) &&
strstr(value, "#{") == NULL &&
style_parse(&sy, &grid_default_cell, value) != 0) {
xasprintf(cause, "invalid style: %s", value);
return (-1);
}
return (0);
}
static int
cmd_set_option_set(struct cmd *self, struct cmdq_item *item, struct options *oo,
struct options_entry *parent, const char *value)
{
const struct options_table_entry *oe;
struct args *args = cmd_get_args(self);
int append = args_has(args, 'a');
long long number;
const char *errstr, *new;
char *old, *cause;
key_code key;
oe = options_table_entry(parent);
if (value == NULL &&
oe->type != OPTIONS_TABLE_FLAG &&
oe->type != OPTIONS_TABLE_CHOICE) {
cmdq_error(item, "empty value");
return (-1);
}
switch (oe->type) {
case OPTIONS_TABLE_STRING:
old = xstrdup(options_get_string(oo, oe->name));
options_set_string(oo, oe->name, append, "%s", value);
new = options_get_string(oo, oe->name);
if (cmd_set_option_check_string(oe, new, &cause) != 0) {
cmdq_error(item, "%s", cause);
free(cause);
options_set_string(oo, oe->name, 0, "%s", old);
free(old);
return (-1);
}
free(old);
return (0);
case OPTIONS_TABLE_NUMBER:
number = strtonum(value, oe->minimum, oe->maximum, &errstr);
if (errstr != NULL) {
cmdq_error(item, "value is %s: %s", errstr, value);
return (-1);
}
options_set_number(oo, oe->name, number);
return (0);
case OPTIONS_TABLE_KEY:
key = key_string_lookup_string(value);
if (key == KEYC_UNKNOWN) {
cmdq_error(item, "bad key: %s", value);
return (-1);
}
options_set_number(oo, oe->name, key);
return (0);
case OPTIONS_TABLE_COLOUR:
if ((number = colour_fromstring(value)) == -1) {
cmdq_error(item, "bad colour: %s", value);
return (-1);
}
options_set_number(oo, oe->name, number);
return (0);
case OPTIONS_TABLE_FLAG:
return (cmd_set_option_flag(item, oe, oo, value));
case OPTIONS_TABLE_CHOICE:
return (cmd_set_option_choice(item, oe, oo, value));
case OPTIONS_TABLE_COMMAND:
break;
}
return (-1);
}
static int
cmd_set_option_flag(struct cmdq_item *item,
const struct options_table_entry *oe, struct options *oo,
const char *value)
{
int flag;
if (value == NULL || *value == '\0')
flag = !options_get_number(oo, oe->name);
else if (strcmp(value, "1") == 0 ||
strcasecmp(value, "on") == 0 ||
strcasecmp(value, "yes") == 0)
flag = 1;
else if (strcmp(value, "0") == 0 ||
strcasecmp(value, "off") == 0 ||
strcasecmp(value, "no") == 0)
flag = 0;
else {
cmdq_error(item, "bad value: %s", value);
return (-1);
}
options_set_number(oo, oe->name, flag);
return (0);
}
static int
cmd_set_option_choice(struct cmdq_item *item,
const struct options_table_entry *oe, struct options *oo,
const char *value)
{
const char **cp;
int n, choice = -1;
if (value == NULL) {
choice = options_get_number(oo, oe->name);
if (choice < 2)
choice = !choice;
} else {
n = 0;
for (cp = oe->choices; *cp != NULL; cp++) {
if (strcmp(*cp, value) == 0)
choice = n;
n++;
}
if (choice == -1) {
cmdq_error(item, "unknown value: %s", value);
return (-1);
}
}
options_set_number(oo, oe->name, choice);
return (0);
}

View File

@ -18,6 +18,7 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
@ -29,6 +30,9 @@
* Show client message log.
*/
#define SHOW_MESSAGES_TEMPLATE \
"#{t/p:message_time}: #{message_text}"
static enum cmd_retval cmd_show_messages_exec(struct cmd *,
struct cmdq_item *);

View File

@ -151,7 +151,7 @@ cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
xasprintf(&tmp, "%s[%d]", name, idx);
name = tmp;
} else {
if (options_isarray(o)) {
if (options_is_array(o)) {
a = options_array_first(o);
if (a == NULL) {
if (!args_has(args, 'v'))
@ -168,10 +168,10 @@ cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
}
}
value = options_tostring(o, idx, 0);
value = options_to_string(o, idx, 0);
if (args_has(args, 'v'))
cmdq_print(item, "%s", value);
else if (options_isstring(o)) {
else if (options_is_string(o)) {
escaped = args_escape(value);
if (parent)
cmdq_print(item, "%s* %s", name, escaped);
@ -229,7 +229,7 @@ cmd_show_options_all(struct cmd *self, struct cmdq_item *item, int scope,
} else
parent = 0;
if (!options_isarray(o))
if (!options_is_array(o))
cmd_show_options_print(self, item, o, -1, parent);
else if ((a = options_array_first(o)) == NULL) {
if (!args_has(args, 'v')) {

2
cmd.c
View File

@ -40,6 +40,7 @@ extern const struct cmd_entry cmd_clock_mode_entry;
extern const struct cmd_entry cmd_command_prompt_entry;
extern const struct cmd_entry cmd_confirm_before_entry;
extern const struct cmd_entry cmd_copy_mode_entry;
extern const struct cmd_entry cmd_customize_mode_entry;
extern const struct cmd_entry cmd_delete_buffer_entry;
extern const struct cmd_entry cmd_detach_client_entry;
extern const struct cmd_entry cmd_display_menu_entry;
@ -130,6 +131,7 @@ const struct cmd_entry *cmd_table[] = {
&cmd_command_prompt_entry,
&cmd_confirm_before_entry,
&cmd_copy_mode_entry,
&cmd_customize_mode_entry,
&cmd_delete_buffer_entry,
&cmd_detach_client_entry,
&cmd_display_menu_entry,

View File

@ -547,7 +547,7 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
*/
cp = expanded;
while (*cp != '\0') {
if (cp[0] != '#' || cp[1] != '[') {
if (cp[0] != '#' || cp[1] != '[' || sy.ignore) {
/* See if this is a UTF-8 character. */
if ((more = utf8_open(ud, *cp)) == UTF8_MORE) {
while (*++cp != '\0' && more == UTF8_MORE)

View File

@ -1392,7 +1392,7 @@ format_find(struct format_tree *ft, const char *key, int modifiers,
if (o == NULL)
o = options_parse_get(global_s_options, key, &idx, 0);
if (o != NULL) {
found = options_tostring(o, idx, 1);
found = options_to_string(o, idx, 1);
goto found;
}

View File

@ -89,9 +89,8 @@ key_bindings_cmp(struct key_binding *bd1, struct key_binding *bd2)
}
static void
key_bindings_free(struct key_table *table, struct key_binding *bd)
key_bindings_free(struct key_binding *bd)
{
RB_REMOVE(key_bindings, &table->key_bindings, bd);
cmd_list_free(bd->cmdlist);
free((void *)bd->note);
free(bd);
@ -110,6 +109,7 @@ key_bindings_get_table(const char *name, int create)
table = xmalloc(sizeof *table);
table->name = xstrdup(name);
RB_INIT(&table->key_bindings);
RB_INIT(&table->default_key_bindings);
table->references = 1; /* one reference in key_tables */
RB_INSERT(key_tables, &key_tables, table);
@ -138,8 +138,14 @@ key_bindings_unref_table(struct key_table *table)
if (--table->references != 0)
return;
RB_FOREACH_SAFE(bd, key_bindings, &table->key_bindings, bd1)
key_bindings_free(table, bd);
RB_FOREACH_SAFE(bd, key_bindings, &table->key_bindings, bd1) {
RB_REMOVE(key_bindings, &table->key_bindings, bd);
key_bindings_free(bd);
}
RB_FOREACH_SAFE(bd, key_bindings, &table->default_key_bindings, bd1) {
RB_REMOVE(key_bindings, &table->default_key_bindings, bd);
key_bindings_free(bd);
}
free((void *)table->name);
free(table);
@ -154,6 +160,15 @@ key_bindings_get(struct key_table *table, key_code key)
return (RB_FIND(key_bindings, &table->key_bindings, &bd));
}
struct key_binding *
key_bindings_get_default(struct key_table *table, key_code key)
{
struct key_binding bd;
bd.key = key;
return (RB_FIND(key_bindings, &table->default_key_bindings, &bd));
}
struct key_binding *
key_bindings_first(struct key_table *table)
{
@ -176,8 +191,10 @@ key_bindings_add(const char *name, key_code key, const char *note, int repeat,
table = key_bindings_get_table(name, 1);
bd = key_bindings_get(table, key & ~KEYC_XTERM);
if (bd != NULL)
key_bindings_free(table, bd);
if (bd != NULL) {
RB_REMOVE(key_bindings, &table->key_bindings, bd);
key_bindings_free(bd);
}
bd = xcalloc(1, sizeof *bd);
bd->key = key;
@ -203,9 +220,12 @@ key_bindings_remove(const char *name, key_code key)
bd = key_bindings_get(table, key & ~KEYC_XTERM);
if (bd == NULL)
return;
key_bindings_free(table, bd);
if (RB_EMPTY(&table->key_bindings)) {
RB_REMOVE(key_bindings, &table->key_bindings, bd);
key_bindings_free(bd);
if (RB_EMPTY(&table->key_bindings) &&
RB_EMPTY(&table->default_key_bindings)) {
RB_REMOVE(key_tables, &key_tables, table);
key_bindings_unref_table(table);
}
@ -228,6 +248,28 @@ key_bindings_remove_table(const char *name)
}
}
static enum cmd_retval
key_bindings_init_done(__unused struct cmdq_item *item, __unused void *data)
{
struct key_table *table;
struct key_binding *bd, *new_bd;
RB_FOREACH(table, key_tables, &key_tables) {
RB_FOREACH(bd, key_bindings, &table->key_bindings) {
new_bd = xcalloc(1, sizeof *bd);
new_bd->key = bd->key;
if (bd->note != NULL)
new_bd->note = xstrdup(bd->note);
new_bd->flags = bd->flags;
new_bd->cmdlist = bd->cmdlist;
new_bd->cmdlist->references++;
RB_INSERT(key_bindings, &table->default_key_bindings,
new_bd);
}
}
return (CMD_RETURN_NORMAL);
}
void
key_bindings_init(void)
{
@ -278,6 +320,7 @@ key_bindings_init(void)
"bind -N 'Toggle the marked pane' m select-pane -m",
"bind -N 'Select the next window' n next-window",
"bind -N 'Select the next pane' o select-pane -t:.+",
"bind -N 'Customize options' C customize-mode -Z",
"bind -N 'Select the previous pane' p previous-window",
"bind -N 'Display pane numbers' q display-panes",
"bind -N 'Redraw the current client' r refresh-client",
@ -524,6 +567,7 @@ key_bindings_init(void)
cmdq_append(NULL, cmdq_get_command(pr->cmdlist, NULL));
cmd_list_free(pr->cmdlist);
}
cmdq_append(NULL, cmdq_get_callback(key_bindings_init_done, NULL));
}
static enum cmd_retval

View File

@ -45,6 +45,7 @@ struct mode_tree_data {
mode_tree_draw_cb drawcb;
mode_tree_search_cb searchcb;
mode_tree_menu_cb menucb;
mode_tree_height_cb heightcb;
struct mode_tree_list children;
struct mode_tree_list saved;
@ -79,6 +80,7 @@ struct mode_tree_item {
int expanded;
int tagged;
int draw_as_parent;
struct mode_tree_list children;
TAILQ_ENTRY(mode_tree_item) entry;
@ -210,7 +212,7 @@ mode_tree_clear_tagged(struct mode_tree_list *mtl)
}
}
static void
void
mode_tree_up(struct mode_tree_data *mtd, int wrap)
{
if (mtd->current == 0) {
@ -247,6 +249,12 @@ mode_tree_get_current(struct mode_tree_data *mtd)
return (mtd->line_list[mtd->current].item->itemdata);
}
const char *
mode_tree_get_current_name(struct mode_tree_data *mtd)
{
return (mtd->line_list[mtd->current].item->name);
}
void
mode_tree_expand_current(struct mode_tree_data *mtd)
{
@ -256,6 +264,15 @@ mode_tree_expand_current(struct mode_tree_data *mtd)
}
}
void
mode_tree_collapse_current(struct mode_tree_data *mtd)
{
if (mtd->line_list[mtd->current].item->expanded) {
mtd->line_list[mtd->current].item->expanded = 0;
mode_tree_build(mtd);
}
}
static int
mode_tree_get_tag(struct mode_tree_data *mtd, uint64_t tag, u_int *found)
{
@ -343,7 +360,8 @@ mode_tree_each_tagged(struct mode_tree_data *mtd, mode_tree_each_cb cb,
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, void *modedata,
mode_tree_search_cb searchcb, mode_tree_menu_cb menucb,
mode_tree_height_cb heightcb, void *modedata,
const struct menu_item *menu, const char **sort_list, u_int sort_size,
struct screen **s)
{
@ -381,6 +399,7 @@ mode_tree_start(struct window_pane *wp, struct args *args,
mtd->drawcb = drawcb;
mtd->searchcb = searchcb;
mtd->menucb = menucb;
mtd->heightcb = heightcb;
TAILQ_INIT(&mtd->children);
@ -404,6 +423,27 @@ mode_tree_zoom(struct mode_tree_data *mtd, struct args *args)
mtd->zoomed = -1;
}
static void
mode_tree_set_height(struct mode_tree_data *mtd)
{
struct screen *s = &mtd->screen;
u_int height;
if (mtd->heightcb != NULL) {
height = mtd->heightcb(mtd, screen_size_y(s));
if (height < screen_size_y(s))
mtd->height = screen_size_y(s) - height;
} else {
mtd->height = (screen_size_y(s) / 3) * 2;
if (mtd->height > mtd->line_size)
mtd->height = screen_size_y(s) / 2;
}
if (mtd->height < 10)
mtd->height = screen_size_y(s);
if (screen_size_y(s) - mtd->height < 2)
mtd->height = screen_size_y(s);
}
void
mode_tree_build(struct mode_tree_data *mtd)
{
@ -434,15 +474,9 @@ mode_tree_build(struct mode_tree_data *mtd)
mode_tree_set_current(mtd, tag);
mtd->width = screen_size_x(s);
if (mtd->preview) {
mtd->height = (screen_size_y(s) / 3) * 2;
if (mtd->height > mtd->line_size)
mtd->height = screen_size_y(s) / 2;
if (mtd->height < 10)
mtd->height = screen_size_y(s);
if (screen_size_y(s) - mtd->height < 2)
mtd->height = screen_size_y(s);
} else
if (mtd->preview)
mode_tree_set_height(mtd);
else
mtd->height = screen_size_y(s);
mode_tree_check_selected(mtd);
}
@ -494,7 +528,7 @@ mode_tree_add(struct mode_tree_data *mtd, struct mode_tree_item *parent,
struct mode_tree_item *mti, *saved;
log_debug("%s: %llu, %s %s", __func__, (unsigned long long)tag,
name, text);
name, (text == NULL ? "" : text));
mti = xcalloc(1, sizeof *mti);
mti->parent = parent;
@ -502,7 +536,8 @@ mode_tree_add(struct mode_tree_data *mtd, struct mode_tree_item *parent,
mti->tag = tag;
mti->name = xstrdup(name);
mti->text = xstrdup(text);
if (text != NULL)
mti->text = xstrdup(text);
saved = mode_tree_find_item(&mtd->saved, tag);
if (saved != NULL) {
@ -524,6 +559,12 @@ mode_tree_add(struct mode_tree_data *mtd, struct mode_tree_item *parent,
return (mti);
}
void
mode_tree_draw_as_parent(struct mode_tree_item *mti)
{
mti->draw_as_parent = 1;
}
void
mode_tree_remove(struct mode_tree_data *mtd, struct mode_tree_item *mti)
{
@ -621,8 +662,8 @@ mode_tree_draw(struct mode_tree_data *mtd)
tag = "*";
else
tag = "";
xasprintf(&text, "%-*s%s%s%s: ", keylen, key, start, mti->name,
tag);
xasprintf(&text, "%-*s%s%s%s%s", keylen, key, start, mti->name,
tag, (mti->text != NULL) ? ": " : "" );
width = utf8_cstrwidth(text);
if (width > w)
width = w;
@ -636,11 +677,17 @@ mode_tree_draw(struct mode_tree_data *mtd)
if (i != mtd->current) {
screen_write_clearendofline(&ctx, 8);
screen_write_nputs(&ctx, w, &gc0, "%s", text);
format_draw(&ctx, &gc0, w - width, mti->text, NULL);
if (mti->text != NULL) {
format_draw(&ctx, &gc0, w - width, mti->text,
NULL);
}
} else {
screen_write_clearendofline(&ctx, gc.bg);
screen_write_nputs(&ctx, w, &gc, "%s", text);
format_draw(&ctx, &gc, w - width, mti->text, NULL);
if (mti->text != NULL) {
format_draw(&ctx, &gc, w - width, mti->text,
NULL);
}
}
free(text);
@ -658,13 +705,18 @@ mode_tree_draw(struct mode_tree_data *mtd)
line = &mtd->line_list[mtd->current];
mti = line->item;
if (mti->draw_as_parent)
mti = mti->parent;
screen_write_cursormove(&ctx, 0, h, 0);
screen_write_box(&ctx, w, sy - h);
xasprintf(&text, " %s (sort: %s%s)", mti->name,
mtd->sort_list[mtd->sort_crit.field],
mtd->sort_crit.reversed ? ", reversed" : "");
if (mtd->sort_list != NULL) {
xasprintf(&text, " %s (sort: %s%s)", mti->name,
mtd->sort_list[mtd->sort_crit.field],
mtd->sort_crit.reversed ? ", reversed" : "");
} else
xasprintf(&text, " %s", mti->name);
if (w - 2 >= strlen(text)) {
screen_write_cursormove(&ctx, 1, h, 0);
screen_write_puts(&ctx, &gc0, "%s", text);
@ -680,7 +732,8 @@ mode_tree_draw(struct mode_tree_data *mtd)
else
screen_write_puts(&ctx, &gc0, "active");
screen_write_puts(&ctx, &gc0, ") ");
}
} else
screen_write_puts(&ctx, &gc0, " ");
}
free(text);
@ -1027,7 +1080,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
break;
case 'O':
mtd->sort_crit.field++;
if (mtd->sort_crit.field == mtd->sort_size)
if (mtd->sort_crit.field >= mtd->sort_size)
mtd->sort_crit.field = 0;
mode_tree_build(mtd);
break;

View File

@ -103,9 +103,9 @@ static const char *options_table_window_size_list[] = {
"," \
"#[range=window|#{window_index} list=focus " \
"#{?#{!=:#{window-status-current-style},default}," \
"#{window-status-current-style}," \
"#{window-status-style}" \
"}" \
"#{window-status-current-style}," \
"#{window-status-style}" \
"}" \
"#{?#{&&:#{window_last_flag}," \
"#{!=:#{window-status-last-style},default}}, " \
"#{window-status-last-style}," \
@ -175,6 +175,7 @@ const struct options_table_entry options_table[] = {
.type = OPTIONS_TABLE_KEY,
.scope = OPTIONS_TABLE_SERVER,
.default_num = '\177',
.text = "The key to send for backspace."
},
{ .name = "buffer-limit",
@ -182,7 +183,9 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_SERVER,
.minimum = 1,
.maximum = INT_MAX,
.default_num = 50
.default_num = 50,
.text = "The maximum number of automatic buffers. "
"When this is reached, the oldest buffer is deleted."
},
{ .name = "command-alias",
@ -195,25 +198,31 @@ const struct options_table_entry options_table[] = {
"info=show-messages -JT,"
"choose-window=choose-tree -w,"
"choose-session=choose-tree -s",
.separator = ","
.separator = ",",
.text = "Array of command aliases. "
"Each entry is an alias and a command separated by '='."
},
{ .name = "copy-command",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.default_str = ""
.default_str = "",
.text = "Shell command run when text is copied. "
"If empty, no command is run."
},
{ .name = "default-terminal",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.default_str = "screen"
.default_str = "screen",
.text = "Default for the 'TERM' environment variable."
},
{ .name = "editor",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.default_str = _PATH_VI
.default_str = _PATH_VI,
.text = "Editor run to edit files."
},
{ .name = "escape-time",
@ -221,31 +230,38 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_SERVER,
.minimum = 0,
.maximum = INT_MAX,
.default_num = 500
.default_num = 500,
.text = "Time to wait before assuming a key is Escape."
},
{ .name = "exit-empty",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_SERVER,
.default_num = 1
.default_num = 1,
.text = "Whether the server should exit if there are no sessions."
},
{ .name = "exit-unattached",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_SERVER,
.default_num = 0
.default_num = 0,
.text = "Whether the server should exit if there are no attached "
"clients."
},
{ .name = "focus-events",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_SERVER,
.default_num = 0
.default_num = 0,
.text = "Whether to send focus events to applications."
},
{ .name = "history-file",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.default_str = ""
.default_str = "",
.text = "Location of the command prompt history file. "
"Empty does not write a history file."
},
{ .name = "message-limit",
@ -253,14 +269,18 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_SERVER,
.minimum = 0,
.maximum = INT_MAX,
.default_num = 1000
.default_num = 1000,
.text = "Maximum number of server messages to keep."
},
{ .name = "set-clipboard",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_SERVER,
.choices = options_table_set_clipboard_list,
.default_num = 1
.default_num = 1,
.text = "Whether to attempt to set the system clipboard ('on' or "
"'external') and whether to allow applications to create "
"paste buffers with an escape sequence ('on' only)."
},
{ .name = "terminal-overrides",
@ -268,7 +288,8 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_SERVER,
.flags = OPTIONS_TABLE_IS_ARRAY,
.default_str = "",
.separator = ","
.separator = ",",
.text = "List of terminal capabilities overrides."
},
{ .name = "terminal-features",
@ -276,8 +297,10 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_SERVER,
.flags = OPTIONS_TABLE_IS_ARRAY,
.default_str = "xterm*:clipboard:ccolour:cstyle:title,"
"screen*:title",
.separator = ","
"screen*:title",
.separator = ",",
.text = "List of terminal features, used if they cannot be "
"automatically detected."
},
{ .name = "user-keys",
@ -285,7 +308,10 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_SERVER,
.flags = OPTIONS_TABLE_IS_ARRAY,
.default_str = "",
.separator = ","
.separator = ",",
.text = "User key assignments. "
"Each sequence in the list is translated into a key: "
"'User0', 'User1' and so on."
},
/* Session options. */
@ -293,7 +319,8 @@ const struct options_table_entry options_table[] = {
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_SESSION,
.choices = options_table_bell_action_list,
.default_num = ALERT_OTHER
.default_num = ALERT_OTHER,
.text = "Action to take on an activity alert."
},
{ .name = "assume-paste-time",
@ -302,6 +329,9 @@ const struct options_table_entry options_table[] = {
.minimum = 0,
.maximum = INT_MAX,
.default_num = 1,
.unit = "milliseconds",
.text = "Maximum time between input to assume it pasting rather "
"than typing."
},
{ .name = "base-index",
@ -309,57 +339,69 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_SESSION,
.minimum = 0,
.maximum = INT_MAX,
.default_num = 0
.default_num = 0,
.text = "Default index of the first window in each session."
},
{ .name = "bell-action",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_SESSION,
.choices = options_table_bell_action_list,
.default_num = ALERT_ANY
.default_num = ALERT_ANY,
.text = "Action to take on a bell alert."
},
{ .name = "default-command",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION,
.default_str = ""
.default_str = "",
.text = "Default command to run in new panes. If empty, a shell is "
"started."
},
{ .name = "default-shell",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION,
.default_str = _PATH_BSHELL
.default_str = _PATH_BSHELL,
.text = "Location of default shell."
},
{ .name = "default-size",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION,
.pattern = "[0-9]*x[0-9]*",
.default_str = "80x24"
.default_str = "80x24",
.text = "Initial size of new sessions."
},
{ .name = "destroy-unattached",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_SESSION,
.default_num = 0
.default_num = 0,
.text = "Whether to destroy sessions when they have no attached "
"clients."
},
{ .name = "detach-on-destroy",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_SESSION,
.default_num = 1
.default_num = 1,
.text = "Whether to detach when a session is destroyed, or switch "
"the client to another session if any exist."
},
{ .name = "display-panes-active-colour",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_SESSION,
.default_num = 1
.default_num = 1,
.text = "Colour of the active pane for 'display-panes'."
},
{ .name = "display-panes-colour",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_SESSION,
.default_num = 4
.default_num = 4,
.text = "Colour of not active panes for 'display-panes'."
},
{ .name = "display-panes-time",
@ -367,7 +409,9 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_SESSION,
.minimum = 1,
.maximum = INT_MAX,
.default_num = 1000
.default_num = 1000,
.unit = "milliseconds",
.text = "Time for which 'display-panes' should show pane numbers."
},
{ .name = "display-time",
@ -375,7 +419,9 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_SESSION,
.minimum = 0,
.maximum = INT_MAX,
.default_num = 750
.default_num = 750,
.unit = "milliseconds",
.text = "Time for which status line messages should appear."
},
{ .name = "history-limit",
@ -383,13 +429,19 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_SESSION,
.minimum = 0,
.maximum = INT_MAX,
.default_num = 2000
.default_num = 2000,
.unit = "lines",
.text = "Maximum number of lines to keep in the history for each "
"pane. "
"If changed, the new value applies only to new panes."
},
{ .name = "key-table",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION,
.default_str = "root"
.default_str = "root",
.text = "Default key table. "
"Key presses are first looked up in this table."
},
{ .name = "lock-after-time",
@ -397,13 +449,16 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_SESSION,
.minimum = 0,
.maximum = INT_MAX,
.default_num = 0
.default_num = 0,
.unit = "seconds",
.text = "Time after which a client is locked if not used."
},
{ .name = "lock-command",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION,
.default_str = "lock -np"
.default_str = "lock -np",
.text = "Shell command to run to lock a client."
},
{ .name = "message-command-style",
@ -411,7 +466,9 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_SESSION,
.default_str = "bg=black,fg=yellow",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ","
.separator = ",",
.text = "Style of the command prompt when in command mode, if "
"'mode-keys' is set to 'vi'."
},
{ .name = "message-style",
@ -419,31 +476,39 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_SESSION,
.default_str = "bg=yellow,fg=black",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ","
.separator = ",",
.text = "Style of the command prompt."
},
{ .name = "mouse",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_SESSION,
.default_num = 0
.default_num = 0,
.text = "Whether the mouse is recognised and mouse key bindings are "
"executed. "
"Applications inside panes can use the mouse even when 'off'."
},
{ .name = "prefix",
.type = OPTIONS_TABLE_KEY,
.scope = OPTIONS_TABLE_SESSION,
.default_num = '\002',
.text = "The prefix key."
},
{ .name = "prefix2",
.type = OPTIONS_TABLE_KEY,
.scope = OPTIONS_TABLE_SESSION,
.default_num = KEYC_NONE,
.text = "A second prefix key."
},
{ .name = "renumber-windows",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_SESSION,
.default_num = 0
.default_num = 0,
.text = "Whether windows are automatically renumbered rather than "
"leaving gaps."
},
{ .name = "repeat-time",
@ -451,45 +516,56 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_SESSION,
.minimum = 0,
.maximum = SHRT_MAX,
.default_num = 500
.default_num = 500,
.unit = "milliseconds",
.text = "Time to wait for a key binding to repeat, if it is bound "
"with the '-r' flag."
},
{ .name = "set-titles",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_SESSION,
.default_num = 0
.default_num = 0,
.text = "Whether to set the terminal title, if supported."
},
{ .name = "set-titles-string",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION,
.default_str = "#S:#I:#W - \"#T\" #{session_alerts}"
.default_str = "#S:#I:#W - \"#T\" #{session_alerts}",
.text = "Format of the terminal title to set."
},
{ .name = "silence-action",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_SESSION,
.choices = options_table_bell_action_list,
.default_num = ALERT_OTHER
.default_num = ALERT_OTHER,
.text = "Action to take on a silence alert."
},
{ .name = "status",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_SESSION,
.choices = options_table_status_list,
.default_num = 1
.default_num = 1,
.text = "Number of lines in the status line."
},
{ .name = "status-bg",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_SESSION,
.default_num = 8,
.text = "Background colour of the status line. This option is "
"deprecated, use 'status-style' instead."
},
{ .name = "status-fg",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_SESSION,
.default_num = 8,
.text = "Foreground colour of the status line. This option is "
"deprecated, use 'status-style' instead."
},
{ .name = "status-format",
@ -497,6 +573,11 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_SESSION,
.flags = OPTIONS_TABLE_IS_ARRAY,
.default_arr = options_table_status_format_default,
.text = "Formats for the status lines. "
"Each array member is the format for one status line. "
"The default status line is made up of several components "
"which may be configured individually with other option such "
"as 'status-left'."
},
{ .name = "status-interval",
@ -504,27 +585,32 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_SESSION,
.minimum = 0,
.maximum = INT_MAX,
.default_num = 15
.default_num = 15,
.unit = "seconds",
.text = "Number of seconds between status line updates."
},
{ .name = "status-justify",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_SESSION,
.choices = options_table_status_justify_list,
.default_num = 0
.default_num = 0,
.text = "Position of the window list in the status line."
},
{ .name = "status-keys",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_SESSION,
.choices = options_table_status_keys_list,
.default_num = MODEKEY_EMACS
.default_num = MODEKEY_EMACS,
.text = "Key set to use at the command prompt."
},
{ .name = "status-left",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION,
.default_str = "[#S] "
.default_str = "[#{session_name}] ",
.text = "Contents of the left side of the status line."
},
{ .name = "status-left-length",
@ -532,7 +618,8 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_SESSION,
.minimum = 0,
.maximum = SHRT_MAX,
.default_num = 10
.default_num = 10,
.text = "Maximum width of the left side of the status line."
},
{ .name = "status-left-style",
@ -540,22 +627,26 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_SESSION,
.default_str = "default",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ","
.separator = ",",
.text = "Style of the left side of the status line."
},
{ .name = "status-position",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_SESSION,
.choices = options_table_status_position_list,
.default_num = 1
.default_num = 1,
.text = "Position of the status line."
},
{ .name = "status-right",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION,
.default_str = "#{?window_bigger,"
"[#{window_offset_x}#,#{window_offset_y}] ,}"
"\"#{=21:pane_title}\" %H:%M %d-%b-%y"
"[#{window_offset_x}#,#{window_offset_y}] ,}"
"\"#{=21:pane_title}\" %H:%M %d-%b-%y",
.text = "Contents of the right side of the status line."
},
{ .name = "status-right-length",
@ -563,7 +654,8 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_SESSION,
.minimum = 0,
.maximum = SHRT_MAX,
.default_num = 40
.default_num = 40,
.text = "Maximum width of the right side of the status line."
},
{ .name = "status-right-style",
@ -571,7 +663,8 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_SESSION,
.default_str = "default",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ","
.separator = ",",
.text = "Style of the right side of the status line."
},
{ .name = "status-style",
@ -579,7 +672,8 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_SESSION,
.default_str = "bg=green,fg=black",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ","
.separator = ",",
.text = "Style of the status line."
},
{ .name = "update-environment",
@ -587,79 +681,100 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_SESSION,
.flags = OPTIONS_TABLE_IS_ARRAY,
.default_str = "DISPLAY KRB5CCNAME SSH_ASKPASS SSH_AUTH_SOCK "
"SSH_AGENT_PID SSH_CONNECTION WINDOWID XAUTHORITY"
"SSH_AGENT_PID SSH_CONNECTION WINDOWID XAUTHORITY",
.text = "List of environment variables to update in the session "
"environment when a client is attached."
},
{ .name = "visual-activity",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_SESSION,
.choices = options_table_visual_bell_list,
.default_num = VISUAL_OFF
.default_num = VISUAL_OFF,
.text = "How activity alerts should be shown: a message ('on'), "
"a message and a bell ('both') or nothing ('off')."
},
{ .name = "visual-bell",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_SESSION,
.choices = options_table_visual_bell_list,
.default_num = VISUAL_OFF
.default_num = VISUAL_OFF,
.text = "How bell alerts should be shown: a message ('on'), "
"a message and a bell ('both') or nothing ('off')."
},
{ .name = "visual-silence",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_SESSION,
.choices = options_table_visual_bell_list,
.default_num = VISUAL_OFF
.default_num = VISUAL_OFF,
.text = "How silence alerts should be shown: a message ('on'), "
"a message and a bell ('both') or nothing ('off')."
},
{ .name = "word-separators",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION,
.default_str = " "
.default_str = " ",
.text = "Characters considered to separate words."
},
/* Window options. */
{ .name = "aggressive-resize",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = 0
.default_num = 0,
.text = "When 'window-size' is 'smallest', whether the maximum size "
"of a window is the smallest attached session where it is "
"the current window ('on') or the smallest session it is "
"linked to ('off')."
},
{ .name = "allow-rename",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
.default_num = 0
.default_num = 0,
.text = "Whether applications are allowed to use the escape sequence "
"to rename windows."
},
{ .name = "alternate-screen",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
.default_num = 1
.default_num = 1,
.text = "Whether applications are allowed to use the alternate "
"screen."
},
{ .name = "automatic-rename",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = 1
.default_num = 1,
.text = "Whether windows are automatically renamed."
},
{ .name = "automatic-rename-format",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "#{?pane_in_mode,[tmux],#{pane_current_command}}"
"#{?pane_dead,[dead],}"
"#{?pane_dead,[dead],}",
.text = "Format used to automatically rename windows."
},
{ .name = "clock-mode-colour",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = 4
.default_num = 4,
.text = "Colour of the clock in clock mode."
},
{ .name = "clock-mode-style",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_WINDOW,
.choices = options_table_clock_mode_style_list,
.default_num = 1
.default_num = 1,
.text = "Time format of the clock in clock mode."
},
{ .name = "copy-mode-match-style",
@ -667,7 +782,8 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "bg=cyan,fg=black",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ","
.separator = ",",
.text = "Style of search matches in copy mode."
},
{ .name = "copy-mode-current-match-style",
@ -675,26 +791,32 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "bg=magenta,fg=black",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ","
.separator = ",",
.text = "Style of the current search match in copy mode."
},
{ .name = "main-pane-height",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "24"
.default_str = "24",
.text = "Height of the main pane in the 'main-horizontal' layout. "
"This may be a percentage, for example '10%'."
},
{ .name = "main-pane-width",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "80"
.default_str = "80",
.text = "Width of the main pane in the 'main-vertical' layout. "
"This may be a percentage, for example '10%'."
},
{ .name = "mode-keys",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_WINDOW,
.choices = options_table_mode_keys_list,
.default_num = MODEKEY_EMACS
.default_num = MODEKEY_EMACS,
.text = "Key set used in copy mode."
},
{ .name = "mode-style",
@ -702,19 +824,22 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "bg=yellow,fg=black",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ","
.separator = ",",
.text = "Style of indicators and highlighting in modes."
},
{ .name = "monitor-activity",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = 0
.default_num = 0,
.text = "Whether an alert is triggered by activity."
},
{ .name = "monitor-bell",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = 1
.default_num = 1,
.text = "Whether an alert is triggered by a bell."
},
{ .name = "monitor-silence",
@ -722,19 +847,26 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_WINDOW,
.minimum = 0,
.maximum = INT_MAX,
.default_num = 0
.default_num = 0,
.text = "Time after which an alert is triggered by silence. "
"Zero means no alert."
},
{ .name = "other-pane-height",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "0"
.default_str = "0",
.text = "Height of the other panes in the 'main-horizontal' layout. "
"This may be a percentage, for example '10%'."
},
{ .name = "other-pane-width",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "0"
.default_str = "0",
.text = "Height of the other panes in the 'main-vertical' layout. "
"This may be a percentage, for example '10%'."
},
{ .name = "pane-active-border-style",
@ -742,7 +874,8 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "#{?pane_in_mode,fg=yellow,#{?synchronize-panes,fg=red,fg=green}}",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ","
.separator = ",",
.text = "Style of the active pane border."
},
{ .name = "pane-base-index",
@ -750,21 +883,24 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_WINDOW,
.minimum = 0,
.maximum = USHRT_MAX,
.default_num = 0
.default_num = 0,
.text = "Index of the first pane in each window."
},
{ .name = "pane-border-format",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "#{?pane_active,#[reverse],}#{pane_index}#[default] "
"\"#{pane_title}\""
"\"#{pane_title}\"",
.text = "Format of text in the pane status lines."
},
{ .name = "pane-border-status",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_WINDOW,
.choices = options_table_pane_status_list,
.default_num = PANE_STATUS_OFF
.default_num = PANE_STATUS_OFF,
.text = "Position of the pane status lines."
},
{ .name = "pane-border-style",
@ -772,19 +908,23 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "default",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ","
.separator = ",",
.text = "Style of the pane status lines."
},
{ .name = "remain-on-exit",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
.default_num = 0
.default_num = 0,
.text = "Whether panes should remain ('on') or be automatically "
"killed ('off') when the program inside exits."
},
{ .name = "synchronize-panes",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = 0
.default_num = 0,
.text = "Whether typing should be sent to all panes simultaneously."
},
{ .name = "window-active-style",
@ -792,14 +932,20 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
.default_str = "default",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ","
.separator = ",",
.text = "Default style of the active pane."
},
{ .name = "window-size",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_WINDOW,
.choices = options_table_window_size_list,
.default_num = WINDOW_SIZE_LATEST
.default_num = WINDOW_SIZE_LATEST,
.text = "How window size is calculated. "
"'latest' uses the size of the most recently used client, "
"'largest' the largest client, 'smallest' the smallest "
"client and 'manual' a size set by the 'resize-window' "
"command."
},
{ .name = "window-style",
@ -807,7 +953,8 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
.default_str = "default",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ","
.separator = ",",
.text = "Default style of panes that are not the active pane."
},
{ .name = "window-status-activity-style",
@ -815,7 +962,8 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "reverse",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ","
.separator = ",",
.text = "Style of windows in the status line with an activity alert."
},
{ .name = "window-status-bell-style",
@ -823,13 +971,15 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "reverse",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ","
.separator = ",",
.text = "Style of windows in the status line with a bell alert."
},
{ .name = "window-status-current-format",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "#I:#W#{?window_flags,#{window_flags}, }"
.default_str = "#I:#W#{?window_flags,#{window_flags}, }",
.text = "Format of the current window in the status line."
},
{ .name = "window-status-current-style",
@ -837,13 +987,16 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "default",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ","
.separator = ",",
.text = "Style of the current window in the status line."
},
{ .name = "window-status-format",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "#I:#W#{?window_flags,#{window_flags}, }"
.default_str = "#I:#W#{?window_flags,#{window_flags}, }",
.text = "Format of windows in the status line, except the current "
"window."
},
{ .name = "window-status-last-style",
@ -851,13 +1004,15 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "default",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ","
.separator = ",",
.text = "Style of the last window in the status line."
},
{ .name = "window-status-separator",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.default_str = " "
.default_str = " ",
.text = "Separator between windows in the status line."
},
{ .name = "window-status-style",
@ -865,19 +1020,24 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "default",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ","
.separator = ",",
.text = "Style of windows in the status line, except the current and "
"last windows."
},
{ .name = "wrap-search",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = 1
.default_num = 1,
.text = "Whether searching in copy mode should wrap at the top or "
"bottom."
},
{ .name = "xterm-keys",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_WINDOW,
.default_num = 1
.default_num = 1,
.text = "Whether xterm-style function key sequences should be sent."
},
/* Hook options. */

252
options.c
View File

@ -19,6 +19,7 @@
#include <sys/types.h>
#include <ctype.h>
#include <fnmatch.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
@ -116,7 +117,7 @@ options_value_free(struct options_entry *o, union options_value *ov)
}
static char *
options_value_tostring(struct options_entry *o, union options_value *ov,
options_value_to_string(struct options_entry *o, union options_value *ov,
int numeric)
{
char *s;
@ -175,6 +176,12 @@ options_free(struct options *oo)
free(oo);
}
struct options *
options_get_parent(struct options *oo)
{
return (oo->parent);
}
void
options_set_parent(struct options *oo, struct options *parent)
{
@ -262,6 +269,35 @@ options_default(struct options *oo, const struct options_table_entry *oe)
return (o);
}
char *
options_default_to_string(const struct options_table_entry *oe)
{
char *s;
switch (oe->type) {
case OPTIONS_TABLE_STRING:
case OPTIONS_TABLE_COMMAND:
s = xstrdup(oe->default_str);
break;
case OPTIONS_TABLE_NUMBER:
xasprintf(&s, "%lld", oe->default_num);
break;
case OPTIONS_TABLE_KEY:
s = xstrdup(key_string_lookup_key(oe->default_num));
break;
case OPTIONS_TABLE_COLOUR:
s = xstrdup(colour_tostring(oe->default_num));
break;
case OPTIONS_TABLE_FLAG:
s = xstrdup(oe->default_num ? "on" : "off");
break;
case OPTIONS_TABLE_CHOICE:
s = xstrdup(oe->choices[oe->default_num]);
break;
}
return (s);
}
static struct options_entry *
options_add(struct options *oo, const char *name)
{
@ -299,6 +335,12 @@ options_name(struct options_entry *o)
return (o->name);
}
struct options *
options_owner(struct options_entry *o)
{
return (o->owner);
}
const struct options_table_entry *
options_table_entry(struct options_entry *o)
{
@ -492,19 +534,19 @@ options_array_item_value(struct options_array_item *a)
}
int
options_isarray(struct options_entry *o)
options_is_array(struct options_entry *o)
{
return (OPTIONS_IS_ARRAY(o));
}
int
options_isstring(struct options_entry *o)
options_is_string(struct options_entry *o)
{
return (OPTIONS_IS_STRING(o));
}
char *
options_tostring(struct options_entry *o, int idx, int numeric)
options_to_string(struct options_entry *o, int idx, int numeric)
{
struct options_array_item *a;
@ -514,9 +556,9 @@ options_tostring(struct options_entry *o, int idx, int numeric)
a = options_array_item(o, idx);
if (a == NULL)
return (xstrdup(""));
return (options_value_tostring(o, &a->value, numeric));
return (options_value_to_string(o, &a->value, numeric));
}
return (options_value_tostring(o, &o->value, numeric));
return (options_value_to_string(o, &o->value, numeric));
}
char *
@ -866,3 +908,201 @@ options_string_to_style(struct options *oo, const char *name,
}
return (&o->style);
}
static int
options_from_string_check(const struct options_table_entry *oe,
const char *value, char **cause)
{
struct style sy;
if (oe == NULL)
return (0);
if (strcmp(oe->name, "default-shell") == 0 && !checkshell(value)) {
xasprintf(cause, "not a suitable shell: %s", value);
return (-1);
}
if (oe->pattern != NULL && fnmatch(oe->pattern, value, 0) != 0) {
xasprintf(cause, "value is invalid: %s", value);
return (-1);
}
if ((oe->flags & OPTIONS_TABLE_IS_STYLE) &&
strstr(value, "#{") == NULL &&
style_parse(&sy, &grid_default_cell, value) != 0) {
xasprintf(cause, "invalid style: %s", value);
return (-1);
}
return (0);
}
static int
options_from_string_flag(struct options *oo, const char *name,
const char *value, char **cause)
{
int flag;
if (value == NULL || *value == '\0')
flag = !options_get_number(oo, name);
else if (strcmp(value, "1") == 0 ||
strcasecmp(value, "on") == 0 ||
strcasecmp(value, "yes") == 0)
flag = 1;
else if (strcmp(value, "0") == 0 ||
strcasecmp(value, "off") == 0 ||
strcasecmp(value, "no") == 0)
flag = 0;
else {
xasprintf(cause, "bad value: %s", value);
return (-1);
}
options_set_number(oo, name, flag);
return (0);
}
static int
options_from_string_choice(const struct options_table_entry *oe,
struct options *oo, const char *name, const char *value, char **cause)
{
const char **cp;
int n, choice = -1;
if (value == NULL) {
choice = options_get_number(oo, name);
if (choice < 2)
choice = !choice;
} else {
n = 0;
for (cp = oe->choices; *cp != NULL; cp++) {
if (strcmp(*cp, value) == 0)
choice = n;
n++;
}
if (choice == -1) {
xasprintf(cause, "unknown value: %s", value);
return (-1);
}
}
options_set_number(oo, name, choice);
return (0);
}
int
options_from_string(struct options *oo, const struct options_table_entry *oe,
const char *name, const char *value, int append, char **cause)
{
enum options_table_type type;
long long number;
const char *errstr, *new;
char *old;
key_code key;
if (oe != NULL) {
if (value == NULL &&
oe->type != OPTIONS_TABLE_FLAG &&
oe->type != OPTIONS_TABLE_CHOICE) {
xasprintf(cause, "empty value");
return (-1);
}
type = oe->type;
} else {
if (*name != '@') {
xasprintf(cause, "bad option name");
return (-1);
}
type = OPTIONS_TABLE_STRING;
}
switch (type) {
case OPTIONS_TABLE_STRING:
old = xstrdup(options_get_string(oo, name));
options_set_string(oo, name, append, "%s", value);
new = options_get_string(oo, name);
if (options_from_string_check(oe, new, cause) != 0) {
options_set_string(oo, name, 0, "%s", old);
free(old);
return (-1);
}
free(old);
return (0);
case OPTIONS_TABLE_NUMBER:
number = strtonum(value, oe->minimum, oe->maximum, &errstr);
if (errstr != NULL) {
xasprintf(cause, "value is %s: %s", errstr, value);
return (-1);
}
options_set_number(oo, name, number);
return (0);
case OPTIONS_TABLE_KEY:
key = key_string_lookup_string(value);
if (key == KEYC_UNKNOWN) {
xasprintf(cause, "bad key: %s", value);
return (-1);
}
options_set_number(oo, name, key);
return (0);
case OPTIONS_TABLE_COLOUR:
if ((number = colour_fromstring(value)) == -1) {
xasprintf(cause, "bad colour: %s", value);
return (-1);
}
options_set_number(oo, name, number);
return (0);
case OPTIONS_TABLE_FLAG:
return (options_from_string_flag(oo, name, value, cause));
case OPTIONS_TABLE_CHOICE:
return (options_from_string_choice(oe, oo, name, value, cause));
case OPTIONS_TABLE_COMMAND:
break;
}
return (-1);
}
void
options_push_changes(const char *name)
{
struct client *loop;
struct session *s;
struct window *w;
struct window_pane *wp;
if (strcmp(name, "automatic-rename") == 0) {
RB_FOREACH(w, windows, &windows) {
if (w->active == NULL)
continue;
if (options_get_number(w->options, "automatic-rename"))
w->active->flags |= PANE_CHANGED;
}
}
if (strcmp(name, "key-table") == 0) {
TAILQ_FOREACH(loop, &clients, entry)
server_client_set_key_table(loop, NULL);
}
if (strcmp(name, "user-keys") == 0) {
TAILQ_FOREACH(loop, &clients, entry) {
if (loop->tty.flags & TTY_OPENED)
tty_keys_build(&loop->tty);
}
}
if (strcmp(name, "status") == 0 ||
strcmp(name, "status-interval") == 0)
status_timer_start_all();
if (strcmp(name, "monitor-silence") == 0)
alerts_reset_all();
if (strcmp(name, "window-style") == 0 ||
strcmp(name, "window-active-style") == 0) {
RB_FOREACH(wp, window_pane_tree, &all_window_panes)
wp->flags |= PANE_STYLECHANGED;
}
if (strcmp(name, "pane-border-status") == 0) {
RB_FOREACH(w, windows, &windows)
layout_fix_panes(w);
}
RB_FOREACH(s, sessions, &sessions)
status_update_cache(s);
recalculate_sizes();
TAILQ_FOREACH(loop, &clients, entry) {
if (loop->session != NULL)
server_redraw_client(loop);
}
}

View File

@ -360,7 +360,97 @@ screen_write_strlen(const char *fmt, ...)
return (size);
}
/* Write simple string (no UTF-8 or maximum length). */
/* Write string wrapped over lines. */
int
screen_write_text(struct screen_write_ctx *ctx, u_int cx, u_int width,
u_int lines, int more, const struct grid_cell *gcp, const char *fmt, ...)
{
struct screen *s = ctx->s;
va_list ap;
char *tmp;
u_int cy = s->cy, i, end, next, idx = 0, at, left;
struct utf8_data *text;
struct grid_cell gc;
memcpy(&gc, gcp, sizeof gc);
va_start(ap, fmt);
xvasprintf(&tmp, fmt, ap);
va_end(ap);
text = utf8_fromcstr(tmp);
free(tmp);
left = (cx + width) - s->cx;
for (;;) {
/* Find the end of what can fit on the line. */
at = 0;
for (end = idx; text[end].size != 0; end++) {
if (text[end].size == 1 && text[end].data[0] == '\n')
break;
if (at + text[end].width > left)
break;
at += text[end].width;
}
/*
* If we're on a space, that's the end. If not, walk back to
* try and find one.
*/
if (text[end].size == 0)
next = end;
else if (text[end].size == 1 && text[end].data[0] == '\n')
next = end + 1;
else if (text[end].size == 1 && text[end].data[0] == ' ')
next = end + 1;
else {
for (i = end; i > idx; i--) {
if (text[i].size == 1 && text[i].data[0] == ' ')
break;
}
if (i != idx) {
next = i + 1;
end = i;
} else
next = end;
}
/* Print the line. */
for (i = idx; i < end; i++) {
utf8_copy(&gc.data, &text[i]);
screen_write_cell(ctx, &gc);
}
/* If at the bottom, stop. */
idx = next;
if (s->cy == cy + lines - 1 || text[idx].size == 0)
break;
screen_write_cursormove(ctx, cx, s->cy + 1, 0);
left = width;
}
/*
* Fail if on the last line and there is more to come or at the end, or
* if the text was not entirely consumed.
*/
if ((s->cy == cy + lines - 1 && (!more || s->cx == cx + width)) ||
text[idx].size != 0) {
free(text);
return (0);
}
free(text);
/*
* If no more to come, move to the next line. Otherwise, leave on
* the same line (except if at the end).
*/
if (!more || s->cx == cx + width)
screen_write_cursormove(ctx, cx, s->cy + 1, 0);
return (1);
}
/* Write simple string (no maximum length). */
void
screen_write_puts(struct screen_write_ctx *ctx, const struct grid_cell *gcp,
const char *fmt, ...)

View File

@ -31,6 +31,7 @@
/* Default style. */
static struct style style_default = {
{ { { ' ' }, 0, 1, 1 }, 0, 0, 8, 8, 0 },
0,
8,
STYLE_ALIGN_DEFAULT,
@ -78,7 +79,11 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in)
sy->gc.bg = base->bg;
sy->gc.attr = base->attr;
sy->gc.flags = base->flags;
} else if (strcasecmp(tmp, "push-default") == 0)
} else if (strcasecmp(tmp, "ignore") == 0)
sy->ignore = 1;
else if (strcasecmp(tmp, "noignore") == 0)
sy->ignore = 0;
else if (strcasecmp(tmp, "push-default") == 0)
sy->default_type = STYLE_DEFAULT_PUSH;
else if (strcasecmp(tmp, "pop-default") == 0)
sy->default_type = STYLE_DEFAULT_POP;

47
tmux.1
View File

@ -1952,6 +1952,53 @@ includes all sessions in any session groups in the tree rather than only the
first.
This command works only if at least one client is attached.
.It Xo
.Ic customize-mode
.Op Fl NZ
.Op Fl F Ar format
.Op Fl f Ar filter
.Op Fl t Ar target-pane
.Op Ar template
.Xc
Put a pane into customize mode, where options and key bindings may be browsed
and modified from a list.
Option values in the list are shown for the active pane in the current window.
.Fl Z
zooms the pane.
The following keys may be used in customize mode:
.Bl -column "Key" "Function" -offset indent
.It Sy "Key" Ta Sy "Function"
.It Li "Enter" Ta "Set pane, window, session or global option value"
.It Li "Up" Ta "Select previous item"
.It Li "Down" Ta "Select next item"
.It Li "+" Ta "Expand selected item"
.It Li "-" Ta "Collapse selected item"
.It Li "M-+" Ta "Expand all items"
.It Li "M--" Ta "Collapse all items"
.It Li "s" Ta "Set option value or key attribute"
.It Li "S" Ta "Set global option value"
.It Li "w" Ta "Set window option value, if option is for pane and window"
.It Li "u" Ta "Unset an option (set to default value if global) or unbind a key"
.It Li "U" Ta "Unset tagged options and unbind tagged keys"
.It Li "C-s" Ta "Search by name"
.It Li "n" Ta "Repeat last search"
.It Li "t" Ta "Toggle if item is tagged"
.It Li "T" Ta "Tag no items"
.It Li "C-t" Ta "Tag all items"
.It Li "f" Ta "Enter a format to filter items"
.It Li "v" Ta "Toggle option information"
.It Li "q" Ta "Exit mode"
.El
.Pp
.Fl f
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.
.Fl N
starts without the option information.
This command works only if at least one client is attached.
.It Xo
.Ic display-panes
.Op Fl b
.Op Fl d Ar duration

33
tmux.h
View File

@ -745,6 +745,7 @@ enum style_default_type {
/* Style option. */
struct style {
struct grid_cell gc;
int ignore;
int fill;
enum style_align align;
@ -1665,6 +1666,7 @@ RB_HEAD(key_bindings, key_binding);
struct key_table {
const char *name;
struct key_bindings key_bindings;
struct key_bindings default_key_bindings;
u_int references;
@ -1719,6 +1721,9 @@ struct options_table_entry {
const char *separator;
const char *pattern;
const char *text;
const char *unit;
};
/* Common command usages. */
@ -1896,6 +1901,7 @@ void notify_pane(const char *, struct window_pane *);
/* options.c */
struct options *options_create(struct options *);
void options_free(struct options *);
struct options *options_get_parent(struct options *);
void options_set_parent(struct options *, struct options *);
struct options_entry *options_first(struct options *);
struct options_entry *options_next(struct options_entry *);
@ -1903,7 +1909,9 @@ struct options_entry *options_empty(struct options *,
const struct options_table_entry *);
struct options_entry *options_default(struct options *,
const struct options_table_entry *);
char *options_default_to_string(const struct options_table_entry *);
const char *options_name(struct options_entry *);
struct options *options_owner(struct options_entry *);
const struct options_table_entry *options_table_entry(struct options_entry *);
struct options_entry *options_get_only(struct options *, const char *);
struct options_entry *options_get(struct options *, const char *);
@ -1918,9 +1926,9 @@ struct options_array_item *options_array_first(struct options_entry *);
struct options_array_item *options_array_next(struct options_array_item *);
u_int options_array_item_index(struct options_array_item *);
union options_value *options_array_item_value(struct options_array_item *);
int options_isarray(struct options_entry *);
int options_isstring(struct options_entry *);
char *options_tostring(struct options_entry *, int, int);
int options_is_array(struct options_entry *);
int options_is_string(struct options_entry *);
char *options_to_string(struct options_entry *, int, int);
char *options_parse(const char *, int *);
struct options_entry *options_parse_get(struct options *, const char *, int *,
int);
@ -1940,6 +1948,10 @@ int options_scope_from_flags(struct args *, int,
struct cmd_find_state *, struct options **, char **);
struct style *options_string_to_style(struct options *, const char *,
struct format_tree *);
int options_from_string(struct options *,
const struct options_table_entry *, const char *,
const char *, int, char **);
void options_push_changes(const char *);
/* options-table.c */
extern const struct options_table_entry options_table[];
@ -2231,6 +2243,7 @@ struct key_table *key_bindings_first_table(void);
struct key_table *key_bindings_next_table(struct key_table *);
void key_bindings_unref_table(struct key_table *);
struct key_binding *key_bindings_get(struct key_table *, key_code);
struct key_binding *key_bindings_get_default(struct key_table *, key_code);
struct key_binding *key_bindings_first(struct key_table *);
struct key_binding *key_bindings_next(struct key_table *, struct key_binding *);
void key_bindings_add(const char *, key_code, const char *, int,
@ -2460,6 +2473,8 @@ void screen_write_start_callback(struct screen_write_ctx *, struct screen *,
void screen_write_stop(struct screen_write_ctx *);
void screen_write_reset(struct screen_write_ctx *);
size_t printflike(1, 2) screen_write_strlen(const char *, ...);
int printflike(7, 8) screen_write_text(struct screen_write_ctx *, u_int, u_int,
u_int, int, const struct grid_cell *, const char *, ...);
void printflike(3, 4) screen_write_puts(struct screen_write_ctx *,
const struct grid_cell *, const char *, ...);
void printflike(4, 5) screen_write_nputs(struct screen_write_ctx *,
@ -2678,19 +2693,23 @@ typedef void (*mode_tree_draw_cb)(void *, void *, struct screen_write_ctx *,
u_int, u_int);
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 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 *);
const char *mode_tree_get_current_name(struct mode_tree_data *);
void mode_tree_expand_current(struct mode_tree_data *);
void mode_tree_collapse_current(struct mode_tree_data *);
void mode_tree_expand(struct mode_tree_data *, uint64_t);
int mode_tree_set_current(struct mode_tree_data *, uint64_t);
void mode_tree_each_tagged(struct mode_tree_data *, mode_tree_each_cb,
struct client *, key_code, int);
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, void *, const struct menu_item *, const char **,
u_int, struct screen **);
mode_tree_menu_cb, mode_tree_height_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 *);
void mode_tree_free(struct mode_tree_data *);
@ -2698,6 +2717,7 @@ void mode_tree_resize(struct mode_tree_data *, u_int, u_int);
struct mode_tree_item *mode_tree_add(struct mode_tree_data *,
struct mode_tree_item *, void *, uint64_t, const char *,
const char *, int);
void mode_tree_draw_as_parent(struct mode_tree_item *);
void mode_tree_remove(struct mode_tree_data *, struct mode_tree_item *);
void mode_tree_draw(struct mode_tree_data *);
int mode_tree_key(struct mode_tree_data *, struct client *, key_code *,
@ -2728,6 +2748,9 @@ void window_copy_start_drag(struct client *, struct mouse_event *);
char *window_copy_get_word(struct window_pane *, u_int, u_int);
char *window_copy_get_line(struct window_pane *, u_int);
/* window-option.c */
extern const struct window_mode window_customize_mode;
/* names.c */
void check_window_name(struct window *);
char *default_window_name(struct window *);

View File

@ -298,8 +298,8 @@ window_buffer_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
data->command = xstrdup(args->argv[0]);
data->data = mode_tree_start(wp, args, window_buffer_build,
window_buffer_draw, window_buffer_search, window_buffer_menu, data,
window_buffer_menu_items, window_buffer_sort_list,
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);
mode_tree_zoom(data->data, args);

View File

@ -271,7 +271,7 @@ window_client_init(struct window_mode_entry *wme,
data->command = xstrdup(args->argv[0]);
data->data = mode_tree_start(wp, args, window_client_build,
window_client_draw, NULL, window_client_menu, data,
window_client_draw, NULL, window_client_menu, NULL, data,
window_client_menu_items, window_client_sort_list,
nitems(window_client_sort_list), &s);
mode_tree_zoom(data->data, args);

1430
window-customize.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -885,7 +885,7 @@ 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, data,
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);
mode_tree_zoom(data->data, args);