static void branch_select(struct view *view, struct line *line) { struct branch *branch = line->data; if (branch_is_all(branch)) { string_copy(view->ref, BRANCH_ALL_NAME); return; } string_copy_rev(view->ref, branch->ref->id); string_copy_rev(view->env->commit, branch->ref->id); string_copy_rev(view->env->head, branch->ref->id); string_copy_rev(view->env->branch, branch->ref->name); }
void ref_update_env(struct argv_env *env, const struct ref *ref, bool recurse) { bool clear = recurse ? !ref->next : true; if (recurse && ref->next) ref_update_env(env, ref->next, true); if (clear) env->tag[0] = env->remote[0] = env->branch[0] = 0; string_copy_rev(env->commit, ref->id); if (ref_is_tag(ref)) { string_ncopy(env->tag, ref->name, strlen(ref->name)); } else if (ref_is_remote(ref)) { const char *sep = strchr(ref->name, '/'); if (!sep) return; string_ncopy(env->remote, ref->name, sep - ref->name); string_ncopy(env->branch, sep + 1, strlen(sep + 1)); } else if (ref->type == REFERENCE_BRANCH || ref->type == REFERENCE_HEAD) { string_ncopy(env->branch, ref->name, strlen(ref->name)); } }
struct ref_list * get_ref_list(const char *id) { struct ref_list *list; size_t i; for (i = 0; i < ref_lists_size; i++) if (!strcmp(id, ref_lists[i]->id)) return ref_lists[i]; if (!realloc_ref_lists(&ref_lists, ref_lists_size, 1)) return NULL; list = calloc(1, sizeof(*list)); if (!list) return NULL; string_copy_rev(list->id, id); for (i = 0; i < refs_size; i++) { if (!strcmp(id, refs[i]->id) && realloc_refs_list(&list->refs, list->size, 1)) list->refs[list->size++] = refs[i]; } if (!list->refs) { free(list); return NULL; } qsort(list->refs, list->size, sizeof(*list->refs), compare_refs); ref_lists[ref_lists_size++] = list; return list; }
static void main_register_commit(struct view *view, struct commit *commit, const char *ids, bool is_boundary) { struct main_state *state = view->private; string_copy_rev(commit->id, ids); if (state->with_graph) graph_add_commit(&state->graph, &commit->graph, commit->id, ids, is_boundary); }
void pager_select(struct view *view, struct line *line) { if (line->type == LINE_COMMIT) { string_copy_rev_from_commit_line(view->env->commit, line->data); if (!view_has_flags(view, VIEW_NO_REF)) string_copy_rev(view->ref, view->env->commit); } }
static enum request blame_request(struct view *view, enum request request, struct line *line) { enum open_flags flags = view_is_displayed(view) ? OPEN_SPLIT : OPEN_DEFAULT; struct blame *blame = line->data; switch (request) { case REQ_VIEW_BLAME: case REQ_PARENT: if (!check_blame_commit(blame, TRUE)) break; blame_go_forward(view, blame, request == REQ_PARENT); break; case REQ_BACK: blame_go_back(view); break; case REQ_ENTER: if (!check_blame_commit(blame, FALSE)) break; if (view_is_displayed(VIEW(REQ_VIEW_DIFF)) && !strcmp(blame->commit->id, VIEW(REQ_VIEW_DIFF)->ref)) break; if (string_rev_is_null(blame->commit->id)) { struct view *diff = VIEW(REQ_VIEW_DIFF); const char *diff_parent_argv[] = { GIT_DIFF_BLAME(encoding_arg, opt_diff_context_arg, opt_ignore_space_arg, view->vid) }; const char *diff_no_parent_argv[] = { GIT_DIFF_BLAME_NO_PARENT(encoding_arg, opt_diff_context_arg, opt_ignore_space_arg, view->vid) }; const char **diff_index_argv = *blame->commit->parent_id ? diff_parent_argv : diff_no_parent_argv; open_argv(view, diff, diff_index_argv, NULL, flags); if (diff->pipe) string_copy_rev(diff->ref, NULL_ID); } else { open_view(view, REQ_VIEW_DIFF, flags); } break; default: return request; } return REQ_NONE; }
static void tree_select(struct view *view, struct line *line) { struct tree_entry *entry = line->data; if (line->type == LINE_HEADER) { string_format(view->ref, "Files in /%s", view->env->directory); return; } if (line->type == LINE_DIRECTORY && tree_path_is_parent(entry->name)) { string_copy(view->ref, "Open parent directory"); view->env->blob[0] = 0; return; } if (line->type == LINE_FILE) { string_copy_rev(view->env->blob, entry->id); string_format(view->env->file, "%s%s", view->env->directory, tree_path(line)); } string_copy_rev(view->ref, entry->id); }
void ref_update_env(struct argv_env *env, const struct ref *ref, bool clear) { if (clear) env->tag[0] = env->remote[0] = env->branch[0] = 0; string_copy_rev(env->commit, ref->id); if (ref_is_tag(ref)) { string_copy_rev(env->tag, ref->name); } else if (ref_is_remote(ref)) { const char *sep = strchr(ref->name, '/'); if (!sep) return; string_ncopy(env->remote, ref->name, sep - ref->name); string_copy_rev(env->branch, sep + 1); } else if (ref->type == REFERENCE_BRANCH) { string_copy_rev(env->branch, ref->name); } }
static void blame_select(struct view *view, struct line *line) { struct blame *blame = line->data; struct blame_commit *commit = blame->commit; if (!commit) return; if (string_rev_is_null(commit->id)) string_ncopy(view->env->commit, "HEAD", 4); else string_copy_rev(view->env->commit, commit->id); }
static void main_register_commit(struct view *view, struct commit *commit, const char *ids, bool is_boundary) { struct main_state *state = view->private; string_copy_rev(commit->id, ids); /* FIXME: lazily check index state here instead of in main_open. */ if ((state->add_changes_unstaged || state->add_changes_staged) && is_head_commit(commit->id)) { main_add_changes(view, state, ids); state->add_changes_unstaged = state->add_changes_staged = FALSE; } if (state->with_graph) graph_add_commit(state->graph, &commit->graph, commit->id, ids, is_boundary); }
static struct line * tree_entry(struct view *view, enum line_type type, const char *path, const char *mode, const char *id, unsigned long size) { bool custom = type == LINE_HEADER || tree_path_is_parent(path); struct tree_entry *entry; struct line *line = add_line_alloc(view, &entry, type, strlen(path), custom); if (!line) return NULL; strncpy(entry->name, path, strlen(path)); if (mode) entry->mode = strtoul(mode, NULL, 8); if (id) string_copy_rev(entry->id, id); entry->size = size; return line; }
static void log_select(struct view *view, struct line *line) { struct log_state *state = view->private; int last_lineno = state->last_lineno; if (!last_lineno || abs(last_lineno - line->lineno) > 1 || (state->last_type == LINE_COMMIT && last_lineno > line->lineno)) { struct line *commit_line = find_prev_line_by_type(view, line, LINE_COMMIT); if (commit_line) log_copy_rev(view, commit_line); } if (line->type == LINE_COMMIT && !view_has_flags(view, VIEW_NO_REF)) log_copy_rev(view, line); string_copy_rev(view->env->commit, view->ref); state->last_lineno = line->lineno; state->last_type = line->type; }
bool parse_blame_info(struct blame_commit *commit, char author[SIZEOF_STR], char *line) { if (match_blame_header("author ", &line)) { string_ncopy_do(author, SIZEOF_STR, line, strlen(line)); } else if (match_blame_header("author-mail ", &line)) { char *end = strchr(line, '>'); if (end) *end = 0; if (*line == '<') line++; commit->author = get_author(author, line); author[0] = 0; } else if (match_blame_header("author-time ", &line)) { parse_timesec(&commit->time, line); } else if (match_blame_header("author-tz ", &line)) { parse_timezone(&commit->time, line); } else if (match_blame_header("summary ", &line)) { string_ncopy(commit->title, line, strlen(line)); } else if (match_blame_header("previous ", &line)) { if (strlen(line) <= SIZEOF_REV) return FALSE; string_copy_rev(commit->parent_id, line); line += SIZEOF_REV; commit->parent_filename = get_path(line); if (!commit->parent_filename) return TRUE; } else if (match_blame_header("filename ", &line)) { commit->filename = get_path(line); return TRUE; } return FALSE; }
void string_copy_rev_from_commit_line(char *dst, const char *src) { string_copy_rev(dst, src + STRING_SIZE("commit ")); }
static bool tree_read_date(struct view *view, struct buffer *buf, struct tree_state *state) { char *text = buf ? buf->data : NULL; if (!text && state->read_date) { state->read_date = FALSE; return TRUE; } else if (!text) { /* Find next entry to process */ const char *log_file[] = { "git", "log", encoding_arg, "--no-color", "--pretty=raw", "--cc", "--raw", view->ops->id, "--", "%(directory)", NULL }; if (!view->lines) { tree_entry(view, LINE_HEADER, view->env->directory, NULL, NULL, 0); tree_entry(view, LINE_DIRECTORY, "..", "040000", view->ref, 0); report("Tree is empty"); return TRUE; } if (!begin_update(view, repo.cdup, log_file, OPEN_EXTRA)) { report("Failed to load tree data"); return TRUE; } state->read_date = TRUE; return FALSE; } else if (*text == 'c' && get_line_type(text) == LINE_COMMIT) { string_copy_rev_from_commit_line(state->commit, text); } else if (*text == 'a' && get_line_type(text) == LINE_AUTHOR) { parse_author_line(text + STRING_SIZE("author "), &state->author, &state->author_time); } else if (*text == ':') { char *pos; size_t annotated = 1; size_t i; pos = strrchr(text, '\t'); if (!pos) return TRUE; text = pos + 1; if (*view->env->directory && !strncmp(text, view->env->directory, strlen(view->env->directory))) text += strlen(view->env->directory); pos = strchr(text, '/'); if (pos) *pos = 0; for (i = 1; i < view->lines; i++) { struct line *line = &view->line[i]; struct tree_entry *entry = line->data; annotated += !!entry->author; if (entry->author || strcmp(entry->name, text)) continue; string_copy_rev(entry->commit, state->commit); entry->author = state->author; entry->time = state->author_time; line->dirty = 1; view_column_info_update(view, line); break; } if (annotated == view->lines) io_kill(view->pipe); } return TRUE; }
static bool blame_open(struct view *view, enum open_flags flags) { struct blame_state *state = view->private; const char *file_argv[] = { repo.cdup, view->env->file , NULL }; char path[SIZEOF_STR]; size_t i; if (is_initial_view(view)) { /* Finish validating and setting up blame options */ if (!opt_file_argv || opt_file_argv[1] || (opt_rev_argv && opt_rev_argv[1])) usage("Invalid number of options to blame"); if (opt_rev_argv) { string_ncopy(view->env->ref, opt_rev_argv[0], strlen(opt_rev_argv[0])); } string_ncopy(view->env->file, opt_file_argv[0], strlen(opt_file_argv[0])); opt_blame_options = opt_cmdline_argv; opt_cmdline_argv = NULL; } if (!view->env->file[0]) { report("No file chosen, press %s to open tree view", get_view_key(view, REQ_VIEW_TREE)); return FALSE; } if (!view->prev && *repo.prefix && !(flags & (OPEN_RELOAD | OPEN_REFRESH))) { string_copy(path, view->env->file); if (!string_format(view->env->file, "%s%s", repo.prefix, path)) { report("Failed to setup the blame view"); return FALSE; } } if (*view->env->ref || !begin_update(view, repo.cdup, file_argv, flags)) { const char *blame_cat_file_argv[] = { "git", "cat-file", "blob", "%(ref):%(file)", NULL }; if (!begin_update(view, repo.cdup, blame_cat_file_argv, flags)) return FALSE; } /* First pass: remove multiple references to the same commit. */ for (i = 0; i < view->lines; i++) { struct blame *blame = view->line[i].data; if (blame->commit && blame->commit->id[0]) blame->commit->id[0] = 0; else blame->commit = NULL; } /* Second pass: free existing references. */ for (i = 0; i < view->lines; i++) { struct blame *blame = view->line[i].data; if (blame->commit) free(blame->commit); } if (!(flags & OPEN_RELOAD)) reset_view_history(&blame_view_history); string_copy_rev(state->history_state.id, view->env->ref); state->history_state.filename = get_path(view->env->file); if (!state->history_state.filename) return FALSE; string_format(view->vid, "%s", view->env->file); string_format(view->ref, "%s ...", view->env->file); return TRUE; }