git

Форк
0
/
graph.c 
1550 строк · 40.2 Кб
1
#define USE_THE_REPOSITORY_VARIABLE
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

65
enum graph_state {
66
	GRAPH_PADDING,
67
	GRAPH_SKIP,
68
	GRAPH_PRE_COMMIT,
69
	GRAPH_COMMIT,
70
	GRAPH_POST_MERGE,
71
	GRAPH_COLLAPSING
72
};
73

74
static void graph_show_line_prefix(const struct diff_options *diffopt)
75
{
76
	if (!diffopt || !diffopt->line_prefix)
77
		return;
78

79
	fwrite(diffopt->line_prefix,
80
	       sizeof(char),
81
	       diffopt->line_prefix_length,
82
	       diffopt->file);
83
}
84

85
static const char **column_colors;
86
static unsigned short column_colors_max;
87

88
static void parse_graph_colors_config(struct strvec *colors, const char *string)
89
{
90
	const char *end, *start;
91

92
	start = string;
93
	end = string + strlen(string);
94
	while (start < end) {
95
		const char *comma = strchrnul(start, ',');
96
		char color[COLOR_MAXLEN];
97

98
		if (!color_parse_mem(start, comma - start, color))
99
			strvec_push(colors, color);
100
		else
101
			warning(_("ignored invalid color '%.*s' in log.graphColors"),
102
				(int)(comma - start), start);
103
		start = comma + 1;
104
	}
105
	strvec_push(colors, GIT_COLOR_RESET);
106
}
107

108
void graph_set_column_colors(const char **colors, unsigned short colors_max)
109
{
110
	column_colors = colors;
111
	column_colors_max = colors_max;
112
}
113

114
static const char *column_get_color_code(unsigned short color)
115
{
116
	return column_colors[color];
117
}
118

119
struct graph_line {
120
	struct strbuf *buf;
121
	size_t width;
122
};
123

124
static inline void graph_line_addch(struct graph_line *line, int c)
125
{
126
	strbuf_addch(line->buf, c);
127
	line->width++;
128
}
129

130
static inline void graph_line_addchars(struct graph_line *line, int c, size_t n)
131
{
132
	strbuf_addchars(line->buf, c, n);
133
	line->width += n;
134
}
135

136
static inline void graph_line_addstr(struct graph_line *line, const char *s)
137
{
138
	strbuf_addstr(line->buf, s);
139
	line->width += strlen(s);
140
}
141

142
static inline void graph_line_addcolor(struct graph_line *line, unsigned short color)
143
{
144
	strbuf_addstr(line->buf, column_get_color_code(color));
145
}
146

147
static void graph_line_write_column(struct graph_line *line, const struct column *c,
148
				    char col_char)
149
{
150
	if (c->color < column_colors_max)
151
		graph_line_addcolor(line, c->color);
152
	graph_line_addch(line, col_char);
153
	if (c->color < column_colors_max)
154
		graph_line_addcolor(line, column_colors_max);
155
}
156

157
struct git_graph {
158
	/*
159
	 * The commit currently being processed
160
	 */
161
	struct commit *commit;
162
	/* The rev-info used for the current traversal */
163
	struct rev_info *revs;
164
	/*
165
	 * The number of interesting parents that this commit has.
166
	 *
167
	 * Note that this is not the same as the actual number of parents.
168
	 * This count excludes parents that won't be printed in the graph
169
	 * output, as determined by graph_is_interesting().
170
	 */
171
	int num_parents;
172
	/*
173
	 * The width of the graph output for this commit.
174
	 * All rows for this commit are padded to this width, so that
175
	 * messages printed after the graph output are aligned.
176
	 */
177
	int width;
178
	/*
179
	 * The next expansion row to print
180
	 * when state is GRAPH_PRE_COMMIT
181
	 */
182
	int expansion_row;
183
	/*
184
	 * The current output state.
185
	 * This tells us what kind of line graph_next_line() should output.
186
	 */
187
	enum graph_state state;
188
	/*
189
	 * The output state for the previous line of output.
190
	 * This is primarily used to determine how the first merge line
191
	 * should appear, based on the last line of the previous commit.
192
	 */
193
	enum graph_state prev_state;
194
	/*
195
	 * The index of the column that refers to this commit.
196
	 *
197
	 * If none of the incoming columns refer to this commit,
198
	 * this will be equal to num_columns.
199
	 */
200
	int commit_index;
201
	/*
202
	 * The commit_index for the previously displayed commit.
203
	 *
204
	 * This is used to determine how the first line of a merge
205
	 * graph output should appear, based on the last line of the
206
	 * previous commit.
207
	 */
208
	int prev_commit_index;
209
	/*
210
	 * Which layout variant to use to display merge commits. If the
211
	 * commit's first parent is known to be in a column to the left of the
212
	 * merge, then this value is 0 and we use the layout on the left.
213
	 * Otherwise, the value is 1 and the layout on the right is used. This
214
	 * field tells us how many columns the first parent occupies.
215
	 *
216
	 * 		0)			1)
217
	 *
218
	 * 		| | | *-.		| | *---.
219
	 * 		| |_|/|\ \		| | |\ \ \
220
	 * 		|/| | | | |		| | | | | *
221
	 */
222
	int merge_layout;
223
	/*
224
	 * The number of columns added to the graph by the current commit. For
225
	 * 2-way and octopus merges, this is usually one less than the
226
	 * number of parents:
227
	 *
228
	 * 		| | |			| |    \
229
	 *		| * |			| *---. \
230
	 *		| |\ \			| |\ \ \ \
231
	 *		| | | |         	| | | | | |
232
	 *
233
	 *		num_parents: 2		num_parents: 4
234
	 *		edges_added: 1		edges_added: 3
235
	 *
236
	 * For left-skewed merges, the first parent fuses with its neighbor and
237
	 * so one less column is added:
238
	 *
239
	 *		| | |			| |  \
240
	 *		| * |			| *-. \
241
	 *		|/| |			|/|\ \ \
242
	 *		| | |			| | | | |
243
	 *
244
	 *		num_parents: 2		num_parents: 4
245
	 *		edges_added: 0		edges_added: 2
246
	 *
247
	 * This number determines how edges to the right of the merge are
248
	 * displayed in commit and post-merge lines; if no columns have been
249
	 * added then a vertical line should be used where a right-tracking
250
	 * line would otherwise be used.
251
	 *
252
	 *		| * \			| * |
253
	 *		| |\ \			|/| |
254
	 *		| | * \			| * |
255
	 */
256
	int edges_added;
257
	/*
258
	 * The number of columns added by the previous commit, which is used to
259
	 * smooth edges appearing to the right of a commit in a commit line
260
	 * following a post-merge line.
261
	 */
262
	int prev_edges_added;
263
	/*
264
	 * The maximum number of columns that can be stored in the columns
265
	 * and new_columns arrays.  This is also half the number of entries
266
	 * that can be stored in the mapping and old_mapping arrays.
267
	 */
268
	int column_capacity;
269
	/*
270
	 * The number of columns (also called "branch lines" in some places)
271
	 */
272
	int num_columns;
273
	/*
274
	 * The number of columns in the new_columns array
275
	 */
276
	int num_new_columns;
277
	/*
278
	 * The number of entries in the mapping array
279
	 */
280
	int mapping_size;
281
	/*
282
	 * The column state before we output the current commit.
283
	 */
284
	struct column *columns;
285
	/*
286
	 * The new column state after we output the current commit.
287
	 * Only valid when state is GRAPH_COLLAPSING.
288
	 */
289
	struct column *new_columns;
290
	/*
291
	 * An array that tracks the current state of each
292
	 * character in the output line during state GRAPH_COLLAPSING.
293
	 * Each entry is -1 if this character is empty, or a non-negative
294
	 * integer if the character contains a branch line.  The value of
295
	 * the integer indicates the target position for this branch line.
296
	 * (I.e., this array maps the current column positions to their
297
	 * desired positions.)
298
	 *
299
	 * The maximum capacity of this array is always
300
	 * sizeof(int) * 2 * column_capacity.
301
	 */
302
	int *mapping;
303
	/*
304
	 * A copy of the contents of the mapping array from the last commit,
305
	 * which we use to improve the display of columns that are tracking
306
	 * from right to left through a commit line.  We also use this to
307
	 * avoid allocating a fresh array when we compute the next mapping.
308
	 */
309
	int *old_mapping;
310
	/*
311
	 * The current default column color being used.  This is
312
	 * stored as an index into the array column_colors.
313
	 */
314
	unsigned short default_column_color;
315
};
316

