completion: drop the hard coded list of config vars
[gitweb.git] / builtin / config.c
index 92fb8d56b11e0be5d781f91aa1e5b1fcae7002a7..69e7270356c5a4da8372201ac80ec0d33e8909c2 100644 (file)
@@ -26,6 +26,7 @@ static char term = '\n';
 static int use_global_config, use_system_config, use_local_config;
 static struct git_config_source given_config_source;
 static int actions, type;
+static char *default_value;
 static int end_null;
 static int respect_includes_opt = -1;
 static struct config_options config_options;
@@ -60,6 +61,63 @@ static int show_origin;
 #define TYPE_BOOL_OR_INT       3
 #define TYPE_PATH              4
 #define TYPE_EXPIRY_DATE       5
+#define TYPE_COLOR             6
+
+#define OPT_CALLBACK_VALUE(s, l, v, h, i) \
+       { OPTION_CALLBACK, (s), (l), (v), NULL, (h), PARSE_OPT_NOARG | \
+       PARSE_OPT_NONEG, option_parse_type, (i) }
+
+static struct option builtin_config_options[];
+
+static int option_parse_type(const struct option *opt, const char *arg,
+                            int unset)
+{
+       int new_type, *to_type;
+
+       if (unset) {
+               *((int *) opt->value) = 0;
+               return 0;
+       }
+
+       /*
+        * To support '--<type>' style flags, begin with new_type equal to
+        * opt->defval.
+        */
+       new_type = opt->defval;
+       if (!new_type) {
+               if (!strcmp(arg, "bool"))
+                       new_type = TYPE_BOOL;
+               else if (!strcmp(arg, "int"))
+                       new_type = TYPE_INT;
+               else if (!strcmp(arg, "bool-or-int"))
+                       new_type = TYPE_BOOL_OR_INT;
+               else if (!strcmp(arg, "path"))
+                       new_type = TYPE_PATH;
+               else if (!strcmp(arg, "expiry-date"))
+                       new_type = TYPE_EXPIRY_DATE;
+               else if (!strcmp(arg, "color"))
+                       new_type = TYPE_COLOR;
+               else
+                       die(_("unrecognized --type argument, %s"), arg);
+       }
+
+       to_type = opt->value;
+       if (*to_type && *to_type != new_type) {
+               /*
+                * Complain when there is a new type not equal to the old type.
+                * This allows for combinations like '--int --type=int' and
+                * '--type=int --type=int', but disallows ones like '--type=bool
+                * --int' and '--type=bool
+                * --type=int'.
+                */
+               error("only one type at a time.");
+               usage_with_options(builtin_config_usage,
+                       builtin_config_options);
+       }
+       *to_type = new_type;
+
+       return 0;
+}
 
 static struct option builtin_config_options[] = {
        OPT_GROUP(N_("Config file location")),
@@ -84,16 +142,18 @@ static struct option builtin_config_options[] = {
        OPT_BIT(0, "get-color", &actions, N_("find the color configured: slot [default]"), ACTION_GET_COLOR),
        OPT_BIT(0, "get-colorbool", &actions, N_("find the color setting: slot [stdout-is-tty]"), ACTION_GET_COLORBOOL),
        OPT_GROUP(N_("Type")),
-       OPT_SET_INT(0, "bool", &type, N_("value is \"true\" or \"false\""), TYPE_BOOL),
-       OPT_SET_INT(0, "int", &type, N_("value is decimal number"), TYPE_INT),
-       OPT_SET_INT(0, "bool-or-int", &type, N_("value is --bool or --int"), TYPE_BOOL_OR_INT),
-       OPT_SET_INT(0, "path", &type, N_("value is a path (file or directory name)"), TYPE_PATH),
-       OPT_SET_INT(0, "expiry-date", &type, N_("value is an expiry date"), TYPE_EXPIRY_DATE),
+       OPT_CALLBACK('t', "type", &type, "", N_("value is given this type"), option_parse_type),
+       OPT_CALLBACK_VALUE(0, "bool", &type, N_("value is \"true\" or \"false\""), TYPE_BOOL),
+       OPT_CALLBACK_VALUE(0, "int", &type, N_("value is decimal number"), TYPE_INT),
+       OPT_CALLBACK_VALUE(0, "bool-or-int", &type, N_("value is --bool or --int"), TYPE_BOOL_OR_INT),
+       OPT_CALLBACK_VALUE(0, "path", &type, N_("value is a path (file or directory name)"), TYPE_PATH),
+       OPT_CALLBACK_VALUE(0, "expiry-date", &type, N_("value is an expiry date"), TYPE_EXPIRY_DATE),
        OPT_GROUP(N_("Other")),
        OPT_BOOL('z', "null", &end_null, N_("terminate values with NUL byte")),
        OPT_BOOL(0, "name-only", &omit_values, N_("show variable names only")),
        OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")),
        OPT_BOOL(0, "show-origin", &show_origin, N_("show origin of config (file, standard input, blob, command line)")),
+       OPT_STRING(0, "default", &default_value, N_("value"), N_("with --get, use default value when missing entry")),
        OPT_END(),
 };
 
@@ -173,6 +233,11 @@ static int format_config(struct strbuf *buf, const char *key_, const char *value
                        if (git_config_expiry_date(&t, key_, value_) < 0)
                                return -1;
                        strbuf_addf(buf, "%"PRItime, t);
+               } else if (type == TYPE_COLOR) {
+                       char v[COLOR_MAXLEN];
+                       if (git_config_color(v, key_, value_) < 0)
+                               return -1;
+                       strbuf_addstr(buf, v);
                } else if (value_) {
                        strbuf_addstr(buf, value_);
                } else {
@@ -258,6 +323,16 @@ static int get_value(const char *key_, const char *regex_)
        config_with_options(collect_config, &values,
                            &given_config_source, &config_options);
 
+       if (!values.nr && default_value) {
+               struct strbuf *item;
+               ALLOC_GROW(values.items, values.nr + 1, values.alloc);
+               item = &values.items[values.nr++];
+               strbuf_init(item, 0);
+               if (format_config(item, key_, default_value) < 0)
+                       die(_("failed to format default config value: %s"),
+                               default_value);
+       }
+
        ret = !values.nr;
 
        for (i = 0; i < values.nr; i++) {
@@ -308,6 +383,20 @@ static char *normalize_value(const char *key, const char *value)
                else
                        return xstrdup(v ? "true" : "false");
        }
+       if (type == TYPE_COLOR) {
+               char v[COLOR_MAXLEN];
+               if (git_config_color(v, key, value))
+                       die("cannot parse color '%s'", value);
+
+               /*
+                * The contents of `v` now contain an ANSI escape
+                * sequence, not suitable for including within a
+                * configuration file. Treat the above as a
+                * "sanity-check", and return the given value, which we
+                * know is representable as valid color code.
+                */
+               return xstrdup(value);
+       }
 
        die("BUG: cannot normalize type %d", type);
 }
@@ -596,6 +685,12 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                usage_with_options(builtin_config_usage, builtin_config_options);
        }
 
+       if (default_value && !(actions & ACTION_GET)) {
+               error("--default is only applicable to --get");
+               usage_with_options(builtin_config_usage,
+                       builtin_config_options);
+       }
+
        if (actions & PAGING_ACTIONS)
                setup_auto_pager("config", 1);