1 /* Copyright (c) 2006-2015 Jonas Fonseca <jonas.fonseca@gmail.com>
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License as
5 * published by the Free Software Foundation; either version 2 of
6 * the License, or (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
16 #include "tig/graph.h"
17 #include "compat/hashtab.h"
22 unsigned int commit
:1;
23 unsigned int boundary
:1;
24 unsigned int initial
:1;
27 unsigned int continued_down
:1;
28 unsigned int continued_up
:1;
29 unsigned int continued_right
:1;
30 unsigned int continued_left
:1;
31 unsigned int continued_up_left
:1;
33 unsigned int parent_down
:1;
34 unsigned int parent_right
:1;
36 unsigned int below_commit
:1;
37 unsigned int flanked
:1;
38 unsigned int next_right
:1;
39 unsigned int matches_commit
:1;
41 unsigned int shift_left
:1;
42 unsigned int continue_shift
:1;
43 unsigned int below_shift
:1;
45 unsigned int new_column
:1;
50 struct graph_symbol symbol
;
51 char id
[SIZEOF_REV
]; /* Parent SHA1 ID. */
56 struct graph_column
*columns
;
61 size_t count
[GRAPH_COLORS
];
67 struct graph_row parents
;
68 struct graph_row prev_row
;
69 struct graph_row next_row
;
79 DEFINE_ALLOCATOR(realloc_graph_columns
, struct graph_column
, 32)
80 DEFINE_ALLOCATOR(realloc_graph_symbols
, struct graph_symbol
, 1)
88 id_color_new(const char *id
, size_t color
)
90 struct id_color
*node
= malloc(sizeof(struct id_color
));
92 node
->id
= (char *) malloc(strlen(id
) + 1);
100 id_color_delete(struct id_color
*node
)
107 id_color_eq(const void *entry
, const void *element
)
109 return strcmp(((const struct id_color
*) entry
)->id
, ((const struct id_color
*) element
)->id
) == 0;
115 id_color_delete((struct id_color
*) key
);
119 id_color_hash(const void *node
)
121 return htab_hash_string(((const struct id_color
*) node
)->id
);
125 colors_add_id(struct colors
*colors
, const char *id
, const size_t color
)
127 struct id_color
*node
= id_color_new(id
, color
);
128 void **slot
= htab_find_slot(colors
->id_map
, node
, INSERT
);
130 if (slot
!= NULL
&& *slot
== NULL
) {
132 colors
->count
[color
]++;
134 id_color_delete(node
);
139 colors_remove_id(struct colors
*colors
, const char *id
)
141 struct id_color
*node
= id_color_new(id
, 0);
142 void **slot
= htab_find_slot(colors
->id_map
, node
, NO_INSERT
);
144 if (slot
!= NULL
&& *slot
!= NULL
) {
145 colors
->count
[((struct id_color
*) *slot
)->color
]--;
146 htab_clear_slot(colors
->id_map
, slot
);
149 id_color_delete(node
);
153 colors_get_color(struct colors
*colors
, const char *id
)
155 struct id_color
*key
= id_color_new(id
, 0);
156 struct id_color
*node
= (struct id_color
*) htab_find(colors
->id_map
, key
);
158 id_color_delete(key
);
161 return (size_t) -1; // Max value of size_t. ID not found.
167 colors_get_free_color(struct colors
*colors
)
169 size_t free_color
= 0;
170 size_t lowest
= (size_t) -1; // Max value of size_t
173 for (i
= 0; i
< ARRAY_SIZE(colors
->count
); i
++) {
174 if (colors
->count
[i
] < lowest
) {
175 lowest
= colors
->count
[i
];
183 colors_init(struct colors
*colors
)
185 if (colors
->id_map
== NULL
) {
188 colors
->id_map
= htab_create_alloc(size
, id_color_hash
, id_color_eq
, key_del
, calloc
, free
);
193 get_color(struct graph_v2
*graph
, char *new_id
)
197 colors_init(&graph
->colors
);
198 color
= colors_get_color(&graph
->colors
, new_id
);
200 if (color
< (size_t) -1) {
204 color
= colors_get_free_color(&graph
->colors
);
205 colors_add_id(&graph
->colors
, new_id
, color
);
211 done_graph_rendering(struct graph
*graph_ref
)
213 struct graph_v2
*graph
= graph_ref
->private;
215 free(graph
->prev_row
.columns
);
216 free(graph
->row
.columns
);
217 free(graph
->next_row
.columns
);
218 free(graph
->parents
.columns
);
222 done_graph(struct graph
*graph_ref
)
224 struct graph_v2
*graph
= graph_ref
->private;
229 #define graph_column_has_commit(col) ((col)->id[0])
232 graph_find_column_by_id(struct graph_row
*row
, const char *id
)
234 size_t free_column
= row
->size
;
237 for (i
= 0; i
< row
->size
; i
++) {
238 if (!graph_column_has_commit(&row
->columns
[i
]) && free_column
== row
->size
)
240 else if (!strcmp(row
->columns
[i
].id
, id
))
248 graph_find_free_column(struct graph_row
*row
)
252 for (i
= 0; i
< row
->size
; i
++) {
253 if (!graph_column_has_commit(&row
->columns
[i
]))
260 static struct graph_column
*
261 graph_insert_column(struct graph_v2
*graph
, struct graph_row
*row
, size_t pos
, const char *id
)
263 struct graph_column
*column
;
265 if (!realloc_graph_columns(&row
->columns
, row
->size
, 1))
268 column
= &row
->columns
[pos
];
269 if (pos
< row
->size
) {
270 memmove(column
+ 1, column
, sizeof(*column
) * (row
->size
- pos
));
274 memset(column
, 0, sizeof(*column
));
275 string_copy_rev(column
->id
, id
);
276 column
->symbol
.boundary
= !!graph
->is_boundary
;
282 graph_add_parent(struct graph
*graph_ref
, const char *parent
)
284 struct graph_v2
*graph
= graph_ref
->private;
286 if (graph
->has_parents
)
288 return graph_insert_column(graph
, &graph
->parents
, graph
->parents
.size
, parent
) != NULL
;
292 graph_needs_expansion(struct graph_v2
*graph
)
294 return graph
->position
+ graph
->parents
.size
> graph
->row
.size
;
298 graph_expand(struct graph_v2
*graph
)
300 while (graph_needs_expansion(graph
)) {
301 if (!graph_insert_column(graph
, &graph
->prev_row
, graph
->prev_row
.size
, ""))
304 if (!graph_insert_column(graph
, &graph
->row
, graph
->row
.size
, ""))
307 if (!graph_insert_column(graph
, &graph
->next_row
, graph
->next_row
.size
, ""))
315 graph_needs_collapsing(struct graph_v2
*graph
)
317 return graph
->row
.size
> 1
318 && !graph_column_has_commit(&graph
->row
.columns
[graph
->row
.size
- 1]);
322 graph_collapse(struct graph_v2
*graph
)
324 while (graph_needs_collapsing(graph
)) {
325 graph
->prev_row
.size
--;
327 graph
->next_row
.size
--;
334 graph_canvas_append_symbol(struct graph_v2
*graph
, struct graph_canvas
*canvas
, struct graph_symbol
*symbol
)
336 if (realloc_graph_symbols(&canvas
->symbols
, canvas
->size
, 1))
337 canvas
->symbols
[canvas
->size
++] = *symbol
;
341 graph_row_clear_commit(struct graph_row
*row
, const char *id
)
345 for (i
= 0; i
< row
->size
; i
++) {
346 if (strcmp(row
->columns
[i
].id
, id
) == 0) {
347 row
->columns
[i
].id
[0] = 0;
353 graph_insert_parents(struct graph_v2
*graph
)
355 struct graph_row
*prev_row
= &graph
->prev_row
;
356 struct graph_row
*row
= &graph
->row
;
357 struct graph_row
*next_row
= &graph
->next_row
;
358 struct graph_row
*parents
= &graph
->parents
;
361 for (i
= 0; i
< parents
->size
; i
++) {
362 struct graph_column
*new = &parents
->columns
[i
];
364 if (graph_column_has_commit(new)) {
365 size_t match
= graph_find_free_column(next_row
);
367 if (match
== next_row
->size
&& *next_row
->columns
[next_row
->size
- 1].id
) {
368 graph_insert_column(graph
, next_row
, next_row
->size
, new->id
);
369 graph_insert_column(graph
, row
, row
->size
, "");
370 graph_insert_column(graph
, prev_row
, prev_row
->size
, "");
372 next_row
->columns
[match
] = *new;
379 commit_is_in_row(const char *id
, struct graph_row
*row
)
383 for (i
= 0; i
< row
->size
; i
++) {
384 if (!graph_column_has_commit(&row
->columns
[i
]))
387 if (strcmp(id
, row
->columns
[i
].id
) == 0)
394 graph_remove_collapsed_columns(struct graph_v2
*graph
)
396 struct graph_row
*row
= &graph
->next_row
;
399 for (i
= row
->size
- 1; i
> 0; i
--) {
400 if (i
== graph
->position
)
403 if (i
== graph
->position
+ 1)
406 if (strcmp(row
->columns
[i
].id
, graph
->id
) == 0)
409 if (strcmp(row
->columns
[i
].id
, row
->columns
[i
- 1].id
) != 0)
412 if (commit_is_in_row(row
->columns
[i
].id
, &graph
->parents
) && !graph_column_has_commit(&graph
->prev_row
.columns
[i
]))
415 if (strcmp(row
->columns
[i
- 1].id
, graph
->prev_row
.columns
[i
- 1].id
) != 0 || graph
->prev_row
.columns
[i
- 1].symbol
.shift_left
) {
416 if (i
+ 1 >= row
->size
)
417 memset(&row
->columns
[i
], 0, sizeof(row
->columns
[i
]));
419 row
->columns
[i
] = row
->columns
[i
+ 1];
425 graph_fill_empty_columns(struct graph_v2
*graph
)
427 struct graph_row
*row
= &graph
->next_row
;
430 for (i
= row
->size
- 2; i
>= 0; i
--) {
431 if (!graph_column_has_commit(&row
->columns
[i
])) {
432 row
->columns
[i
] = row
->columns
[i
+ 1];
438 graph_generate_next_row(struct graph_v2
*graph
)
440 graph_row_clear_commit(&graph
->next_row
, graph
->id
);
441 graph_insert_parents(graph
);
442 graph_remove_collapsed_columns(graph
);
443 graph_fill_empty_columns(graph
);
447 commits_in_row(struct graph_row
*row
)
452 for (i
= 0; i
< row
->size
;i
++) {
453 if (graph_column_has_commit(&row
->columns
[i
]))
461 graph_commit_next_row(struct graph_v2
*graph
)
465 for (i
= 0; i
< graph
->row
.size
; i
++) {
466 graph
->prev_row
.columns
[i
] = graph
->row
.columns
[i
];
468 if (i
== graph
->position
&& commits_in_row(&graph
->parents
) > 0)
469 graph
->prev_row
.columns
[i
] = graph
->next_row
.columns
[i
];
471 if (!graph_column_has_commit(&graph
->prev_row
.columns
[i
]))
472 graph
->prev_row
.columns
[i
] = graph
->next_row
.columns
[i
];
474 graph
->row
.columns
[i
] = graph
->next_row
.columns
[i
];
477 graph
->prev_position
= graph
->position
;
481 continued_down(struct graph_row
*row
, struct graph_row
*next_row
, int pos
)
483 if (strcmp(row
->columns
[pos
].id
, next_row
->columns
[pos
].id
) != 0)
486 if (row
->columns
[pos
].symbol
.shift_left
)
493 shift_left(struct graph_row
*row
, struct graph_row
*prev_row
, int pos
)
497 if (!graph_column_has_commit(&row
->columns
[pos
]))
500 for (i
= pos
- 1; i
>= 0; i
--) {
501 if (!graph_column_has_commit(&row
->columns
[i
]))
504 if (strcmp(row
->columns
[i
].id
, row
->columns
[pos
].id
) != 0)
507 if (!continued_down(prev_row
, row
, i
))
517 new_column(struct graph_row
*row
, struct graph_row
*prev_row
, int pos
)
521 if (!graph_column_has_commit(&prev_row
->columns
[pos
]))
524 for (i
= pos
; i
< row
->size
; i
++) {
525 if (strcmp(row
->columns
[pos
].id
, prev_row
->columns
[i
].id
) == 0)
533 continued_right(struct graph_row
*row
, int pos
, int commit_pos
)
537 if (pos
< commit_pos
)
542 for (i
= pos
+ 1; i
< end
; i
++) {
543 if (strcmp(row
->columns
[pos
].id
, row
->columns
[i
].id
) == 0)
551 continued_left(struct graph_row
*row
, int pos
, int commit_pos
)
555 if (pos
< commit_pos
)
560 for (i
= start
; i
< pos
; i
++) {
561 if (!graph_column_has_commit(&row
->columns
[i
]))
564 if (strcmp(row
->columns
[pos
].id
, row
->columns
[i
].id
) == 0)
572 parent_down(struct graph_row
*parents
, struct graph_row
*next_row
, int pos
)
576 for (parent
= 0; parent
< parents
->size
; parent
++) {
577 if (!graph_column_has_commit(&parents
->columns
[parent
]))
580 if (strcmp(parents
->columns
[parent
].id
, next_row
->columns
[pos
].id
) == 0)
588 parent_right(struct graph_row
*parents
, struct graph_row
*row
, struct graph_row
*next_row
, int pos
)
592 for (parent
= 0; parent
< parents
->size
; parent
++) {
593 if (!graph_column_has_commit(&parents
->columns
[parent
]))
596 for (i
= pos
+ 1; i
< next_row
->size
; i
++) {
597 if (strcmp(parents
->columns
[parent
].id
, next_row
->columns
[i
].id
) != 0)
600 if (strcmp(parents
->columns
[parent
].id
, row
->columns
[i
].id
) != 0)
609 flanked(struct graph_row
*row
, int pos
, int commit_pos
, const char *commit_id
)
613 if (pos
< commit_pos
) {
621 for (i
= start
; i
< end
; i
++) {
622 if (strcmp(row
->columns
[i
].id
, commit_id
) == 0)
630 below_commit(int pos
, struct graph_v2
*graph
)
632 if (pos
!= graph
->prev_position
)
635 if (strcmp(graph
->row
.columns
[pos
].id
, graph
->prev_row
.columns
[pos
].id
))
642 graph_generate_symbols(struct graph_v2
*graph
, struct graph_canvas
*canvas
)
644 struct graph_row
*prev_row
= &graph
->prev_row
;
645 struct graph_row
*row
= &graph
->row
;
646 struct graph_row
*next_row
= &graph
->next_row
;
647 struct graph_row
*parents
= &graph
->parents
;
650 for (pos
= 0; pos
< row
->size
; pos
++) {
651 struct graph_column
*column
= &row
->columns
[pos
];
652 struct graph_symbol
*symbol
= &column
->symbol
;
653 char *id
= next_row
->columns
[pos
].id
;
655 symbol
->commit
= (pos
== graph
->position
);
656 symbol
->boundary
= (pos
== graph
->position
&& next_row
->columns
[pos
].symbol
.boundary
);
657 symbol
->initial
= (commits_in_row(parents
) < 1);
658 symbol
->merge
= (commits_in_row(parents
) > 1);
660 symbol
->continued_down
= continued_down(row
, next_row
, pos
);
661 symbol
->continued_up
= continued_down(prev_row
, row
, pos
);
662 symbol
->continued_right
= continued_right(row
, pos
, graph
->position
);
663 symbol
->continued_left
= continued_left(row
, pos
, graph
->position
);
664 symbol
->continued_up_left
= continued_left(prev_row
, pos
, prev_row
->size
);
666 symbol
->parent_down
= parent_down(parents
, next_row
, pos
);
667 symbol
->parent_right
= (pos
> graph
->position
&& parent_right(parents
, row
, next_row
, pos
));
669 symbol
->below_commit
= below_commit(pos
, graph
);
670 symbol
->flanked
= flanked(row
, pos
, graph
->position
, graph
->id
);
671 symbol
->next_right
= continued_right(next_row
, pos
, 0);
672 symbol
->matches_commit
= (strcmp(column
->id
, graph
->id
) == 0);
674 symbol
->shift_left
= shift_left(row
, prev_row
, pos
);
675 symbol
->continue_shift
= (pos
+ 1 < row
->size
) ? shift_left(row
, prev_row
, pos
+ 1) : 0;
676 symbol
->below_shift
= prev_row
->columns
[pos
].symbol
.shift_left
;
678 symbol
->new_column
= new_column(row
, prev_row
, pos
);
679 symbol
->empty
= (!graph_column_has_commit(&row
->columns
[pos
]));
681 if (graph_column_has_commit(column
)) {
684 symbol
->color
= get_color(graph
, id
);
686 graph_canvas_append_symbol(graph
, canvas
, symbol
);
689 colors_remove_id(&graph
->colors
, graph
->id
);
693 graph_render_parents(struct graph
*graph_ref
, struct graph_canvas
*canvas
)
695 struct graph_v2
*graph
= graph_ref
->private;
697 if (graph
->parents
.size
== 0 &&
698 !graph_add_parent(graph_ref
, ""))
701 if (!graph_expand(graph
))
704 graph_generate_next_row(graph
);
705 graph_generate_symbols(graph
, canvas
);
706 graph_commit_next_row(graph
);
708 graph
->parents
.size
= graph
->position
= 0;
710 if (!graph_collapse(graph
))
717 graph_add_commit(struct graph
*graph_ref
, struct graph_canvas
*canvas
,
718 const char *id
, const char *parents
, bool is_boundary
)
720 struct graph_v2
*graph
= graph_ref
->private;
723 graph
->position
= graph_find_column_by_id(&graph
->row
, id
);
724 string_copy_rev(graph
->id
, id
);
725 graph
->is_boundary
= is_boundary
;
726 graph
->has_parents
= false;
728 while ((parents
= strchr(parents
, ' '))) {
730 if (!graph_add_parent(graph_ref
, parents
))
735 graph
->has_parents
= has_parents
> 0;
741 graph_symbol_forks(const struct graph_symbol
*symbol
)
743 if (!symbol
->continued_down
)
746 if (!symbol
->continued_right
)
749 if (!symbol
->continued_up
)
756 graph_symbol_cross_over(const struct graph_symbol
*symbol
)
761 if (!symbol
->continued_down
)
764 if (!symbol
->continued_up
&& !symbol
->new_column
&& !symbol
->below_commit
)
767 if (symbol
->shift_left
)
770 if (symbol
->parent_right
&& symbol
->merge
)
780 graph_symbol_turn_left(const struct graph_symbol
*symbol
)
782 if (symbol
->matches_commit
&& symbol
->continued_right
&& !symbol
->continued_down
)
785 if (symbol
->continue_shift
)
788 if (symbol
->continued_up
|| symbol
->new_column
|| symbol
->below_commit
) {
789 if (symbol
->matches_commit
)
792 if (symbol
->shift_left
)
800 graph_symbol_turn_down_cross_over(const struct graph_symbol
*symbol
)
802 if (!symbol
->continued_down
)
805 if (!symbol
->continued_right
)
818 graph_symbol_turn_down(const struct graph_symbol
*symbol
)
820 if (!symbol
->continued_down
)
823 if (!symbol
->continued_right
)
830 graph_symbol_merge(const struct graph_symbol
*symbol
)
832 if (symbol
->continued_down
)
835 if (!symbol
->parent_down
)
838 if (symbol
->parent_right
)
845 graph_symbol_multi_merge(const struct graph_symbol
*symbol
)
847 if (!symbol
->parent_down
)
850 if (!symbol
->parent_right
)
857 graph_symbol_vertical_bar(const struct graph_symbol
*symbol
)
862 if (symbol
->shift_left
)
865 if (!symbol
->continued_down
)
868 if (symbol
->continued_up
)
871 if (symbol
->parent_right
)
877 if (symbol
->continued_right
)
884 graph_symbol_horizontal_bar(const struct graph_symbol
*symbol
)
886 if (symbol
->shift_left
)
889 if (symbol
->continued_down
)
892 if (!symbol
->parent_right
&& !symbol
->continued_right
)
895 if ((symbol
->continued_up
&& !symbol
->continued_up_left
))
898 if (!symbol
->below_commit
)
905 graph_symbol_multi_branch(const struct graph_symbol
*symbol
)
907 if (symbol
->continued_down
)
910 if (!symbol
->continued_right
)
913 if (symbol
->below_shift
)
916 if (symbol
->continued_up
|| symbol
->new_column
|| symbol
->below_commit
) {
917 if (symbol
->matches_commit
)
920 if (symbol
->shift_left
)
928 graph_symbol_to_utf8(const struct graph_symbol
*symbol
)
930 if (symbol
->commit
) {
931 if (symbol
->boundary
)
933 else if (symbol
->initial
)
935 else if (symbol
->merge
)
940 if (graph_symbol_cross_over(symbol
))
943 if (graph_symbol_vertical_bar(symbol
))
946 if (graph_symbol_turn_left(symbol
))
949 if (graph_symbol_multi_branch(symbol
))
952 if (graph_symbol_horizontal_bar(symbol
))
955 if (graph_symbol_forks(symbol
))
958 if (graph_symbol_turn_down_cross_over(symbol
))
961 if (graph_symbol_turn_down(symbol
))
964 if (graph_symbol_merge(symbol
))
967 if (graph_symbol_multi_merge(symbol
))
973 static const chtype
*
974 graph_symbol_to_chtype(const struct graph_symbol
*symbol
)
976 static chtype graphics
[2];
978 if (symbol
->commit
) {
980 if (symbol
->boundary
)
982 else if (symbol
->initial
)
984 else if (symbol
->merge
)
987 graphics
[1] = 'o'; //ACS_DIAMOND; //'*';
990 } else if (graph_symbol_cross_over(symbol
)) {
991 graphics
[0] = ACS_HLINE
;
992 graphics
[1] = ACS_VLINE
;
994 } else if (graph_symbol_vertical_bar(symbol
)) {
996 graphics
[1] = ACS_VLINE
;
998 } else if (graph_symbol_turn_left(symbol
)) {
999 graphics
[0] = ACS_HLINE
;
1000 graphics
[1] = ACS_LRCORNER
;
1002 } else if (graph_symbol_multi_branch(symbol
)) {
1003 graphics
[0] = ACS_HLINE
;
1004 graphics
[1] = ACS_BTEE
;
1006 } else if (graph_symbol_horizontal_bar(symbol
)) {
1007 graphics
[0] = graphics
[1] = ACS_HLINE
;
1009 } else if (graph_symbol_forks(symbol
)) {
1011 graphics
[1] = ACS_LTEE
;
1013 } else if (graph_symbol_turn_down_cross_over(symbol
)) {
1014 graphics
[0] = ACS_HLINE
;
1015 graphics
[1] = ACS_ULCORNER
;
1017 } else if (graph_symbol_turn_down(symbol
)) {
1019 graphics
[1] = ACS_ULCORNER
;
1021 } else if (graph_symbol_merge(symbol
)) {
1022 graphics
[0] = ACS_HLINE
;
1023 graphics
[1] = ACS_URCORNER
;
1025 } else if (graph_symbol_multi_merge(symbol
)) {
1026 graphics
[0] = ACS_HLINE
;
1027 graphics
[1] = ACS_TTEE
;
1030 graphics
[0] = graphics
[1] = ' ';
1037 graph_symbol_to_ascii(const struct graph_symbol
*symbol
)
1039 if (symbol
->commit
) {
1040 if (symbol
->boundary
)
1042 else if (symbol
->initial
)
1044 else if (symbol
->merge
)
1049 if (graph_symbol_cross_over(symbol
))
1052 if (graph_symbol_vertical_bar(symbol
))
1055 if (graph_symbol_turn_left(symbol
))
1058 if (graph_symbol_multi_branch(symbol
))
1061 if (graph_symbol_horizontal_bar(symbol
))
1064 if (graph_symbol_forks(symbol
))
1067 if (graph_symbol_turn_down_cross_over(symbol
))
1070 if (graph_symbol_turn_down(symbol
))
1073 if (graph_symbol_merge(symbol
))
1076 if (graph_symbol_multi_merge(symbol
))
1083 graph_foreach_symbol(const struct graph
*graph
, const struct graph_canvas
*canvas
,
1084 graph_symbol_iterator_fn fn
, void *data
)
1088 for (i
= 0; i
< canvas
->size
; i
++) {
1089 struct graph_symbol
*symbol
= &canvas
->symbols
[i
];
1090 int color_id
= symbol
->commit
? GRAPH_COMMIT_COLOR
: symbol
->color
;
1092 if (fn(data
, graph
, symbol
, color_id
, i
== 0))
1100 struct graph_v2
*graph
= calloc(1, sizeof(*graph
));
1107 api
->private = graph
;
1108 api
->done
= done_graph
;
1109 api
->done_rendering
= done_graph_rendering
;
1110 api
->add_commit
= graph_add_commit
;
1111 api
->add_parent
= graph_add_parent
;
1112 api
->render_parents
= graph_render_parents
;
1113 api
->foreach_symbol
= graph_foreach_symbol
;
1114 api
->symbol_to_ascii
= graph_symbol_to_ascii
;
1115 api
->symbol_to_utf8
= graph_symbol_to_utf8
;
1116 api
->symbol_to_chtype
= graph_symbol_to_chtype
;
1121 /* vim: set ts=8 sw=8 noexpandtab: */