unsigned int next:1; /* For ref lists: are there more refs? */
};
-struct commit {
- char id[41]; /* SHA1 ID. */
- char title[75]; /* The first line of the commit message. */
- char author[75]; /* The author of the commit. */
- struct tm time; /* Date from the author ident. */
- struct ref **refs; /* Repository references; tags & branch heads. */
-};
+static struct ref **get_refs(char *id);
/*
const char *cmd_fmt; /* Default command line format */
const char *cmd_env; /* Command line set via environment */
const char *id; /* Points to either of ref_{head,commit} */
- size_t objsize; /* Size of objects in the line index */
struct view_ops {
/* What type of content being displayed. Used in the
unsigned long offset; /* Offset of the window top */
unsigned long lineno; /* Current line number */
+ /* If non-NULL, points to the view that opened this view. If this view
+ * is closed tig will switch back to the parent view. */
+ struct view *parent;
+
/* Buffering */
unsigned long lines; /* Total number of lines */
void **line; /* Line index; each line contains user data */
static struct view_ops pager_ops;
static struct view_ops main_ops;
-#define VIEW_STR(name, cmd, env, ref, objsize, ops) \
- { name, cmd, #env, ref, objsize, ops }
+#define VIEW_STR(name, cmd, env, ref, ops) \
+ { name, cmd, #env, ref, ops }
-#define VIEW_(id, name, ops, ref, objsize) \
- VIEW_STR(name, TIG_##id##_CMD, TIG_##id##_CMD, ref, objsize, ops)
+#define VIEW_(id, name, ops, ref) \
+ VIEW_STR(name, TIG_##id##_CMD, TIG_##id##_CMD, ref, ops)
/**
* Views
**/
static struct view views[] = {
- VIEW_(MAIN, "main", &main_ops, ref_head, sizeof(struct commit)),
- VIEW_(DIFF, "diff", &pager_ops, ref_commit, sizeof(char)),
- VIEW_(LOG, "log", &pager_ops, ref_head, sizeof(char)),
- VIEW_(HELP, "help", &pager_ops, "static", sizeof(char)),
- VIEW_(PAGER, "pager", &pager_ops, "static", sizeof(char)),
+ VIEW_(MAIN, "main", &main_ops, ref_head),
+ VIEW_(DIFF, "diff", &pager_ops, ref_commit),
+ VIEW_(LOG, "log", &pager_ops, ref_head),
+ VIEW_(HELP, "help", &pager_ops, "static"),
+ VIEW_(PAGER, "pager", &pager_ops, "static"),
};
#define VIEW(req) (&views[(req) - REQ_OFFSET - 1])
bool split = !!(flags & OPEN_SPLIT);
bool reload = !!(flags & OPEN_RELOAD);
struct view *view = VIEW(request);
- struct view *displayed;
- int nviews;
-
- /* Cycle between displayed views and count the views. */
- foreach_view (displayed, nviews) {
- if (prev != view &&
- view == displayed &&
- !strcmp(view->vid, prev->vid)) {
- current_view = nviews;
- /* Blur out the title of the previous view. */
- update_view_title(prev);
- report("");
- return;
- }
- }
+ int nviews = display[1] ? 2 : 1;
if (view == prev && nviews == 1 && !reload) {
report("Already in %s view", view->name);
/* Continue loading split views in the background. */
if (!split)
end_update(prev);
+ view->parent = prev;
}
if (view->pipe) {
return TRUE;
case REQ_VIEW_CLOSE:
- if (display[1]) {
- view = display[(current_view + 1) % ARRAY_SIZE(display)];
+ if (view->parent) {
memset(display, 0, sizeof(display));
current_view = 0;
- display[current_view] = view;
+ display[current_view] = view->parent;
+ view->parent = NULL;
resize_display();
redraw_display();
break;
/*
- * View backend handlers
+ * Pager backend
*/
static bool
pager_enter(struct view *view)
{
char *line = view->line[view->lineno];
+ int split = 0;
- if (view == VIEW(REQ_VIEW_DIFF)) {
- scroll_view(view, REQ_SCROLL_LINE_DOWN);
- return TRUE;
+ if ((view == VIEW(REQ_VIEW_LOG) ||
+ view == VIEW(REQ_VIEW_PAGER)) &&
+ get_line_type(line) == LINE_COMMIT) {
+ open_view(view, REQ_VIEW_DIFF, OPEN_SPLIT);
+ split = 1;
}
- if (get_line_type(line) == LINE_COMMIT) {
- if (view == VIEW(REQ_VIEW_LOG))
- open_view(view, REQ_VIEW_DIFF, OPEN_SPLIT | OPEN_BACKGROUNDED);
- else
- open_view(view, REQ_VIEW_DIFF, OPEN_DEFAULT);
- }
+ /* Always scroll the view even if it was split. That way
+ * you can use Enter to scroll through the log view and
+ * split open each commit diff. */
+ scroll_view(view, REQ_SCROLL_LINE_DOWN);
+
+ /* FIXME: A minor workaround. Scrolling the view will call report("")
+ * but if we are scolling a non-current view this won't properly update
+ * the view title. */
+ if (split)
+ update_view_title(view);
return TRUE;
}
};
-static struct ref **get_refs(char *id);
+/*
+ * Main view backend
+ */
+
+struct commit {
+ char id[41]; /* SHA1 ID. */
+ char title[75]; /* The first line of the commit message. */
+ char author[75]; /* The author of the commit. */
+ struct tm time; /* Date from the author ident. */
+ struct ref **refs; /* Repository references; tags & branch heads. */
+};
static bool
main_draw(struct view *view, unsigned int lineno)
* h::
* Show man page.
* q::
- * Close view if multiple views are open, else quit.
+ * Close view, if multiple views are open it will jump back to the
+ * previous view in the view stack. If it is the last open view it
+ * will quit. Use 'Q' to quit all views at once.
* Enter::
* This key is "context sensitive" depending on what view you are
* currently in. When in log view on a commit line or in the main
static struct ref *refs;
static size_t refs_size;
+/* Id <-> ref store */
+static struct ref ***id_refs;
+static size_t id_refs_size;
+
static struct ref **
get_refs(char *id)
{
- struct ref **id_refs = NULL;
- size_t id_refs_size = 0;
+ struct ref ***tmp_id_refs;
+ struct ref **ref_list = NULL;
+ size_t ref_list_size = 0;
size_t i;
+ for (i = 0; i < id_refs_size; i++)
+ if (!strcmp(id, id_refs[i][0]->id))
+ return id_refs[i];
+
+ tmp_id_refs = realloc(id_refs, (id_refs_size + 1) * sizeof(*id_refs));
+ if (!tmp_id_refs)
+ return NULL;
+
+ id_refs = tmp_id_refs;
+
for (i = 0; i < refs_size; i++) {
struct ref **tmp;
if (strcmp(id, refs[i].id))
continue;
- tmp = realloc(id_refs, (id_refs_size + 1) * sizeof(*id_refs));
+ tmp = realloc(ref_list, (ref_list_size + 1) * sizeof(*ref_list));
if (!tmp) {
- if (id_refs)
- free(id_refs);
+ if (ref_list)
+ free(ref_list);
return NULL;
}
- id_refs = tmp;
- if (id_refs_size > 0)
- id_refs[id_refs_size - 1]->next = 1;
- id_refs[id_refs_size] = &refs[i];
+ ref_list = tmp;
+ if (ref_list_size > 0)
+ ref_list[ref_list_size - 1]->next = 1;
+ ref_list[ref_list_size] = &refs[i];
/* XXX: The properties of the commit chains ensures that we can
* safely modify the shared ref. The repo references will
* always be similar for the same id. */
- id_refs[id_refs_size]->next = 0;
- id_refs_size++;
+ ref_list[ref_list_size]->next = 0;
+ ref_list_size++;
}
- return id_refs;
+ if (ref_list)
+ id_refs[id_refs_size++] = ref_list;
+
+ return ref_list;
}
static int
pclose(pipe);
- if (refs_size == 0)
- die("Not a git repository");
-
return OK;
}
if (load_refs() == ERR)
die("Failed to load refs.");
+ /* Require a git repository unless when running in pager mode. */
+ if (refs_size == 0 && opt_request != REQ_VIEW_PAGER)
+ die("Not a git repository");
+
for (i = 0; i < ARRAY_SIZE(views) && (view = &views[i]); i++)
view->cmd_env = getenv(view->cmd_env);