static enum view_flag prompt_toggle(struct view *view, const char *argv[], char msg[SIZEOF_STR]) { struct prompt_toggle option_toggles[] = { #define TOGGLE_OPTIONS(name, type, flags) { #name, #type, flags, &opt_ ## name }, OPTION_INFO(TOGGLE_OPTIONS) }; const char *option = argv[1]; size_t optionlen = option ? strlen(option) : 0; struct prompt_toggle *toggle; if (!option) { string_format_size(msg, SIZEOF_STR, "%s", "No option name given to :toggle"); return VIEW_NO_FLAGS; } if (enum_equals_static("sort-field", option, optionlen) || enum_equals_static("sort-order", option, optionlen)) { if (!view_has_flags(view, VIEW_SORTABLE)) { report("Sorting is not yet supported for the %s view", view->name); } else { bool sort_field = enum_equals_static("sort-field", option, optionlen); struct sort_state *sort = &view->sort; sort_view(view, sort_field); string_format_size(msg, SIZEOF_STR, "set %s = %s", option, sort_field ? enum_name(view_column_type_map->entries[get_sort_field(view)]) : sort->reverse ? "descending" : "ascending"); } return VIEW_NO_FLAGS; } toggle = find_prompt_toggle(option_toggles, ARRAY_SIZE(option_toggles), option, optionlen); if (toggle) return prompt_toggle_option(view, argv, toggle, msg); string_format_size(msg, SIZEOF_STR, "`:toggle %s` not supported", option); return VIEW_NO_FLAGS; }
static enum view_flag toggle_option(struct view *view, enum request request, char msg[SIZEOF_STR]) { const struct { enum request request; const struct enum_map *map; enum view_flag reload_flags; } data[] = { #define DEFINE_TOGGLE_DATA(id, key, help, value, map, vflags) { REQ_TOGGLE_ ## id, map, vflags } TOGGLE_MENU_INFO(DEFINE_TOGGLE_DATA) }; const struct menu_item menu[] = { #define DEFINE_TOGGLE_MENU(id, key, help, value, map, vflags) { key, help, value } TOGGLE_MENU_INFO(DEFINE_TOGGLE_MENU) { 0 } }; int i = 0; if (request == REQ_OPTIONS) { if (!prompt_menu("Toggle option", menu, &i)) return VIEW_NO_FLAGS; } 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; if (data[i].map == ignore_space_map) { string_format_size(msg, SIZEOF_STR, "Ignoring %s %s", enum_name(data[i].map->entries[*opt]), menu[i].text); } else if (data[i].map == commit_order_map) { string_format_size(msg, SIZEOF_STR, "Using %s %s", enum_name(data[i].map->entries[*opt]), menu[i].text); } else { string_format_size(msg, SIZEOF_STR, "Displaying %s %s", enum_name(data[i].map->entries[*opt]), menu[i].text); } } else if (menu[i].data == &opt_title_overflow) { int *option = menu[i].data; *option = *option ? -*option : 50; string_format_size(msg, SIZEOF_STR, "%sabling %s", *option > 0 ? "En" : "Dis", menu[i].text); } else { bool *option = menu[i].data; *option = !*option; string_format_size(msg, SIZEOF_STR, "%sabling %s", *option ? "En" : "Dis", menu[i].text); } return data[i].reload_flags; }
static enum view_flag prompt_toggle_option(struct view *view, const char *argv[], struct prompt_toggle *toggle, char msg[SIZEOF_STR]) { char name[SIZEOF_STR]; enum_name_copy(name, toggle->name, strlen(toggle->name)); if (!strcmp(toggle->type, "bool")) { bool *opt = toggle->opt; *opt = !*opt; string_format_size(msg, SIZEOF_STR, "set %s = %s", name, *opt ? "yes" : "no"); } else if (!strncmp(toggle->type, "enum", 4)) { const char *type = toggle->type + STRING_SIZE("enum "); enum author *opt = toggle->opt; const struct enum_map *map = find_enum_map(type); *opt = (*opt + 1) % map->size; string_format_size(msg, SIZEOF_STR, "set %s = %s", name, enum_name(map->entries[*opt])); } else if (!strcmp(toggle->type, "int")) { const char *arg = argv[2] ? argv[2] : "1"; int diff = atoi(arg); int *opt = toggle->opt; if (!diff) diff = *arg == '-' ? -1 : 1; if (opt == &opt_diff_context && diff < 0) { if (!*opt) { report("Diff context cannot be less than zero"); return VIEW_NO_FLAGS; } if (*opt < -diff) diff = -*opt; } if (opt == &opt_title_overflow) { *opt = *opt ? -*opt : 50; if (*opt < 0) { string_format_size(msg, SIZEOF_STR, "set %s = no", name); return toggle->flags; } } *opt += diff; string_format_size(msg, SIZEOF_STR, "set %s = %d", name, *opt); } else if (!strcmp(toggle->type, "double")) { const char *arg = argv[2] ? argv[2] : "1.0"; double *opt = toggle->opt; int sign = 1; double diff; if (*arg == '-') { sign = -1; arg++; } if (parse_step(&diff, arg) != SUCCESS) diff = strtod(arg, NULL); *opt += sign * diff; string_format_size(msg, SIZEOF_STR, "set %s = %.2f", name, *opt); } else if (!strcmp(toggle->type, "const char **")) { const char ***opt = toggle->opt; bool found = TRUE; int i; for (i = 2; argv[i]; i++) { if (!find_arg(*opt, argv[i])) { found = FALSE; break; } } if (found) { int next, pos; for (next = 0, pos = 0; (*opt)[pos]; pos++) { const char *arg = (*opt)[pos]; if (find_arg(argv + 2, arg)) { free((void *) arg); continue; } (*opt)[next++] = arg; } (*opt)[next] = NULL; } else if (!argv_copy(opt, argv + 2)) { report("Failed to append arguments"); return VIEW_NO_FLAGS; } } else { die("Unsupported `:toggle %s` (%s)", name, toggle->type); } return toggle->flags; }