317
static struct strbuf *diff_output_prefix_callback(struct diff_options *opt, void *data)
318
{
319
	struct git_graph *graph = data;
320
	static struct strbuf msgbuf = STRBUF_INIT;
321

322
	assert(opt);
323

324
	strbuf_reset(&msgbuf);
325
	if (opt->line_prefix)
326
		strbuf_add(&msgbuf, opt->line_prefix,
327
			   opt->line_prefix_length);
328
	if (graph)
329
		graph_padding_line(graph, &msgbuf);
330
	return &msgbuf;
331
}
332

333
static const struct diff_options *default_diffopt;
334

335
void graph_setup_line_prefix(struct diff_options *diffopt)
336
{
337
	default_diffopt = diffopt;
338

339
	/* setup an output prefix callback if necessary */
340
	if (diffopt && !diffopt->output_prefix)
341
		diffopt->output_prefix = diff_output_prefix_callback;
342
}
343

344
struct git_graph *graph_init(struct rev_info *opt)
345
{
346
	struct git_graph *graph = xmalloc(sizeof(struct git_graph));
347

348
	if (!column_colors) {
349
		char *string;
350
		if (git_config_get_string("log.graphcolors", &string)) {
351
			/* not configured -- use default */
352
			graph_set_column_colors(column_colors_ansi,
353
						column_colors_ansi_max);
354
		} else {
355
			static struct strvec custom_colors = STRVEC_INIT;
356
			strvec_clear(&custom_colors);
357
			parse_graph_colors_config(&custom_colors, string);
358
			free(string);
359
			/* graph_set_column_colors takes a max-index, not a count */
360
			graph_set_column_colors(custom_colors.v,
361
						custom_colors.nr - 1);
362
		}
363
	}
364

365
	graph->commit = NULL;
366
	graph->revs = opt;
367
	graph->num_parents = 0;
368
	graph->expansion_row = 0;
369
	graph->state = GRAPH_PADDING;
370
	graph->prev_state = GRAPH_PADDING;
371
	graph->commit_index = 0;
372
	graph->prev_commit_index = 0;
373
	graph->merge_layout = 0;
374
	graph->edges_added = 0;
375
	graph->prev_edges_added = 0;
376
	graph->num_columns = 0;
377
	graph->num_new_columns = 0;
378
	graph->mapping_size = 0;
379
	/*
380
	 * Start the column color at the maximum value, since we'll
381
	 * always increment it for the first commit we output.
382
	 * This way we start at 0 for the first commit.
383
	 */
384
	graph->default_column_color = column_colors_max - 1;
385

386
	/*
387
	 * Allocate a reasonably large default number of columns
388
	 * We'll automatically grow columns later if we need more room.
389
	 */
390
	graph->column_capacity = 30;
391
	ALLOC_ARRAY(graph->columns, graph->column_capacity);
392
	ALLOC_ARRAY(graph->new_columns, graph->column_capacity);
393
	ALLOC_ARRAY(graph->mapping, 2 * graph->column_capacity);
394
	ALLOC_ARRAY(graph->old_mapping, 2 * graph->column_capacity);
395

396
	/*
397
	 * The diff output prefix callback, with this we can make
398
	 * all the diff output to align with the graph lines.
399
	 */
400
	opt->diffopt.output_prefix = diff_output_prefix_callback;
401
	opt->diffopt.output_prefix_data = graph;
402

403
	return graph;
404
}
405

406
void graph_clear(struct git_graph *graph)
407
{
408
	if (!graph)
409
		return;
410

411
	free(graph->columns);
412
	free(graph->new_columns);
413
	free(graph->mapping);
414
	free(graph->old_mapping);
415
	free(graph);
416
}
417

418
static void graph_update_state(struct git_graph *graph, enum graph_state s)
419
{
420
	graph->prev_state = graph->state;
421
	graph->state = s;
422
}
423

424
static void graph_ensure_capacity(struct git_graph *graph, int num_columns)
425
{
426
	if (graph->column_capacity >= num_columns)
427
		return;
428

429
	do {
430
		graph->column_capacity *= 2;
431
	} while (graph->column_capacity < num_columns);
432

433
	REALLOC_ARRAY(graph->columns, graph->column_capacity);
434
	REALLOC_ARRAY(graph->new_columns, graph->column_capacity);
435
	REALLOC_ARRAY(graph->mapping, graph->column_capacity * 2);
436
	REALLOC_ARRAY(graph->old_mapping, graph->column_capacity * 2);
437
}
438

