summaryrefslogtreecommitdiffstats
path: root/options.c
diff options
context:
space:
mode:
authornicm <nicm>2020-05-16 16:02:24 +0000
committernicm <nicm>2020-05-16 16:02:24 +0000
commitd67245c734c9c600ad6d186570a1230aa21b80c8 (patch)
tree9e71286a88716251c09d3dd2c2b323074f9f40ff /options.c
parent472d77fd0f4af8431267473df3cf109030760fa1 (diff)
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.
Diffstat (limited to 'options.c')
-rw-r--r--options.c252
1 files changed, 246 insertions, 6 deletions
diff --git a/options.c b/options.c
index 39a0d08f..58b7f7c1 100644
--- a/options.c
+++ b/options.c
@@ -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);
+ }
+}