static bool set_color(int *color, const char *name) { if (map_enum(color, color_map, name)) return TRUE; /* Git expects a plain int w/o prefix, however, color<int> is * the preferred Tig color notation. */ if (!prefixcmp(name, "color")) name += 5; return string_isnumber(name) && parse_int(color, name, 0, 255) == SUCCESS; }
static enum request parse_options(int argc, const char *argv[], bool pager_mode) { enum request request; const char *subcommand; bool seen_dashdash = false; bool rev_parse = true; const char **filter_argv = NULL; int i; request = pager_mode ? REQ_VIEW_PAGER : REQ_VIEW_MAIN; if (argc <= 1) return request; subcommand = argv[1]; if (!strcmp(subcommand, "status")) { request = REQ_VIEW_STATUS; } else if (!strcmp(subcommand, "blame")) { request = REQ_VIEW_BLAME; } else if (!strcmp(subcommand, "grep")) { request = REQ_VIEW_GREP; rev_parse = false; } else if (!strcmp(subcommand, "show")) { request = REQ_VIEW_DIFF; } else if (!strcmp(subcommand, "log")) { request = REQ_VIEW_LOG; } else if (!strcmp(subcommand, "stash")) { request = REQ_VIEW_STASH; } else if (!strcmp(subcommand, "refs")) { request = REQ_VIEW_REFS; } else { subcommand = NULL; } for (i = 1 + !!subcommand; i < argc; i++) { const char *opt = argv[i]; // stop parsing our options after -- and let rev-parse handle the rest if (!seen_dashdash) { if (!strcmp(opt, "--")) { seen_dashdash = true; continue; } else if (!strcmp(opt, "-v") || !strcmp(opt, "--version")) { printf("tig version %s\n", TIG_VERSION); exit(EXIT_SUCCESS); } else if (!strcmp(opt, "-h") || !strcmp(opt, "--help")) { printf("%s\n", usage_string); exit(EXIT_SUCCESS); } else if (strlen(opt) >= 2 && *opt == '+' && string_isnumber(opt + 1)) { int lineno = atoi(opt + 1); argv_env.goto_lineno = lineno > 0 ? lineno - 1 : 0; continue; } } if (!argv_append(&filter_argv, opt)) die("command too long"); } if (filter_argv) filter_options(filter_argv, rev_parse); return request; }
static enum request run_prompt_command(struct view *view, char *cmd) { enum request request; if (cmd && string_isnumber(cmd)) { int lineno = view->pos.lineno + 1; if (parse_int(&lineno, cmd, 1, view->lines + 1) == SUCCESS) { select_view_line(view, lineno - 1); report_clear(); } else { report("Unable to parse '%s' as a line number", cmd); } } else if (cmd && iscommit(cmd)) { string_ncopy(view->env->search, cmd, strlen(cmd)); request = view_request(view, REQ_JUMP_COMMIT); if (request == REQ_JUMP_COMMIT) { report("Jumping to commits is not supported by the '%s' view", view->name); } } else if (cmd && strlen(cmd) == 1) { struct key_input input = { { cmd[0] } }; return get_keybinding(&view->ops->keymap, &input); } else if (cmd && cmd[0] == '!') { struct view *next = VIEW(REQ_VIEW_PAGER); const char *argv[SIZEOF_ARG]; int argc = 0; cmd++; /* When running random commands, initially show the * command in the title. However, it maybe later be * overwritten if a commit line is selected. */ string_ncopy(next->ref, cmd, strlen(cmd)); if (!argv_from_string(argv, &argc, cmd)) { report("Too many arguments"); } else if (!argv_format(view->env, &next->argv, argv, FALSE, TRUE)) { report("Argument formatting failed"); } else { next->dir = NULL; open_view(view, REQ_VIEW_PAGER, OPEN_PREPARED); } } else if (cmd) { request = get_request(cmd); if (request != REQ_UNKNOWN) return request; char *args = strchr(cmd, ' '); if (args) { *args++ = 0; if (set_option(cmd, args) == SUCCESS) { request = !view->unrefreshable ? REQ_REFRESH : REQ_SCREEN_REDRAW; if (!strcmp(cmd, "color")) init_colors(); } } return request; } return REQ_NONE; }
enum request run_prompt_command(struct view *view, const char *argv[]) { enum request request; const char *cmd = argv[0]; size_t cmdlen = cmd ? strlen(cmd) : 0; if (!cmd) return REQ_NONE; if (string_isnumber(cmd)) { int lineno = view->pos.lineno + 1; if (parse_int(&lineno, cmd, 0, view->lines + 1) == SUCCESS) { if (!lineno) lineno = 1; select_view_line(view, lineno - 1); report_clear(); } else { report("Unable to parse '%s' as a line number", cmd); } } else if (iscommit(cmd)) { int lineno; if (!(view->ops->column_bits & view_column_bit(ID))) { report("Jumping to commits is not supported by the %s view", view->name); return REQ_NONE; } for (lineno = 0; lineno < view->lines; lineno++) { struct view_column_data column_data = {}; struct line *line = &view->line[lineno]; if (view->ops->get_column_data(view, line, &column_data) && column_data.id && !strncasecmp(column_data.id, cmd, cmdlen)) { string_ncopy(view->env->search, cmd, cmdlen); select_view_line(view, lineno); report_clear(); return REQ_NONE; } } report("Unable to find commit '%s'", view->env->search); return REQ_NONE; } else if (cmdlen > 1 && (cmd[0] == '/' || cmd[0] == '?')) { char search[SIZEOF_STR]; if (!argv_to_string(argv, search, sizeof(search), " ")) { report("Failed to copy search string"); return REQ_NONE; } if (!strcmp(search + 1, view->env->search)) return cmd[0] == '/' ? REQ_FIND_NEXT : REQ_FIND_PREV; string_ncopy(view->env->search, search + 1, strlen(search + 1)); return cmd[0] == '/' ? REQ_SEARCH : REQ_SEARCH_BACK; } else if (cmdlen > 1 && cmd[0] == '!') { struct view *next = &pager_view; bool copied; /* Trim the leading '!'. */ argv[0] = cmd + 1; copied = argv_format(view->env, &next->argv, argv, FALSE, TRUE); argv[0] = cmd; if (!copied) { report("Argument formatting failed"); } else { /* When running random commands, initially show the * command in the title. However, it maybe later be * overwritten if a commit line is selected. */ argv_to_string(next->argv, next->ref, sizeof(next->ref), " "); next->dir = NULL; open_pager_view(view, OPEN_PREPARED | OPEN_WITH_STDERR); } } else if (!strcmp(cmd, "save-display")) { const char *path = argv[1] ? argv[1] : "tig-display.txt"; if (!save_display(path)) report("Failed to save screen to %s", path); else report("Saved screen to %s", path); } else if (!strcmp(cmd, "exec")) { struct run_request req = { view->keymap, {}, argv + 1 }; enum status_code code = parse_run_request_flags(&req.flags, argv + 1); if (code != SUCCESS) { report("Failed to execute command: %s", get_status_message(code)); } else { return exec_run_request(view, &req); } } else if (!strcmp(cmd, "toggle")) { enum view_flag flags = VIEW_NO_FLAGS; enum status_code code = prompt_toggle(view, argv, &flags); const char *action = get_status_message(code); if (code != SUCCESS) { report("%s", action); return REQ_NONE; } prompt_update_display(flags); if (*action) report("%s", action); } else if (!strcmp(cmd, "script")) { if (is_script_executing()) { report("Scripts cannot be run from scripts"); } else if (!open_script(argv[1])) { report("Failed to open %s", argv[1]); } } else { struct key key = {}; enum status_code code; enum view_flag flags = VIEW_NO_FLAGS; /* Try :<key> */ key.modifiers.multibytes = 1; string_ncopy(key.data.bytes, cmd, cmdlen); request = get_keybinding(view->keymap, &key, 1); if (request != REQ_NONE) return request; /* Try :<command> */ request = get_request(cmd); if (request != REQ_UNKNOWN) return request; code = set_option(argv[0], argv_size(argv + 1), &argv[1]); if (code != SUCCESS) { report("%s", get_status_message(code)); return REQ_NONE; } if (!strcmp(cmd, "set")) { struct prompt_toggle *toggle; toggle = find_prompt_toggle(option_toggles, ARRAY_SIZE(option_toggles), "", argv[1], strlen(argv[1])); if (toggle) flags = toggle->flags; } if (flags) { prompt_update_display(flags); } else { request = view_can_refresh(view) ? REQ_REFRESH : REQ_SCREEN_REDRAW; if (!strcmp(cmd, "color")) init_colors(); resize_display(); redraw_display(TRUE); } } return REQ_NONE; }
static enum request parse_options(int argc, const char *argv[], bool pager_mode) { enum request request; const char *subcommand; bool seen_dashdash = false; bool rev_parse = true; const char **filter_argv = NULL; int i; request = pager_mode ? REQ_VIEW_PAGER : REQ_VIEW_MAIN; /* Options that must come before any subcommand. */ for (i = 1; i < argc; i++) { const char *opt = argv[i]; if (!strncmp(opt, "-C", 2)) { if (chdir(opt + 2)) die("Failed to change directory to %s", opt + 2); continue; } else { break; } } if (i >= argc) return request; subcommand = argv[i++]; if (!strcmp(subcommand, "status")) { request = REQ_VIEW_STATUS; } else if (!strcmp(subcommand, "blame")) { request = REQ_VIEW_BLAME; } else if (!strcmp(subcommand, "grep")) { request = REQ_VIEW_GREP; rev_parse = false; } else if (!strcmp(subcommand, "show")) { request = REQ_VIEW_DIFF; } else if (!strcmp(subcommand, "log")) { request = REQ_VIEW_LOG; } else if (!strcmp(subcommand, "stash")) { request = REQ_VIEW_STASH; } else if (!strcmp(subcommand, "refs")) { request = REQ_VIEW_REFS; } else { subcommand = NULL; i--; /* revisit option in loop below */ } for (; i < argc; i++) { const char *opt = argv[i]; // stop parsing our options after -- and let rev-parse handle the rest if (!seen_dashdash) { if (!strcmp(opt, "--")) { seen_dashdash = true; } else if (!strcmp(opt, "-v") || !strcmp(opt, "--version")) { printf("tig version %s\n", TIG_VERSION); #ifdef NCURSES_VERSION printf("%s version %s.%d\n", #ifdef NCURSES_WIDECHAR "ncursesw", #else "ncurses", #endif NCURSES_VERSION, NCURSES_VERSION_PATCH); #endif #ifdef HAVE_READLINE printf("readline version %s\n", rl_library_version); #endif exit(EXIT_SUCCESS); } else if (!strcmp(opt, "-h") || !strcmp(opt, "--help")) { printf("%s\n", usage_string); exit(EXIT_SUCCESS); } else if (strlen(opt) >= 2 && *opt == '+' && string_isnumber(opt + 1)) { int lineno = atoi(opt + 1); argv_env.goto_lineno = lineno > 0 ? lineno - 1 : 0; continue; } } if (!argv_append(&filter_argv, opt)) die("command too long"); } if (filter_argv) filter_options(filter_argv, rev_parse); return request; }
enum request run_prompt_command(struct view *view, const char *argv[]) { enum request request; const char *cmd = argv[0]; size_t cmdlen = cmd ? strlen(cmd) : 0; if (!cmd) return REQ_NONE; if (string_isnumber(cmd)) { int lineno = view->pos.lineno + 1; if (parse_int(&lineno, cmd, 1, view->lines + 1) == SUCCESS) { select_view_line(view, lineno - 1); report_clear(); } else { report("Unable to parse '%s' as a line number", cmd); } } else if (iscommit(cmd)) { string_ncopy(view->env->search, cmd, cmdlen); return REQ_JUMP_COMMIT; } else if (cmdlen > 1 && (cmd[0] == '/' || cmd[0] == '?')) { char search[SIZEOF_STR]; if (!argv_to_string(argv, search, sizeof(search), " ")) { report("Failed to copy search string"); return REQ_NONE; } if (!strcmp(search + 1, view->env->search)) return cmd[0] == '/' ? REQ_FIND_NEXT : REQ_FIND_PREV; string_ncopy(view->env->search, search + 1, strlen(search + 1)); return cmd[0] == '/' ? REQ_SEARCH : REQ_SEARCH_BACK; } else if (cmdlen > 1 && cmd[0] == '!') { struct view *next = &pager_view; bool copied; /* Trim the leading '!'. */ argv[0] = cmd + 1; copied = argv_format(view->env, &next->argv, argv, FALSE, TRUE); argv[0] = cmd; if (!copied) { report("Argument formatting failed"); } else { /* When running random commands, initially show the * command in the title. However, it maybe later be * overwritten if a commit line is selected. */ argv_to_string(next->argv, next->ref, sizeof(next->ref), " "); next->dir = NULL; open_pager_view(view, OPEN_PREPARED | OPEN_WITH_STDERR); } } else if (!strcmp(cmd, "toggle")) { char action[SIZEOF_STR] = ""; enum view_flag flags = prompt_toggle(view, argv, action); int i; if (flags & VIEW_RESET_DISPLAY) { resize_display(); redraw_display(TRUE); } foreach_displayed_view(view, i) { if (view_has_flags(view, flags) && !view->unrefreshable) reload_view(view); else redraw_view(view); } if (*action) report("%s", action); } else {