X-Git-Url: https://git.distorted.org.uk/~mdw/tig/blobdiff_plain/c65a501a6607eaa39537e3189d7057940559b97a..18ffaa238dfd737bc8205a6a949dc3d55cb4fd7b:/tig.c diff --git a/tig.c b/tig.c index 8549620..0948cb7 100644 --- a/tig.c +++ b/tig.c @@ -71,9 +71,6 @@ static size_t utf8_length(const char *string, size_t max_width, int *coloffset, #define SIZEOF_REVGRAPH 19 /* Size of revision ancestry graphics. */ -/* Size of rev graph with no "padding" columns */ -#define SIZEOF_REVITEMS (SIZEOF_REVGRAPH - (SIZEOF_REVGRAPH / 2)) - /* This color name can be used to refer to the default term colors. */ #define COLOR_DEFAULT (-1) @@ -2668,7 +2665,7 @@ static struct view_ops blob_ops = { /* - * Main view backend + * Revision graph */ struct commit { @@ -2681,6 +2678,175 @@ struct commit { size_t graph_size; /* The width of the graph array. */ }; +/* Size of rev graph with no "padding" columns */ +#define SIZEOF_REVITEMS (SIZEOF_REVGRAPH - (SIZEOF_REVGRAPH / 2)) + +struct rev_graph { + struct rev_graph *prev, *next, *parents; + char rev[SIZEOF_REVITEMS][SIZEOF_REV]; + size_t size; + struct commit *commit; + size_t pos; +}; + +/* Parents of the commit being visualized. */ +static struct rev_graph graph_parents[3]; + +/* The current stack of revisions on the graph. */ +static struct rev_graph graph_stacks[3] = { + { &graph_stacks[2], &graph_stacks[1], &graph_parents[0] }, + { &graph_stacks[0], &graph_stacks[2], &graph_parents[1] }, + { &graph_stacks[1], &graph_stacks[0], &graph_parents[2] }, +}; + +static inline bool +graph_parent_is_merge(struct rev_graph *graph) +{ + return graph->parents->size > 1; +} + +static inline void +append_to_rev_graph(struct rev_graph *graph, chtype symbol) +{ + if (graph->commit->graph_size < ARRAY_SIZE(graph->commit->graph) - 1) + graph->commit->graph[graph->commit->graph_size++] = symbol; +} + +static void +done_rev_graph(struct rev_graph *graph) +{ + if (graph_parent_is_merge(graph) && + graph->pos < graph->size - 1 && + graph->next->size == graph->size + graph->parents->size - 1) { + size_t i = graph->pos + graph->parents->size - 1; + + graph->commit->graph_size = i * 2; + while (i < graph->next->size - 1) { + append_to_rev_graph(graph, ' '); + append_to_rev_graph(graph, '\\'); + i++; + } + } + + graph->size = graph->pos = 0; + graph->commit = NULL; + memset(graph->parents, 0, sizeof(*graph->parents)); +} + +static void +push_rev_graph(struct rev_graph *graph, char *parent) +{ + /* Combine duplicate parents lines. */ + if (graph->size > 0 && + !strncmp(graph->rev[graph->size - 1], parent, SIZEOF_REV)) + return; + + if (graph->size < SIZEOF_REVITEMS) { + string_ncopy(graph->rev[graph->size++], parent, SIZEOF_REV); + } +} + +static chtype +get_rev_graph_symbol(struct rev_graph *graph) +{ + chtype symbol; + + if (graph->parents->size == 0) + symbol = REVGRAPH_INIT; + else if (graph_parent_is_merge(graph)) + symbol = REVGRAPH_MERGE; + else if (graph->pos >= graph->size) + symbol = REVGRAPH_BRANCH; + else + symbol = REVGRAPH_COMMIT; + + return symbol; +} + +static void +draw_rev_graph(struct rev_graph *graph) +{ + chtype separator, line; + chtype symbol = get_rev_graph_symbol(graph); + size_t i; + + separator = ' '; + line = REVGRAPH_LINE; + + for (i = 0; i < graph->pos; i++) { + append_to_rev_graph(graph, line); + if (graph_parent_is_merge(graph->prev) && + graph->prev->pos == i) { + separator = '`'; + line = '.'; + } + append_to_rev_graph(graph, separator); + } + + /* Place the symbol for this revision. */ + append_to_rev_graph(graph, symbol); + + if (graph->prev->size > graph->size) { + separator = '\''; + line = ' '; + } else { + separator = ' '; + line = REVGRAPH_LINE; + } + i++; + + for (; i < graph->size; i++) { + append_to_rev_graph(graph, separator); + append_to_rev_graph(graph, line); + if (graph_parent_is_merge(graph->prev)) { + if (i < graph->prev->pos + graph->parents->size) { + separator = '`'; + line = '.'; + } + } + if (graph->prev->size > graph->size) { + separator = '/'; + line = ' '; + } + } + + if (graph->prev->size > graph->size) { + append_to_rev_graph(graph, separator); + if (line != ' ') + append_to_rev_graph(graph, line); + } +} + +void +update_rev_graph(struct rev_graph *graph) +{ + size_t i; + + /* First, traverse all lines of revisions up to the active one. */ + for (graph->pos = 0; graph->pos < graph->size; graph->pos++) { + if (!strcmp(graph->rev[graph->pos], graph->commit->id)) + break; + + push_rev_graph(graph->next, graph->rev[graph->pos]); + } + + /* Interleave the new revision parent(s). */ + for (i = 0; i < graph->parents->size; i++) + push_rev_graph(graph->next, graph->parents->rev[i]); + + /* Lastly, put any remaining revisions. */ + for (i = graph->pos + 1; i < graph->size; i++) + push_rev_graph(graph->next, graph->rev[i]); + + draw_rev_graph(graph); + done_rev_graph(graph->prev); +} + + +/* + * Main view backend + */ + static bool main_draw(struct view *view, struct line *line, unsigned int lineno, bool selected) { @@ -2788,155 +2954,11 @@ main_draw(struct view *view, struct line *line, unsigned int lineno, bool select return TRUE; } - -struct rev_stack { - struct rev_stack *prev, *next, *parents; - char rev[SIZEOF_REVITEMS][SIZEOF_REV]; - size_t size; - struct commit *commit; - size_t pos; -}; - -/* Parents of the commit being visualized. */ -static struct rev_stack graph_parents[3]; - -/* The current stack of revisions on the graph. */ -static struct rev_stack graph_stacks[3] = { - { &graph_stacks[2], &graph_stacks[1], &graph_parents[0] }, - { &graph_stacks[0], &graph_stacks[2], &graph_parents[1] }, - { &graph_stacks[1], &graph_stacks[0], &graph_parents[2] }, -}; - -static void -reset_rev_graph(struct rev_stack *graph) -{ - graph->size = graph->pos = 0; - graph->commit = NULL; - memset(graph->parents, 0, sizeof(*graph->parents)); -} - -static inline void -append_to_rev_graph(struct rev_stack *stack, chtype symbol) -{ - if (stack->commit->graph_size < ARRAY_SIZE(stack->commit->graph) - 1) - stack->commit->graph[stack->commit->graph_size++] = symbol; -} - -static void -push_rev_stack(struct rev_stack *stack, char *parent) -{ - /* Combine duplicate parents lines. */ - if (stack->size > 0 && - !strncmp(stack->rev[stack->size - 1], parent, SIZEOF_REV)) - return; - - if (stack->size < SIZEOF_REVITEMS) { - string_ncopy(stack->rev[stack->size++], parent, SIZEOF_REV); - } -} - -static void -draw_rev_graph(struct rev_stack *graph) -{ - chtype symbol, separator, line; - size_t i; - - /* Place the symbol for this commit. */ - if (graph->parents->size == 0) - symbol = REVGRAPH_INIT; - else if (graph->parents->size > 1) - symbol = REVGRAPH_MERGE; - else if (graph->pos >= graph->size) - symbol = REVGRAPH_BRANCH; - else - symbol = REVGRAPH_COMMIT; - - separator = ' '; - line = REVGRAPH_LINE; - - for (i = 0; i < graph->pos; i++) { - append_to_rev_graph(graph, line); - if (graph->prev->parents->size > 1 && - graph->prev->pos == i) { - separator = '`'; - line = '.'; - } - append_to_rev_graph(graph, separator); - } - - append_to_rev_graph(graph, symbol); - - if (graph->prev->size > graph->size) { - separator = '\''; - line = ' '; - } else { - separator = ' '; - line = REVGRAPH_LINE; - } - i++; - - for (; i < graph->size; i++) { - append_to_rev_graph(graph, separator); - append_to_rev_graph(graph, line); - if (graph->prev->parents->size > 1) { - if (i < graph->prev->pos + graph->parents->size) { - separator = '`'; - line = '.'; - } - } - if (graph->prev->size > graph->size) { - separator = '/'; - line = ' '; - } - } - - if (graph->prev->size > graph->size) { - append_to_rev_graph(graph, separator); - if (line != ' ') - append_to_rev_graph(graph, line); - } -} - -void -update_rev_graph(struct rev_stack *graph) -{ - size_t i; - - /* First traverse all lines of revisions up to the active one. */ - for (graph->pos = 0; graph->pos < graph->size; graph->pos++) { - if (!strcmp(graph->rev[graph->pos], graph->commit->id)) - break; - - push_rev_stack(graph->next, graph->rev[graph->pos]); - } - - for (i = 0; i < graph->parents->size; i++) - push_rev_stack(graph->next, graph->parents->rev[i]); - - /* FIXME: Moving branches left and right when collapsing a branch. */ - for (i = graph->pos + 1; i < graph->size; i++) - push_rev_stack(graph->next, graph->rev[i]); - - draw_rev_graph(graph); - if (graph->prev->parents->size > 1 && - graph->prev->pos < graph->prev->size - 1 && - graph->size == graph->prev->size + graph->prev->parents->size - 1) { - i = graph->prev->pos + graph->prev->parents->size - 1; - graph->prev->commit->graph_size = i * 2; - while (i < graph->size - 1) { - append_to_rev_graph(graph->prev, ' '); - append_to_rev_graph(graph->prev, '\\'); - i++; - } - } - reset_rev_graph(graph->prev); -} - /* Reads git log --pretty=raw output and parses it into the commit struct. */ static bool main_read(struct view *view, char *line) { - static struct rev_stack *graph = graph_stacks; + static struct rev_graph *graph = graph_stacks; enum line_type type = get_line_type(line); struct commit *commit = view->lines ? view->line[view->lines - 1].data : NULL; @@ -2958,7 +2980,7 @@ main_read(struct view *view, char *line) case LINE_PARENT: if (commit) { line += STRING_SIZE("parent "); - push_rev_stack(graph->parents, line); + push_rev_graph(graph->parents, line); } break;