439
/*
440
 * Returns 1 if the commit will be printed in the graph output,
441
 * and 0 otherwise.
442
 */
443
static int graph_is_interesting(struct git_graph *graph, struct commit *commit)
444
{
445
	/*
446
	 * If revs->boundary is set, commits whose children have
447
	 * been shown are always interesting, even if they have the
448
	 * UNINTERESTING or TREESAME flags set.
449
	 */
450
	if (graph->revs && graph->revs->boundary) {
451
		if (commit->object.flags & CHILD_SHOWN)
452
			return 1;
453
	}
454

455
	/*
456
	 * Otherwise, use get_commit_action() to see if this commit is
457
	 * interesting
458
	 */
459
	return get_commit_action(graph->revs, commit) == commit_show;
460
}
461

462
static struct commit_list *next_interesting_parent(struct git_graph *graph,
463
						   struct commit_list *orig)
464
{
465
	struct commit_list *list;
466

467
	/*
468
	 * If revs->first_parent_only is set, only the first
469
	 * parent is interesting.  None of the others are.
470
	 */
471
	if (graph->revs->first_parent_only)
472
		return NULL;
473

474
	/*
475
	 * Return the next interesting commit after orig
476
	 */
477
	for (list = orig->next; list; list = list->next) {
478
		if (graph_is_interesting(graph, list->item))
479
			return list;
480
	}
481

482
	return NULL;
483
}
484

485
static struct commit_list *first_interesting_parent(struct git_graph *graph)
486
{
487
	struct commit_list *parents = graph->commit->parents;
488

489
	/*
490
	 * If this commit has no parents, ignore it
491
	 */
492
	if (!parents)
493
		return NULL;
494

495
	/*
496
	 * If the first parent is interesting, return it
497
	 */
498
	if (graph_is_interesting(graph, parents->item))
499
		return parents;
500

501
	/*
502
	 * Otherwise, call next_interesting_parent() to get
503
	 * the next interesting parent
504
	 */
505
	return next_interesting_parent(graph, parents);
506
}
507

508
static unsigned short graph_get_current_column_color(const struct git_graph *graph)
509
{
510
	if (!want_color(graph->revs->diffopt.use_color))
511
		return column_colors_max;
512
	return graph->default_column_color;
513
}
514

515
/*
516
 * Update the graph's default column color.
517
 */
518
static void graph_increment_column_color(struct git_graph *graph)
519
{
520
	graph->default_column_color = (graph->default_column_color + 1) %
521
		column_colors_max;
522
}
523

524
static unsigned short graph_find_commit_color(const struct git_graph *graph,
525
					      const struct commit *commit)
526
{
527
	int i;
528
	for (i = 0; i < graph->num_columns; i++) {
529
		if (graph->columns[i].commit == commit)
530
			return graph->columns[i].color;
531
	}
532
	return graph_get_current_column_color(graph);
533
}
534

535
static int graph_find_new_column_by_commit(struct git_graph *graph,
536
					   struct commit *commit)
537
{
538
	int i;
539
	for (i = 0; i < graph->num_new_columns; i++) {
540
		if (graph->new_columns[i].commit == commit)
541
			return i;
542
	}
543
	return -1;
544
}
545

546
static void graph_insert_into_new_columns(struct git_graph *graph,
547
					  struct commit *commit,
548
					  int idx)
549
{
550
	int i = graph_find_new_column_by_commit(graph, commit);
551
	int mapping_idx;
552

553
	/*
554
	 * If the commit is not already in the new_columns array, then add it
555
	 * and record it as being in the final column.
556
	 */
557
	if (i < 0) {
558
		i = graph->num_new_columns++;
559
		graph->new_columns[i].commit = commit;
560
		graph->new_columns[i].color = graph_find_commit_color(graph, commit);
561
	}
562

563
	if (graph->num_parents > 1 && idx > -1 && graph->merge_layout == -1) {
564
		/*
565
		 * If this is the first parent of a merge, choose a layout for
566
		 * the merge line based on whether the parent appears in a
567
		 * column to the left of the merge
568
		 */
569
		int dist, shift;
570

571
		dist = idx - i;
572
		shift = (dist > 1) ? 2 * dist - 3 : 1;
573

574
		graph->merge_layout = (dist > 0) ? 0 : 1;
575
		graph->edges_added = graph->num_parents + graph->merge_layout  - 2;
576

577
		mapping_idx = graph->width + (graph->merge_layout - 1) * shift;
578
		graph->width += 2 * graph->merge_layout;
579

580
	} else if (graph->edges_added > 0 && i == graph->mapping[graph->width - 2]) {
581
		/*
582
		 * If some columns have been added by a merge, but this commit
583
		 * was found in the last existing column, then adjust the
584
		 * numbers so that the two edges immediately join, i.e.:
585
		 *
586
		 *		* |		* |
587
		 *		|\ \	=>	|\|
588
		 *		| |/		| *
589
		 *		| *
590
		 */
591
		mapping_idx = graph->width - 2;
592
		graph->edges_added = -1;
593
	} else {
594
		mapping_idx = graph->width;
595
		graph->width += 2;
596
	}
597

598
	graph->mapping[mapping_idx] = i;
599
}
600

