diff options
| -rw-r--r-- | sam.c | 51 | ||||
| -rw-r--r-- | vis-cmds.c | 111 | ||||
| -rw-r--r-- | vis.c | 4 | ||||
| -rw-r--r-- | vis.h | 15 |
4 files changed, 127 insertions, 54 deletions
@@ -267,18 +267,11 @@ static const CommandDef cmddef_select = { /* :set command options */ typedef struct { - const char *names[3]; /* name and optional alias */ - enum { - OPTION_TYPE_STRING, - OPTION_TYPE_BOOL, - OPTION_TYPE_NUMBER, - } type; - enum { - OPTION_FLAG_NONE = 0, - OPTION_FLAG_OPTIONAL = 1 << 0, /* value is optional */ - OPTION_FLAG_WINDOW = 1 << 1, /* option requires an active window */ - } flags; - VIS_HELP_DECL(const char *help;) /* short, one line help text */ + const char *names[3]; /* name and optional alias */ + enum VisOption flags; /* option type, etc. */ + VIS_HELP_DECL(const char *help;) /* short, one line help text */ + VisOptionFunction *func; /* option handler, NULL for bulitins */ + void *context; /* context passed to option handler function */ } OptionDef; enum { @@ -304,87 +297,87 @@ enum { static const OptionDef options[] = { [OPTION_SHELL] = { { "shell" }, - OPTION_TYPE_STRING, OPTION_FLAG_NONE, + VIS_OPTION_TYPE_STRING, VIS_HELP("Shell to use for external commands (default: $SHELL, /etc/passwd, /bin/sh)") }, [OPTION_ESCDELAY] = { { "escdelay" }, - OPTION_TYPE_NUMBER, OPTION_FLAG_NONE, + VIS_OPTION_TYPE_NUMBER, VIS_HELP("Miliseconds to wait to distinguish <Escape> from terminal escape sequences") }, [OPTION_AUTOINDENT] = { { "autoindent", "ai" }, - OPTION_TYPE_BOOL, OPTION_FLAG_NONE, + VIS_OPTION_TYPE_BOOL, VIS_HELP("Copy leading white space from previous line") }, [OPTION_EXPANDTAB] = { { "expandtab", "et" }, - OPTION_TYPE_BOOL, OPTION_FLAG_NONE, + VIS_OPTION_TYPE_BOOL, VIS_HELP("Replace entered <Tab> with `tabwidth` spaces") }, [OPTION_TABWIDTH] = { { "tabwidth", "tw" }, - OPTION_TYPE_NUMBER, OPTION_FLAG_NONE, + VIS_OPTION_TYPE_NUMBER, VIS_HELP("Number of spaces to display (and insert if `expandtab` is enabled) for a tab") }, [OPTION_THEME] = { { "theme" }, - OPTION_TYPE_STRING, OPTION_FLAG_NONE, + VIS_OPTION_TYPE_STRING, VIS_HELP("Color theme to use filename without extension") }, [OPTION_SYNTAX] = { { "syntax" }, - OPTION_TYPE_STRING, OPTION_FLAG_WINDOW|OPTION_FLAG_OPTIONAL, + VIS_OPTION_TYPE_STRING|VIS_OPTION_VALUE_OPTIONAL|VIS_OPTION_NEED_WINDOW, VIS_HELP("Syntax highlighting lexer to use filename without extension") }, [OPTION_SHOW_SPACES] = { { "show-spaces" }, - OPTION_TYPE_BOOL, OPTION_FLAG_WINDOW, + VIS_OPTION_TYPE_BOOL|VIS_OPTION_NEED_WINDOW, VIS_HELP("Display replacement symbol instead of a space") }, [OPTION_SHOW_TABS] = { { "show-tabs" }, - OPTION_TYPE_BOOL, OPTION_FLAG_WINDOW, + VIS_OPTION_TYPE_BOOL|VIS_OPTION_NEED_WINDOW, VIS_HELP("Display replacement symbol for tabs") }, [OPTION_SHOW_NEWLINES] = { { "show-newlines" }, - OPTION_TYPE_BOOL, OPTION_FLAG_WINDOW, + VIS_OPTION_TYPE_BOOL|VIS_OPTION_NEED_WINDOW, VIS_HELP("Display replacement symbol for newlines") }, [OPTION_NUMBER] = { { "numbers", "nu" }, - OPTION_TYPE_BOOL, OPTION_FLAG_WINDOW, + VIS_OPTION_TYPE_BOOL|VIS_OPTION_NEED_WINDOW, VIS_HELP("Display absolute line numbers") }, [OPTION_NUMBER_RELATIVE] = { { "relativenumbers", "rnu" }, - OPTION_TYPE_BOOL, OPTION_FLAG_WINDOW, + VIS_OPTION_TYPE_BOOL|VIS_OPTION_NEED_WINDOW, VIS_HELP("Display relative line numbers") }, [OPTION_CURSOR_LINE] = { { "cursorline", "cul" }, - OPTION_TYPE_BOOL, OPTION_FLAG_WINDOW, + VIS_OPTION_TYPE_BOOL|VIS_OPTION_NEED_WINDOW, VIS_HELP("Highlight current cursor line") }, [OPTION_COLOR_COLUMN] = { { "colorcolumn", "cc" }, - OPTION_TYPE_NUMBER, OPTION_FLAG_WINDOW, + VIS_OPTION_TYPE_NUMBER|VIS_OPTION_NEED_WINDOW, VIS_HELP("Highlight a fixed column") }, [OPTION_HORIZON] = { { "horizon" }, - OPTION_TYPE_NUMBER, OPTION_FLAG_WINDOW, + VIS_OPTION_TYPE_NUMBER|VIS_OPTION_NEED_WINDOW, VIS_HELP("Number of bytes to consider for syntax highlighting") }, [OPTION_SAVE_METHOD] = { { "savemethod" }, - OPTION_TYPE_STRING, OPTION_FLAG_WINDOW, + VIS_OPTION_TYPE_STRING|VIS_OPTION_NEED_WINDOW, VIS_HELP("Save method to use for current file 'auto', 'atomic' or 'inplace'") }, [OPTION_CHANGE_256COLORS] = { { "change-256colors" }, - OPTION_TYPE_BOOL, OPTION_FLAG_NONE, + VIS_OPTION_TYPE_BOOL, VIS_HELP("Change 256 color palette to support 24bit colors") }, }; @@ -62,6 +62,60 @@ bool vis_cmd_unregister(Vis *vis, const char *name) { return true; } +static void option_free(OptionDef *opt) { + if (!opt) + return; + for (size_t i = 0; i < LENGTH(options); i++) { + if (opt == &options[i]) + return; + } + + for (const char **name = opt->names; *name; name++) + free((char*)*name); + free(VIS_HELP_USE((char*)opt->help)); + free(opt); +} + +bool vis_option_register(Vis *vis, const char *names[], enum VisOption flags, + VisOptionFunction *func, void *context, const char *help) { + for (const char **name = names; *name; name++) { + if (map_get(vis->options, *name)) + return false; + } + OptionDef *opt = calloc(1, sizeof *opt); + if (!opt) + return false; + for (size_t i = 0; i < LENGTH(opt->names)-1 && names[i]; i++) { + if (!(opt->names[i] = strdup(names[i]))) + goto err; + } + opt->flags = flags; + opt->func = func; + opt->context = context; +#if CONFIG_HELP + if (help && !(opt->help = strdup(help))) + goto err; +#endif + for (const char **name = names; *name; name++) + map_put(vis->options, *name, opt); + return true; +err: + option_free(opt); + return false; +} + +bool vis_option_unregister(Vis *vis, const char *name) { + OptionDef *opt = map_get(vis->options, name); + if (!opt) + return false; + for (const char **alias = opt->names; *alias; alias++) { + if (!map_delete(vis->options, *alias)) + return false; + } + option_free(opt); + return true; +} + static bool cmd_user(Vis *vis, Win *win, Command *cmd, const char *argv[], Cursor *cur, Filerange *range) { CmdUser *user = map_get(vis->usercmds, argv[0]); return user && user->func(vis, win, user->data, cmd->flags == '!', argv, cur, range); @@ -117,13 +171,13 @@ static bool cmd_set(Vis *vis, Win *win, Command *cmd, const char *argv[], Cursor return false; } - if (!win && (opt->flags & OPTION_FLAG_WINDOW)) { + if (!win && (opt->flags & VIS_OPTION_NEED_WINDOW)) { vis_info_show(vis, "Need active window for `:set %s'", name); return false; } if (toggle) { - if (opt->type != OPTION_TYPE_BOOL) { + if (!(opt->flags & VIS_OPTION_TYPE_BOOL)) { vis_info_show(vis, "Only boolean options can be toggled"); return false; } @@ -134,23 +188,20 @@ static bool cmd_set(Vis *vis, Win *win, Command *cmd, const char *argv[], Cursor } Arg arg; - switch (opt->type) { - case OPTION_TYPE_STRING: - if (!(opt->flags & OPTION_FLAG_OPTIONAL) && !argv[2]) { + if (opt->flags & VIS_OPTION_TYPE_STRING) { + if (!(opt->flags & VIS_OPTION_VALUE_OPTIONAL) && !argv[2]) { vis_info_show(vis, "Expecting string option value"); return false; } arg.s = argv[2]; - break; - case OPTION_TYPE_BOOL: + } else if (opt->flags & VIS_OPTION_TYPE_BOOL) { if (!argv[2]) { arg.b = !toggle; } else if (!parse_bool(argv[2], &arg.b)) { vis_info_show(vis, "Expecting boolean option value not: `%s'", argv[2]); return false; } - break; - case OPTION_TYPE_NUMBER: + } else if (opt->flags & VIS_OPTION_TYPE_NUMBER) { if (!argv[2]) { vis_info_show(vis, "Expecting number"); return false; @@ -174,12 +225,16 @@ static bool cmd_set(Vis *vis, Win *win, Command *cmd, const char *argv[], Cursor return false; } arg.i = lval; - break; - default: + } else { return false; } - size_t opt_index = opt - options; + size_t opt_index = 0; + for (; opt_index < LENGTH(options); opt_index++) { + if (opt == &options[opt_index]) + break; + } + switch (opt_index) { case OPTION_SHELL: { @@ -301,7 +356,9 @@ static bool cmd_set(Vis *vis, Win *win, Command *cmd, const char *argv[], Cursor vis->change_colors = toggle ? !vis->change_colors : arg.b; break; default: - return false; + if (!opt->func) + return false; + return opt->func(vis, win, opt->context, toggle, opt->flags, name, &arg); } return true; @@ -596,6 +653,21 @@ static bool print_cmd(const char *key, void *value, void *data) { return text_appendf(data, " %-30s %s\n", usage, help ? help : ""); } +static bool print_option(const char *key, void *value, void *txt) { + char desc[256]; + const OptionDef *opt = value; + const char *help = VIS_HELP_USE(opt->help); + if (strcmp(key, opt->names[0])) + return true; + snprintf(desc, sizeof desc, "%s%s%s%s%s", + opt->names[0], + opt->names[1] ? "|" : "", + opt->names[1] ? opt->names[1] : "", + opt->flags & VIS_OPTION_TYPE_BOOL ? " on|off" : "", + opt->flags & VIS_OPTION_TYPE_NUMBER ? " nn" : ""); + return text_appendf(txt, " %-30s %s\n", desc, help ? help : ""); +} + static void print_symbolic_keys(Vis *vis, Text *txt) { static const int keys[] = { TERMKEY_SYM_BACKSPACE, @@ -710,18 +782,7 @@ static bool cmd_help(Vis *vis, Win *win, Command *cmd, const char *argv[], Curso } text_appendf(txt, "\n :set command options\n\n"); - for (int i = 0; i < LENGTH(options); i++) { - char names[256]; - const OptionDef *opt = &options[i]; - const char *help = VIS_HELP_USE(opt->help); - snprintf(names, sizeof names, "%s%s%s%s%s", - opt->names[0], - opt->names[1] ? "|" : "", - opt->names[1] ? opt->names[1] : "", - opt->type == OPTION_TYPE_BOOL ? " on|off" : "", - opt->type == OPTION_TYPE_NUMBER ? " nn" : ""); - text_appendf(txt, " %-30s %s\n", names, help ? help : ""); - } + map_iterate(vis->options, print_option, txt); text_appendf(txt, "\n Key binding actions\n\n"); map_iterate(vis->actions, print_action, txt); @@ -754,6 +754,10 @@ void vis_free(Vis *vis) { } map_free(vis->usercmds); map_free(vis->cmds); + if (vis->options) { + const char *name; + while (map_first(vis->options, &name) && vis_option_unregister(vis, name)); + } map_free(vis->options); map_free(vis->actions); map_free(vis->keymap); @@ -482,6 +482,21 @@ typedef bool (CmdFunc)(Vis*, Win*, void *data, bool force, * unique prefix of the given name is executed */ bool vis_cmd_register(Vis*, const char *name, const char *help, void *data, CmdFunc*); bool vis_cmd_unregister(Vis*, const char *name); + +enum VisOption { + VIS_OPTION_TYPE_BOOL = 1 << 0, + VIS_OPTION_TYPE_STRING = 1 << 1, + VIS_OPTION_TYPE_NUMBER = 1 << 2, + VIS_OPTION_VALUE_OPTIONAL = 1 << 3, + VIS_OPTION_NEED_WINDOW = 1 << 4, +}; + +typedef bool (VisOptionFunction)(Vis*, Win*, void *context, bool toggle, + enum VisOption, const char *name, Arg *value); +bool vis_option_register(Vis*, const char *names[], enum VisOption, + VisOptionFunction*, void *context, const char *help); +bool vis_option_unregister(Vis*, const char *name); + /* execute any kind (:,?,/) of prompt command */ bool vis_prompt_cmd(Vis*, const char *cmd); |
