#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)
/*
- * Main view backend
+ * Revision graph
*/
struct commit {
size_t graph_size; /* The width of the graph array. */
};
-static bool
-main_draw(struct view *view, struct line *line, unsigned int lineno, bool selected)
-{
- char buf[DATE_COLS + 1];
- struct commit *commit = line->data;
- enum line_type type;
- int col = 0;
- size_t timelen;
- size_t authorlen;
- int trimmed = 1;
-
- if (!*commit->author)
- return FALSE;
-
- wmove(view->win, lineno, col);
-
- if (selected) {
- type = LINE_CURSOR;
- wattrset(view->win, get_line_attr(type));
- wchgat(view->win, -1, 0, type, NULL);
-
- } else {
- type = LINE_MAIN_COMMIT;
- wattrset(view->win, get_line_attr(LINE_MAIN_DATE));
- }
-
- timelen = strftime(buf, sizeof(buf), DATE_FORMAT, &commit->time);
- waddnstr(view->win, buf, timelen);
- waddstr(view->win, " ");
-
- col += DATE_COLS;
- wmove(view->win, lineno, col);
- if (type != LINE_CURSOR)
- wattrset(view->win, get_line_attr(LINE_MAIN_AUTHOR));
-
- if (opt_utf8) {
- authorlen = utf8_length(commit->author, AUTHOR_COLS - 2, &col, &trimmed);
- } else {
- authorlen = strlen(commit->author);
- if (authorlen > AUTHOR_COLS - 2) {
- authorlen = AUTHOR_COLS - 2;
- trimmed = 1;
- }
- }
-
- if (trimmed) {
- waddnstr(view->win, commit->author, authorlen);
- if (type != LINE_CURSOR)
- wattrset(view->win, get_line_attr(LINE_MAIN_DELIM));
- waddch(view->win, '~');
- } else {
- waddstr(view->win, commit->author);
- }
-
- col += AUTHOR_COLS;
- if (type != LINE_CURSOR)
- wattrset(view->win, A_NORMAL);
-
- if (opt_rev_graph && commit->graph_size) {
- size_t i;
-
- wmove(view->win, lineno, col);
- /* Using waddch() instead of waddnstr() ensures that
- * they'll be rendered correctly for the cursor line. */
- for (i = 0; i < commit->graph_size; i++)
- waddch(view->win, commit->graph[i]);
-
- col += commit->graph_size + 1;
- }
-
- wmove(view->win, lineno, col);
-
- if (commit->refs) {
- size_t i = 0;
-
- do {
- if (type == LINE_CURSOR)
- ;
- else if (commit->refs[i]->tag)
- wattrset(view->win, get_line_attr(LINE_MAIN_TAG));
- else
- wattrset(view->win, get_line_attr(LINE_MAIN_REF));
- waddstr(view->win, "[");
- waddstr(view->win, commit->refs[i]->name);
- waddstr(view->win, "]");
- if (type != LINE_CURSOR)
- wattrset(view->win, A_NORMAL);
- waddstr(view->win, " ");
- col += strlen(commit->refs[i]->name) + STRING_SIZE("[] ");
- } while (commit->refs[i++]->next);
- }
-
- if (type != LINE_CURSOR)
- wattrset(view->win, get_line_attr(type));
-
- {
- int titlelen = strlen(commit->title);
-
- if (col + titlelen > view->width)
- titlelen = view->width - col;
-
- waddnstr(view->win, commit->title, titlelen);
- }
-
- return TRUE;
-}
-
+/* Size of rev graph with no "padding" columns */
+#define SIZEOF_REVITEMS (SIZEOF_REVGRAPH - (SIZEOF_REVGRAPH / 2))
-struct rev_stack {
- struct rev_stack *prev, *next, *parents;
+struct rev_graph {
+ struct rev_graph *prev, *next, *parents;
char rev[SIZEOF_REVITEMS][SIZEOF_REV];
size_t size;
struct commit *commit;
};
/* Parents of the commit being visualized. */
-static struct rev_stack graph_parents[3];
+static struct rev_graph graph_parents[3];
/* The current stack of revisions on the graph. */
-static struct rev_stack graph_stacks[3] = {
+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_stack *graph)
+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
-reset_rev_graph(struct rev_stack *graph)
+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 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)
+push_rev_graph(struct rev_graph *graph, char *parent)
{
/* Combine duplicate parents lines. */
- if (stack->size > 0 &&
- !strncmp(stack->rev[stack->size - 1], parent, SIZEOF_REV))
+ if (graph->size > 0 &&
+ !strncmp(graph->rev[graph->size - 1], parent, SIZEOF_REV))
return;
- if (stack->size < SIZEOF_REVITEMS) {
- string_ncopy(stack->rev[stack->size++], parent, SIZEOF_REV);
+ if (graph->size < SIZEOF_REVITEMS) {
+ string_ncopy(graph->rev[graph->size++], parent, SIZEOF_REV);
}
}
-static void
-draw_rev_graph(struct rev_stack *graph)
+static chtype
+get_rev_graph_symbol(struct rev_graph *graph)
{
- chtype symbol, separator, line;
- size_t i;
+ chtype symbol;
- /* Place the symbol for this commit. */
if (graph->parents->size == 0)
symbol = REVGRAPH_INIT;
- else if (graph->parents->size > 1)
+ 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;
append_to_rev_graph(graph, separator);
}
+ /* Place the symbol for this revision. */
append_to_rev_graph(graph, symbol);
if (graph->prev->size > graph->size) {
}
void
-update_rev_graph(struct rev_stack *graph)
+update_rev_graph(struct rev_graph *graph)
{
size_t i;
- /* First traverse all lines of revisions up to the active one. */
+ /* 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]);
+ 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_stack(graph->next, graph->parents->rev[i]);
+ push_rev_graph(graph->next, graph->parents->rev[i]);
- /* FIXME: Moving branches left and right when collapsing a branch. */
+ /* Lastly, put any remaining revisions. */
for (i = graph->pos + 1; i < graph->size; i++)
- push_rev_stack(graph->next, graph->rev[i]);
+ push_rev_graph(graph->next, graph->rev[i]);
draw_rev_graph(graph);
+ done_rev_graph(graph->prev);
+}
- graph = graph->prev;
- if (graph_parent_is_merge(graph) &&
- graph->pos < graph->size - 1 &&
- graph->next->size == graph->size + graph->parents->size - 1) {
- 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++;
+/*
+ * Main view backend
+ */
+
+static bool
+main_draw(struct view *view, struct line *line, unsigned int lineno, bool selected)
+{
+ char buf[DATE_COLS + 1];
+ struct commit *commit = line->data;
+ enum line_type type;
+ int col = 0;
+ size_t timelen;
+ size_t authorlen;
+ int trimmed = 1;
+
+ if (!*commit->author)
+ return FALSE;
+
+ wmove(view->win, lineno, col);
+
+ if (selected) {
+ type = LINE_CURSOR;
+ wattrset(view->win, get_line_attr(type));
+ wchgat(view->win, -1, 0, type, NULL);
+
+ } else {
+ type = LINE_MAIN_COMMIT;
+ wattrset(view->win, get_line_attr(LINE_MAIN_DATE));
+ }
+
+ timelen = strftime(buf, sizeof(buf), DATE_FORMAT, &commit->time);
+ waddnstr(view->win, buf, timelen);
+ waddstr(view->win, " ");
+
+ col += DATE_COLS;
+ wmove(view->win, lineno, col);
+ if (type != LINE_CURSOR)
+ wattrset(view->win, get_line_attr(LINE_MAIN_AUTHOR));
+
+ if (opt_utf8) {
+ authorlen = utf8_length(commit->author, AUTHOR_COLS - 2, &col, &trimmed);
+ } else {
+ authorlen = strlen(commit->author);
+ if (authorlen > AUTHOR_COLS - 2) {
+ authorlen = AUTHOR_COLS - 2;
+ trimmed = 1;
}
}
- reset_rev_graph(graph);
+ if (trimmed) {
+ waddnstr(view->win, commit->author, authorlen);
+ if (type != LINE_CURSOR)
+ wattrset(view->win, get_line_attr(LINE_MAIN_DELIM));
+ waddch(view->win, '~');
+ } else {
+ waddstr(view->win, commit->author);
+ }
+
+ col += AUTHOR_COLS;
+ if (type != LINE_CURSOR)
+ wattrset(view->win, A_NORMAL);
+
+ if (opt_rev_graph && commit->graph_size) {
+ size_t i;
+
+ wmove(view->win, lineno, col);
+ /* Using waddch() instead of waddnstr() ensures that
+ * they'll be rendered correctly for the cursor line. */
+ for (i = 0; i < commit->graph_size; i++)
+ waddch(view->win, commit->graph[i]);
+
+ col += commit->graph_size + 1;
+ }
+
+ wmove(view->win, lineno, col);
+
+ if (commit->refs) {
+ size_t i = 0;
+
+ do {
+ if (type == LINE_CURSOR)
+ ;
+ else if (commit->refs[i]->tag)
+ wattrset(view->win, get_line_attr(LINE_MAIN_TAG));
+ else
+ wattrset(view->win, get_line_attr(LINE_MAIN_REF));
+ waddstr(view->win, "[");
+ waddstr(view->win, commit->refs[i]->name);
+ waddstr(view->win, "]");
+ if (type != LINE_CURSOR)
+ wattrset(view->win, A_NORMAL);
+ waddstr(view->win, " ");
+ col += strlen(commit->refs[i]->name) + STRING_SIZE("[] ");
+ } while (commit->refs[i++]->next);
+ }
+
+ if (type != LINE_CURSOR)
+ wattrset(view->win, get_line_attr(type));
+
+ {
+ int titlelen = strlen(commit->title);
+
+ if (col + titlelen > view->width)
+ titlelen = view->width - col;
+
+ waddnstr(view->win, commit->title, titlelen);
+ }
+
+ return TRUE;
}
/* 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;
case LINE_PARENT:
if (commit) {
line += STRING_SIZE("parent ");
- push_rev_stack(graph->parents, line);
+ push_rev_graph(graph->parents, line);
}
break;