X-Git-Url: https://git.tokkee.org/?p=tig.git;a=blobdiff_plain;f=tig.c;h=fd19f5403e8351618b37e2e1a97bcc1af9a6906b;hp=8bca63498e8b0417ed1278e4c6d0eb87aeb0c348;hb=8869ebf96178755c9c88e011db35048b93647ae2;hpb=f0fc79b198d1205eccde1aae23b7127e49cf4bd9 diff --git a/tig.c b/tig.c index 8bca634..fd19f54 100644 --- a/tig.c +++ b/tig.c @@ -1802,9 +1802,36 @@ add_builtin_run_requests(void) * User config file handling. */ -static int config_lineno; -static bool config_errors; -static const char *config_msg; +#define OPT_ERR_INFO \ + OPT_ERR_(INTEGER_VALUE_OUT_OF_BOUND, "Integer value out of bound"), \ + OPT_ERR_(INVALID_STEP_VALUE, "Invalid step value"), \ + OPT_ERR_(NO_OPTION_VALUE, "No option value"), \ + OPT_ERR_(NO_VALUE_ASSIGNED, "No value assigned"), \ + OPT_ERR_(OBSOLETE_REQUEST_NAME, "Obsolete request name"), \ + OPT_ERR_(TOO_MANY_OPTION_ARGUMENTS, "Too many option arguments"), \ + OPT_ERR_(UNKNOWN_ATTRIBUTE, "Unknown attribute"), \ + OPT_ERR_(UNKNOWN_COLOR, "Unknown color"), \ + OPT_ERR_(UNKNOWN_COLOR_NAME, "Unknown color name"), \ + OPT_ERR_(UNKNOWN_KEY, "Unknown key"), \ + OPT_ERR_(UNKNOWN_KEY_MAP, "Unknown key map"), \ + OPT_ERR_(UNKNOWN_OPTION_COMMAND, "Unknown option command"), \ + OPT_ERR_(UNKNOWN_REQUEST_NAME, "Unknown request name"), \ + OPT_ERR_(UNKNOWN_VARIABLE_NAME, "Unknown variable name"), \ + OPT_ERR_(UNMATCHED_QUOTATION, "Unmatched quotation"), \ + OPT_ERR_(WRONG_NUMBER_OF_ARGUMENTS, "Wrong number of arguments"), + +enum option_code { +#define OPT_ERR_(name, msg) OPT_ERR_ ## name + OPT_ERR_INFO +#undef OPT_ERR_ + OPT_OK +}; + +static const char *option_errors[] = { +#define OPT_ERR_(name, msg) msg + OPT_ERR_INFO +#undef OPT_ERR_ +}; static const struct enum_map color_map[] = { #define COLOR_MAP(name) ENUM_MAP(#name, COLOR_##name) @@ -1832,39 +1859,37 @@ static const struct enum_map attr_map[] = { #define set_attribute(attr, name) map_enum(attr, attr_map, name) -static int parse_step(double *opt, const char *arg) +static enum option_code +parse_step(double *opt, const char *arg) { *opt = atoi(arg); if (!strchr(arg, '%')) - return OK; + return OPT_OK; /* "Shift down" so 100% and 1 does not conflict. */ *opt = (*opt - 1) / 100; if (*opt >= 1.0) { *opt = 0.99; - config_msg = "Step value larger than 100%"; - return ERR; + return OPT_ERR_INVALID_STEP_VALUE; } if (*opt < 0.0) { *opt = 1; - config_msg = "Invalid step value"; - return ERR; + return OPT_ERR_INVALID_STEP_VALUE; } - return OK; + return OPT_OK; } -static int +static enum option_code parse_int(int *opt, const char *arg, int min, int max) { int value = atoi(arg); if (min <= value && value <= max) { *opt = value; - return OK; + return OPT_OK; } - config_msg = "Integer value out of bound"; - return ERR; + return OPT_ERR_INTEGER_VALUE_OUT_OF_BOUND; } static bool @@ -1878,15 +1903,13 @@ set_color(int *color, const char *name) } /* Wants: object fgcolor bgcolor [attribute] */ -static int +static enum option_code option_color_command(int argc, const char *argv[]) { struct line_info *info; - if (argc < 3) { - config_msg = "Wrong number of arguments given to color command"; - return ERR; - } + if (argc < 3) + return OPT_ERR_WRONG_NUMBER_OF_ARGUMENTS; info = get_line_info(argv[0]); if (!info) { @@ -1898,16 +1921,14 @@ option_color_command(int argc, const char *argv[]) int index; if (!map_enum(&index, obsolete, argv[0])) { - config_msg = "Unknown color name"; - return ERR; + return OPT_ERR_UNKNOWN_COLOR_NAME; } info = &line_info[index]; } if (!set_color(&info->fg, argv[1]) || !set_color(&info->bg, argv[2])) { - config_msg = "Unknown color"; - return ERR; + return OPT_ERR_UNKNOWN_COLOR; } info->attr = 0; @@ -1915,43 +1936,42 @@ option_color_command(int argc, const char *argv[]) int attr; if (!set_attribute(&attr, argv[argc])) { - config_msg = "Unknown attribute"; - return ERR; + return OPT_ERR_UNKNOWN_ATTRIBUTE; } info->attr |= attr; } - return OK; + return OPT_OK; } -static int parse_bool(bool *opt, const char *arg) +static enum option_code +parse_bool(bool *opt, const char *arg) { *opt = (!strcmp(arg, "1") || !strcmp(arg, "true") || !strcmp(arg, "yes")) ? TRUE : FALSE; - return OK; + return OPT_OK; } -static int parse_enum_do(unsigned int *opt, const char *arg, - const struct enum_map *map, size_t map_size) +static enum option_code +parse_enum_do(unsigned int *opt, const char *arg, + const struct enum_map *map, size_t map_size) { bool is_true; assert(map_size > 1); if (map_enum_do(map, map_size, (int *) opt, arg)) - return OK; - - if (parse_bool(&is_true, arg) != OK) - return ERR; + return OPT_OK; + parse_bool(&is_true, arg); *opt = is_true ? map[1].value : map[0].value; - return OK; + return OPT_OK; } #define parse_enum(opt, arg, map) \ parse_enum_do(opt, arg, map, ARRAY_SIZE(map)) -static int +static enum option_code parse_string(char *opt, const char *arg, size_t optsize) { int arglen = strlen(arg); @@ -1959,30 +1979,24 @@ parse_string(char *opt, const char *arg, size_t optsize) switch (arg[0]) { case '\"': case '\'': - if (arglen == 1 || arg[arglen - 1] != arg[0]) { - config_msg = "Unmatched quotation"; - return ERR; - } + if (arglen == 1 || arg[arglen - 1] != arg[0]) + return OPT_ERR_UNMATCHED_QUOTATION; arg += 1; arglen -= 2; default: string_ncopy_do(opt, optsize, arg, arglen); - return OK; + return OPT_OK; } } /* Wants: name = value */ -static int +static enum option_code option_set_command(int argc, const char *argv[]) { - if (argc != 3) { - config_msg = "Wrong number of arguments given to set command"; - return ERR; - } + if (argc != 3) + return OPT_ERR_WRONG_NUMBER_OF_ARGUMENTS; - if (strcmp(argv[1], "=")) { - config_msg = "No value assigned"; - return ERR; - } + if (strcmp(argv[1], "=")) + return OPT_ERR_NO_VALUE_ASSIGNED; if (!strcmp(argv[0], "show-author")) return parse_enum(&opt_author, argv[2], author_map); @@ -2023,33 +2037,26 @@ option_set_command(int argc, const char *argv[]) if (!strcmp(argv[0], "status-untracked-dirs")) return parse_bool(&opt_untracked_dirs_content, argv[2]); - config_msg = "Unknown variable name"; - return ERR; + return OPT_ERR_UNKNOWN_VARIABLE_NAME; } /* Wants: mode request key */ -static int +static enum option_code option_bind_command(int argc, const char *argv[]) { enum request request; int keymap = -1; int key; - if (argc < 3) { - config_msg = "Wrong number of arguments given to bind command"; - return ERR; - } + if (argc < 3) + return OPT_ERR_WRONG_NUMBER_OF_ARGUMENTS; - if (!set_keymap(&keymap, argv[0])) { - config_msg = "Unknown key map"; - return ERR; - } + if (!set_keymap(&keymap, argv[0])) + return OPT_ERR_UNKNOWN_KEY_MAP; key = get_key_value(argv[1]); - if (key == ERR) { - config_msg = "Unknown key"; - return ERR; - } + if (key == ERR) + return OPT_ERR_UNKNOWN_KEY; request = get_request(argv[2]); if (request == REQ_UNKNOWN) { @@ -2063,32 +2070,27 @@ option_bind_command(int argc, const char *argv[]) if (map_enum(&alias, obsolete, argv[2])) { if (alias != REQ_NONE) add_keybinding(keymap, alias, key); - config_msg = "Obsolete request name"; - return ERR; + return OPT_ERR_OBSOLETE_REQUEST_NAME; } } if (request == REQ_UNKNOWN && *argv[2]++ == '!') request = add_run_request(keymap, key, argv + 2); - if (request == REQ_UNKNOWN) { - config_msg = "Unknown request name"; - return ERR; - } + if (request == REQ_UNKNOWN) + return OPT_ERR_UNKNOWN_REQUEST_NAME; add_keybinding(keymap, request, key); - return OK; + return OPT_OK; } -static int +static enum option_code set_option(const char *opt, char *value) { const char *argv[SIZEOF_ARG]; int argc = 0; - if (!argv_from_string(argv, &argc, value)) { - config_msg = "Too many option arguments"; - return ERR; - } + if (!argv_from_string(argv, &argc, value)) + return OPT_ERR_TOO_MANY_OPTION_ARGUMENTS; if (!strcmp(opt, "color")) return option_color_command(argc, argv); @@ -2099,17 +2101,21 @@ set_option(const char *opt, char *value) if (!strcmp(opt, "bind")) return option_bind_command(argc, argv); - config_msg = "Unknown option command"; - return ERR; + return OPT_ERR_UNKNOWN_OPTION_COMMAND; } +struct config_state { + int lineno; + bool errors; +}; + static int read_option(char *opt, size_t optlen, char *value, size_t valuelen, void *data) { - int status = OK; + struct config_state *config = data; + enum option_code status = OPT_ERR_NO_OPTION_VALUE; - config_lineno++; - config_msg = "Internal error"; + config->lineno++; /* Check for comment markers, since read_properties() will * only ensure opt and value are split at first " \t". */ @@ -2117,11 +2123,7 @@ read_option(char *opt, size_t optlen, char *value, size_t valuelen, void *data) if (optlen == 0) return OK; - if (opt[optlen] != 0) { - config_msg = "No option value"; - status = ERR; - - } else { + if (opt[optlen] == 0) { /* Look for comment endings in the value. */ size_t len = strcspn(value, "#"); @@ -2133,10 +2135,10 @@ read_option(char *opt, size_t optlen, char *value, size_t valuelen, void *data) status = set_option(opt, value); } - if (status == ERR) { + if (status != OPT_OK) { warn("Error on line %d, near '%.*s': %s", - config_lineno, (int) optlen, opt, config_msg); - config_errors = TRUE; + config->lineno, (int) optlen, opt, option_errors[status]); + config->errors = TRUE; } /* Always keep going if errors are encountered. */ @@ -2146,17 +2148,15 @@ read_option(char *opt, size_t optlen, char *value, size_t valuelen, void *data) static void load_option_file(const char *path) { + struct config_state config = { 0, FALSE }; struct io io; /* It's OK that the file doesn't exist. */ if (!io_open(&io, "%s", path)) return; - config_lineno = 0; - config_errors = FALSE; - - if (io_load(&io, " \t", read_option, NULL) == ERR || - config_errors == TRUE) + if (io_load(&io, " \t", read_option, &config) == ERR || + config.errors == TRUE) warn("Errors while loading %s.", path); } @@ -2768,49 +2768,56 @@ redraw_display(bool clear) * Option management */ -static void -toggle_enum_option_do(unsigned int *opt, const char *help, - const struct enum_map *map, size_t size) -{ - *opt = (*opt + 1) % size; - redraw_display(FALSE); - report("Displaying %s %s", enum_name(map[*opt]), help); -} - -#define toggle_enum_option(opt, help, map) \ - toggle_enum_option_do(opt, help, map, ARRAY_SIZE(map)) - -#define toggle_date() toggle_enum_option(&opt_date, "dates", date_map) -#define toggle_author() toggle_enum_option(&opt_author, "author names", author_map) +#define TOGGLE_MENU \ + TOGGLE_(LINENO, '.', "line numbers", &opt_line_number, NULL) \ + TOGGLE_(DATE, 'D', "dates", &opt_date, date_map) \ + TOGGLE_(AUTHOR, 'A', "author names", &opt_author, author_map) \ + TOGGLE_(REV_GRAPH, 'g', "revision graph", &opt_rev_graph, NULL) \ + TOGGLE_(REFS, 'F', "reference display", &opt_show_refs, NULL) static void -toggle_view_option(bool *option, const char *help) -{ - *option = !*option; - redraw_display(FALSE); - report("%sabling %s", *option ? "En" : "Dis", help); -} - -static void -open_option_menu(void) -{ +toggle_option(enum request request) +{ + const struct { + enum request request; + const struct enum_map *map; + size_t map_size; + } data[] = { +#define TOGGLE_(id, key, help, value, map) { REQ_TOGGLE_ ## id, map, ARRAY_SIZE(map) }, + TOGGLE_MENU +#undef TOGGLE_ + }; const struct menu_item menu[] = { - { '.', "line numbers", &opt_line_number }, - { 'D', "date display", &opt_date }, - { 'A', "author display", &opt_author }, - { 'g', "revision graph display", &opt_rev_graph }, - { 'F', "reference display", &opt_show_refs }, +#define TOGGLE_(id, key, help, value, map) { key, help, value }, + TOGGLE_MENU +#undef TOGGLE_ { 0 } }; - int selected = 0; + int i = 0; - if (prompt_menu("Toggle option", menu, &selected)) { - if (menu[selected].data == &opt_date) - toggle_date(); - else if (menu[selected].data == &opt_author) - toggle_author(); - else - toggle_view_option(menu[selected].data, menu[selected].text); + if (request == REQ_OPTIONS) { + if (!prompt_menu("Toggle option", menu, &i)) + return; + } else { + while (i < ARRAY_SIZE(data) && data[i].request != request) + i++; + if (i >= ARRAY_SIZE(data)) + die("Invalid request (%d)", request); + } + + if (data[i].map != NULL) { + unsigned int *opt = menu[i].data; + + *opt = (*opt + 1) % data[i].map_size; + redraw_display(FALSE); + report("Displaying %s %s", enum_name(data[i].map[*opt]), menu[i].text); + + } else { + bool *option = menu[i].data; + + *option = !*option; + redraw_display(FALSE); + report("%sabling %s", *option ? "En" : "Dis", menu[i].text); } } @@ -3825,27 +3832,12 @@ view_driver(struct view *view, enum request request) break; case REQ_OPTIONS: - open_option_menu(); - break; - case REQ_TOGGLE_LINENO: - toggle_view_option(&opt_line_number, "line numbers"); - break; - case REQ_TOGGLE_DATE: - toggle_date(); - break; - case REQ_TOGGLE_AUTHOR: - toggle_author(); - break; - case REQ_TOGGLE_REV_GRAPH: - toggle_view_option(&opt_rev_graph, "revision graph display"); - break; - case REQ_TOGGLE_REFS: - toggle_view_option(&opt_show_refs, "reference display"); + toggle_option(request); break; case REQ_TOGGLE_SORT_FIELD: @@ -7592,19 +7584,19 @@ set_remote_branch(const char *name, const char *value, size_t valuelen) } static void -set_repo_config_option(char *name, char *value, int (*cmd)(int, const char **)) +set_repo_config_option(char *name, char *value, enum option_code (*cmd)(int, const char **)) { const char *argv[SIZEOF_ARG] = { name, "=" }; int argc = 1 + (cmd == option_set_command); - int error = ERR; + enum option_code error; if (!argv_from_string(argv, &argc, value)) - config_msg = "Too many option arguments"; + error = OPT_ERR_TOO_MANY_OPTION_ARGUMENTS; else error = cmd(argc, argv); - if (error == ERR) - warn("Option 'tig.%s': %s", name, config_msg); + if (error != OPT_OK) + warn("Option 'tig.%s': %s", name, option_errors[error]); } static bool