Raw
1 #define DISABLE_SIGN_COMPARE_WARNINGS
2
3 #include "git-compat-util.h"
4 #include "gettext.h"
5 #include "config.h"
6 #include "commit.h"
7 #include "color.h"
8 #include "graph.h"
9 #include "revision.h"
10 #include "strvec.h"
11
12 /* Internal API */
13
14 /*
15 * Output a padding line in the graph.
16 * This is similar to graph_next_line(). However, it is guaranteed to
17 * never print the current commit line. Instead, if the commit line is
18 * next, it will simply output a line of vertical padding, extending the
19 * branch lines downwards, but leaving them otherwise unchanged.
20 */
21 static void graph_padding_line(struct git_graph *graph, struct strbuf *sb);
22
23 /*
24 * Print a strbuf. If the graph is non-NULL, all lines but the first will be
25 * prefixed with the graph output.
26 *
27 * If the strbuf ends with a newline, the output will end after this
28 * newline. A new graph line will not be printed after the final newline.
29 * If the strbuf is empty, no output will be printed.
30 *
31 * Since the first line will not include the graph output, the caller is
32 * responsible for printing this line's graph (perhaps via
33 * graph_show_commit() or graph_show_oneline()) before calling
34 * graph_show_strbuf().
35 *
36 * Note that unlike some other graph display functions, you must pass the file
37 * handle directly. It is assumed that this is the same file handle as the
38 * file specified by the graph diff options. This is necessary so that
39 * graph_show_strbuf can be called even with a NULL graph.
40 * If a NULL graph is supplied, the strbuf is printed as-is.
41 */
42 static void graph_show_strbuf(struct git_graph *graph,
43 FILE *file,
44 struct strbuf const *sb);
45
46 /*
47 * TODO:
48 * - Limit the number of columns, similar to the way gitk does.
49 * If we reach more than a specified number of columns, omit
50 * sections of some columns.
51 */
52
53 struct column {
54 /*
55 * The parent commit of this column.
56 */
57 struct commit *commit;
58 /*
59 * The color to (optionally) print this column in. This is an
60 * index into column_colors.
61 */
62 unsigned short color;
63 /*
64 * Marks if a commit is a non-first parent of a merge. These columns are
65 * already visually connected to the merge commit and do not need
66 * indentation.
67 *
68 * The first parent is the one that inherits the column and it can need
69 * indentation if turns out to be a visual root and there's still
70 * commits to render.
71 */
72 unsigned int is_merge_parent:1;
73 };
74
75 enum graph_state {
76 GRAPH_PADDING,
77 GRAPH_SKIP,
78 GRAPH_PRE_COMMIT,
79 GRAPH_PRE_ROOT,
80 GRAPH_COMMIT,
81 GRAPH_POST_MERGE,
82 GRAPH_COLLAPSING
83 };
84
85 static void graph_show_line_prefix(const struct diff_options *diffopt)
86 {
87 if (!diffopt || !diffopt->line_prefix)
88 return;
89
90 fputs(diffopt->line_prefix, diffopt->file);
91 }
92
93 static const char **column_colors;
94 static unsigned short column_colors_max;
95
96 static void parse_graph_colors_config(struct strvec *colors, const char *string)
97 {
98 const char *end, *start;
99
100 start = string;
101 end = string + strlen(string);
102 while (start < end) {
103 const char *comma = strchrnul(start, ',');
104 char color[COLOR_MAXLEN];
105
106 if (!color_parse_mem(start, comma - start, color))
107 strvec_push(colors, color);
108 else
109 warning(_("ignored invalid color '%.*s' in log.graphColors"),
110 (int)(comma - start), start);
111 start = comma + 1;
112 }
113 strvec_push(colors, GIT_COLOR_RESET);
114 }
115
116 void graph_set_column_colors(const char **colors, unsigned short colors_max)
117 {
118 column_colors = colors;
119 column_colors_max = colors_max;
120 }
121
122 static const char *column_get_color_code(unsigned short color)
123 {
124 return column_colors[color];
125 }
126
127 struct graph_line {
128 struct strbuf *buf;
129 size_t width;
130 };
131
132 static inline void graph_line_addch(struct graph_line *line, int c)
133 {
134 strbuf_addch(line->buf, c);
135 line->width++;
136 }
137
138 static inline void graph_line_addchars(struct graph_line *line, int c, size_t n)
139 {
140 strbuf_addchars(line->buf, c, n);
141 line->width += n;
142 }
143
144 static inline void graph_line_addstr(struct graph_line *line, const char *s)
145 {
146 strbuf_addstr(line->buf, s);
147 line->width += strlen(s);
148 }
149
150 static inline void graph_line_addcolor(struct graph_line *line, unsigned short color)
151 {
152 strbuf_addstr(line->buf, column_get_color_code(color));
153 }
154
155 static void graph_line_write_column(struct graph_line *line, const struct column *c,
156 char col_char)
157 {
158 if (c->color < column_colors_max)
159 graph_line_addcolor(line, c->color);
160 graph_line_addch(line, col_char);
161 if (c->color < column_colors_max)
162 graph_line_addcolor(line, column_colors_max);
163 }
164
165 struct git_graph {
166 /*
167 * The commit currently being processed
168 */
169 struct commit *commit;
170 /* The rev-info used for the current traversal */
171 struct rev_info *revs;
172 /*
173 * The number of interesting parents that this commit has.
174 *
175 * Note that this is not the same as the actual number of parents.
176 * This count excludes parents that won't be printed in the graph
177 * output, as determined by graph_is_interesting().
178 */
179 int num_parents;
180 /*
181 * The width of the graph output for this commit.
182 * All rows for this commit are padded to this width, so that
183 * messages printed after the graph output are aligned.
184 */
185 int width;
186 /*
187 * The next expansion row to print
188 * when state is GRAPH_PRE_COMMIT
189 */
190 int expansion_row;
191 /*
192 * The current output state.
193 * This tells us what kind of line graph_next_line() should output.
194 */
195 enum graph_state state;
196 /*
197 * The output state for the previous line of output.
198 * This is primarily used to determine how the first merge line
199 * should appear, based on the last line of the previous commit.
200 */
201 enum graph_state prev_state;
202 /*
203 * The index of the column that refers to this commit.
204 *
205 * If none of the incoming columns refer to this commit,
206 * this will be equal to num_columns.
207 */
208 int commit_index;
209 /*
210 * The commit_index for the previously displayed commit.
211 *
212 * This is used to determine how the first line of a merge
213 * graph output should appear, based on the last line of the
214 * previous commit.
215 */
216 int prev_commit_index;
217 /*
218 * Which layout variant to use to display merge commits. If the
219 * commit's first parent is known to be in a column to the left of the
220 * merge, then this value is 0 and we use the layout on the left.
221 * Otherwise, the value is 1 and the layout on the right is used. This
222 * field tells us how many columns the first parent occupies.
223 *
224 * 0) 1)
225 *
226 * | | | *-. | | *---.
227 * | |_|/|\ \ | | |\ \ \
228 * |/| | | | | | | | | | *
229 */
230 int merge_layout;
231 /*
232 * The number of columns added to the graph by the current commit. For
233 * 2-way and octopus merges, this is usually one less than the
234 * number of parents:
235 *
236 * | | | | | \
237 * | * | | *---. \
238 * | |\ \ | |\ \ \ \
239 * | | | | | | | | | |
240 *
241 * num_parents: 2 num_parents: 4
242 * edges_added: 1 edges_added: 3
243 *
244 * For left-skewed merges, the first parent fuses with its neighbor and
245 * so one less column is added:
246 *
247 * | | | | | \
248 * | * | | *-. \
249 * |/| | |/|\ \ \
250 * | | | | | | | |
251 *
252 * num_parents: 2 num_parents: 4
253 * edges_added: 0 edges_added: 2
254 *
255 * This number determines how edges to the right of the merge are
256 * displayed in commit and post-merge lines; if no columns have been
257 * added then a vertical line should be used where a right-tracking
258 * line would otherwise be used.
259 *
260 * | * \ | * |
261 * | |\ \ |/| |
262 * | | * \ | * |
263 */
264 int edges_added;
265 /*
266 * The number of columns added by the previous commit, which is used to
267 * smooth edges appearing to the right of a commit in a commit line
268 * following a post-merge line.
269 */
270 int prev_edges_added;
271 /*
272 * The maximum number of columns that can be stored in the columns
273 * and new_columns arrays. This is also half the number of entries
274 * that can be stored in the mapping and old_mapping arrays.
275 */
276 int column_capacity;
277 /*
278 * The number of columns (also called "branch lines" in some places)
279 */
280 int num_columns;
281 /*
282 * The number of columns in the new_columns array
283 */
284 int num_new_columns;
285 /*
286 * The number of entries in the mapping array
287 */
288 int mapping_size;
289 /*
290 * The column state before we output the current commit.
291 */
292 struct column *columns;
293 /*
294 * The new column state after we output the current commit.
295 * Only valid when state is GRAPH_COLLAPSING.
296 */
297 struct column *new_columns;
298 /*
299 * An array that tracks the current state of each
300 * character in the output line during state GRAPH_COLLAPSING.
301 * Each entry is -1 if this character is empty, or a non-negative
302 * integer if the character contains a branch line. The value of
303 * the integer indicates the target position for this branch line.
304 * (I.e., this array maps the current column positions to their
305 * desired positions.)
306 *
307 * The maximum capacity of this array is always
308 * sizeof(int) * 2 * column_capacity.
309 */
310 int *mapping;
311 /*
312 * A copy of the contents of the mapping array from the last commit,
313 * which we use to improve the display of columns that are tracking
314 * from right to left through a commit line. We also use this to
315 * avoid allocating a fresh array when we compute the next mapping.
316 */
317 int *old_mapping;
318 /*
319 * The current default column color being used. This is
320 * stored as an index into the array column_colors.
321 */
322 unsigned short default_column_color;
323
324 /*
325 * Scratch buffer for generating prefixes to be used with
326 * diff_output_prefix_callback().
327 */
328 struct strbuf prefix_buf;
329
330 /*
331 * Lookahead buffer: up to 2 pre-fetched commits that will be shown.
332 * Populated by get_revision() so graph_peek_next_visible() can use
333 * actual walk results instead of peeking at rev_info internals.
334 */
335 struct commit *lookahead[2];
336 int lookahead_nr;
337
338 /*
339 * If a commit is a visual root, we need to indent it to prevent
340 * unrelated commits from being vertically adjacent to it.
341 */
342 unsigned int is_visual_root:1;
343
344 /*
345 * Indentation increases for each visual root adjacent to another visual
346 * root, making visual root commits indentation cascade.
347 */
348 unsigned int visual_root_depth;
349
350 /*
351 * When a visual root is adjacent to other visual roots, the first one
352 * can avoid indentation and the rest cascades, increasing the indentation
353 * for each one.
354 */
355 unsigned int visual_root_cascade:1;
356
357 /*
358 * Set when the current commit was already present in graph->columns
359 * before being processed.
360 */
361 unsigned int commit_in_columns:1;
362 };
363
364 struct graph_lookahead_flags {
365
366 /*
367 * Set when there will be a commit after the current one that will be
368 * rendered.
369 */
370 unsigned int is_next_visible:1;
371
372 /*
373 * Set when the next visible commit is candidate to be a visual root.
374 */
375 unsigned int is_next_visual_root:1;
376
377 /*
378 * Set when the next visible commit will be rendered under the current
379 * commit.
380 */
381 unsigned int next_has_column:1;
382 };
383
384 static inline int graph_needs_truncation(struct git_graph *graph, int lane)
385 {
386 int max = graph->revs->graph_max_lanes;
387 /*
388 * Ignore values <= 0, meaning no limit.
389 */
390 return max > 0 && lane >= max;
391 }
392
393 static const char *diff_output_prefix_callback(struct diff_options *opt, void *data)
394 {
395 struct git_graph *graph = data;
396
397 assert(opt);
398
399 if (!graph)
400 return opt->line_prefix;
401
402 strbuf_reset(&graph->prefix_buf);
403 if (opt->line_prefix)
404 strbuf_addstr(&graph->prefix_buf, opt->line_prefix);
405 graph_padding_line(graph, &graph->prefix_buf);
406 return graph->prefix_buf.buf;
407 }
408
409 static const struct diff_options *default_diffopt;
410
411 void graph_setup_line_prefix(struct diff_options *diffopt)
412 {
413 default_diffopt = diffopt;
414
415 /* setup an output prefix callback if necessary */
416 if (diffopt && !diffopt->output_prefix)
417 diffopt->output_prefix = diff_output_prefix_callback;
418 }
419
420 static void graph_read_config(struct rev_info *revs)
421 {
422 int val;
423
424 if (!column_colors) {
425 char *string;
426 if (repo_config_get_string(revs->repo, "log.graphcolors", &string)) {
427 /* not configured -- use default */
428 graph_set_column_colors(column_colors_ansi,
429 column_colors_ansi_max);
430 } else {
431 static struct strvec custom_colors = STRVEC_INIT;
432 strvec_clear(&custom_colors);
433 parse_graph_colors_config(&custom_colors, string);
434 free(string);
435 /* graph_set_column_colors takes a max-index, not a count */
436 graph_set_column_colors(custom_colors.v,
437 custom_colors.nr - 1);
438 }
439 }
440
441 if (!repo_config_get_bool(revs->repo, "log.graphIndent", &val))
442 revs->no_graph_indent = !val;
443 }
444
445 struct git_graph *graph_init(struct rev_info *opt)
446 {
447 struct git_graph *graph = xmalloc(sizeof(struct git_graph));
448
449 graph_read_config(opt);
450
451 graph->commit = NULL;
452 graph->revs = opt;
453 graph->num_parents = 0;
454 graph->expansion_row = 0;
455 graph->state = GRAPH_PADDING;
456 graph->prev_state = GRAPH_PADDING;
457 graph->commit_index = 0;
458 graph->prev_commit_index = 0;
459 graph->merge_layout = 0;
460 graph->edges_added = 0;
461 graph->prev_edges_added = 0;
462 graph->num_columns = 0;
463 graph->num_new_columns = 0;
464 graph->mapping_size = 0;
465 graph->lookahead[0] = NULL;
466 graph->lookahead[1] = NULL;
467 graph->lookahead_nr = 0;
468 graph->visual_root_depth = 0;
469 graph->visual_root_cascade = 0;
470 /*
471 * Start the column color at the maximum value, since we'll
472 * always increment it for the first commit we output.
473 * This way we start at 0 for the first commit.
474 */
475 graph->default_column_color = column_colors_max - 1;
476
477 /*
478 * Allocate a reasonably large default number of columns
479 * We'll automatically grow columns later if we need more room.
480 */
481 graph->column_capacity = 30;
482 ALLOC_ARRAY(graph->columns, graph->column_capacity);
483 ALLOC_ARRAY(graph->new_columns, graph->column_capacity);
484 ALLOC_ARRAY(graph->mapping, 2 * graph->column_capacity);
485 ALLOC_ARRAY(graph->old_mapping, 2 * graph->column_capacity);
486
487 /*
488 * The diff output prefix callback, with this we can make
489 * all the diff output to align with the graph lines.
490 */
491 strbuf_init(&graph->prefix_buf, 0);
492 opt->diffopt.output_prefix = diff_output_prefix_callback;
493 opt->diffopt.output_prefix_data = graph;
494
495 return graph;
496 }
497
498 void graph_clear(struct git_graph *graph)
499 {
500 if (!graph)
501 return;
502
503 free(graph->columns);
504 free(graph->new_columns);
505 free(graph->mapping);
506 free(graph->old_mapping);
507 strbuf_release(&graph->prefix_buf);
508 free(graph);
509 }
510
511 static void graph_update_state(struct git_graph *graph, enum graph_state s)
512 {
513 graph->prev_state = graph->state;
514 graph->state = s;
515 }
516
517 static void graph_ensure_capacity(struct git_graph *graph, int num_columns)
518 {
519 if (graph->column_capacity >= num_columns)
520 return;
521
522 do {
523 graph->column_capacity *= 2;
524 } while (graph->column_capacity < num_columns);
525
526 REALLOC_ARRAY(graph->columns, graph->column_capacity);
527 REALLOC_ARRAY(graph->new_columns, graph->column_capacity);
528 REALLOC_ARRAY(graph->mapping, graph->column_capacity * 2);
529 REALLOC_ARRAY(graph->old_mapping, graph->column_capacity * 2);
530 }
531
532 /*
533 * Returns 1 if the commit will be printed in the graph output,
534 * and 0 otherwise.
535 */
536 static int graph_is_interesting(struct git_graph *graph, struct commit *commit)
537 {
538 /*
539 * Commits in the lookahead buffer have been pre-fetched by
540 * get_revision() and will be shown in the future. They already have
541 * the SHOWN flag set when they were pre-fetched but the graph still
542 * needs to treat them as interesting parents.
543 */
544 for (int i = 0; i < graph->lookahead_nr; i++)
545 if (graph->lookahead[i] == commit)
546 return 1;
547 /*
548 * If revs->boundary is set, commits whose children have
549 * been shown are always interesting, even if they have the
550 * UNINTERESTING or TREESAME flags set.
551 */
552 if (graph->revs && graph->revs->boundary) {
553 if (commit->object.flags & CHILD_SHOWN)
554 return 1;
555 }
556
557 /*
558 * Otherwise, use get_commit_action() to see if this commit is
559 * interesting
560 */
561 return get_commit_action(graph->revs, commit) == commit_show;
562 }
563
564 static struct commit_list *next_interesting_parent(struct git_graph *graph,
565 struct commit_list *orig)
566 {
567 struct commit_list *list;
568
569 /*
570 * If revs->first_parent_only is set, only the first
571 * parent is interesting. None of the others are.
572 */
573 if (graph->revs->first_parent_only)
574 return NULL;
575
576 /*
577 * Return the next interesting commit after orig
578 */
579 for (list = orig->next; list; list = list->next) {
580 if (graph_is_interesting(graph, list->item))
581 return list;
582 }
583
584 return NULL;
585 }
586
587 static struct commit_list *first_interesting_parent(struct git_graph *graph)
588 {
589 struct commit_list *parents = graph->commit->parents;
590
591 /*
592 * If this commit has no parents, ignore it
593 */
594 if (!parents)
595 return NULL;
596
597 /*
598 * If the first parent is interesting, return it
599 */
600 if (graph_is_interesting(graph, parents->item))
601 return parents;
602
603 /*
604 * Otherwise, call next_interesting_parent() to get
605 * the next interesting parent
606 */
607 return next_interesting_parent(graph, parents);
608 }
609
610 static unsigned short graph_get_current_column_color(const struct git_graph *graph)
611 {
612 if (!want_color(graph->revs->diffopt.use_color))
613 return column_colors_max;
614 return graph->default_column_color;
615 }
616
617 /*
618 * Update the graph's default column color.
619 */
620 static void graph_increment_column_color(struct git_graph *graph)
621 {
622 graph->default_column_color = (graph->default_column_color + 1) %
623 column_colors_max;
624 }
625
626 static unsigned short graph_find_commit_color(const struct git_graph *graph,
627 const struct commit *commit)
628 {
629 int i;
630 for (i = 0; i < graph->num_columns; i++) {
631 if (graph->columns[i].commit == commit)
632 return graph->columns[i].color;
633 }
634 return graph_get_current_column_color(graph);
635 }
636
637 static int graph_find_new_column_by_commit(struct git_graph *graph,
638 struct commit *commit)
639 {
640 int i;
641 for (i = 0; i < graph->num_new_columns; i++) {
642 if (graph->new_columns[i].commit == commit)
643 return i;
644 }
645 return -1;
646 }
647
648 static void graph_insert_into_new_columns(struct git_graph *graph,
649 struct commit *commit,
650 int idx)
651 {
652 /*
653 * Get the initial merge_layout before it's modified to know if this
654 * is a merge.
655 */
656 int initial_merge_layout = graph->merge_layout;
657 int i = graph_find_new_column_by_commit(graph, commit);
658 int mapping_idx;
659
660 /*
661 * If the commit is not already in the new_columns array, then add it
662 * and record it as being in the final column.
663 */
664 if (i < 0) {
665 i = graph->num_new_columns++;
666 graph->new_columns[i].commit = commit;
667 graph->new_columns[i].color = graph_find_commit_color(graph, commit);
668 graph->new_columns[i].is_merge_parent = 0;
669 }
670
671 if (graph->num_parents > 1 && idx > -1 && graph->merge_layout == -1) {
672 /*
673 * If this is the first parent of a merge, choose a layout for
674 * the merge line based on whether the parent appears in a
675 * column to the left of the merge
676 */
677 int dist, shift;
678
679 dist = idx - i;
680 shift = (dist > 1) ? 2 * dist - 3 : 1;
681
682 graph->merge_layout = (dist > 0) ? 0 : 1;
683 graph->edges_added = graph->num_parents + graph->merge_layout - 2;
684
685 mapping_idx = graph->width + (graph->merge_layout - 1) * shift;
686 graph->width += 2 * graph->merge_layout;
687
688 } else if (graph->edges_added > 0 && i == graph->mapping[graph->width - 2]) {
689 /*
690 * If some columns have been added by a merge, but this commit
691 * was found in the last existing column, then adjust the
692 * numbers so that the two edges immediately join, i.e.:
693 *
694 * * | * |
695 * |\ \ => |\|
696 * | |/ | *
697 * | *
698 */
699 mapping_idx = graph->width - 2;
700 graph->edges_added = -1;
701 } else {
702 mapping_idx = graph->width;
703 graph->width += 2;
704 }
705
706 graph->mapping[mapping_idx] = i;
707
708 /*
709 * Mark non-first parents of a merge.
710 */
711 if (graph->num_parents > 1 && initial_merge_layout >= 0 && idx > -1)
712 graph->new_columns[i].is_merge_parent = 1;
713 }
714
715 static void graph_update_columns(struct git_graph *graph)
716 {
717 struct commit_list *parent;
718 int max_new_columns;
719 int i, seen_this, is_commit_in_columns;
720
721 /*
722 * Swap graph->columns with graph->new_columns
723 * graph->columns contains the state for the previous commit,
724 * and new_columns now contains the state for our commit.
725 *
726 * We'll re-use the old columns array as storage to compute the new
727 * columns list for the commit after this one.
728 */
729 SWAP(graph->columns, graph->new_columns);
730 graph->num_columns = graph->num_new_columns;
731 graph->num_new_columns = 0;
732
733 /*
734 * Now update new_columns and mapping with the information for the
735 * commit after this one.
736 *
737 * First, make sure we have enough room. At most, there will
738 * be graph->num_columns + graph->num_parents columns for the next
739 * commit.
740 */
741 max_new_columns = graph->num_columns + graph->num_parents;
742 graph_ensure_capacity(graph, max_new_columns);
743
744 /*
745 * Clear out graph->mapping
746 */
747 graph->mapping_size = 2 * max_new_columns;
748 for (i = 0; i < graph->mapping_size; i++)
749 graph->mapping[i] = -1;
750
751 graph->width = 0;
752 graph->prev_edges_added = graph->edges_added;
753 graph->edges_added = 0;
754
755 /*
756 * Populate graph->new_columns and graph->mapping
757 *
758 * Some of the parents of this commit may already be in
759 * graph->columns. If so, graph->new_columns should only contain a
760 * single entry for each such commit. graph->mapping should
761 * contain information about where each current branch line is
762 * supposed to end up after the collapsing is performed.
763 */
764 seen_this = 0;
765 is_commit_in_columns = 1;
766 for (i = 0; i <= graph->num_columns; i++) {
767 struct commit *col_commit;
768 if (i == graph->num_columns) {
769 if (seen_this)
770 break;
771 is_commit_in_columns = 0;
772 col_commit = graph->commit;
773 } else {
774 col_commit = graph->columns[i].commit;
775 }
776
777 if (col_commit == graph->commit) {
778 seen_this = 1;
779 graph->commit_index = i;
780 graph->merge_layout = -1;
781 for (parent = first_interesting_parent(graph);
782 parent;
783 parent = next_interesting_parent(graph, parent)) {
784 /*
785 * If this is a merge, or the start of a new
786 * childless column, increment the current
787 * color.
788 */
789 if (graph->num_parents > 1 ||
790 !is_commit_in_columns) {
791 graph_increment_column_color(graph);
792 }
793 graph_insert_into_new_columns(graph, parent->item, i);
794 }
795 /*
796 * We always need to increment graph->width by at
797 * least 2, even if it has no interesting parents.
798 * The current commit always takes up at least 2
799 * spaces.
800 */
801 if (graph->num_parents == 0)
802 graph->width += 2;
803 } else {
804 int j;
805 graph_insert_into_new_columns(graph, col_commit, -1);
806 /*
807 * This column is not the current commit, but we need to
808 * propagate the flag until the commit is processed.
809 */
810 j = graph_find_new_column_by_commit(graph, col_commit);
811 if (j >= 0 && graph->columns[i].is_merge_parent)
812 graph->new_columns[j].is_merge_parent = 1;
813 }
814 }
815
816 graph->commit_in_columns = is_commit_in_columns;
817
818 /*
819 * If graph_max_lanes is set, cap the width
820 */
821 if (graph->revs->graph_max_lanes > 0) {
822 /*
823 * width of "| " per lanes plus truncation mark "~ ".
824 * Allow commits from merges to align to the merged lane.
825 */
826 int max_width = graph->revs->graph_max_lanes * 2 + 2;
827 if (graph->width > max_width)
828 graph->width = max_width;
829 }
830
831 /*
832 * Shrink mapping_size to be the minimum necessary
833 */
834 while (graph->mapping_size > 1 &&
835 graph->mapping[graph->mapping_size - 1] < 0)
836 graph->mapping_size--;
837 }
838
839 static int graph_num_dashed_parents(struct git_graph *graph)
840 {
841 return graph->num_parents + graph->merge_layout - 3;
842 }
843
844 static int graph_num_expansion_rows(struct git_graph *graph)
845 {
846 /*
847 * Normally, we need two expansion rows for each dashed parent line from
848 * an octopus merge:
849 *
850 * | *
851 * | |\
852 * | | \
853 * | | \
854 * | *-. \
855 * | |\ \ \
856 *
857 * If the merge is skewed to the left, then its parents occupy one less
858 * column, and we don't need as many expansion rows to route around it;
859 * in some cases that means we don't need any expansion rows at all:
860 *
861 * | *
862 * | |\
863 * | * \
864 * |/|\ \
865 */
866 return graph_num_dashed_parents(graph) * 2;
867 }
868
869 static int graph_needs_pre_commit_line(struct git_graph *graph)
870 {
871 return graph->num_parents >= 3 &&
872 graph->commit_index < (graph->num_columns - 1) &&
873 graph->expansion_row < graph_num_expansion_rows(graph);
874 }
875
876 struct commit *graph_pop_lookahead(struct git_graph *graph)
877 {
878 struct commit *c;
879
880 if (!graph->lookahead_nr)
881 return NULL;
882
883 c = graph->lookahead[0];
884 if (!c)
885 BUG("lookahead buffer has %d entries but the first one is NULL",
886 graph->lookahead_nr);
887
888 graph->lookahead[0] = graph->lookahead[1];
889 graph->lookahead[1] = NULL;
890 graph->lookahead_nr--;
891 return c;
892 }
893
894 int graph_get_lookahead_room(struct git_graph *graph)
895 {
896 return (int)ARRAY_SIZE(graph->lookahead) - graph->lookahead_nr;
897 }
898
899 void graph_push_lookahead(struct git_graph *graph, struct commit *c)
900 {
901 if (!graph_get_lookahead_room(graph))
902 BUG("pushing into lookahead buffer when it is already full");
903
904 graph->lookahead[graph->lookahead_nr++] = c;
905 }
906
907 /*
908 * A commit can be a visual root when:
909 *
910 * - It has no parents.
911 *
912 * - It has parents but they are all filtered out and
913 * commit->parents arrives NULL.
914 *
915 * - Its parents are uninteresting.
916 *
917 * - It is not a boundary commit. Boundary commits also have no visible
918 * parents, but they are not selected as visual roots because they cannot
919 * cause the ambiguity of being vertically adjacent because:
920 *
921 * 1. A boundary only appears because an included commit is its child.
922 * Children are always above, and the renderer draws an edge down to
923 * the boundary from that child. Rather than starting a column like a
924 * visual root would do, it inherits its child column.
925 *
926 * 2. Included commits cannot appear below a boundary. Boundaries are
927 * ancestors of the exclusion point; if an included commit were an
928 * ancestor of the boundary it would be excluded and not rendered.
929 * Boundaries therefore always sink to the bottom.
930 */
931 static int graph_is_visual_root_candidate(struct commit *c, struct git_graph *graph)
932 {
933 struct commit_list *p;
934
935 if (c->object.flags & BOUNDARY)
936 return 0;
937 for (p = c->parents; p; p = p->next)
938 if (graph_is_interesting(graph, p->item))
939 return 0;
940 return 1;
941 }
942
943 static int graph_is_visual_root(struct git_graph *graph,
944 struct graph_lookahead_flags *flags)
945 {
946 /*
947 * This must be only called for the current commit as graph contains
948 * the state for the current commit only.
949 *
950 * To check if a commit is a visual root, call graph_is_visual_root_candidate()
951 * but we won't know if it is really a visual root until we get to the
952 * next commit state.
953 *
954 * The current commit is an actual visual root if it is a candidate and
955 * the commit is not a non-first parent of a merge.
956 *
957 * *
958 * |\
959 * | * <- it is a visual root candidate but it shouldn't be indented
960 * * because it is already connected by an edge.
961 * ^ if commit_in_columns && is_merge_parent means the commit
962 * | was put by a merge and is connected.
963 * |
964 * `-------- if !is_next_visible means we're on the last commit, avoid
965 * indentation unless the one before is a visual root, then
966 * we need to differentiate from the one above.
967 *
968 * If next_has_columns means that the next commit has
969 * already a column, so it will not be rendered below, the
970 * current commit has to act as the last commit and omit
971 * indentation.
972 */
973 return graph_is_visual_root_candidate(graph->commit, graph) &&
974 !(graph->commit_in_columns &&
975 graph->columns[graph->commit_index].is_merge_parent) &&
976 flags->is_next_visible &&
977 (!flags->next_has_column || graph->visual_root_depth > 0);
978 }
979
980 /*
981 * Peeks the next commits via the lookahead buffer and sets the lookahead flags.
982 */
983 static void graph_peek_next_visible(struct git_graph *graph,
984 struct graph_lookahead_flags *flags)
985 {
986 flags->is_next_visible = 0;
987 flags->is_next_visual_root = 0;
988 flags->next_has_column = 0;
989
990 if (!graph->lookahead_nr)
991 return;
992
993 flags->is_next_visible = 1;
994 flags->next_has_column =
995 graph_find_new_column_by_commit(graph, graph->lookahead[0]) >= 0;
996
997 if (!graph_is_visual_root_candidate(graph->lookahead[0], graph))
998 return;
999
1000 if (graph->lookahead_nr >= 2)
1001 flags->is_next_visual_root = 1;
1002 }
1003
1004 static int graph_needs_pre_root_line(struct git_graph *graph)
1005 {
1006 return graph->commit_in_columns && graph->is_visual_root &&
1007 graph->num_columns > 0 && !graph->visual_root_cascade &&
1008 !graph->revs->no_graph_indent;
1009 }
1010
1011 void graph_update(struct git_graph *graph, struct commit *commit)
1012 {
1013 struct commit_list *parent;
1014 struct graph_lookahead_flags flags;
1015
1016 /*
1017 * Set the new commit
1018 */
1019 graph->commit = commit;
1020
1021 /*
1022 * Count how many interesting parents this commit has
1023 */
1024 graph->num_parents = 0;
1025 for (parent = first_interesting_parent(graph);
1026 parent;
1027 parent = next_interesting_parent(graph, parent))
1028 {
1029 graph->num_parents++;
1030 }
1031
1032 /*
1033 * Store the old commit_index in prev_commit_index.
1034 * graph_update_columns() will update graph->commit_index for this
1035 * commit.
1036 */
1037 graph->prev_commit_index = graph->commit_index;
1038
1039 /*
1040 * Call graph_update_columns() to update
1041 * columns, new_columns, and mapping.
1042 */
1043 graph_update_columns(graph);
1044
1045 graph_peek_next_visible(graph, &flags);
1046
1047 graph->is_visual_root = graph_is_visual_root(graph, &flags);
1048
1049 if (graph->is_visual_root) {
1050 /*
1051 * If next is a visual root we can omit the indent for the first
1052 * visual root and start cascading.
1053 */
1054 if (!graph->visual_root_depth && flags.is_next_visual_root)
1055 graph->visual_root_cascade = 1;
1056
1057 /*
1058 * We wrap the cascading at a max of four columns at most, after
1059 * that we wrap it back to the initial column.
1060 *
1061 * This could cause ambiguity in case of the next commit not
1062 * being a visual root and be at the initial column after the
1063 * first wrap.
1064 *
1065 * In case of being a non-visual-root the next, stop the
1066 * cascading to get the commit indented.
1067 */
1068 if (!flags.is_next_visual_root &&
1069 graph->visual_root_depth &&
1070 !(graph->visual_root_depth % 4))
1071 graph->visual_root_cascade = 0;
1072
1073 graph->visual_root_depth++;
1074 } else {
1075 graph->visual_root_depth = 0;
1076 graph->visual_root_cascade = 0;
1077 }
1078
1079 graph->expansion_row = 0;
1080
1081 /*
1082 * Update graph->state.
1083 * Note that we don't call graph_update_state() here, since
1084 * we don't want to update graph->prev_state. No line for
1085 * graph->state was ever printed.
1086 *
1087 * If the previous commit didn't get to the GRAPH_PADDING state,
1088 * it never finished its output. Goto GRAPH_SKIP, to print out
1089 * a line to indicate that portion of the graph is missing.
1090 *
1091 * If there are 3 or more parents, we may need to print extra rows
1092 * before the commit, to expand the branch lines around it and make
1093 * room for it. We need to do this only if there is a branch row
1094 * (or more) to the right of this commit.
1095 *
1096 * If it is a visual root, we need to print an extra row to
1097 * connect the indentation.
1098 *
1099 * If there are less than 3 parents, we can immediately print the
1100 * commit line.
1101 */
1102 if (graph->state != GRAPH_PADDING)
1103 graph->state = GRAPH_SKIP;
1104 else if (graph_needs_pre_root_line(graph))
1105 graph->state = GRAPH_PRE_ROOT;
1106 else if (graph_needs_pre_commit_line(graph))
1107 graph->state = GRAPH_PRE_COMMIT;
1108 else
1109 graph->state = GRAPH_COMMIT;
1110 }
1111
1112 static int graph_is_mapping_correct(struct git_graph *graph)
1113 {
1114 int i;
1115
1116 /*
1117 * The mapping is up to date if each entry is at its target,
1118 * or is 1 greater than its target.
1119 * (If it is 1 greater than the target, '/' will be printed, so it
1120 * will look correct on the next row.)
1121 */
1122 for (i = 0; i < graph->mapping_size; i++) {
1123 int target = graph->mapping[i];
1124 if (target < 0)
1125 continue;
1126 if (target == (i / 2))
1127 continue;
1128 return 0;
1129 }
1130
1131 return 1;
1132 }
1133
1134 static void graph_pad_horizontally(struct git_graph *graph, struct graph_line *line)
1135 {
1136 /*
1137 * Add additional spaces to the end of the strbuf, so that all
1138 * lines for a particular commit have the same width.
1139 *
1140 * This way, fields printed to the right of the graph will remain
1141 * aligned for the entire commit.
1142 */
1143 if (line->width < graph->width)
1144 graph_line_addchars(line, ' ', graph->width - line->width);
1145 }
1146
1147 static void graph_output_padding_line(struct git_graph *graph,
1148 struct graph_line *line)
1149 {
1150 int i;
1151
1152 /*
1153 * Output a padding row, that leaves all branch lines unchanged
1154 */
1155 for (i = 0; i < graph->num_new_columns; i++) {
1156 if (graph_needs_truncation(graph, i)) {
1157 graph_line_addstr(line, "~ ");
1158 break;
1159 }
1160 graph_line_write_column(line, &graph->new_columns[i], '|');
1161 graph_line_addch(line, ' ');
1162 }
1163 }
1164
1165
1166 int graph_width(struct git_graph *graph)
1167 {
1168 return graph->width;
1169 }
1170
1171
1172 static void graph_output_skip_line(struct git_graph *graph, struct graph_line *line)
1173 {
1174 /*
1175 * Output an ellipsis to indicate that a portion
1176 * of the graph is missing.
1177 */
1178 graph_line_addstr(line, "...");
1179
1180 if (graph_needs_pre_commit_line(graph))
1181 graph_update_state(graph, GRAPH_PRE_COMMIT);
1182 else
1183 graph_update_state(graph, GRAPH_COMMIT);
1184 }
1185
1186 static void graph_output_pre_commit_line(struct git_graph *graph,
1187 struct graph_line *line)
1188 {
1189 int i, seen_this;
1190
1191 /*
1192 * This function formats a row that increases the space around a commit
1193 * with multiple parents, to make room for it. It should only be
1194 * called when there are 3 or more parents.
1195 *
1196 * We need 2 extra rows for every parent over 2.
1197 */
1198 assert(graph->num_parents >= 3);
1199
1200 /*
1201 * graph->expansion_row tracks the current expansion row we are on.
1202 * It should be in the range [0, num_expansion_rows - 1]
1203 */
1204 assert(0 <= graph->expansion_row &&
1205 graph->expansion_row < graph_num_expansion_rows(graph));
1206
1207 /*
1208 * Output the row
1209 */
1210 seen_this = 0;
1211 for (i = 0; i < graph->num_columns; i++) {
1212 struct column *col = &graph->columns[i];
1213 if (col->commit == graph->commit) {
1214 seen_this = 1;
1215 graph_line_write_column(line, col, '|');
1216 graph_line_addchars(line, ' ', graph->expansion_row);
1217 } else if (seen_this && graph_needs_truncation(graph, i)) {
1218 graph_line_addstr(line, "~ ");
1219 break;
1220 } else if (seen_this && (graph->expansion_row == 0)) {
1221 /*
1222 * This is the first line of the pre-commit output.
1223 * If the previous commit was a merge commit and
1224 * ended in the GRAPH_POST_MERGE state, all branch
1225 * lines after graph->prev_commit_index were
1226 * printed as "\" on the previous line. Continue
1227 * to print them as "\" on this line. Otherwise,
1228 * print the branch lines as "|".
1229 */
1230 if (graph->prev_state == GRAPH_POST_MERGE &&
1231 graph->prev_commit_index < i)
1232 graph_line_write_column(line, col, '\\');
1233 else
1234 graph_line_write_column(line, col, '|');
1235 } else if (seen_this && (graph->expansion_row > 0)) {
1236 graph_line_write_column(line, col, '\\');
1237 } else {
1238 graph_line_write_column(line, col, '|');
1239 }
1240 graph_line_addch(line, ' ');
1241 }
1242
1243 /*
1244 * Increment graph->expansion_row,
1245 * and move to state GRAPH_COMMIT if necessary
1246 */
1247 graph->expansion_row++;
1248 if (!graph_needs_pre_commit_line(graph))
1249 graph_update_state(graph, GRAPH_COMMIT);
1250 }
1251
1252 static void graph_output_commit_char(struct git_graph *graph, struct graph_line *line)
1253 {
1254 /*
1255 * For boundary commits, print 'o'
1256 * (We should only see boundary commits when revs->boundary is set.)
1257 */
1258 if (graph->commit->object.flags & BOUNDARY) {
1259 assert(graph->revs->boundary);
1260 graph_line_addch(line, 'o');
1261 return;
1262 }
1263
1264 /*
1265 * get_revision_mark() handles all other cases without assert()
1266 */
1267 graph_line_addstr(line, get_revision_mark(graph->revs, graph->commit));
1268 }
1269
1270 /*
1271 * Draw the horizontal dashes of an octopus merge.
1272 */
1273 static void graph_draw_octopus_merge(struct git_graph *graph, struct graph_line *line)
1274 {
1275 /*
1276 * The parents of a merge commit can be arbitrarily reordered as they
1277 * are mapped onto display columns, for example this is a valid merge:
1278 *
1279 * | | *---.
1280 * | | |\ \ \
1281 * | | |/ / /
1282 * | |/| | /
1283 * | |_|_|/
1284 * |/| | |
1285 * 3 1 0 2
1286 *
1287 * The numbers denote which parent of the merge each visual column
1288 * corresponds to; we can't assume that the parents will initially
1289 * display in the order given by new_columns.
1290 *
1291 * To find the right color for each dash, we need to consult the
1292 * mapping array, starting from the column 2 places to the right of the
1293 * merge commit, and use that to find out which logical column each
1294 * edge will collapse to.
1295 *
1296 * Commits are rendered once all edges have collapsed to their correct
1297 * logcial column, so commit_index gives us the right visual offset for
1298 * the merge commit.
1299 */
1300
1301 int i, j;
1302 struct column *col;
1303
1304 int dashed_parents = graph_num_dashed_parents(graph);
1305
1306 for (i = 0; i < dashed_parents; i++) {
1307 j = graph->mapping[(graph->commit_index + i + 2) * 2];
1308 col = &graph->new_columns[j];
1309
1310 graph_line_write_column(line, col, '-');
1311
1312 /*
1313 * Commit is at commit_index, each iteration move one lane to
1314 * the right from the commit.
1315 */
1316 if (graph_needs_truncation(graph, graph->commit_index + 1 + i)) {
1317 graph_line_addstr(line, "~ ");
1318 break;
1319 }
1320
1321 graph_line_write_column(line, col, (i == dashed_parents - 1) ? '.' : '-');
1322 }
1323
1324 return;
1325 }
1326
1327 static void graph_output_commit_line(struct git_graph *graph, struct graph_line *line)
1328 {
1329 int seen_this = 0;
1330 int i;
1331
1332 /*
1333 * Output the row containing this commit
1334 * Iterate up to and including graph->num_columns,
1335 * since the current commit may not be in any of the existing
1336 * columns. (This happens when the current commit doesn't have any
1337 * children that we have already processed.)
1338 */
1339 seen_this = 0;
1340 for (i = 0; i <= graph->num_columns; i++) {
1341 struct column *col = &graph->columns[i];
1342 struct commit *col_commit;
1343 if (i == graph->num_columns) {
1344 if (seen_this)
1345 break;
1346 col_commit = graph->commit;
1347 } else {
1348 col_commit = graph->columns[i].commit;
1349 }
1350
1351 if (col_commit == graph->commit) {
1352 seen_this = 1;
1353 if (graph->is_visual_root && !graph->revs->no_graph_indent) {
1354 int depth = graph->visual_root_depth;
1355 /*
1356 * Each visual column is 2 characters wide.
1357 * Omit the indentation for the first visual
1358 * root in cascade mode.
1359 *
1360 * Have a max of 4 columns when cascading, after
1361 * that wrap it and repeat.
1362 */
1363 int padding = ((depth - graph->visual_root_cascade) % 4) * 2;
1364 graph_line_addchars(line, ' ', padding);
1365 graph->width += padding;
1366 }
1367 graph_output_commit_char(graph, line);
1368
1369 if (graph_needs_truncation(graph, i)) {
1370 graph_line_addch(line, ' ');
1371 break;
1372 }
1373
1374 if (graph->num_parents > 2)
1375 graph_draw_octopus_merge(graph, line);
1376 } else if (graph_needs_truncation(graph, i)) {
1377 graph_line_addstr(line, "~ ");
1378 seen_this = 1;
1379 break;
1380 } else if (seen_this && (graph->edges_added > 1)) {
1381 graph_line_write_column(line, col, '\\');
1382 } else if (seen_this && (graph->edges_added == 1)) {
1383 /*
1384 * This is either a right-skewed 2-way merge
1385 * commit, or a left-skewed 3-way merge.
1386 * There is no GRAPH_PRE_COMMIT stage for such
1387 * merges, so this is the first line of output
1388 * for this commit. Check to see what the previous
1389 * line of output was.
1390 *
1391 * If it was GRAPH_POST_MERGE, the branch line
1392 * coming into this commit may have been '\',
1393 * and not '|' or '/'. If so, output the branch
1394 * line as '\' on this line, instead of '|'. This
1395 * makes the output look nicer.
1396 */
1397 if (graph->prev_state == GRAPH_POST_MERGE &&
1398 graph->prev_edges_added > 0 &&
1399 graph->prev_commit_index < i)
1400 graph_line_write_column(line, col, '\\');
1401 else
1402 graph_line_write_column(line, col, '|');
1403 } else if (graph->prev_state == GRAPH_COLLAPSING &&
1404 graph->old_mapping[2 * i + 1] == i &&
1405 graph->mapping[2 * i] < i) {
1406 graph_line_write_column(line, col, '/');
1407 } else {
1408 graph_line_write_column(line, col, '|');
1409 }
1410 graph_line_addch(line, ' ');
1411 }
1412
1413 /*
1414 * Update graph->state
1415 *
1416 * If the commit is a merge and the first parent is in a visible lane,
1417 * then the GRAPH_POST_MERGE is needed to draw the merge lane.
1418 *
1419 * If the commit is over the truncation limit, but the first parent is on
1420 * a visible lane, then we still need the merge lane but truncated.
1421 *
1422 * If both commit and first parent are over the truncation limit, then
1423 * there's no need to draw the merge lane because it would work as a
1424 * padding lane.
1425 */
1426 if (graph->num_parents > 1) {
1427 if (!graph_needs_truncation(graph, graph->commit_index)) {
1428 graph_update_state(graph, GRAPH_POST_MERGE);
1429 } else {
1430 struct commit_list *p = first_interesting_parent(graph);
1431 int lane;
1432
1433 /*
1434 * graph->num_parents are found using first_interesting_parent
1435 * and next_interesting_parent so it can't be a scenario
1436 * where num_parents > 1 and there are no interesting parents
1437 */
1438 if (!p)
1439 BUG("num_parents > 1 but no interesting parent");
1440
1441 lane = graph_find_new_column_by_commit(graph, p->item);
1442
1443 if (!graph_needs_truncation(graph, lane))
1444 graph_update_state(graph, GRAPH_POST_MERGE);
1445 else if (graph_is_mapping_correct(graph))
1446 graph_update_state(graph, GRAPH_PADDING);
1447 else
1448 graph_update_state(graph, GRAPH_COLLAPSING);
1449 }
1450 } else if (graph_is_mapping_correct(graph)) {
1451 graph_update_state(graph, GRAPH_PADDING);
1452 } else {
1453 graph_update_state(graph, GRAPH_COLLAPSING);
1454 }
1455 }
1456
1457 static const char merge_chars[] = {'/', '|', '\\'};
1458
1459 static void graph_output_post_merge_line(struct git_graph *graph, struct graph_line *line)
1460 {
1461 int seen_this = 0;
1462 int i, j;
1463
1464 struct commit_list *first_parent = first_interesting_parent(graph);
1465 struct column *parent_col = NULL;
1466
1467 /*
1468 * Output the post-merge row
1469 */
1470 for (i = 0; i <= graph->num_columns; i++) {
1471 struct column *col = &graph->columns[i];
1472 struct commit *col_commit;
1473 if (i == graph->num_columns) {
1474 if (seen_this)
1475 break;
1476 col_commit = graph->commit;
1477 } else {
1478 col_commit = col->commit;
1479 }
1480
1481 if (col_commit == graph->commit) {
1482 /*
1483 * Since the current commit is a merge find
1484 * the columns for the parent commits in
1485 * new_columns and use those to format the
1486 * edges.
1487 */
1488 struct commit_list *parents = first_parent;
1489 int par_column;
1490 int idx = graph->merge_layout;
1491 char c;
1492 int truncated = 0;
1493 seen_this = 1;
1494
1495 for (j = 0; j < graph->num_parents; j++) {
1496 par_column = graph_find_new_column_by_commit(graph, parents->item);
1497 assert(par_column >= 0);
1498
1499 c = merge_chars[idx];
1500 graph_line_write_column(line, &graph->new_columns[par_column], c);
1501
1502 /*
1503 * j counts parents, it needs to be halved to be
1504 * comparable with i. Don't truncate if there are
1505 * no more lanes to print (end of the lane)
1506 */
1507 if (graph_needs_truncation(graph, j / 2 + i) &&
1508 j / 2 + i <= graph->num_columns) {
1509 if ((j + i * 2) % 2 != 0)
1510 graph_line_addch(line, ' ');
1511 graph_line_addstr(line, "~ ");
1512 truncated = 1;
1513 break;
1514 }
1515
1516 if (idx == 2) {
1517 /*
1518 * Check if the next lane needs truncation
1519 * to avoid having the padding doubled
1520 */
1521 if (graph_needs_truncation(graph, (j + 1) / 2 + i) &&
1522 j < graph->num_parents - 1) {
1523 graph_line_addstr(line, "~ ");
1524 truncated = 1;
1525 break;
1526 } else if (graph->edges_added > 0 || j < graph->num_parents - 1)
1527 graph_line_addch(line, ' ');
1528 } else {
1529 idx++;
1530 }
1531 parents = next_interesting_parent(graph, parents);
1532 }
1533 if (truncated)
1534 break;
1535 if (graph->edges_added == 0)
1536 graph_line_addch(line, ' ');
1537 } else if (graph_needs_truncation(graph, i)) {
1538 graph_line_addstr(line, "~ ");
1539 break;
1540 } else if (seen_this) {
1541 if (graph->edges_added > 0)
1542 graph_line_write_column(line, col, '\\');
1543 else
1544 graph_line_write_column(line, col, '|');
1545 /*
1546 * If it's between two lanes and next would be truncated,
1547 * don't add space padding.
1548 */
1549 if (!graph_needs_truncation(graph, i + 1))
1550 graph_line_addch(line, ' ');
1551 } else {
1552 graph_line_write_column(line, col, '|');
1553 if (graph->merge_layout != 0 || i != graph->commit_index - 1) {
1554 if (parent_col)
1555 graph_line_write_column(
1556 line, parent_col, '_');
1557 else
1558 graph_line_addch(line, ' ');
1559 }
1560 }
1561
1562 if (col_commit == first_parent->item)
1563 parent_col = col;
1564 }
1565
1566 /*
1567 * Update graph->state
1568 */
1569 if (graph_is_mapping_correct(graph))
1570 graph_update_state(graph, GRAPH_PADDING);
1571 else
1572 graph_update_state(graph, GRAPH_COLLAPSING);
1573 }
1574
1575 static void graph_output_collapsing_line(struct git_graph *graph, struct graph_line *line)
1576 {
1577 int i;
1578 short used_horizontal = 0;
1579 int horizontal_edge = -1;
1580 int horizontal_edge_target = -1;
1581 int truncated = 0;
1582
1583 /*
1584 * Swap the mapping and old_mapping arrays
1585 */
1586 SWAP(graph->mapping, graph->old_mapping);
1587
1588 /*
1589 * Clear out the mapping array
1590 */
1591 for (i = 0; i < graph->mapping_size; i++)
1592 graph->mapping[i] = -1;
1593
1594 for (i = 0; i < graph->mapping_size; i++) {
1595 int target = graph->old_mapping[i];
1596 if (target < 0)
1597 continue;
1598
1599 /*
1600 * Since update_columns() always inserts the leftmost
1601 * column first, each branch's target location should
1602 * always be either its current location or to the left of
1603 * its current location.
1604 *
1605 * We never have to move branches to the right. This makes
1606 * the graph much more legible, since whenever branches
1607 * cross, only one is moving directions.
1608 */
1609 assert(target * 2 <= i);
1610
1611 if (target * 2 == i) {
1612 /*
1613 * This column is already in the
1614 * correct place
1615 */
1616 assert(graph->mapping[i] == -1);
1617 graph->mapping[i] = target;
1618 } else if (graph->mapping[i - 1] < 0) {
1619 /*
1620 * Nothing is to the left.
1621 * Move to the left by one
1622 */
1623 graph->mapping[i - 1] = target;
1624 /*
1625 * If there isn't already an edge moving horizontally
1626 * select this one.
1627 */
1628 if (horizontal_edge == -1) {
1629 int j;
1630 horizontal_edge = i;
1631 horizontal_edge_target = target;
1632 /*
1633 * The variable target is the index of the graph
1634 * column, and therefore target*2+3 is the
1635 * actual screen column of the first horizontal
1636 * line.
1637 */
1638 for (j = (target * 2)+3; j < (i - 2); j += 2)
1639 graph->mapping[j] = target;
1640 }
1641 } else if (graph->mapping[i - 1] == target) {
1642 /*
1643 * There is a branch line to our left
1644 * already, and it is our target. We
1645 * combine with this line, since we share
1646 * the same parent commit.
1647 *
1648 * We don't have to add anything to the
1649 * output or mapping, since the
1650 * existing branch line has already taken
1651 * care of it.
1652 */
1653 } else {
1654 /*
1655 * There is a branch line to our left,
1656 * but it isn't our target. We need to
1657 * cross over it.
1658 *
1659 * The space just to the left of this
1660 * branch should always be empty.
1661 */
1662 assert(graph->mapping[i - 1] > target);
1663 assert(graph->mapping[i - 2] < 0);
1664 graph->mapping[i - 2] = target;
1665 /*
1666 * Mark this branch as the horizontal edge to
1667 * prevent any other edges from moving
1668 * horizontally.
1669 */
1670 if (horizontal_edge == -1) {
1671 int j;
1672 horizontal_edge_target = target;
1673 horizontal_edge = i - 1;
1674
1675 for (j = (target * 2) + 3; j < (i - 2); j += 2)
1676 graph->mapping[j] = target;
1677 }
1678 }
1679 }
1680
1681 /*
1682 * Copy the current mapping array into old_mapping
1683 */
1684 COPY_ARRAY(graph->old_mapping, graph->mapping, graph->mapping_size);
1685
1686 /*
1687 * The new mapping may be 1 smaller than the old mapping
1688 */
1689 if (graph->mapping[graph->mapping_size - 1] < 0)
1690 graph->mapping_size--;
1691
1692 /*
1693 * Output out a line based on the new mapping info
1694 */
1695 for (i = 0; i < graph->mapping_size; i++) {
1696 int target = graph->mapping[i];
1697
1698 if (!truncated && graph_needs_truncation(graph, i / 2)) {
1699 graph_line_addstr(line, "~ ");
1700 truncated = 1;
1701 }
1702
1703 if (target < 0) {
1704 if (!truncated)
1705 graph_line_addch(line, ' ');
1706 } else if (target * 2 == i) {
1707 if (!truncated)
1708 graph_line_write_column(line, &graph->new_columns[target], '|');
1709 } else if (target == horizontal_edge_target &&
1710 i != horizontal_edge - 1) {
1711 /*
1712 * Set the mappings for all but the
1713 * first segment to -1 so that they
1714 * won't continue into the next line.
1715 */
1716 if (i != (target * 2)+3)
1717 graph->mapping[i] = -1;
1718 used_horizontal = 1;
1719 if (!truncated)
1720 graph_line_write_column(line, &graph->new_columns[target], '_');
1721 } else {
1722 if (used_horizontal && i < horizontal_edge)
1723 graph->mapping[i] = -1;
1724 if (!truncated)
1725 graph_line_write_column(line, &graph->new_columns[target], '/');
1726 }
1727 }
1728
1729 /*
1730 * If graph->mapping indicates that all of the branch lines
1731 * are already in the correct positions, we are done.
1732 * Otherwise, we need to collapse some branch lines together.
1733 */
1734 if (graph_is_mapping_correct(graph))
1735 graph_update_state(graph, GRAPH_PADDING);
1736 }
1737
1738 static void graph_output_pre_root_line(struct git_graph *graph, struct graph_line *line)
1739 {
1740 /*
1741 * This function adds a row before a visual root, to connect the
1742 * branch to the indented commit. It must only be called on a
1743 * visual root.
1744 */
1745 if (!graph->is_visual_root)
1746 BUG("commit must be a visual root to call pre_root_line");
1747
1748 for (int i = 0; i < graph->num_columns; i++) {
1749 struct column *col = &graph->columns[i];
1750 if (col->commit == graph->commit) {
1751 graph_line_addch(line, ' ');
1752 graph_line_write_column(line, col, '\\');
1753 } else {
1754 graph_line_write_column(line, col, '|');
1755 }
1756 graph_line_addch(line, ' ');
1757 }
1758
1759 graph_update_state(graph, GRAPH_COMMIT);
1760 }
1761
1762 int graph_next_line(struct git_graph *graph, struct strbuf *sb)
1763 {
1764 int shown_commit_line = 0;
1765 struct graph_line line = { .buf = sb, .width = 0 };
1766
1767 /*
1768 * We could conceivable be called with a NULL commit
1769 * if our caller has a bug, and invokes graph_next_line()
1770 * immediately after graph_init(), without first calling
1771 * graph_update(). Return without outputting anything in this
1772 * case.
1773 */
1774 if (!graph->commit)
1775 return -1;
1776
1777 switch (graph->state) {
1778 case GRAPH_PADDING:
1779 graph_output_padding_line(graph, &line);
1780 break;
1781 case GRAPH_SKIP:
1782 graph_output_skip_line(graph, &line);
1783 break;
1784 case GRAPH_PRE_COMMIT:
1785 graph_output_pre_commit_line(graph, &line);
1786 break;
1787 case GRAPH_PRE_ROOT:
1788 graph_output_pre_root_line(graph, &line);
1789 break;
1790 case GRAPH_COMMIT:
1791 graph_output_commit_line(graph, &line);
1792 shown_commit_line = 1;
1793 break;
1794 case GRAPH_POST_MERGE:
1795 graph_output_post_merge_line(graph, &line);
1796 break;
1797 case GRAPH_COLLAPSING:
1798 graph_output_collapsing_line(graph, &line);
1799 break;
1800 }
1801
1802 graph_pad_horizontally(graph, &line);
1803 return shown_commit_line;
1804 }
1805
1806 static void graph_padding_line(struct git_graph *graph, struct strbuf *sb)
1807 {
1808 int i;
1809 struct graph_line line = { .buf = sb, .width = 0 };
1810
1811 if (graph->state != GRAPH_COMMIT) {
1812 graph_next_line(graph, sb);
1813 return;
1814 }
1815
1816 /*
1817 * Output the row containing this commit
1818 * Iterate up to and including graph->num_columns,
1819 * since the current commit may not be in any of the existing
1820 * columns. (This happens when the current commit doesn't have any
1821 * children that we have already processed.)
1822 */
1823 for (i = 0; i < graph->num_columns; i++) {
1824 struct column *col = &graph->columns[i];
1825
1826 if (graph_needs_truncation(graph, i)) {
1827 graph_line_addstr(&line, "~ ");
1828 break;
1829 }
1830
1831 graph_line_write_column(&line, col, '|');
1832
1833 if (col->commit == graph->commit && graph->num_parents > 2) {
1834 int len = (graph->num_parents - 2) * 2;
1835 graph_line_addchars(&line, ' ', len);
1836 } else {
1837 graph_line_addch(&line, ' ');
1838 }
1839 }
1840
1841 graph_pad_horizontally(graph, &line);
1842
1843 /*
1844 * Update graph->prev_state since we have output a padding line
1845 */
1846 graph->prev_state = GRAPH_PADDING;
1847 }
1848
1849 int graph_is_commit_finished(struct git_graph const *graph)
1850 {
1851 return (graph->state == GRAPH_PADDING);
1852 }
1853
1854 void graph_show_commit(struct git_graph *graph)
1855 {
1856 struct strbuf msgbuf = STRBUF_INIT;
1857 int shown_commit_line = 0;
1858
1859 graph_show_line_prefix(default_diffopt);
1860
1861 if (!graph)
1862 return;
1863
1864 /*
1865 * When showing a diff of a merge against each of its parents, we
1866 * are called once for each parent without graph_update having been
1867 * called. In this case, simply output a single padding line.
1868 */
1869 if (graph_is_commit_finished(graph)) {
1870 graph_show_padding(graph);
1871 shown_commit_line = 1;
1872 }
1873
1874 while (!shown_commit_line && !graph_is_commit_finished(graph)) {
1875 shown_commit_line = graph_next_line(graph, &msgbuf);
1876 fwrite(msgbuf.buf, sizeof(char), msgbuf.len,
1877 graph->revs->diffopt.file);
1878 if (!shown_commit_line) {
1879 putc('\n', graph->revs->diffopt.file);
1880 graph_show_line_prefix(&graph->revs->diffopt);
1881 }
1882 strbuf_setlen(&msgbuf, 0);
1883 }
1884
1885 strbuf_release(&msgbuf);
1886 }
1887
1888 void graph_show_oneline(struct git_graph *graph)
1889 {
1890 struct strbuf msgbuf = STRBUF_INIT;
1891
1892 graph_show_line_prefix(default_diffopt);
1893
1894 if (!graph)
1895 return;
1896
1897 graph_next_line(graph, &msgbuf);
1898 fwrite(msgbuf.buf, sizeof(char), msgbuf.len, graph->revs->diffopt.file);
1899 strbuf_release(&msgbuf);
1900 }
1901
1902 void graph_show_padding(struct git_graph *graph)
1903 {
1904 struct strbuf msgbuf = STRBUF_INIT;
1905
1906 graph_show_line_prefix(default_diffopt);
1907
1908 if (!graph)
1909 return;
1910
1911 graph_padding_line(graph, &msgbuf);
1912 fwrite(msgbuf.buf, sizeof(char), msgbuf.len, graph->revs->diffopt.file);
1913 strbuf_release(&msgbuf);
1914 }
1915
1916 int graph_show_remainder(struct git_graph *graph)
1917 {
1918 struct strbuf msgbuf = STRBUF_INIT;
1919 int shown = 0;
1920
1921 graph_show_line_prefix(default_diffopt);
1922
1923 if (!graph)
1924 return 0;
1925
1926 if (graph_is_commit_finished(graph))
1927 return 0;
1928
1929 for (;;) {
1930 graph_next_line(graph, &msgbuf);
1931 fwrite(msgbuf.buf, sizeof(char), msgbuf.len,
1932 graph->revs->diffopt.file);
1933 strbuf_setlen(&msgbuf, 0);
1934 shown = 1;
1935
1936 if (!graph_is_commit_finished(graph)) {
1937 putc('\n', graph->revs->diffopt.file);
1938 graph_show_line_prefix(&graph->revs->diffopt);
1939 } else {
1940 break;
1941 }
1942 }
1943 strbuf_release(&msgbuf);
1944
1945 return shown;
1946 }
1947
1948 static void graph_show_strbuf(struct git_graph *graph,
1949 FILE *file,
1950 struct strbuf const *sb)
1951 {
1952 char *p;
1953
1954 /*
1955 * Print the strbuf line by line,
1956 * and display the graph info before each line but the first.
1957 */
1958 p = sb->buf;
1959 while (p) {
1960 size_t len;
1961 char *next_p = strchr(p, '\n');
1962 if (next_p) {
1963 next_p++;
1964 len = next_p - p;
1965 } else {
1966 len = (sb->buf + sb->len) - p;
1967 }
1968 fwrite(p, sizeof(char), len, file);
1969 if (next_p && *next_p != '\0')
1970 graph_show_oneline(graph);
1971 p = next_p;
1972 }
1973 }
1974
1975 void graph_show_commit_msg(struct git_graph *graph,
1976 FILE *file,
1977 struct strbuf const *sb)
1978 {
1979 int newline_terminated;
1980
1981 /*
1982 * Show the commit message
1983 */
1984 graph_show_strbuf(graph, file, sb);
1985
1986 if (!graph)
1987 return;
1988
1989 newline_terminated = (sb->len && sb->buf[sb->len - 1] == '\n');
1990
1991 /*
1992 * If there is more output needed for this commit, show it now
1993 */
1994 if (!graph_is_commit_finished(graph)) {
1995 /*
1996 * If sb doesn't have a terminating newline, print one now,
1997 * so we can start the remainder of the graph output on a
1998 * new line.
1999 */
2000 if (!newline_terminated)
2001 putc('\n', file);
2002
2003 graph_show_remainder(graph);
2004
2005 /*
2006 * If sb ends with a newline, our output should too.
2007 */
2008 if (newline_terminated)
2009 putc('\n', file);
2010 }
2011 }