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 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; }