601
static void graph_update_columns(struct git_graph *graph)
602
{
603
	struct commit_list *parent;
604
	int max_new_columns;
605
	int i, seen_this, is_commit_in_columns;
606

607
	/*
608
	 * Swap graph->columns with graph->new_columns
609
	 * graph->columns contains the state for the previous commit,
610
	 * and new_columns now contains the state for our commit.
611
	 *
612
	 * We'll re-use the old columns array as storage to compute the new
613
	 * columns list for the commit after this one.
614
	 */
615
	SWAP(graph->columns, graph->new_columns);
616
	graph->num_columns = graph->num_new_columns;
617
	graph->num_new_columns = 0;
618

619
	/*
620
	 * Now update new_columns and mapping with the information for the
621
	 * commit after this one.
622
	 *
623
	 * First, make sure we have enough room.  At most, there will
624
	 * be graph->num_columns + graph->num_parents columns for the next
625
	 * commit.
626
	 */
627
	max_new_columns = graph->num_columns + graph->num_parents;
628
	graph_ensure_capacity(graph, max_new_columns);
629

630
	/*
631
	 * Clear out graph->mapping
632
	 */
633
	graph->mapping_size = 2 * max_new_columns;
634
	for (i = 0; i < graph->mapping_size; i++)
635
		graph->mapping[i] = -1;
636

637
	graph->width = 0;
638
	graph->prev_edges_added = graph->edges_added;
639
	graph->edges_added = 0;
640

641
	/*
642
	 * Populate graph->new_columns and graph->mapping
643
	 *
644
	 * Some of the parents of this commit may already be in
645
	 * graph->columns.  If so, graph->new_columns should only contain a
646
	 * single entry for each such commit.  graph->mapping should
647
	 * contain information about where each current branch line is
648
	 * supposed to end up after the collapsing is performed.
649
	 */
650
	seen_this = 0;
651
	is_commit_in_columns = 1;
652
	for (i = 0; i <= graph->num_columns; i++) {
653
		struct commit *col_commit;
654
		if (i == graph->num_columns) {
655
			if (seen_this)
656
				break;
657
			is_commit_in_columns = 0;
658
			col_commit = graph->commit;
659
		} else {
660
			col_commit = graph->columns[i].commit;
661
		}
662

663
		if (col_commit == graph->commit) {
664
			seen_this = 1;
665
			graph->commit_index = i;
666
			graph->merge_layout = -1;
667
			for (parent = first_interesting_parent(graph);
668
			     parent;
669
			     parent = next_interesting_parent(graph, parent)) {
670
				/*
671
				 * If this is a merge, or the start of a new
672
				 * childless column, increment the current
673
				 * color.
674
				 */
675
				if (graph->num_parents > 1 ||
676
				    !is_commit_in_columns) {
677
					graph_increment_column_color(graph);
678
				}
679
				graph_insert_into_new_columns(graph, parent->item, i);
680
			}
681
			/*
682
			 * We always need to increment graph->width by at
683
			 * least 2, even if it has no interesting parents.
684
			 * The current commit always takes up at least 2
685
			 * spaces.
686
			 */
687
			if (graph->num_parents == 0)
688
				graph->width += 2;
689
		} else {
690
			graph_insert_into_new_columns(graph, col_commit, -1);
691
		}
692
	}
693

694
	/*
695
	 * Shrink mapping_size to be the minimum necessary
696
	 */
697
	while (graph->mapping_size > 1 &&
698
	       graph->mapping[graph->mapping_size - 1] < 0)
699
		graph->mapping_size--;
700
}
701

702
static int graph_num_dashed_parents(struct git_graph *graph)
703
{
704
	return graph->num_parents + graph->merge_layout - 3;
705
}
706

707
static int graph_num_expansion_rows(struct git_graph *graph)
708
{
709
	/*
710
	 * Normally, we need two expansion rows for each dashed parent line from
711
	 * an octopus merge:
712
	 *
713
	 * 		| *
714
	 * 		| |\
715
	 * 		| | \
716
	 * 		| |  \
717
	 * 		| *-. \
718
	 * 		| |\ \ \
719
	 *
720
	 * If the merge is skewed to the left, then its parents occupy one less
721
	 * column, and we don't need as many expansion rows to route around it;
722
	 * in some cases that means we don't need any expansion rows at all:
723
	 *
724
	 * 		| *
725
	 * 		| |\
726
	 * 		| * \
727
	 * 		|/|\ \
728
	 */
729
	return graph_num_dashed_parents(graph) * 2;
730
}
731

732
static int graph_needs_pre_commit_line(struct git_graph *graph)
733
{
734
	return graph->num_parents >= 3 &&
735
	       graph->commit_index < (graph->num_columns - 1) &&
736
	       graph->expansion_row < graph_num_expansion_rows(graph);
737
}
738

739
void graph_update(struct git_graph *graph, struct commit *commit)
740
{
741
	struct commit_list *parent;
742

743
	/*
744
	 * Set the new commit
745
	 */
746
	graph->commit = commit;
747

748
	/*
749
	 * Count how many interesting parents this commit has
750
	 */
751
	graph->num_parents = 0;
752
	for (parent = first_interesting_parent(graph);
753
	     parent;
754
	     parent = next_interesting_parent(graph, parent))
755
	{
756
		graph->num_parents++;
757
	}
758

759
	/*
760
	 * Store the old commit_index in prev_commit_index.
761
	 * graph_update_columns() will update graph->commit_index for this
762
	 * commit.
763
	 */
764
	graph->prev_commit_index = graph->commit_index;
765

766
	/*
767
	 * Call graph_update_columns() to update
768
	 * columns, new_columns, and mapping.
769
	 */
770
	graph_update_columns(graph);
771

772
	graph->expansion_row = 0;
773

774
	/*
775
	 * Update graph->state.
776
	 * Note that we don't call graph_update_state() here, since
777
	 * we don't want to update graph->prev_state.  No line for
778
	 * graph->state was ever printed.
779
	 *
780
	 * If the previous commit didn't get to the GRAPH_PADDING state,
781
	 * it never finished its output.  Goto GRAPH_SKIP, to print out
782
	 * a line to indicate that portion of the graph is missing.
783
	 *
784
	 * If there are 3 or more parents, we may need to print extra rows
785
	 * before the commit, to expand the branch lines around it and make
786
	 * room for it.  We need to do this only if there is a branch row
787
	 * (or more) to the right of this commit.
788
	 *
789
	 * If there are less than 3 parents, we can immediately print the
790
	 * commit line.
791
	 */
792
	if (graph->state != GRAPH_PADDING)
793
		graph->state = GRAPH_SKIP;
794
	else if (graph_needs_pre_commit_line(graph))
795
		graph->state = GRAPH_PRE_COMMIT;
796
	else
797
		graph->state = GRAPH_COMMIT;
798
}
799

800
static int graph_is_mapping_correct(struct git_graph *graph)
801
{
802
	int i;
803

804
	/*
805
	 * The mapping is up to date if each entry is at its target,
806
	 * or is 1 greater than its target.
807
	 * (If it is 1 greater than the target, '/' will be printed, so it
808
	 * will look correct on the next row.)
809
	 */
810
	for (i = 0; i < graph->mapping_size; i++) {
811
		int target = graph->mapping[i];
812
		if (target < 0)
813
			continue;
814
		if (target == (i / 2))
815
			continue;
816
		return 0;
817
	}
818

819
	return 1;
820
}
821

