More graph_parent_is_merge usage
[tig] / tig.c
diff --git a/tig.c b/tig.c
index cc3dc50..0948cb7 100644 (file)
--- a/tig.c
+++ b/tig.c
@@ -71,9 +71,6 @@ static size_t utf8_length(const char *string, size_t max_width, int *coloffset,
 
 #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)
 
@@ -2668,7 +2665,7 @@ static struct view_ops blob_ops = {
 
 
 /*
- * Main view backend
+ * Revision graph
  */
 
 struct commit {
@@ -2681,116 +2678,11 @@ struct commit {
        size_t graph_size;              /* The width of the graph array. */
 };
 
-static bool
-main_draw(struct view *view, struct line *line, unsigned int lineno, bool selected)
-{
-       char buf[DATE_COLS + 1];
-       struct commit *commit = line->data;
-       enum line_type type;
-       int col = 0;
-       size_t timelen;
-       size_t authorlen;
-       int trimmed = 1;
-
-       if (!*commit->author)
-               return FALSE;
-
-       wmove(view->win, lineno, col);
-
-       if (selected) {
-               type = LINE_CURSOR;
-               wattrset(view->win, get_line_attr(type));
-               wchgat(view->win, -1, 0, type, NULL);
-
-       } else {
-               type = LINE_MAIN_COMMIT;
-               wattrset(view->win, get_line_attr(LINE_MAIN_DATE));
-       }
-
-       timelen = strftime(buf, sizeof(buf), DATE_FORMAT, &commit->time);
-       waddnstr(view->win, buf, timelen);
-       waddstr(view->win, " ");
-
-       col += DATE_COLS;
-       wmove(view->win, lineno, col);
-       if (type != LINE_CURSOR)
-               wattrset(view->win, get_line_attr(LINE_MAIN_AUTHOR));
-
-       if (opt_utf8) {
-               authorlen = utf8_length(commit->author, AUTHOR_COLS - 2, &col, &trimmed);
-       } else {
-               authorlen = strlen(commit->author);
-               if (authorlen > AUTHOR_COLS - 2) {
-                       authorlen = AUTHOR_COLS - 2;
-                       trimmed = 1;
-               }
-       }
-
-       if (trimmed) {
-               waddnstr(view->win, commit->author, authorlen);
-               if (type != LINE_CURSOR)
-                       wattrset(view->win, get_line_attr(LINE_MAIN_DELIM));
-               waddch(view->win, '~');
-       } else {
-               waddstr(view->win, commit->author);
-       }
-
-       col += AUTHOR_COLS;
-       if (type != LINE_CURSOR)
-               wattrset(view->win, A_NORMAL);
-
-       if (opt_rev_graph && commit->graph_size) {
-               size_t i;
-
-               wmove(view->win, lineno, col);
-               /* Using waddch() instead of waddnstr() ensures that
-                * they'll be rendered correctly for the cursor line. */
-               for (i = 0; i < commit->graph_size; i++)
-                       waddch(view->win, commit->graph[i]);
-
-               col += commit->graph_size + 1;
-       }
-
-       wmove(view->win, lineno, col);
-
-       if (commit->refs) {
-               size_t i = 0;
-
-               do {
-                       if (type == LINE_CURSOR)
-                               ;
-                       else if (commit->refs[i]->tag)
-                               wattrset(view->win, get_line_attr(LINE_MAIN_TAG));
-                       else
-                               wattrset(view->win, get_line_attr(LINE_MAIN_REF));
-                       waddstr(view->win, "[");
-                       waddstr(view->win, commit->refs[i]->name);
-                       waddstr(view->win, "]");
-                       if (type != LINE_CURSOR)
-                               wattrset(view->win, A_NORMAL);
-                       waddstr(view->win, " ");
-                       col += strlen(commit->refs[i]->name) + STRING_SIZE("[] ");
-               } while (commit->refs[i++]->next);
-       }
-
-       if (type != LINE_CURSOR)
-               wattrset(view->win, get_line_attr(type));
-
-       {
-               int titlelen = strlen(commit->title);
-
-               if (col + titlelen > view->width)
-                       titlelen = view->width - col;
-
-               waddnstr(view->win, commit->title, titlelen);
-       }
-
-       return TRUE;
-}
-
+/* Size of rev graph with no  "padding" columns */
+#define SIZEOF_REVITEMS        (SIZEOF_REVGRAPH - (SIZEOF_REVGRAPH / 2))
 
-struct rev_stack {
-       struct rev_stack *prev, *next, *parents;
+struct rev_graph {
+       struct rev_graph *prev, *next, *parents;
        char rev[SIZEOF_REVITEMS][SIZEOF_REV];
        size_t size;
        struct commit *commit;
@@ -2798,65 +2690,86 @@ struct rev_stack {
 };
 
 /* Parents of the commit being visualized. */
-static struct rev_stack graph_parents[3];
+static struct rev_graph graph_parents[3];
 
 /* The current stack of revisions on the graph. */
-static struct rev_stack graph_stacks[3] = {
+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_stack *graph)
+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
-reset_rev_graph(struct rev_stack *graph)
+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 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)
+push_rev_graph(struct rev_graph *graph, char *parent)
 {
        /* Combine duplicate parents lines. */
-       if (stack->size > 0 &&
-           !strncmp(stack->rev[stack->size - 1], parent, SIZEOF_REV))
+       if (graph->size > 0 &&
+           !strncmp(graph->rev[graph->size - 1], parent, SIZEOF_REV))
                return;
 
-       if (stack->size < SIZEOF_REVITEMS) {
-               string_ncopy(stack->rev[stack->size++], parent, SIZEOF_REV);
+       if (graph->size < SIZEOF_REVITEMS) {
+               string_ncopy(graph->rev[graph->size++], parent, SIZEOF_REV);
        }
 }
 
-static void
-draw_rev_graph(struct rev_stack *graph)
+static chtype
+get_rev_graph_symbol(struct rev_graph *graph)
 {
-       chtype symbol, separator, line;
-       size_t i;
+       chtype symbol;
 
-       /* Place the symbol for this commit. */
        if (graph->parents->size == 0)
                symbol = REVGRAPH_INIT;
-       else if (graph->parents->size > 1)
+       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;
 
@@ -2870,6 +2783,7 @@ draw_rev_graph(struct rev_stack *graph)
                append_to_rev_graph(graph, separator);
        }
 
+       /* Place the symbol for this revision. */
        append_to_rev_graph(graph, symbol);
 
        if (graph->prev->size > graph->size) {
@@ -2904,49 +2818,147 @@ draw_rev_graph(struct rev_stack *graph)
 }
 
 void
-update_rev_graph(struct rev_stack *graph)
+update_rev_graph(struct rev_graph *graph)
 {
        size_t i;
 
-       /* First traverse all lines of revisions up to the active one. */
+       /* 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]);
+               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_stack(graph->next, graph->parents->rev[i]);
+               push_rev_graph(graph->next, graph->parents->rev[i]);
 
-       /* FIXME: Moving branches left and right when collapsing a branch. */
+       /* Lastly, put any remaining revisions. */
        for (i = graph->pos + 1; i < graph->size; i++)
-               push_rev_stack(graph->next, graph->rev[i]);
+               push_rev_graph(graph->next, graph->rev[i]);
 
        draw_rev_graph(graph);
+       done_rev_graph(graph->prev);
+}
 
-       graph = graph->prev;
 
-       if (graph_parent_is_merge(graph) &&
-           graph->pos < graph->size - 1 &&
-           graph->next->size == graph->size + graph->parents->size - 1) {
-               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++;
+/*
+ * Main view backend
+ */
+
+static bool
+main_draw(struct view *view, struct line *line, unsigned int lineno, bool selected)
+{
+       char buf[DATE_COLS + 1];
+       struct commit *commit = line->data;
+       enum line_type type;
+       int col = 0;
+       size_t timelen;
+       size_t authorlen;
+       int trimmed = 1;
+
+       if (!*commit->author)
+               return FALSE;
+
+       wmove(view->win, lineno, col);
+
+       if (selected) {
+               type = LINE_CURSOR;
+               wattrset(view->win, get_line_attr(type));
+               wchgat(view->win, -1, 0, type, NULL);
+
+       } else {
+               type = LINE_MAIN_COMMIT;
+               wattrset(view->win, get_line_attr(LINE_MAIN_DATE));
+       }
+
+       timelen = strftime(buf, sizeof(buf), DATE_FORMAT, &commit->time);
+       waddnstr(view->win, buf, timelen);
+       waddstr(view->win, " ");
+
+       col += DATE_COLS;
+       wmove(view->win, lineno, col);
+       if (type != LINE_CURSOR)
+               wattrset(view->win, get_line_attr(LINE_MAIN_AUTHOR));
+
+       if (opt_utf8) {
+               authorlen = utf8_length(commit->author, AUTHOR_COLS - 2, &col, &trimmed);
+       } else {
+               authorlen = strlen(commit->author);
+               if (authorlen > AUTHOR_COLS - 2) {
+                       authorlen = AUTHOR_COLS - 2;
+                       trimmed = 1;
                }
        }
 
-       reset_rev_graph(graph);
+       if (trimmed) {
+               waddnstr(view->win, commit->author, authorlen);
+               if (type != LINE_CURSOR)
+                       wattrset(view->win, get_line_attr(LINE_MAIN_DELIM));
+               waddch(view->win, '~');
+       } else {
+               waddstr(view->win, commit->author);
+       }
+
+       col += AUTHOR_COLS;
+       if (type != LINE_CURSOR)
+               wattrset(view->win, A_NORMAL);
+
+       if (opt_rev_graph && commit->graph_size) {
+               size_t i;
+
+               wmove(view->win, lineno, col);
+               /* Using waddch() instead of waddnstr() ensures that
+                * they'll be rendered correctly for the cursor line. */
+               for (i = 0; i < commit->graph_size; i++)
+                       waddch(view->win, commit->graph[i]);
+
+               col += commit->graph_size + 1;
+       }
+
+       wmove(view->win, lineno, col);
+
+       if (commit->refs) {
+               size_t i = 0;
+
+               do {
+                       if (type == LINE_CURSOR)
+                               ;
+                       else if (commit->refs[i]->tag)
+                               wattrset(view->win, get_line_attr(LINE_MAIN_TAG));
+                       else
+                               wattrset(view->win, get_line_attr(LINE_MAIN_REF));
+                       waddstr(view->win, "[");
+                       waddstr(view->win, commit->refs[i]->name);
+                       waddstr(view->win, "]");
+                       if (type != LINE_CURSOR)
+                               wattrset(view->win, A_NORMAL);
+                       waddstr(view->win, " ");
+                       col += strlen(commit->refs[i]->name) + STRING_SIZE("[] ");
+               } while (commit->refs[i++]->next);
+       }
+
+       if (type != LINE_CURSOR)
+               wattrset(view->win, get_line_attr(type));
+
+       {
+               int titlelen = strlen(commit->title);
+
+               if (col + titlelen > view->width)
+                       titlelen = view->width - col;
+
+               waddnstr(view->win, commit->title, titlelen);
+       }
+
+       return TRUE;
 }
 
 /* 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;
@@ -2968,7 +2980,7 @@ main_read(struct view *view, char *line)
        case LINE_PARENT:
                if (commit) {
                        line += STRING_SIZE("parent ");
-                       push_rev_stack(graph->parents, line);
+                       push_rev_graph(graph->parents, line);
                }
                break;