Code

Merge branch 'maint'
[git.git] / graph.c
1 #include "cache.h"
2 #include "commit.h"
3 #include "color.h"
4 #include "graph.h"
5 #include "diff.h"
6 #include "revision.h"
8 /* Internal API */
10 /*
11  * Output the next line for a graph.
12  * This formats the next graph line into the specified strbuf.  It is not
13  * terminated with a newline.
14  *
15  * Returns 1 if the line includes the current commit, and 0 otherwise.
16  * graph_next_line() will return 1 exactly once for each time
17  * graph_update() is called.
18  */
19 static int graph_next_line(struct git_graph *graph, struct strbuf *sb);
21 /*
22  * Output a padding line in the graph.
23  * This is similar to graph_next_line().  However, it is guaranteed to
24  * never print the current commit line.  Instead, if the commit line is
25  * next, it will simply output a line of vertical padding, extending the
26  * branch lines downwards, but leaving them otherwise unchanged.
27  */
28 static void graph_padding_line(struct git_graph *graph, struct strbuf *sb);
30 /*
31  * Print a strbuf to stdout.  If the graph is non-NULL, all lines but the
32  * first will be prefixed with the graph output.
33  *
34  * If the strbuf ends with a newline, the output will end after this
35  * newline.  A new graph line will not be printed after the final newline.
36  * If the strbuf is empty, no output will be printed.
37  *
38  * Since the first line will not include the graph output, the caller is
39  * responsible for printing this line's graph (perhaps via
40  * graph_show_commit() or graph_show_oneline()) before calling
41  * graph_show_strbuf().
42  */
43 static void graph_show_strbuf(struct git_graph *graph, struct strbuf const *sb);
45 /*
46  * TODO:
47  * - Limit the number of columns, similar to the way gitk does.
48  *   If we reach more than a specified number of columns, omit
49  *   sections of some columns.
50  */
52 struct column {
53         /*
54          * The parent commit of this column.
55          */
56         struct commit *commit;
57         /*
58          * The color to (optionally) print this column in.  This is an
59          * index into column_colors.
60          */
61         unsigned short color;
62 };
64 enum graph_state {
65         GRAPH_PADDING,
66         GRAPH_SKIP,
67         GRAPH_PRE_COMMIT,
68         GRAPH_COMMIT,
69         GRAPH_POST_MERGE,
70         GRAPH_COLLAPSING
71 };
73 /*
74  * The list of available column colors.
75  */
76 static char column_colors[][COLOR_MAXLEN] = {
77         GIT_COLOR_RED,
78         GIT_COLOR_GREEN,
79         GIT_COLOR_YELLOW,
80         GIT_COLOR_BLUE,
81         GIT_COLOR_MAGENTA,
82         GIT_COLOR_CYAN,
83         GIT_COLOR_BOLD GIT_COLOR_RED,
84         GIT_COLOR_BOLD GIT_COLOR_GREEN,
85         GIT_COLOR_BOLD GIT_COLOR_YELLOW,
86         GIT_COLOR_BOLD GIT_COLOR_BLUE,
87         GIT_COLOR_BOLD GIT_COLOR_MAGENTA,
88         GIT_COLOR_BOLD GIT_COLOR_CYAN,
89 };
91 #define COLUMN_COLORS_MAX (ARRAY_SIZE(column_colors))
93 static const char *column_get_color_code(const struct column *c)
94 {
95         return column_colors[c->color];
96 }
98 static void strbuf_write_column(struct strbuf *sb, const struct column *c,
99                                 char col_char)
101         if (c->color < COLUMN_COLORS_MAX)
102                 strbuf_addstr(sb, column_get_color_code(c));
103         strbuf_addch(sb, col_char);
104         if (c->color < COLUMN_COLORS_MAX)
105                 strbuf_addstr(sb, GIT_COLOR_RESET);
108 struct git_graph {
109         /*
110          * The commit currently being processed
111          */
112         struct commit *commit;
113         /* The rev-info used for the current traversal */
114         struct rev_info *revs;
115         /*
116          * The number of interesting parents that this commit has.
117          *
118          * Note that this is not the same as the actual number of parents.
119          * This count excludes parents that won't be printed in the graph
120          * output, as determined by graph_is_interesting().
121          */
122         int num_parents;
123         /*
124          * The width of the graph output for this commit.
125          * All rows for this commit are padded to this width, so that
126          * messages printed after the graph output are aligned.
127          */
128         int width;
129         /*
130          * The next expansion row to print
131          * when state is GRAPH_PRE_COMMIT
132          */
133         int expansion_row;
134         /*
135          * The current output state.
136          * This tells us what kind of line graph_next_line() should output.
137          */
138         enum graph_state state;
139         /*
140          * The output state for the previous line of output.
141          * This is primarily used to determine how the first merge line
142          * should appear, based on the last line of the previous commit.
143          */
144         enum graph_state prev_state;
145         /*
146          * The index of the column that refers to this commit.
147          *
148          * If none of the incoming columns refer to this commit,
149          * this will be equal to num_columns.
150          */
151         int commit_index;
152         /*
153          * The commit_index for the previously displayed commit.
154          *
155          * This is used to determine how the first line of a merge
156          * graph output should appear, based on the last line of the
157          * previous commit.
158          */
159         int prev_commit_index;
160         /*
161          * The maximum number of columns that can be stored in the columns
162          * and new_columns arrays.  This is also half the number of entries
163          * that can be stored in the mapping and new_mapping arrays.
164          */
165         int column_capacity;
166         /*
167          * The number of columns (also called "branch lines" in some places)
168          */
169         int num_columns;
170         /*
171          * The number of columns in the new_columns array
172          */
173         int num_new_columns;
174         /*
175          * The number of entries in the mapping array
176          */
177         int mapping_size;
178         /*
179          * The column state before we output the current commit.
180          */
181         struct column *columns;
182         /*
183          * The new column state after we output the current commit.
184          * Only valid when state is GRAPH_COLLAPSING.
185          */
186         struct column *new_columns;
187         /*
188          * An array that tracks the current state of each
189          * character in the output line during state GRAPH_COLLAPSING.
190          * Each entry is -1 if this character is empty, or a non-negative
191          * integer if the character contains a branch line.  The value of
192          * the integer indicates the target position for this branch line.
193          * (I.e., this array maps the current column positions to their
194          * desired positions.)
195          *
196          * The maximum capacity of this array is always
197          * sizeof(int) * 2 * column_capacity.
198          */
199         int *mapping;
200         /*
201          * A temporary array for computing the next mapping state
202          * while we are outputting a mapping line.  This is stored as part
203          * of the git_graph simply so we don't have to allocate a new
204          * temporary array each time we have to output a collapsing line.
205          */
206         int *new_mapping;
207         /*
208          * The current default column color being used.  This is
209          * stored as an index into the array column_colors.
210          */
211         unsigned short default_column_color;
212 };
214 struct git_graph *graph_init(struct rev_info *opt)
216         struct git_graph *graph = xmalloc(sizeof(struct git_graph));
217         graph->commit = NULL;
218         graph->revs = opt;
219         graph->num_parents = 0;
220         graph->expansion_row = 0;
221         graph->state = GRAPH_PADDING;
222         graph->prev_state = GRAPH_PADDING;
223         graph->commit_index = 0;
224         graph->prev_commit_index = 0;
225         graph->num_columns = 0;
226         graph->num_new_columns = 0;
227         graph->mapping_size = 0;
228         graph->default_column_color = 0;
230         /*
231          * Allocate a reasonably large default number of columns
232          * We'll automatically grow columns later if we need more room.
233          */
234         graph->column_capacity = 30;
235         graph->columns = xmalloc(sizeof(struct column) *
236                                  graph->column_capacity);
237         graph->new_columns = xmalloc(sizeof(struct column) *
238                                      graph->column_capacity);
239         graph->mapping = xmalloc(sizeof(int) * 2 * graph->column_capacity);
240         graph->new_mapping = xmalloc(sizeof(int) * 2 * graph->column_capacity);
242         return graph;
245 static void graph_update_state(struct git_graph *graph, enum graph_state s)
247         graph->prev_state = graph->state;
248         graph->state = s;
251 static void graph_ensure_capacity(struct git_graph *graph, int num_columns)
253         if (graph->column_capacity >= num_columns)
254                 return;
256         do {
257                 graph->column_capacity *= 2;
258         } while (graph->column_capacity < num_columns);
260         graph->columns = xrealloc(graph->columns,
261                                   sizeof(struct column) *
262                                   graph->column_capacity);
263         graph->new_columns = xrealloc(graph->new_columns,
264                                       sizeof(struct column) *
265                                       graph->column_capacity);
266         graph->mapping = xrealloc(graph->mapping,
267                                   sizeof(int) * 2 * graph->column_capacity);
268         graph->new_mapping = xrealloc(graph->new_mapping,
269                                       sizeof(int) * 2 * graph->column_capacity);
272 /*
273  * Returns 1 if the commit will be printed in the graph output,
274  * and 0 otherwise.
275  */
276 static int graph_is_interesting(struct git_graph *graph, struct commit *commit)
278         /*
279          * If revs->boundary is set, commits whose children have
280          * been shown are always interesting, even if they have the
281          * UNINTERESTING or TREESAME flags set.
282          */
283         if (graph->revs && graph->revs->boundary) {
284                 if (commit->object.flags & CHILD_SHOWN)
285                         return 1;
286         }
288         /*
289          * Uninteresting and pruned commits won't be printed
290          */
291         return (commit->object.flags & (UNINTERESTING | TREESAME)) ? 0 : 1;
294 static struct commit_list *next_interesting_parent(struct git_graph *graph,
295                                                    struct commit_list *orig)
297         struct commit_list *list;
299         /*
300          * If revs->first_parent_only is set, only the first
301          * parent is interesting.  None of the others are.
302          */
303         if (graph->revs->first_parent_only)
304                 return NULL;
306         /*
307          * Return the next interesting commit after orig
308          */
309         for (list = orig->next; list; list = list->next) {
310                 if (graph_is_interesting(graph, list->item))
311                         return list;
312         }
314         return NULL;
317 static struct commit_list *first_interesting_parent(struct git_graph *graph)
319         struct commit_list *parents = graph->commit->parents;
321         /*
322          * If this commit has no parents, ignore it
323          */
324         if (!parents)
325                 return NULL;
327         /*
328          * If the first parent is interesting, return it
329          */
330         if (graph_is_interesting(graph, parents->item))
331                 return parents;
333         /*
334          * Otherwise, call next_interesting_parent() to get
335          * the next interesting parent
336          */
337         return next_interesting_parent(graph, parents);
340 static unsigned short graph_get_current_column_color(const struct git_graph *graph)
342         if (!DIFF_OPT_TST(&graph->revs->diffopt, COLOR_DIFF))
343                 return COLUMN_COLORS_MAX;
344         return graph->default_column_color;
347 /*
348  * Update the graph's default column color.
349  */
350 static void graph_increment_column_color(struct git_graph *graph)
352         graph->default_column_color = (graph->default_column_color + 1) %
353                 COLUMN_COLORS_MAX;
356 static unsigned short graph_find_commit_color(const struct git_graph *graph,
357                                               const struct commit *commit)
359         int i;
360         for (i = 0; i < graph->num_columns; i++) {
361                 if (graph->columns[i].commit == commit)
362                         return graph->columns[i].color;
363         }
364         return graph_get_current_column_color(graph);
367 static void graph_insert_into_new_columns(struct git_graph *graph,
368                                           struct commit *commit,
369                                           int *mapping_index)
371         int i;
373         /*
374          * If the commit is already in the new_columns list, we don't need to
375          * add it.  Just update the mapping correctly.
376          */
377         for (i = 0; i < graph->num_new_columns; i++) {
378                 if (graph->new_columns[i].commit == commit) {
379                         graph->mapping[*mapping_index] = i;
380                         *mapping_index += 2;
381                         return;
382                 }
383         }
385         /*
386          * This commit isn't already in new_columns.  Add it.
387          */
388         graph->new_columns[graph->num_new_columns].commit = commit;
389         graph->new_columns[graph->num_new_columns].color = graph_find_commit_color(graph, commit);
390         graph->mapping[*mapping_index] = graph->num_new_columns;
391         *mapping_index += 2;
392         graph->num_new_columns++;
395 static void graph_update_width(struct git_graph *graph,
396                                int is_commit_in_existing_columns)
398         /*
399          * Compute the width needed to display the graph for this commit.
400          * This is the maximum width needed for any row.  All other rows
401          * will be padded to this width.
402          *
403          * Compute the number of columns in the widest row:
404          * Count each existing column (graph->num_columns), and each new
405          * column added by this commit.
406          */
407         int max_cols = graph->num_columns + graph->num_parents;
409         /*
410          * Even if the current commit has no parents to be printed, it
411          * still takes up a column for itself.
412          */
413         if (graph->num_parents < 1)
414                 max_cols++;
416         /*
417          * We added a column for the the current commit as part of
418          * graph->num_parents.  If the current commit was already in
419          * graph->columns, then we have double counted it.
420          */
421         if (is_commit_in_existing_columns)
422                 max_cols--;
424         /*
425          * Each column takes up 2 spaces
426          */
427         graph->width = max_cols * 2;
430 static void graph_update_columns(struct git_graph *graph)
432         struct commit_list *parent;
433         struct column *tmp_columns;
434         int max_new_columns;
435         int mapping_idx;
436         int i, seen_this, is_commit_in_columns;
438         /*
439          * Swap graph->columns with graph->new_columns
440          * graph->columns contains the state for the previous commit,
441          * and new_columns now contains the state for our commit.
442          *
443          * We'll re-use the old columns array as storage to compute the new
444          * columns list for the commit after this one.
445          */
446         tmp_columns = graph->columns;
447         graph->columns = graph->new_columns;
448         graph->num_columns = graph->num_new_columns;
450         graph->new_columns = tmp_columns;
451         graph->num_new_columns = 0;
453         /*
454          * Now update new_columns and mapping with the information for the
455          * commit after this one.
456          *
457          * First, make sure we have enough room.  At most, there will
458          * be graph->num_columns + graph->num_parents columns for the next
459          * commit.
460          */
461         max_new_columns = graph->num_columns + graph->num_parents;
462         graph_ensure_capacity(graph, max_new_columns);
464         /*
465          * Clear out graph->mapping
466          */
467         graph->mapping_size = 2 * max_new_columns;
468         for (i = 0; i < graph->mapping_size; i++)
469                 graph->mapping[i] = -1;
471         /*
472          * Populate graph->new_columns and graph->mapping
473          *
474          * Some of the parents of this commit may already be in
475          * graph->columns.  If so, graph->new_columns should only contain a
476          * single entry for each such commit.  graph->mapping should
477          * contain information about where each current branch line is
478          * supposed to end up after the collapsing is performed.
479          */
480         seen_this = 0;
481         mapping_idx = 0;
482         is_commit_in_columns = 1;
483         for (i = 0; i <= graph->num_columns; i++) {
484                 struct commit *col_commit;
485                 if (i == graph->num_columns) {
486                         if (seen_this)
487                                 break;
488                         is_commit_in_columns = 0;
489                         col_commit = graph->commit;
490                 } else {
491                         col_commit = graph->columns[i].commit;
492                 }
494                 if (col_commit == graph->commit) {
495                         int old_mapping_idx = mapping_idx;
496                         seen_this = 1;
497                         graph->commit_index = i;
498                         for (parent = first_interesting_parent(graph);
499                              parent;
500                              parent = next_interesting_parent(graph, parent)) {
501                                 /*
502                                  * If this is a merge increment the current
503                                  * color.
504                                  */
505                                 if (graph->num_parents > 1)
506                                         graph_increment_column_color(graph);
507                                 graph_insert_into_new_columns(graph,
508                                                               parent->item,
509                                                               &mapping_idx);
510                         }
511                         /*
512                          * We always need to increment mapping_idx by at
513                          * least 2, even if it has no interesting parents.
514                          * The current commit always takes up at least 2
515                          * spaces.
516                          */
517                         if (mapping_idx == old_mapping_idx)
518                                 mapping_idx += 2;
519                 } else {
520                         graph_insert_into_new_columns(graph, col_commit,
521                                                       &mapping_idx);
522                 }
523         }
525         /*
526          * Shrink mapping_size to be the minimum necessary
527          */
528         while (graph->mapping_size > 1 &&
529                graph->mapping[graph->mapping_size - 1] < 0)
530                 graph->mapping_size--;
532         /*
533          * Compute graph->width for this commit
534          */
535         graph_update_width(graph, is_commit_in_columns);
538 void graph_update(struct git_graph *graph, struct commit *commit)
540         struct commit_list *parent;
542         /*
543          * Set the new commit
544          */
545         graph->commit = commit;
547         /*
548          * Count how many interesting parents this commit has
549          */
550         graph->num_parents = 0;
551         for (parent = first_interesting_parent(graph);
552              parent;
553              parent = next_interesting_parent(graph, parent))
554         {
555                 graph->num_parents++;
556         }
558         /*
559          * Store the old commit_index in prev_commit_index.
560          * graph_update_columns() will update graph->commit_index for this
561          * commit.
562          */
563         graph->prev_commit_index = graph->commit_index;
565         /*
566          * Call graph_update_columns() to update
567          * columns, new_columns, and mapping.
568          */
569         graph_update_columns(graph);
571         graph->expansion_row = 0;
573         /*
574          * Update graph->state.
575          * Note that we don't call graph_update_state() here, since
576          * we don't want to update graph->prev_state.  No line for
577          * graph->state was ever printed.
578          *
579          * If the previous commit didn't get to the GRAPH_PADDING state,
580          * it never finished its output.  Goto GRAPH_SKIP, to print out
581          * a line to indicate that portion of the graph is missing.
582          *
583          * If there are 3 or more parents, we may need to print extra rows
584          * before the commit, to expand the branch lines around it and make
585          * room for it.  We need to do this only if there is a branch row
586          * (or more) to the right of this commit.
587          *
588          * If there are less than 3 parents, we can immediately print the
589          * commit line.
590          */
591         if (graph->state != GRAPH_PADDING)
592                 graph->state = GRAPH_SKIP;
593         else if (graph->num_parents >= 3 &&
594                  graph->commit_index < (graph->num_columns - 1))
595                 graph->state = GRAPH_PRE_COMMIT;
596         else
597                 graph->state = GRAPH_COMMIT;
600 static int graph_is_mapping_correct(struct git_graph *graph)
602         int i;
604         /*
605          * The mapping is up to date if each entry is at its target,
606          * or is 1 greater than its target.
607          * (If it is 1 greater than the target, '/' will be printed, so it
608          * will look correct on the next row.)
609          */
610         for (i = 0; i < graph->mapping_size; i++) {
611                 int target = graph->mapping[i];
612                 if (target < 0)
613                         continue;
614                 if (target == (i / 2))
615                         continue;
616                 return 0;
617         }
619         return 1;
622 static void graph_pad_horizontally(struct git_graph *graph, struct strbuf *sb,
623                                    int chars_written)
625         /*
626          * Add additional spaces to the end of the strbuf, so that all
627          * lines for a particular commit have the same width.
628          *
629          * This way, fields printed to the right of the graph will remain
630          * aligned for the entire commit.
631          */
632         int extra;
633         if (chars_written >= graph->width)
634                 return;
636         extra = graph->width - chars_written;
637         strbuf_addf(sb, "%*s", (int) extra, "");
640 static void graph_output_padding_line(struct git_graph *graph,
641                                       struct strbuf *sb)
643         int i;
645         /*
646          * We could conceivable be called with a NULL commit
647          * if our caller has a bug, and invokes graph_next_line()
648          * immediately after graph_init(), without first calling
649          * graph_update().  Return without outputting anything in this
650          * case.
651          */
652         if (!graph->commit)
653                 return;
655         /*
656          * Output a padding row, that leaves all branch lines unchanged
657          */
658         for (i = 0; i < graph->num_new_columns; i++) {
659                 strbuf_write_column(sb, &graph->new_columns[i], '|');
660                 strbuf_addch(sb, ' ');
661         }
663         graph_pad_horizontally(graph, sb, graph->num_new_columns * 2);
666 static void graph_output_skip_line(struct git_graph *graph, struct strbuf *sb)
668         /*
669          * Output an ellipsis to indicate that a portion
670          * of the graph is missing.
671          */
672         strbuf_addstr(sb, "...");
673         graph_pad_horizontally(graph, sb, 3);
675         if (graph->num_parents >= 3 &&
676             graph->commit_index < (graph->num_columns - 1))
677                 graph_update_state(graph, GRAPH_PRE_COMMIT);
678         else
679                 graph_update_state(graph, GRAPH_COMMIT);
682 static void graph_output_pre_commit_line(struct git_graph *graph,
683                                          struct strbuf *sb)
685         int num_expansion_rows;
686         int i, seen_this;
687         int chars_written;
689         /*
690          * This function formats a row that increases the space around a commit
691          * with multiple parents, to make room for it.  It should only be
692          * called when there are 3 or more parents.
693          *
694          * We need 2 extra rows for every parent over 2.
695          */
696         assert(graph->num_parents >= 3);
697         num_expansion_rows = (graph->num_parents - 2) * 2;
699         /*
700          * graph->expansion_row tracks the current expansion row we are on.
701          * It should be in the range [0, num_expansion_rows - 1]
702          */
703         assert(0 <= graph->expansion_row &&
704                graph->expansion_row < num_expansion_rows);
706         /*
707          * Output the row
708          */
709         seen_this = 0;
710         chars_written = 0;
711         for (i = 0; i < graph->num_columns; i++) {
712                 struct column *col = &graph->columns[i];
713                 if (col->commit == graph->commit) {
714                         seen_this = 1;
715                         strbuf_write_column(sb, col, '|');
716                         strbuf_addf(sb, "%*s", graph->expansion_row, "");
717                         chars_written += 1 + graph->expansion_row;
718                 } else if (seen_this && (graph->expansion_row == 0)) {
719                         /*
720                          * This is the first line of the pre-commit output.
721                          * If the previous commit was a merge commit and
722                          * ended in the GRAPH_POST_MERGE state, all branch
723                          * lines after graph->prev_commit_index were
724                          * printed as "\" on the previous line.  Continue
725                          * to print them as "\" on this line.  Otherwise,
726                          * print the branch lines as "|".
727                          */
728                         if (graph->prev_state == GRAPH_POST_MERGE &&
729                             graph->prev_commit_index < i)
730                                 strbuf_write_column(sb, col, '\\');
731                         else
732                                 strbuf_write_column(sb, col, '|');
733                         chars_written++;
734                 } else if (seen_this && (graph->expansion_row > 0)) {
735                         strbuf_write_column(sb, col, '\\');
736                         chars_written++;
737                 } else {
738                         strbuf_write_column(sb, col, '|');
739                         chars_written++;
740                 }
741                 strbuf_addch(sb, ' ');
742                 chars_written++;
743         }
745         graph_pad_horizontally(graph, sb, chars_written);
747         /*
748          * Increment graph->expansion_row,
749          * and move to state GRAPH_COMMIT if necessary
750          */
751         graph->expansion_row++;
752         if (graph->expansion_row >= num_expansion_rows)
753                 graph_update_state(graph, GRAPH_COMMIT);
756 static void graph_output_commit_char(struct git_graph *graph, struct strbuf *sb)
758         /*
759          * For boundary commits, print 'o'
760          * (We should only see boundary commits when revs->boundary is set.)
761          */
762         if (graph->commit->object.flags & BOUNDARY) {
763                 assert(graph->revs->boundary);
764                 strbuf_addch(sb, 'o');
765                 return;
766         }
768         /*
769          * If revs->left_right is set, print '<' for commits that
770          * come from the left side, and '>' for commits from the right
771          * side.
772          */
773         if (graph->revs && graph->revs->left_right) {
774                 if (graph->commit->object.flags & SYMMETRIC_LEFT)
775                         strbuf_addch(sb, '<');
776                 else
777                         strbuf_addch(sb, '>');
778                 return;
779         }
781         /*
782          * Print '*' in all other cases
783          */
784         strbuf_addch(sb, '*');
787 /*
788  * Draw an octopus merge and return the number of characters written.
789  */
790 static int graph_draw_octopus_merge(struct git_graph *graph,
791                                     struct strbuf *sb)
793         /*
794          * Here dashless_commits represents the number of parents
795          * which don't need to have dashes (because their edges fit
796          * neatly under the commit).
797          */
798         const int dashless_commits = 2;
799         int col_num, i;
800         int num_dashes =
801                 ((graph->num_parents - dashless_commits) * 2) - 1;
802         for (i = 0; i < num_dashes; i++) {
803                 col_num = (i / 2) + dashless_commits;
804                 strbuf_write_column(sb, &graph->new_columns[col_num], '-');
805         }
806         col_num = (i / 2) + dashless_commits;
807         strbuf_write_column(sb, &graph->new_columns[col_num], '.');
808         return num_dashes + 1;
811 static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
813         int seen_this = 0;
814         int i, chars_written;
816         /*
817          * Output the row containing this commit
818          * Iterate up to and including graph->num_columns,
819          * since the current commit may not be in any of the existing
820          * columns.  (This happens when the current commit doesn't have any
821          * children that we have already processed.)
822          */
823         seen_this = 0;
824         chars_written = 0;
825         for (i = 0; i <= graph->num_columns; i++) {
826                 struct column *col = &graph->columns[i];
827                 struct commit *col_commit;
828                 if (i == graph->num_columns) {
829                         if (seen_this)
830                                 break;
831                         col_commit = graph->commit;
832                 } else {
833                         col_commit = graph->columns[i].commit;
834                 }
836                 if (col_commit == graph->commit) {
837                         seen_this = 1;
838                         graph_output_commit_char(graph, sb);
839                         chars_written++;
841                         if (graph->num_parents > 2)
842                                 chars_written += graph_draw_octopus_merge(graph,
843                                                                           sb);
844                 } else if (seen_this && (graph->num_parents > 2)) {
845                         strbuf_write_column(sb, col, '\\');
846                         chars_written++;
847                 } else if (seen_this && (graph->num_parents == 2)) {
848                         /*
849                          * This is a 2-way merge commit.
850                          * There is no GRAPH_PRE_COMMIT stage for 2-way
851                          * merges, so this is the first line of output
852                          * for this commit.  Check to see what the previous
853                          * line of output was.
854                          *
855                          * If it was GRAPH_POST_MERGE, the branch line
856                          * coming into this commit may have been '\',
857                          * and not '|' or '/'.  If so, output the branch
858                          * line as '\' on this line, instead of '|'.  This
859                          * makes the output look nicer.
860                          */
861                         if (graph->prev_state == GRAPH_POST_MERGE &&
862                             graph->prev_commit_index < i)
863                                 strbuf_write_column(sb, col, '\\');
864                         else
865                                 strbuf_write_column(sb, col, '|');
866                         chars_written++;
867                 } else {
868                         strbuf_write_column(sb, col, '|');
869                         chars_written++;
870                 }
871                 strbuf_addch(sb, ' ');
872                 chars_written++;
873         }
875         graph_pad_horizontally(graph, sb, chars_written);
877         /*
878          * Update graph->state
879          */
880         if (graph->num_parents > 1)
881                 graph_update_state(graph, GRAPH_POST_MERGE);
882         else if (graph_is_mapping_correct(graph))
883                 graph_update_state(graph, GRAPH_PADDING);
884         else
885                 graph_update_state(graph, GRAPH_COLLAPSING);
888 static struct column *find_new_column_by_commit(struct git_graph *graph,
889                                                 struct commit *commit)
891         int i;
892         for (i = 0; i < graph->num_new_columns; i++) {
893                 if (graph->new_columns[i].commit == commit)
894                         return &graph->new_columns[i];
895         }
896         return NULL;
899 static void graph_output_post_merge_line(struct git_graph *graph, struct strbuf *sb)
901         int seen_this = 0;
902         int i, j, chars_written;
904         /*
905          * Output the post-merge row
906          */
907         chars_written = 0;
908         for (i = 0; i <= graph->num_columns; i++) {
909                 struct column *col = &graph->columns[i];
910                 struct commit *col_commit;
911                 if (i == graph->num_columns) {
912                         if (seen_this)
913                                 break;
914                         col_commit = graph->commit;
915                 } else {
916                         col_commit = col->commit;
917                 }
919                 if (col_commit == graph->commit) {
920                         /*
921                          * Since the current commit is a merge find
922                          * the columns for the parent commits in
923                          * new_columns and use those to format the
924                          * edges.
925                          */
926                         struct commit_list *parents = NULL;
927                         struct column *par_column;
928                         seen_this = 1;
929                         parents = first_interesting_parent(graph);
930                         assert(parents);
931                         par_column = find_new_column_by_commit(graph, parents->item);
932                         assert(par_column);
934                         strbuf_write_column(sb, par_column, '|');
935                         chars_written++;
936                         for (j = 0; j < graph->num_parents - 1; j++) {
937                                 parents = next_interesting_parent(graph, parents);
938                                 assert(parents);
939                                 par_column = find_new_column_by_commit(graph, parents->item);
940                                 assert(par_column);
941                                 strbuf_write_column(sb, par_column, '\\');
942                                 strbuf_addch(sb, ' ');
943                         }
944                         chars_written += j * 2;
945                 } else if (seen_this) {
946                         strbuf_write_column(sb, col, '\\');
947                         strbuf_addch(sb, ' ');
948                         chars_written += 2;
949                 } else {
950                         strbuf_write_column(sb, col, '|');
951                         strbuf_addch(sb, ' ');
952                         chars_written += 2;
953                 }
954         }
956         graph_pad_horizontally(graph, sb, chars_written);
958         /*
959          * Update graph->state
960          */
961         if (graph_is_mapping_correct(graph))
962                 graph_update_state(graph, GRAPH_PADDING);
963         else
964                 graph_update_state(graph, GRAPH_COLLAPSING);
967 static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf *sb)
969         int i;
970         int *tmp_mapping;
971         short used_horizontal = 0;
972         int horizontal_edge = -1;
973         int horizontal_edge_target = -1;
975         /*
976          * Clear out the new_mapping array
977          */
978         for (i = 0; i < graph->mapping_size; i++)
979                 graph->new_mapping[i] = -1;
981         for (i = 0; i < graph->mapping_size; i++) {
982                 int target = graph->mapping[i];
983                 if (target < 0)
984                         continue;
986                 /*
987                  * Since update_columns() always inserts the leftmost
988                  * column first, each branch's target location should
989                  * always be either its current location or to the left of
990                  * its current location.
991                  *
992                  * We never have to move branches to the right.  This makes
993                  * the graph much more legible, since whenever branches
994                  * cross, only one is moving directions.
995                  */
996                 assert(target * 2 <= i);
998                 if (target * 2 == i) {
999                         /*
1000                          * This column is already in the
1001                          * correct place
1002                          */
1003                         assert(graph->new_mapping[i] == -1);
1004                         graph->new_mapping[i] = target;
1005                 } else if (graph->new_mapping[i - 1] < 0) {
1006                         /*
1007                          * Nothing is to the left.
1008                          * Move to the left by one
1009                          */
1010                         graph->new_mapping[i - 1] = target;
1011                         /*
1012                          * If there isn't already an edge moving horizontally
1013                          * select this one.
1014                          */
1015                         if (horizontal_edge == -1) {
1016                                 int j;
1017                                 horizontal_edge = i;
1018                                 horizontal_edge_target = target;
1019                                 /*
1020                                  * The variable target is the index of the graph
1021                                  * column, and therefore target*2+3 is the
1022                                  * actual screen column of the first horizontal
1023                                  * line.
1024                                  */
1025                                 for (j = (target * 2)+3; j < (i - 2); j += 2)
1026                                         graph->new_mapping[j] = target;
1027                         }
1028                 } else if (graph->new_mapping[i - 1] == target) {
1029                         /*
1030                          * There is a branch line to our left
1031                          * already, and it is our target.  We
1032                          * combine with this line, since we share
1033                          * the same parent commit.
1034                          *
1035                          * We don't have to add anything to the
1036                          * output or new_mapping, since the
1037                          * existing branch line has already taken
1038                          * care of it.
1039                          */
1040                 } else {
1041                         /*
1042                          * There is a branch line to our left,
1043                          * but it isn't our target.  We need to
1044                          * cross over it.
1045                          *
1046                          * The space just to the left of this
1047                          * branch should always be empty.
1048                          *
1049                          * The branch to the left of that space
1050                          * should be our eventual target.
1051                          */
1052                         assert(graph->new_mapping[i - 1] > target);
1053                         assert(graph->new_mapping[i - 2] < 0);
1054                         assert(graph->new_mapping[i - 3] == target);
1055                         graph->new_mapping[i - 2] = target;
1056                         /*
1057                          * Mark this branch as the horizontal edge to
1058                          * prevent any other edges from moving
1059                          * horizontally.
1060                          */
1061                         if (horizontal_edge == -1)
1062                                 horizontal_edge = i;
1063                 }
1064         }
1066         /*
1067          * The new mapping may be 1 smaller than the old mapping
1068          */
1069         if (graph->new_mapping[graph->mapping_size - 1] < 0)
1070                 graph->mapping_size--;
1072         /*
1073          * Output out a line based on the new mapping info
1074          */
1075         for (i = 0; i < graph->mapping_size; i++) {
1076                 int target = graph->new_mapping[i];
1077                 if (target < 0)
1078                         strbuf_addch(sb, ' ');
1079                 else if (target * 2 == i)
1080                         strbuf_write_column(sb, &graph->new_columns[target], '|');
1081                 else if (target == horizontal_edge_target &&
1082                          i != horizontal_edge - 1) {
1083                                 /*
1084                                  * Set the mappings for all but the
1085                                  * first segment to -1 so that they
1086                                  * won't continue into the next line.
1087                                  */
1088                                 if (i != (target * 2)+3)
1089                                         graph->new_mapping[i] = -1;
1090                                 used_horizontal = 1;
1091                         strbuf_write_column(sb, &graph->new_columns[target], '_');
1092                 } else {
1093                         if (used_horizontal && i < horizontal_edge)
1094                                 graph->new_mapping[i] = -1;
1095                         strbuf_write_column(sb, &graph->new_columns[target], '/');
1097                 }
1098         }
1100         graph_pad_horizontally(graph, sb, graph->mapping_size);
1102         /*
1103          * Swap mapping and new_mapping
1104          */
1105         tmp_mapping = graph->mapping;
1106         graph->mapping = graph->new_mapping;
1107         graph->new_mapping = tmp_mapping;
1109         /*
1110          * If graph->mapping indicates that all of the branch lines
1111          * are already in the correct positions, we are done.
1112          * Otherwise, we need to collapse some branch lines together.
1113          */
1114         if (graph_is_mapping_correct(graph))
1115                 graph_update_state(graph, GRAPH_PADDING);
1118 static int graph_next_line(struct git_graph *graph, struct strbuf *sb)
1120         switch (graph->state) {
1121         case GRAPH_PADDING:
1122                 graph_output_padding_line(graph, sb);
1123                 return 0;
1124         case GRAPH_SKIP:
1125                 graph_output_skip_line(graph, sb);
1126                 return 0;
1127         case GRAPH_PRE_COMMIT:
1128                 graph_output_pre_commit_line(graph, sb);
1129                 return 0;
1130         case GRAPH_COMMIT:
1131                 graph_output_commit_line(graph, sb);
1132                 return 1;
1133         case GRAPH_POST_MERGE:
1134                 graph_output_post_merge_line(graph, sb);
1135                 return 0;
1136         case GRAPH_COLLAPSING:
1137                 graph_output_collapsing_line(graph, sb);
1138                 return 0;
1139         }
1141         assert(0);
1142         return 0;
1145 static void graph_padding_line(struct git_graph *graph, struct strbuf *sb)
1147         int i, j;
1149         if (graph->state != GRAPH_COMMIT) {
1150                 graph_next_line(graph, sb);
1151                 return;
1152         }
1154         /*
1155          * Output the row containing this commit
1156          * Iterate up to and including graph->num_columns,
1157          * since the current commit may not be in any of the existing
1158          * columns.  (This happens when the current commit doesn't have any
1159          * children that we have already processed.)
1160          */
1161         for (i = 0; i < graph->num_columns; i++) {
1162                 struct column *col = &graph->columns[i];
1163                 struct commit *col_commit = col->commit;
1164                 if (col_commit == graph->commit) {
1165                         strbuf_write_column(sb, col, '|');
1167                         if (graph->num_parents < 3)
1168                                 strbuf_addch(sb, ' ');
1169                         else {
1170                                 int num_spaces = ((graph->num_parents - 2) * 2);
1171                                 for (j = 0; j < num_spaces; j++)
1172                                         strbuf_addch(sb, ' ');
1173                         }
1174                 } else {
1175                         strbuf_write_column(sb, col, '|');
1176                         strbuf_addch(sb, ' ');
1177                 }
1178         }
1180         graph_pad_horizontally(graph, sb, graph->num_columns);
1182         /*
1183          * Update graph->prev_state since we have output a padding line
1184          */
1185         graph->prev_state = GRAPH_PADDING;
1188 int graph_is_commit_finished(struct git_graph const *graph)
1190         return (graph->state == GRAPH_PADDING);
1193 void graph_show_commit(struct git_graph *graph)
1195         struct strbuf msgbuf = STRBUF_INIT;
1196         int shown_commit_line = 0;
1198         if (!graph)
1199                 return;
1201         while (!shown_commit_line) {
1202                 shown_commit_line = graph_next_line(graph, &msgbuf);
1203                 fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
1204                 if (!shown_commit_line)
1205                         putchar('\n');
1206                 strbuf_setlen(&msgbuf, 0);
1207         }
1209         strbuf_release(&msgbuf);
1212 void graph_show_oneline(struct git_graph *graph)
1214         struct strbuf msgbuf = STRBUF_INIT;
1216         if (!graph)
1217                 return;
1219         graph_next_line(graph, &msgbuf);
1220         fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
1221         strbuf_release(&msgbuf);
1224 void graph_show_padding(struct git_graph *graph)
1226         struct strbuf msgbuf = STRBUF_INIT;
1228         if (!graph)
1229                 return;
1231         graph_padding_line(graph, &msgbuf);
1232         fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
1233         strbuf_release(&msgbuf);
1236 int graph_show_remainder(struct git_graph *graph)
1238         struct strbuf msgbuf = STRBUF_INIT;
1239         int shown = 0;
1241         if (!graph)
1242                 return 0;
1244         if (graph_is_commit_finished(graph))
1245                 return 0;
1247         for (;;) {
1248                 graph_next_line(graph, &msgbuf);
1249                 fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
1250                 strbuf_setlen(&msgbuf, 0);
1251                 shown = 1;
1253                 if (!graph_is_commit_finished(graph))
1254                         putchar('\n');
1255                 else
1256                         break;
1257         }
1258         strbuf_release(&msgbuf);
1260         return shown;
1264 static void graph_show_strbuf(struct git_graph *graph, struct strbuf const *sb)
1266         char *p;
1268         if (!graph) {
1269                 fwrite(sb->buf, sizeof(char), sb->len, stdout);
1270                 return;
1271         }
1273         /*
1274          * Print the strbuf line by line,
1275          * and display the graph info before each line but the first.
1276          */
1277         p = sb->buf;
1278         while (p) {
1279                 size_t len;
1280                 char *next_p = strchr(p, '\n');
1281                 if (next_p) {
1282                         next_p++;
1283                         len = next_p - p;
1284                 } else {
1285                         len = (sb->buf + sb->len) - p;
1286                 }
1287                 fwrite(p, sizeof(char), len, stdout);
1288                 if (next_p && *next_p != '\0')
1289                         graph_show_oneline(graph);
1290                 p = next_p;
1291         }
1294 void graph_show_commit_msg(struct git_graph *graph,
1295                            struct strbuf const *sb)
1297         int newline_terminated;
1299         if (!graph) {
1300                 /*
1301                  * If there's no graph, just print the message buffer.
1302                  *
1303                  * The message buffer for CMIT_FMT_ONELINE and
1304                  * CMIT_FMT_USERFORMAT are already missing a terminating
1305                  * newline.  All of the other formats should have it.
1306                  */
1307                 fwrite(sb->buf, sizeof(char), sb->len, stdout);
1308                 return;
1309         }
1311         newline_terminated = (sb->len && sb->buf[sb->len - 1] == '\n');
1313         /*
1314          * Show the commit message
1315          */
1316         graph_show_strbuf(graph, sb);
1318         /*
1319          * If there is more output needed for this commit, show it now
1320          */
1321         if (!graph_is_commit_finished(graph)) {
1322                 /*
1323                  * If sb doesn't have a terminating newline, print one now,
1324                  * so we can start the remainder of the graph output on a
1325                  * new line.
1326                  */
1327                 if (!newline_terminated)
1328                         putchar('\n');
1330                 graph_show_remainder(graph);
1332                 /*
1333                  * If sb ends with a newline, our output should too.
1334                  */
1335                 if (newline_terminated)
1336                         putchar('\n');
1337         }