822
static void graph_pad_horizontally(struct git_graph *graph, struct graph_line *line)
823
{
824
	/*
825
	 * Add additional spaces to the end of the strbuf, so that all
826
	 * lines for a particular commit have the same width.
827
	 *
828
	 * This way, fields printed to the right of the graph will remain
829
	 * aligned for the entire commit.
830
	 */
831
	if (line->width < graph->width)
832
		graph_line_addchars(line, ' ', graph->width - line->width);
833
}
834

835
static void graph_output_padding_line(struct git_graph *graph,
836
				      struct graph_line *line)
837
{
838
	int i;
839

840
	/*
841
	 * Output a padding row, that leaves all branch lines unchanged
842
	 */
843
	for (i = 0; i < graph->num_new_columns; i++) {
844
		graph_line_write_column(line, &graph->new_columns[i], '|');
845
		graph_line_addch(line, ' ');
846
	}
847
}
848

849

850
int graph_width(struct git_graph *graph)
851
{
852
	return graph->width;
853
}
854

855

856
static void graph_output_skip_line(struct git_graph *graph, struct graph_line *line)
857
{
858
	/*
859
	 * Output an ellipsis to indicate that a portion
860
	 * of the graph is missing.
861
	 */
862
	graph_line_addstr(line, "...");
863

864
	if (graph_needs_pre_commit_line(graph))
865
		graph_update_state(graph, GRAPH_PRE_COMMIT);
866
	else
867
		graph_update_state(graph, GRAPH_COMMIT);
868
}
869

870
static void graph_output_pre_commit_line(struct git_graph *graph,
871
					 struct graph_line *line)
872
{
873
	int i, seen_this;
874

875
	/*
876
	 * This function formats a row that increases the space around a commit
877
	 * with multiple parents, to make room for it.  It should only be
878
	 * called when there are 3 or more parents.
879
	 *
880
	 * We need 2 extra rows for every parent over 2.
881
	 */
882
	assert(graph->num_parents >= 3);
883

884
	/*
885
	 * graph->expansion_row tracks the current expansion row we are on.
886
	 * It should be in the range [0, num_expansion_rows - 1]
887
	 */
888
	assert(0 <= graph->expansion_row &&
889
	       graph->expansion_row < graph_num_expansion_rows(graph));
890

891
	/*
892
	 * Output the row
893
	 */
894
	seen_this = 0;
895
	for (i = 0; i < graph->num_columns; i++) {
896
		struct column *col = &graph->columns[i];
897
		if (col->commit == graph->commit) {
898
			seen_this = 1;
899
			graph_line_write_column(line, col, '|');
900
			graph_line_addchars(line, ' ', graph->expansion_row);
901
		} else if (seen_this && (graph->expansion_row == 0)) {
902
			/*
903
			 * This is the first line of the pre-commit output.
904
			 * If the previous commit was a merge commit and
905
			 * ended in the GRAPH_POST_MERGE state, all branch
906
			 * lines after graph->prev_commit_index were
907
			 * printed as "\" on the previous line.  Continue
908
			 * to print them as "\" on this line.  Otherwise,
909
			 * print the branch lines as "|".
910
			 */
911
			if (graph->prev_state == GRAPH_POST_MERGE &&
912
			    graph->prev_commit_index < i)
913
				graph_line_write_column(line, col, '\\');
914
			else
915
				graph_line_write_column(line, col, '|');
916
		} else if (seen_this && (graph->expansion_row > 0)) {
917
			graph_line_write_column(line, col, '\\');
918
		} else {
919
			graph_line_write_column(line, col, '|');
920
		}
921
		graph_line_addch(line, ' ');
922
	}
923

924
	/*
925
	 * Increment graph->expansion_row,
926
	 * and move to state GRAPH_COMMIT if necessary
927
	 */
928
	graph->expansion_row++;
929
	if (!graph_needs_pre_commit_line(graph))
930
		graph_update_state(graph, GRAPH_COMMIT);
931
}
932

933
static void graph_output_commit_char(struct git_graph *graph, struct graph_line *line)
934
{
935
	/*
936
	 * For boundary commits, print 'o'
937
	 * (We should only see boundary commits when revs->boundary is set.)
938
	 */
939
	if (graph->commit->object.flags & BOUNDARY) {
940
		assert(graph->revs->boundary);
941
		graph_line_addch(line, 'o');
942
		return;
943
	}
944

945
	/*
946
	 * get_revision_mark() handles all other cases without assert()
947
	 */
948
	graph_line_addstr(line, get_revision_mark(graph->revs, graph->commit));
949
}
950

951
/*
952
 * Draw the horizontal dashes of an octopus merge.
953
 */
954
static void graph_draw_octopus_merge(struct git_graph *graph, struct graph_line *line)
955
{
956
	/*
957
	 * The parents of a merge commit can be arbitrarily reordered as they
958
	 * are mapped onto display columns, for example this is a valid merge:
959
	 *
960
	 *	| | *---.
961
	 *	| | |\ \ \
962
	 *	| | |/ / /
963
	 *	| |/| | /
964
	 *	| |_|_|/
965
	 *	|/| | |
966
	 *	3 1 0 2
967
	 *
968
	 * The numbers denote which parent of the merge each visual column
969
	 * corresponds to; we can't assume that the parents will initially
970
	 * display in the order given by new_columns.
971
	 *
972
	 * To find the right color for each dash, we need to consult the
973
	 * mapping array, starting from the column 2 places to the right of the
974
	 * merge commit, and use that to find out which logical column each
975
	 * edge will collapse to.
976
	 *
977
	 * Commits are rendered once all edges have collapsed to their correct
978
	 * logcial column, so commit_index gives us the right visual offset for
979
	 * the merge commit.
980
	 */
981

982
	int i, j;
983
	struct column *col;
984

985
	int dashed_parents = graph_num_dashed_parents(graph);
986

987
	for (i = 0; i < dashed_parents; i++) {
988
		j = graph->mapping[(graph->commit_index + i + 2) * 2];
989
		col = &graph->new_columns[j];
990

991
		graph_line_write_column(line, col, '-');
992
		graph_line_write_column(line, col, (i == dashed_parents - 1) ? '.' : '-');
993
	}
994

995
	return;
996
}
997

