static void blame_go_forward(struct view *view, struct blame *blame, bool parent) { struct blame_state *state = view->private; struct blame_history_state *history_state = &state->history_state; struct blame_commit *commit = blame->commit; const char *id = parent ? commit->parent_id : commit->id; const char *filename = parent ? commit->parent_filename : commit->filename; if (!*id && parent) { report("The selected commit has no parents"); return; } if (!strcmp(history_state->id, id) && !strcmp(history_state->filename, filename)) { report("The selected commit is already displayed"); return; } if (!push_view_history_state(&blame_view_history, &view->pos, history_state)) { report("Failed to save current view state"); return; } string_ncopy(view->env->ref, id, sizeof(commit->id)); string_ncopy(view->env->file, filename, strlen(filename)); if (parent) setup_blame_parent_line(view, blame); view->env->lineno = blame->lineno; reload_view(view); }
static void blame_go_back(struct view *view) { struct blame_history_state history_state; if (!pop_view_history_state(&blame_view_history, &view->pos, &history_state)) { report("Already at start of history"); return; } string_copy(view->env->ref, history_state.id); string_ncopy(view->env->file, history_state.filename, strlen(history_state.filename)); view->env->lineno = view->pos.lineno; reload_view(view); }
static void prompt_update_display(enum view_flag flags) { struct view *view; int i; if (flags & VIEW_RESET_DISPLAY) { resize_display(); redraw_display(TRUE); } foreach_displayed_view(view, i) { if (view_has_flags(view, flags) && view_can_refresh(view)) reload_view(view); else redraw_view(view); } }
static enum request tree_request(struct view *view, enum request request, struct line *line) { enum open_flags flags; struct tree_entry *entry = line->data; switch (request) { case REQ_VIEW_BLAME: if (line->type != LINE_FILE) { report("Blame only supported for files"); return REQ_NONE; } string_copy(view->env->ref, view->vid); return request; case REQ_EDIT: if (line->type != LINE_FILE) { report("Edit only supported for files"); } else if (!is_head_commit(view->vid)) { open_blob_editor(entry->id, entry->name, 0); } else { open_editor(view->env->file, 0); } return REQ_NONE; case REQ_PARENT: case REQ_BACK: if (!*view->env->directory) { /* quit view if at top of tree */ return REQ_VIEW_CLOSE; } /* fake 'cd ..' */ pop_tree_stack_entry(&view->pos); reload_view(view); break; case REQ_ENTER: break; default: return request; } /* Cleanup the stack if the tree view is at a different tree. */ if (!*view->env->directory) reset_view_history(&tree_view_history); switch (line->type) { case LINE_DIRECTORY: /* Depending on whether it is a subdirectory or parent link * mangle the path buffer. */ if (tree_path_is_parent(entry->name) && *view->env->directory) { pop_tree_stack_entry(&view->pos); } else { const char *basename = tree_path(line); push_tree_stack_entry(view, basename, &view->pos); } /* Trees and subtrees share the same ID, so they are not not * unique like blobs. */ reload_view(view); break; case LINE_FILE: flags = view_is_displayed(view) ? OPEN_SPLIT : OPEN_DEFAULT; open_blob_view(view, flags); break; default: return REQ_NONE; } return REQ_NONE; }
static int view_driver(struct view *view, enum request request) { int i; if (request == REQ_NONE) return TRUE; if (request >= REQ_RUN_REQUESTS) { request = open_run_request(view, request); // exit quickly rather than going through view_request and back if (request == REQ_QUIT) return FALSE; } request = view_request(view, request); if (request == REQ_NONE) return TRUE; switch (request) { case REQ_MOVE_UP: case REQ_MOVE_DOWN: case REQ_MOVE_PAGE_UP: case REQ_MOVE_PAGE_DOWN: case REQ_MOVE_FIRST_LINE: case REQ_MOVE_LAST_LINE: move_view(view, request); break; case REQ_SCROLL_FIRST_COL: case REQ_SCROLL_LEFT: case REQ_SCROLL_RIGHT: case REQ_SCROLL_LINE_DOWN: case REQ_SCROLL_LINE_UP: case REQ_SCROLL_PAGE_DOWN: case REQ_SCROLL_PAGE_UP: case REQ_SCROLL_WHEEL_DOWN: case REQ_SCROLL_WHEEL_UP: scroll_view(view, request); break; case REQ_VIEW_GREP: open_grep_view(view); break; case REQ_VIEW_MAIN: case REQ_VIEW_DIFF: case REQ_VIEW_LOG: case REQ_VIEW_TREE: case REQ_VIEW_HELP: case REQ_VIEW_BRANCH: case REQ_VIEW_BLAME: case REQ_VIEW_BLOB: case REQ_VIEW_STATUS: case REQ_VIEW_STAGE: case REQ_VIEW_PAGER: case REQ_VIEW_STASH: open_view(view, request, OPEN_DEFAULT); break; case REQ_NEXT: case REQ_PREVIOUS: if (view->parent) { int line; view = view->parent; line = view->pos.lineno; view_request(view, request); move_view(view, request); if (view_is_displayed(view)) update_view_title(view); if (line != view->pos.lineno) view_request(view, REQ_ENTER); } else { move_view(view, request); } break; case REQ_VIEW_NEXT: { int nviews = displayed_views(); int next_view = (current_view + 1) % nviews; if (next_view == current_view) { report("Only one view is displayed"); break; } current_view = next_view; /* Blur out the title of the previous view. */ update_view_title(view); report_clear(); break; } case REQ_REFRESH: report("Refreshing is not supported by the %s view", view->name); break; case REQ_PARENT: report("Moving to parent is not supported by the the %s view", view->name); break; case REQ_BACK: report("Going back is not supported for by %s view", view->name); break; case REQ_MAXIMIZE: if (displayed_views() == 2) maximize_view(view, TRUE); break; case REQ_OPTIONS: case REQ_TOGGLE_LINENO: case REQ_TOGGLE_DATE: case REQ_TOGGLE_AUTHOR: case REQ_TOGGLE_FILENAME: case REQ_TOGGLE_GRAPHIC: case REQ_TOGGLE_REV_GRAPH: case REQ_TOGGLE_REFS: case REQ_TOGGLE_CHANGES: case REQ_TOGGLE_IGNORE_SPACE: case REQ_TOGGLE_ID: case REQ_TOGGLE_FILES: case REQ_TOGGLE_TITLE_OVERFLOW: case REQ_TOGGLE_FILE_SIZE: case REQ_TOGGLE_UNTRACKED_DIRS: case REQ_TOGGLE_VERTICAL_SPLIT: { char action[SIZEOF_STR] = ""; enum view_flag flags = toggle_option(view, request, action); if (flags == VIEW_FLAG_RESET_DISPLAY) { resize_display(); redraw_display(TRUE); } else { 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); } break; case REQ_TOGGLE_SORT_FIELD: case REQ_TOGGLE_SORT_ORDER: report("Sorting is not yet supported for the %s view", view->name); break; case REQ_DIFF_CONTEXT_UP: case REQ_DIFF_CONTEXT_DOWN: report("Changing the diff context is not yet supported for the %s view", view->name); break; case REQ_SEARCH: case REQ_SEARCH_BACK: search_view(view, request); break; case REQ_FIND_NEXT: case REQ_FIND_PREV: find_next(view, request); break; case REQ_STOP_LOADING: foreach_view(view, i) { if (view->pipe) report("Stopped loading the %s view", view->name), end_update(view, TRUE); } break; case REQ_SHOW_VERSION: report("tig-%s (built %s)", TIG_VERSION, __DATE__); return TRUE; case REQ_SCREEN_REDRAW: redraw_display(TRUE); break; case REQ_EDIT: report("Nothing to edit"); break; case REQ_ENTER: report("Nothing to enter"); break; case REQ_VIEW_CLOSE: /* XXX: Mark closed views by letting view->prev point to the * view itself. Parents to closed view should never be * followed. */ if (view->prev && view->prev != view) { maximize_view(view->prev, TRUE); view->prev = view; break; } /* Fall-through */ case REQ_QUIT: return FALSE; default: report("Unknown key, press %s for help", get_view_key(view, REQ_VIEW_HELP)); return TRUE; } return TRUE; }
/* Handles view data reloading key. */ static void cmd_R(key_info_t key_info, keys_info_t *keys_info) { reload_view(vi, NOSILENT); }
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 {