#define SIZEOF_REVGRAPH 19 /* Size of revision ancestry graphics. */
-/* Size of rev graph with no "padding" columns */
-#define SIZEOF_REVITEMS (SIZEOF_REVGRAPH - (SIZEOF_REVGRAPH / 2))
-
/* This color name can be used to refer to the default term colors. */
#define COLOR_DEFAULT (-1)
/*
- * Main view backend
+ * Revision graph
*/
struct commit {
size_t graph_size; /* The width of the graph array. */
};
+/* Size of rev graph with no "padding" columns */
+#define SIZEOF_REVITEMS (SIZEOF_REVGRAPH - (SIZEOF_REVGRAPH / 2))
+
+struct rev_graph {
+ struct rev_graph *prev, *next, *parents;
+ char rev[SIZEOF_REVITEMS][SIZEOF_REV];
+ size_t size;
+ struct commit *commit;
+ size_t pos;
+};
+
+/* Parents of the commit being visualized. */
+static struct rev_graph graph_parents[3];
+
+/* The current stack of revisions on the graph. */
+static struct rev_graph graph_stacks[3] = {
+ { &graph_stacks[2], &graph_stacks[1], &graph_parents[0] },
+ { &graph_stacks[0], &graph_stacks[2], &graph_parents[1] },
+ { &graph_stacks[1], &graph_stacks[0], &graph_parents[2] },
+};
+
+static inline bool
+graph_parent_is_merge(struct rev_graph *graph)
+{
+ return graph->parents->size > 1;
+}
+
+static inline void
+append_to_rev_graph(struct rev_graph *graph, chtype symbol)
+{
+ if (graph->commit->graph_size < ARRAY_SIZE(graph->commit->graph) - 1)
+ graph->commit->graph[graph->commit->graph_size++] = symbol;
+}
+
+static void
+done_rev_graph(struct rev_graph *graph)
+{
+ if (graph_parent_is_merge(graph) &&
+ graph->pos < graph->size - 1 &&
+ graph->next->size == graph->size + graph->parents->size - 1) {
+ size_t i = graph->pos + graph->parents->size - 1;
+
+ graph->commit->graph_size = i * 2;
+ while (i < graph->next->size - 1) {
+ append_to_rev_graph(graph, ' ');
+ append_to_rev_graph(graph, '\\');
+ i++;
+ }
+ }
+
+ graph->size = graph->pos = 0;
+ graph->commit = NULL;
+ memset(graph->parents, 0, sizeof(*graph->parents));
+}
+
+static void
+push_rev_graph(struct rev_graph *graph, char *parent)
+{
+ /* Combine duplicate parents lines. */
+ if (graph->size > 0 &&
+ !strncmp(graph->rev[graph->size - 1], parent, SIZEOF_REV))
+ return;
+
+ if (graph->size < SIZEOF_REVITEMS) {
+ string_ncopy(graph->rev[graph->size++], parent, SIZEOF_REV);
+ }
+}
+
+static chtype
+get_rev_graph_symbol(struct rev_graph *graph)
+{
+ chtype symbol;
+
+ if (graph->parents->size == 0)
+ symbol = REVGRAPH_INIT;
+ else if (graph_parent_is_merge(graph))
+ symbol = REVGRAPH_MERGE;
+ else if (graph->pos >= graph->size)
+ symbol = REVGRAPH_BRANCH;
+ else
+ symbol = REVGRAPH_COMMIT;
+
+ return symbol;
+}
+
+static void
+draw_rev_graph(struct rev_graph *graph)
+{
+ chtype separator, line;
+ chtype symbol = get_rev_graph_symbol(graph);
+ size_t i;
+
+ separator = ' ';
+ line = REVGRAPH_LINE;
+
+ for (i = 0; i < graph->pos; i++) {
+ append_to_rev_graph(graph, line);
+ if (graph_parent_is_merge(graph->prev) &&
+ graph->prev->pos == i) {
+ separator = '`';
+ line = '.';
+ }
+ append_to_rev_graph(graph, separator);
+ }
+
+ /* Place the symbol for this revision. */
+ append_to_rev_graph(graph, symbol);
+
+ if (graph->prev->size > graph->size) {
+ separator = '\'';
+ line = ' ';
+ } else {
+ separator = ' ';
+ line = REVGRAPH_LINE;
+ }
+ i++;
+
+ for (; i < graph->size; i++) {
+ append_to_rev_graph(graph, separator);
+ append_to_rev_graph(graph, line);
+ if (graph_parent_is_merge(graph->prev)) {
+ if (i < graph->prev->pos + graph->parents->size) {
+ separator = '`';
+ line = '.';
+ }
+ }
+ if (graph->prev->size > graph->size) {
+ separator = '/';
+ line = ' ';
+ }
+ }
+
+ if (graph->prev->size > graph->size) {
+ append_to_rev_graph(graph, separator);
+ if (line != ' ')
+ append_to_rev_graph(graph, line);
+ }
+}
+
+void
+update_rev_graph(struct rev_graph *graph)
+{
+ size_t i;
+
+ /* First, traverse all lines of revisions up to the active one. */
+ for (graph->pos = 0; graph->pos < graph->size; graph->pos++) {
+ if (!strcmp(graph->rev[graph->pos], graph->commit->id))
+ break;
+
+ push_rev_graph(graph->next, graph->rev[graph->pos]);
+ }
+
+ /* Interleave the new revision parent(s). */
+ for (i = 0; i < graph->parents->size; i++)
+ push_rev_graph(graph->next, graph->parents->rev[i]);
+
+ /* Lastly, put any remaining revisions. */
+ for (i = graph->pos + 1; i < graph->size; i++)
+ push_rev_graph(graph->next, graph->rev[i]);
+
+ draw_rev_graph(graph);
+ done_rev_graph(graph->prev);
+}
+
+
+/*
+ * Main view backend
+ */
+
static bool
main_draw(struct view *view, struct line *line, unsigned int lineno, bool selected)
{
return TRUE;
}
-
-struct rev_stack {
- struct rev_stack *prev, *next, *parents;
- char rev[SIZEOF_REVITEMS][SIZEOF_REV];
- size_t size;
- struct commit *commit;
- size_t pos;
-};
-
-/* Parents of the commit being visualized. */
-static struct rev_stack graph_parents[3];
-
-/* The current stack of revisions on the graph. */
-static struct rev_stack graph_stacks[3] = {
- { &graph_stacks[2], &graph_stacks[1], &graph_parents[0] },
- { &graph_stacks[0], &graph_stacks[2], &graph_parents[1] },
- { &graph_stacks[1], &graph_stacks[0], &graph_parents[2] },
-};
-
-static void
-reset_rev_graph(struct rev_stack *graph)
-{
- graph->size = graph->pos = 0;
- graph->commit = NULL;
- memset(graph->parents, 0, sizeof(*graph->parents));
-}
-
-static inline void
-append_to_rev_graph(struct rev_stack *stack, chtype symbol)
-{
- if (stack->commit->graph_size < ARRAY_SIZE(stack->commit->graph) - 1)
- stack->commit->graph[stack->commit->graph_size++] = symbol;
-}
-
-static void
-push_rev_stack(struct rev_stack *stack, char *parent)
-{
- /* Combine duplicate parents lines. */
- if (stack->size > 0 &&
- !strncmp(stack->rev[stack->size - 1], parent, SIZEOF_REV))
- return;
-
- if (stack->size < SIZEOF_REVITEMS) {
- string_ncopy(stack->rev[stack->size++], parent, SIZEOF_REV);
- }
-}
-
-static void
-draw_rev_graph(struct rev_stack *graph)
-{
- chtype symbol, separator, line;
- size_t i;
-
- /* Place the symbol for this commit. */
- if (graph->parents->size == 0)
- symbol = REVGRAPH_INIT;
- else if (graph->parents->size > 1)
- symbol = REVGRAPH_MERGE;
- else if (graph->pos >= graph->size)
- symbol = REVGRAPH_BRANCH;
- else
- symbol = REVGRAPH_COMMIT;
-
- separator = ' ';
- line = REVGRAPH_LINE;
-
- for (i = 0; i < graph->pos; i++) {
- append_to_rev_graph(graph, line);
- if (graph->prev->parents->size > 1 &&
- graph->prev->pos == i) {
- separator = '`';
- line = '.';
- }
- append_to_rev_graph(graph, separator);
- }
-
- append_to_rev_graph(graph, symbol);
-
- if (graph->prev->size > graph->size) {
- separator = '\'';
- line = ' ';
- } else {
- separator = ' ';
- line = REVGRAPH_LINE;
- }
- i++;
-
- for (; i < graph->size; i++) {
- append_to_rev_graph(graph, separator);
- append_to_rev_graph(graph, line);
- if (graph->prev->parents->size > 1) {
- if (i < graph->prev->pos + graph->parents->size) {
- separator = '`';
- line = '.';
- }
- }
- if (graph->prev->size > graph->size) {
- separator = '/';
- line = ' ';
- }
- }
-
- if (graph->prev->size > graph->size) {
- append_to_rev_graph(graph, separator);
- if (line != ' ')
- append_to_rev_graph(graph, line);
- }
-}
-
-void
-update_rev_graph(struct rev_stack *graph)
-{
- size_t i;
-
- /* First traverse all lines of revisions up to the active one. */
- for (graph->pos = 0; graph->pos < graph->size; graph->pos++) {
- if (!strcmp(graph->rev[graph->pos], graph->commit->id))
- break;
-
- push_rev_stack(graph->next, graph->rev[graph->pos]);
- }
-
- for (i = 0; i < graph->parents->size; i++)
- push_rev_stack(graph->next, graph->parents->rev[i]);
-
- /* FIXME: Moving branches left and right when collapsing a branch. */
- for (i = graph->pos + 1; i < graph->size; i++)
- push_rev_stack(graph->next, graph->rev[i]);
-
- draw_rev_graph(graph);
- if (graph->prev->parents->size > 1 &&
- graph->prev->pos < graph->prev->size - 1 &&
- graph->size == graph->prev->size + graph->prev->parents->size - 1) {
- i = graph->prev->pos + graph->prev->parents->size - 1;
- graph->prev->commit->graph_size = i * 2;
- while (i < graph->size - 1) {
- append_to_rev_graph(graph->prev, ' ');
- append_to_rev_graph(graph->prev, '\\');
- i++;
- }
- }
- reset_rev_graph(graph->prev);
-}
-
/* Reads git log --pretty=raw output and parses it into the commit struct. */
static bool
main_read(struct view *view, char *line)
{
- static struct rev_stack *graph = graph_stacks;
+ static struct rev_graph *graph = graph_stacks;
enum line_type type = get_line_type(line);
struct commit *commit = view->lines
? view->line[view->lines - 1].data : NULL;
case LINE_PARENT:
if (commit) {
line += STRING_SIZE("parent ");
- push_rev_stack(graph->parents, line);
+ push_rev_graph(graph->parents, line);
}
break;