998
static void graph_output_commit_line(struct git_graph *graph, struct graph_line *line)
999
{
1000
	int seen_this = 0;
1001
	int i;
1002

1003
	/*
1004
	 * Output the row containing this commit
1005
	 * Iterate up to and including graph->num_columns,
1006
	 * since the current commit may not be in any of the existing
1007
	 * columns.  (This happens when the current commit doesn't have any
1008
	 * children that we have already processed.)
1009
	 */
1010
	seen_this = 0;
1011
	for (i = 0; i <= graph->num_columns; i++) {
1012
		struct column *col = &graph->columns[i];
1013
		struct commit *col_commit;
1014
		if (i == graph->num_columns) {
1015
			if (seen_this)
1016
				break;
1017
			col_commit = graph->commit;
1018
		} else {
1019
			col_commit = graph->columns[i].commit;
1020
		}
1021

1022
		if (col_commit == graph->commit) {
1023
			seen_this = 1;
1024
			graph_output_commit_char(graph, line);
1025

1026
			if (graph->num_parents > 2)
1027
				graph_draw_octopus_merge(graph, line);
1028
		} else if (seen_this && (graph->edges_added > 1)) {
1029
			graph_line_write_column(line, col, '\\');
1030
		} else if (seen_this && (graph->edges_added == 1)) {
1031
			/*
1032
			 * This is either a right-skewed 2-way merge
1033
			 * commit, or a left-skewed 3-way merge.
1034
			 * There is no GRAPH_PRE_COMMIT stage for such
1035
			 * merges, so this is the first line of output
1036
			 * for this commit.  Check to see what the previous
1037
			 * line of output was.
1038
			 *
1039
			 * If it was GRAPH_POST_MERGE, the branch line
1040
			 * coming into this commit may have been '\',
1041
			 * and not '|' or '/'.  If so, output the branch
1042
			 * line as '\' on this line, instead of '|'.  This
1043
			 * makes the output look nicer.
1044
			 */
1045
			if (graph->prev_state == GRAPH_POST_MERGE &&
1046
			    graph->prev_edges_added > 0 &&
1047
			    graph->prev_commit_index < i)
1048
				graph_line_write_column(line, col, '\\');
1049
			else
1050
				graph_line_write_column(line, col, '|');
1051
		} else if (graph->prev_state == GRAPH_COLLAPSING &&
1052
			   graph->old_mapping[2 * i + 1] == i &&
1053
			   graph->mapping[2 * i] < i) {
1054
			graph_line_write_column(line, col, '/');
1055
		} else {
1056
			graph_line_write_column(line, col, '|');
1057
		}
1058
		graph_line_addch(line, ' ');
1059
	}
1060

1061
	/*
1062
	 * Update graph->state
1063
	 */
1064
	if (graph->num_parents > 1)
1065
		graph_update_state(graph, GRAPH_POST_MERGE);
1066
	else if (graph_is_mapping_correct(graph))
1067
		graph_update_state(graph, GRAPH_PADDING);
1068
	else
1069
		graph_update_state(graph, GRAPH_COLLAPSING);
1070
}
1071

1072
static const char merge_chars[] = {'/', '|', '\\'};
1073

1074
static void graph_output_post_merge_line(struct git_graph *graph, struct graph_line *line)
1075
{
1076
	int seen_this = 0;
1077
	int i, j;
1078

1079
	struct commit_list *first_parent = first_interesting_parent(graph);
1080
	struct column *parent_col = NULL;
1081

1082
	/*
1083
	 * Output the post-merge row
1084
	 */
1085
	for (i = 0; i <= graph->num_columns; i++) {
1086
		struct column *col = &graph->columns[i];
1087
		struct commit *col_commit;
1088
		if (i == graph->num_columns) {
1089
			if (seen_this)
1090
				break;
1091
			col_commit = graph->commit;
1092
		} else {
1093
			col_commit = col->commit;
1094
		}
1095

1096
		if (col_commit == graph->commit) {
1097
			/*
1098
			 * Since the current commit is a merge find
1099
			 * the columns for the parent commits in
1100
			 * new_columns and use those to format the
1101
			 * edges.
1102
			 */
1103
			struct commit_list *parents = first_parent;
1104
			int par_column;
1105
			int idx = graph->merge_layout;
1106
			char c;
1107
			seen_this = 1;
1108

1109
			for (j = 0; j < graph->num_parents; j++) {
1110
				par_column = graph_find_new_column_by_commit(graph, parents->item);
1111
				assert(par_column >= 0);
1112

1113
				c = merge_chars[idx];
1114
				graph_line_write_column(line, &graph->new_columns[par_column], c);
1115
				if (idx == 2) {
1116
					if (graph->edges_added > 0 || j < graph->num_parents - 1)
1117
						graph_line_addch(line, ' ');
1118
				} else {
1119
					idx++;
1120
				}
1121
				parents = next_interesting_parent(graph, parents);
1122
			}
1123
			if (graph->edges_added == 0)
1124
				graph_line_addch(line, ' ');
1125

1126
		} else if (seen_this) {
1127
			if (graph->edges_added > 0)
1128
				graph_line_write_column(line, col, '\\');
1129
			else
1130
				graph_line_write_column(line, col, '|');
1131
			graph_line_addch(line, ' ');
1132
		} else {
1133
			graph_line_write_column(line, col, '|');
1134
			if (graph->merge_layout != 0 || i != graph->commit_index - 1) {
1135
				if (parent_col)
1136
					graph_line_write_column(
1137
						line, parent_col, '_');
1138
				else
1139
					graph_line_addch(line, ' ');
1140
			}
1141
		}
1142

1143
		if (col_commit == first_parent->item)
1144
			parent_col = col;
1145
	}
1146

1147
	/*
1148
	 * Update graph->state
1149
	 */
1150
	if (graph_is_mapping_correct(graph))
1151
		graph_update_state(graph, GRAPH_PADDING);
1152
	else
1153
		graph_update_state(graph, GRAPH_COLLAPSING);
1154
}
1155

