aboutsummaryrefslogtreecommitdiff
path: root/vis.c
diff options
context:
space:
mode:
authorMarc André Tanner <mat@brain-dump.org>2015-01-04 11:51:36 +0100
committerMarc André Tanner <mat@brain-dump.org>2015-01-04 11:51:36 +0100
commit280252386dcbca231bb4e4006033a90183595267 (patch)
tree6cacd48a968f6c323bdb9d5ca3182e7abe1c8212 /vis.c
parentcb5a83dfd1d6c8bf417a3ad280bac0826635397d (diff)
downloadvis-280252386dcbca231bb4e4006033a90183595267.tar.gz
vis-280252386dcbca231bb4e4006033a90183595267.tar.xz
Make :set option parsing more robust
Among other things boolean options can now be prefixed with "no". For example ":set nonu" disables line numbers etc. Based on a patch from Sebastian Götte.
Diffstat (limited to 'vis.c')
-rw-r--r--vis.c136
1 files changed, 115 insertions, 21 deletions
diff --git a/vis.c b/vis.c
index 8504946..cb401d9 100644
--- a/vis.c
+++ b/vis.c
@@ -17,6 +17,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
+#include <strings.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
@@ -1284,40 +1285,133 @@ static void switchmode_to(Mode *new_mode) {
/** ':'-command implementations */
+/* parse human-readable boolean value in s. If successful, store the result in
+ * outval and return true. Else return false and leave outval alone. */
+static bool parse_bool(const char *s, bool *outval) {
+ for (const char **t = (const char*[]){"1", "true", "yes", "on", NULL}; *t; t++) {
+ if (!strcasecmp(s, *t)) {
+ *outval = true;
+ return true;
+ }
+ }
+ for (const char **f = (const char*[]){"0", "false", "no", "off", NULL}; *f; f++) {
+ if (!strcasecmp(s, *f)) {
+ *outval = false;
+ return true;
+ }
+ }
+ return false;
+}
+
static bool cmd_set(Filerange *range, const char *argv[]) {
- if (!argv[2]) {
- editor_info_show(vis, "Expecting: set option value");
+
+ typedef struct {
+ const char *name;
+ enum {
+ OPTION_TYPE_STRING,
+ OPTION_TYPE_BOOL,
+ OPTION_TYPE_NUMBER,
+ } type;
+ regex_t regex;
+ } OptionDef;
+
+ enum {
+ OPTION_EXPANDTAB,
+ OPTION_TABWIDTH,
+ OPTION_SYNTAX,
+ OPTION_NUMBER,
+ };
+
+ static OptionDef options[] = {
+ [OPTION_EXPANDTAB] = { "^(expandtab|et)$", OPTION_TYPE_BOOL },
+ [OPTION_TABWIDTH] = { "^(tabwidth|tw)$", OPTION_TYPE_NUMBER },
+ [OPTION_SYNTAX] = { "^syntax$", OPTION_TYPE_STRING },
+ [OPTION_NUMBER] = { "^(numbers?|nu)$", OPTION_TYPE_BOOL },
+ };
+
+ static bool init = false;
+
+ if (!init) {
+ for (int i = 0; i < LENGTH(options); i++)
+ regcomp(&options[i].regex, options[i].name, REG_EXTENDED|REG_ICASE);
+ init = true;
+ }
+
+ if (!argv[1]) {
+ editor_info_show(vis, "Expecting: set option [value]");
return false;
}
- if (!strcmp("tabwidth", argv[1])) {
- editor_tabwidth_set(vis, strtoul(argv[2], NULL, 10));
- } else if (!strcmp("expandtab", argv[1])) {
- switch (argv[2][0]) {
- case '1': case 't': /* true */ case 'y': /* yes */
- vis->expandtab = true;
+ int opt = -1; Arg arg; bool invert = false;
+
+ for (int i = 0; i < LENGTH(options); i++) {
+ if (!regexec(&options[i].regex, argv[1], 0, NULL, 0)) {
+ opt = i;
break;
- case '0': case 'f': /* false */ case 'n': /* no */
- vis->expandtab = false;
+ }
+ if (options[i].type == OPTION_TYPE_BOOL && !strncasecmp(argv[1], "no", 2) &&
+ !regexec(&options[i].regex, argv[1]+2, 0, NULL, 0)) {
+ opt = i;
+ invert = true;
break;
- default:
- editor_info_show(vis, "Expecting: set expandtab [0|1]");
+ }
+ }
+
+ if (opt == -1) {
+ editor_info_show(vis, "Unknown option: `%s'", argv[1]);
+ return false;
+ }
+
+ switch (options[opt].type) {
+ case OPTION_TYPE_STRING:
+ if (!argv[2]) {
+ editor_info_show(vis, "Expecting string option value");
return false;
}
- } else if (!strcmp("syntax", argv[1])) {
+ break;
+ case OPTION_TYPE_BOOL:
+ if (!argv[2]) {
+ arg.b = true;
+ } else if (!parse_bool(argv[2], &arg.b)) {
+ editor_info_show(vis, "Expecting boolean option value not: `%s'", argv[2]);
+ return false;
+ }
+ if (invert)
+ arg.b = !arg.b;
+ break;
+ case OPTION_TYPE_NUMBER:
+ if (!argv[2]) {
+ editor_info_show(vis, "Expecting number");
+ return false;
+ }
+ /* TODO: error checking? long type */
+ arg.i = strtoul(argv[2], NULL, 10);
+ break;
+ }
+
+ switch (opt) {
+ case OPTION_EXPANDTAB:
+ vis->expandtab = arg.b;
+ break;
+ case OPTION_TABWIDTH:
+ editor_tabwidth_set(vis, arg.i);
+ break;
+ case OPTION_SYNTAX:
for (Syntax *syntax = syntaxes; syntax && syntax->name; syntax++) {
- if (!strcmp(syntax->name, argv[2])) {
+ if (!strcasecmp(syntax->name, argv[2])) {
window_syntax_set(vis->win->win, syntax);
return true;
}
}
- window_syntax_set(vis->win->win, NULL);
- return false;
- } else if (!strcmp("number", argv[1])) {
- window_line_numbers_show(vis->win->win, argv[2][0] == '1');
- } else {
- editor_info_show(vis, "Unknown option: `%s'", argv[1]);
- return false;
+
+ if (parse_bool(argv[2], &arg.b) && !arg.b)
+ window_syntax_set(vis->win->win, NULL);
+ else
+ editor_info_show(vis, "Unknown syntax definition: `%s'", argv[2]);
+ break;
+ case OPTION_NUMBER:
+ window_line_numbers_show(vis->win->win, arg.b);
+ break;
}
return true;