1156
static void graph_output_collapsing_line(struct git_graph *graph, struct graph_line *line)
1157
{
1158
	int i;
1159
	short used_horizontal = 0;
1160
	int horizontal_edge = -1;
1161
	int horizontal_edge_target = -1;
1162

1163
	/*
1164
	 * Swap the mapping and old_mapping arrays
1165
	 */
1166
	SWAP(graph->mapping, graph->old_mapping);
1167

1168
	/*
1169
	 * Clear out the mapping array
1170
	 */
1171
	for (i = 0; i < graph->mapping_size; i++)
1172
		graph->mapping[i] = -1;
1173

1174
	for (i = 0; i < graph->mapping_size; i++) {
1175
		int target = graph->old_mapping[i];
1176
		if (target < 0)
1177
			continue;
1178

1179
		/*
1180
		 * Since update_columns() always inserts the leftmost
1181
		 * column first, each branch's target location should
1182
		 * always be either its current location or to the left of
1183
		 * its current location.
1184
		 *
1185
		 * We never have to move branches to the right.  This makes
1186
		 * the graph much more legible, since whenever branches
1187
		 * cross, only one is moving directions.
1188
		 */
1189
		assert(target * 2 <= i);
1190

1191
		if (target * 2 == i) {
1192
			/*
1193
			 * This column is already in the
1194
			 * correct place
1195
			 */
1196
			assert(graph->mapping[i] == -1);
1197
			graph->mapping[i] = target;
1198
		} else if (graph->mapping[i - 1] < 0) {
1199
			/*
1200
			 * Nothing is to the left.
1201
			 * Move to the left by one
1202
			 */
1203
			graph->mapping[i - 1] = target;
1204
			/*
1205
			 * If there isn't already an edge moving horizontally
1206
			 * select this one.
1207
			 */
1208
			if (horizontal_edge == -1) {
1209
				int j;
1210
				horizontal_edge = i;
1211
				horizontal_edge_target = target;
1212
				/*
1213
				 * The variable target is the index of the graph
1214
				 * column, and therefore target*2+3 is the
1215
				 * actual screen column of the first horizontal
1216
				 * line.
1217
				 */
1218
				for (j = (target * 2)+3; j < (i - 2); j += 2)
1219
					graph->mapping[j] = target;
1220
			}
1221
		} else if (graph->mapping[i - 1] == target) {
1222
			/*
1223
			 * There is a branch line to our left
1224
			 * already, and it is our target.  We
1225
			 * combine with this line, since we share
1226
			 * the same parent commit.
1227
			 *
1228
			 * We don't have to add anything to the
1229
			 * output or mapping, since the
1230
			 * existing branch line has already taken
1231
			 * care of it.
1232
			 */
1233
		} else {
1234
			/*
1235
			 * There is a branch line to our left,
1236
			 * but it isn't our target.  We need to
1237
			 * cross over it.
1238
			 *
1239
			 * The space just to the left of this
1240
			 * branch should always be empty.
1241
			 */
1242
			assert(graph->mapping[i - 1] > target);
1243
			assert(graph->mapping[i - 2] < 0);
1244
			graph->mapping[i - 2] = target;
1245
			/*
1246
			 * Mark this branch as the horizontal edge to
1247
			 * prevent any other edges from moving
1248
			 * horizontally.
1249
			 */
1250
			if (horizontal_edge == -1) {
1251
				int j;
1252
				horizontal_edge_target = target;
1253
				horizontal_edge = i - 1;
1254

1255
				for (j = (target * 2) + 3; j < (i - 2); j += 2)
1256
					graph->mapping[j] = target;
1257
			}
1258
		}
1259
	}
1260

1261
	/*
1262
	 * Copy the current mapping array into old_mapping
1263
	 */
1264
	COPY_ARRAY(graph->old_mapping, graph->mapping, graph->mapping_size);
1265

1266
	/*
1267
	 * The new mapping may be 1 smaller than the old mapping
1268
	 */
1269
	if (graph->mapping[graph->mapping_size - 1] < 0)
1270
		graph->mapping_size--;
1271

1272
	/*
1273
	 * Output out a line based on the new mapping info
1274
	 */
1275
	for (i = 0; i < graph->mapping_size; i++) {
1276
		int target = graph->mapping[i];
1277
		if (target < 0)
1278
			graph_line_addch(line, ' ');
1279
		else if (target * 2 == i)
1280
			graph_line_write_column(line, &graph->new_columns[target], '|');
1281
		else if (target == horizontal_edge_target &&
1282
			 i != horizontal_edge - 1) {
1283
				/*
1284
				 * Set the mappings for all but the
1285
				 * first segment to -1 so that they
1286
				 * won't continue into the next line.
1287
				 */
1288
				if (i != (target * 2)+3)
1289
					graph->mapping[i] = -1;
1290
				used_horizontal = 1;
1291
			graph_line_write_column(line, &graph->new_columns[target], '_');
1292
		} else {
1293
			if (used_horizontal && i < horizontal_edge)
1294
				graph->mapping[i] = -1;
1295
			graph_line_write_column(line, &graph->new_columns[target], '/');
1296

1297
		}
1298
	}
1299

1300
	/*
1301
	 * If graph->mapping indicates that all of the branch lines
1302
	 * are already in the correct positions, we are done.
1303
	 * Otherwise, we need to collapse some branch lines together.
1304
	 */
1305
	if (graph_is_mapping_correct(graph))
1306
		graph_update_state(graph, GRAPH_PADDING);
1307
}
1308

1309
int graph_next_line(struct git_graph *graph, struct strbuf *sb)
1310
{
1311
	int shown_commit_line = 0;
1312
	struct graph_line line = { .buf = sb, .width = 0 };
1313

1314
	/*
1315
	 * We could conceivable be called with a NULL commit
1316
	 * if our caller has a bug, and invokes graph_next_line()
1317
	 * immediately after graph_init(), without first calling
1318
	 * graph_update().  Return without outputting anything in this
1319
	 * case.
1320
	 */
1321
	if (!graph->commit)
1322
		return -1;
1323

1324
	switch (graph->state) {
1325
	case GRAPH_PADDING:
1326
		graph_output_padding_line(graph, &line);
1327
		break;
1328
	case GRAPH_SKIP:
1329
		graph_output_skip_line(graph, &line);
1330
		break;
1331
	case GRAPH_PRE_COMMIT:
1332
		graph_output_pre_commit_line(graph, &line);
1333
		break;
1334
	case GRAPH_COMMIT:
1335
		graph_output_commit_line(graph, &line);
1336
		shown_commit_line = 1;
1337
		break;
1338
	case GRAPH_POST_MERGE:
1339
		graph_output_post_merge_line(graph, &line);
1340
		break;
1341
	case GRAPH_COLLAPSING:
1342
		graph_output_collapsing_line(graph, &line);
1343
		break;
1344
	}
1345

1346
	graph_pad_horizontally(graph, &line);
1347
	return shown_commit_line;
1348
}
1349

1350
static void graph_padding_line(struct git_graph *graph, struct strbuf *sb)
1351
{
1352
	int i;
1353
	struct graph_line line = { .buf = sb, .width = 0 };
1354

1355
	if (graph->state != GRAPH_COMMIT) {
1356
		graph_next_line(graph, sb);
1357
		return;
1358
	}
1359

1360
	/*
1361
	 * Output the row containing this commit
1362
	 * Iterate up to and including graph->num_columns,
1363
	 * since the current commit may not be in any of the existing
1364
	 * columns.  (This happens when the current commit doesn't have any
1365
	 * children that we have already processed.)
1366
	 */
1367
	for (i = 0; i < graph->num_columns; i++) {
1368
		struct column *col = &graph->columns[i];
1369

1370
		graph_line_write_column(&line, col, '|');
1371

1372
		if (col->commit == graph->commit && graph->num_parents > 2) {
1373
			int len = (graph->num_parents - 2) * 2;
1374
			graph_line_addchars(&line, ' ', len);
1375
		} else {
1376
			graph_line_addch(&line, ' ');
1377
		}
1378
	}
1379

1380
	graph_pad_horizontally(graph, &line);
1381

1382
	/*
1383
	 * Update graph->prev_state since we have output a padding line
1384
	 */
1385
	graph->prev_state = GRAPH_PADDING;
1386
}
1387

1388
int graph_is_commit_finished(struct git_graph const *graph)
1389
{
1390
	return (graph->state == GRAPH_PADDING);
1391
}
1392

1393
void graph_show_commit(struct git_graph *graph)
1394
{
1395
	struct strbuf msgbuf = STRBUF_INIT;
1396
	int shown_commit_line = 0;
1397

1398
	graph_show_line_prefix(default_diffopt);
1399

1400
	if (!graph)
1401
		return;
1402

1403
	/*
1404
	 * When showing a diff of a merge against each of its parents, we
1405
	 * are called once for each parent without graph_update having been
1406
	 * called.  In this case, simply output a single padding line.
1407
	 */
1408
	if (graph_is_commit_finished(graph)) {
1409
		graph_show_padding(graph);
1410
		shown_commit_line = 1;
1411
	}
1412

1413
	while (!shown_commit_line && !graph_is_commit_finished(graph)) {
1414
		shown_commit_line = graph_next_line(graph, &msgbuf);
1415
		fwrite(msgbuf.buf, sizeof(char), msgbuf.len,
1416
			graph->revs->diffopt.file);
1417
		if (!shown_commit_line) {
1418
			putc('\n', graph->revs->diffopt.file);
1419
			graph_show_line_prefix(&graph->revs->diffopt);
1420
		}
1421
		strbuf_setlen(&msgbuf, 0);
1422
	}
1423

1424
	strbuf_release(&msgbuf);
1425
}
1426

1427
void graph_show_oneline(struct git_graph *graph)
1428
{
1429
	struct strbuf msgbuf = STRBUF_INIT;
1430

1431
	graph_show_line_prefix(default_diffopt);
1432

1433
	if (!graph)
1434
		return;
1435

1436
	graph_next_line(graph, &msgbuf);
1437
	fwrite(msgbuf.buf, sizeof(char), msgbuf.len, graph->revs->diffopt.file);
1438
	strbuf_release(&msgbuf);
1439
}
1440

1441
void graph_show_padding(struct git_graph *graph)
1442
{
1443
	struct strbuf msgbuf = STRBUF_INIT;
1444

1445
	graph_show_line_prefix(default_diffopt);
1446

1447
	if (!graph)
1448
		return;
1449

1450
	graph_padding_line(graph, &msgbuf);
1451
	fwrite(msgbuf.buf, sizeof(char), msgbuf.len, graph->revs->diffopt.file);
1452
	strbuf_release(&msgbuf);
1453
}
1454

1455
int graph_show_remainder(struct git_graph *graph)
1456
{
1457
	struct strbuf msgbuf = STRBUF_INIT;
1458
	int shown = 0;
1459

1460
	graph_show_line_prefix(default_diffopt);
1461

1462
	if (!graph)
1463
		return 0;
1464

1465
	if (graph_is_commit_finished(graph))
1466
		return 0;
1467

1468
	for (;;) {
1469
		graph_next_line(graph, &msgbuf);
1470
		fwrite(msgbuf.buf, sizeof(char), msgbuf.len,
1471
			graph->revs->diffopt.file);
1472
		strbuf_setlen(&msgbuf, 0);
1473
		shown = 1;
1474

1475
		if (!graph_is_commit_finished(graph)) {
1476
			putc('\n', graph->revs->diffopt.file);
1477
			graph_show_line_prefix(&graph->revs->diffopt);
1478
		} else {
1479
			break;
1480
		}
1481
	}
1482
	strbuf_release(&msgbuf);
1483

1484
	return shown;
1485
}
1486

1487
static void graph_show_strbuf(struct git_graph *graph,
1488
			      FILE *file,
1489
			      struct strbuf const *sb)
1490
{
1491
	char *p;
1492

1493
	/*
1494
	 * Print the strbuf line by line,
1495
	 * and display the graph info before each line but the first.
1496
	 */
1497
	p = sb->buf;
1498
	while (p) {
1499
		size_t len;
1500
		char *next_p = strchr(p, '\n');
1501
		if (next_p) {
1502
			next_p++;
1503
			len = next_p - p;
1504
		} else {
1505
			len = (sb->buf + sb->len) - p;
1506
		}
1507
		fwrite(p, sizeof(char), len, file);
1508
		if (next_p && *next_p != '\0')
1509
			graph_show_oneline(graph);
1510
		p = next_p;
1511
	}
1512
}
1513

1514
void graph_show_commit_msg(struct git_graph *graph,
1515
			   FILE *file,
1516
			   struct strbuf const *sb)
1517
{
1518
	int newline_terminated;
1519

1520
	/*
1521
	 * Show the commit message
1522
	 */
1523
	graph_show_strbuf(graph, file, sb);
1524

1525
	if (!graph)
1526
		return;
1527

1528
	newline_terminated = (sb->len && sb->buf[sb->len - 1] == '\n');
1529

1530
	/*
1531
	 * If there is more output needed for this commit, show it now
1532
	 */
1533
	if (!graph_is_commit_finished(graph)) {
1534
		/*
1535
		 * If sb doesn't have a terminating newline, print one now,
1536
		 * so we can start the remainder of the graph output on a
1537
		 * new line.
1538
		 */
1539
		if (!newline_terminated)
1540
			putc('\n', file);
1541

1542
		graph_show_remainder(graph);
1543

1544
		/*
1545
		 * If sb ends with a newline, our output should too.
1546
		 */
1547
		if (newline_terminated)
1548
			putc('\n', file);
1549
	}
1550
}
1551

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.