{"thread":{"id":"24385","subject":"[PATCH 0/2] Preparing the graph API for external users","startedAt":"2010-07-13T21:23:37Z","lastAt":"2010-07-18T13:26:09Z","messageCount":12,"participants":["Johan Herland","Lars Hjemli"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"145466","messageId":"1279056219-27096-1-git-send-email-johan@herland.net","threadId":"24385","inReplyTo":null,"subject":"[PATCH 0/2] Preparing the graph API for external users","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2010-07-13T21:23:37Z","receivedAt":"2010-07-13T21:23:37Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"Hi,\n\nI'm playing around with some CGit patches for enabling an ASCII-art\ncommit graph to be displayed on CGit's 'log' page. These patches reuse\nthe ASCII-art commit graph that is produced by 'git log --graph'.\n\nHowever, in order to allow proper reuse by CGit, I need to make a\ncouple of changes to the graph API:\n\nThe first patch exposes graph_next_line() in the graph.h API. This\nfunction is needed to drive the graph generation from CGit. (Since\nthe graph_show_* functions print directly to stdout, they can not be\nused by CGit.)\n\nThe second patch allows CGit to use a different coloring mechanism\nthan the default ANSI color escapes in graph.c. CGit replaces the\ncolumn_colors array of ANSI escapes in graph.c with its own array that\ncontains HTML <span> tags (which are then styled to the appropriate\ncolors using CSS).\n\nFor reference, the corresponding CGit patches that generate the commit\ngraph on CGit's log page will follow as a separate patch series.\n\n\nJohan Herland (2):\n  Make graph_next_line() available in the graph.h API\n  Enable custom schemes for column colors in the graph API\n\n graph.c |   50 +++++++++++++++++++++++++++-----------------------\n graph.h |   28 ++++++++++++++++++++++++++++\n 2 files changed, 55 insertions(+), 23 deletions(-)\n"},{"id":"145467","messageId":"1279056219-27096-2-git-send-email-johan@herland.net","threadId":"24385","inReplyTo":"1279056219-27096-1-git-send-email-johan@herland.net","subject":"[PATCH 1/2] Make graph_next_line() available in the graph.h API","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2010-07-13T21:23:38Z","receivedAt":"2010-07-13T21:23:38Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"In order to successfully use the graph API from a context other than the\nstdout/command-line scenario (where the graph_show_* functions are\nsuitable), we need direct access to graph_next_line(), to drive the\ngraph drawing process.\n\nSigned-off-by: Johan Herland <johan@herland.net>\n---\n graph.c |   13 +------------\n graph.h |   11 +++++++++++\n 2 files changed, 12 insertions(+), 12 deletions(-)\n\ndiff --git a/graph.c b/graph.c\nindex ac7c605..47397da 100644\n--- a/graph.c\n+++ b/graph.c\n@@ -8,17 +8,6 @@\n /* Internal API */\n \n /*\n- * Output the next line for a graph.\n- * This formats the next graph line into the specified strbuf.  It is not\n- * terminated with a newline.\n- *\n- * Returns 1 if the line includes the current commit, and 0 otherwise.\n- * graph_next_line() will return 1 exactly once for each time\n- * graph_update() is called.\n- */\n-static int graph_next_line(struct git_graph *graph, struct strbuf *sb);\n-\n-/*\n  * Output a padding line in the graph.\n  * This is similar to graph_next_line().  However, it is guaranteed to\n  * never print the current commit line.  Instead, if the commit line is\n@@ -1143,7 +1132,7 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf\n \t\tgraph_update_state(graph, GRAPH_PADDING);\n }\n \n-static int graph_next_line(struct git_graph *graph, struct strbuf *sb)\n+int graph_next_line(struct git_graph *graph, struct strbuf *sb)\n {\n \tswitch (graph->state) {\n \tcase GRAPH_PADDING:\ndiff --git a/graph.h b/graph.h\nindex b82ae87..f188168 100644\n--- a/graph.h\n+++ b/graph.h\n@@ -32,6 +32,17 @@ void graph_update(struct git_graph *graph, struct commit *commit);\n  */\n int graph_is_commit_finished(struct git_graph const *graph);\n \n+/*\n+ * Output the next line for a graph.\n+ * This formats the next graph line into the specified strbuf.  It is not\n+ * terminated with a newline.\n+ *\n+ * Returns 1 if the line includes the current commit, and 0 otherwise.\n+ * graph_next_line() will return 1 exactly once for each time\n+ * graph_update() is called.\n+ */\n+int graph_next_line(struct git_graph *graph, struct strbuf *sb);\n+\n \n /*\n  * graph_show_*: helper functions for printing to stdout\n-- \n1.7.0.4\n"},{"id":"145468","messageId":"1279056219-27096-3-git-send-email-johan@herland.net","threadId":"24385","inReplyTo":"1279056219-27096-1-git-send-email-johan@herland.net","subject":"[PATCH 2/2] Enable custom schemes for column colors in the graph API","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2010-07-13T21:23:39Z","receivedAt":"2010-07-13T21:23:39Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"Currently, the graph code is hardcoded to use ANSI color escapes for\ncoloring the column characters in the generated graphs. This patch\nallows a custom scheme of colors to be set at runtime, allowing\ndifferent types of color escapes to be used.\n\nA new function - graph_set_column_colors() - is added to the graph.h API,\nwhich allows a custom column_colors array (and column_colors_max value)\nto replace the builtin ANSI array (and _max value). The new function -\nif used - must be called before graph_init() is called.\n\nSigned-off-by: Johan Herland <johan@herland.net>\n---\n graph.c |   37 ++++++++++++++++++++++++++-----------\n graph.h |   17 +++++++++++++++++\n 2 files changed, 43 insertions(+), 11 deletions(-)\n\ndiff --git a/graph.c b/graph.c\nindex 47397da..e2a5860 100644\n--- a/graph.c\n+++ b/graph.c\n@@ -62,7 +62,7 @@ enum graph_state {\n /*\n  * The list of available column colors.\n  */\n-static char column_colors[][COLOR_MAXLEN] = {\n+static const char *column_colors_ansi[] = {\n \tGIT_COLOR_RED,\n \tGIT_COLOR_GREEN,\n \tGIT_COLOR_YELLOW,\n@@ -75,23 +75,33 @@ static char column_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_BOLD_BLUE,\n \tGIT_COLOR_BOLD_MAGENTA,\n \tGIT_COLOR_BOLD_CYAN,\n+\tGIT_COLOR_RESET,\n };\n \n-#define COLUMN_COLORS_MAX (ARRAY_SIZE(column_colors))\n+#define COLUMN_COLORS_ANSI_MAX (ARRAY_SIZE(column_colors_ansi) - 1)\n \n-static const char *column_get_color_code(const struct column *c)\n+static const char **column_colors;\n+static unsigned short column_colors_max;\n+\n+void graph_set_column_colors(const char **colors, unsigned short colors_max)\n+{\n+\tcolumn_colors = colors;\n+\tcolumn_colors_max = colors_max;\n+}\n+\n+static const char *column_get_color_code(unsigned short color)\n {\n-\treturn column_colors[c->color];\n+\treturn column_colors[color];\n }\n \n static void strbuf_write_column(struct strbuf *sb, const struct column *c,\n \t\t\t\tchar col_char)\n {\n-\tif (c->color < COLUMN_COLORS_MAX)\n-\t\tstrbuf_addstr(sb, column_get_color_code(c));\n+\tif (c->color < column_colors_max)\n+\t\tstrbuf_addstr(sb, column_get_color_code(c->color));\n \tstrbuf_addch(sb, col_char);\n-\tif (c->color < COLUMN_COLORS_MAX)\n-\t\tstrbuf_addstr(sb, GIT_COLOR_RESET);\n+\tif (c->color < column_colors_max)\n+\t\tstrbuf_addstr(sb, column_get_color_code(column_colors_max));\n }\n \n struct git_graph {\n@@ -215,6 +225,11 @@ static struct strbuf *diff_output_prefix_callback(struct diff_options *opt, void\n struct git_graph *graph_init(struct rev_info *opt)\n {\n \tstruct git_graph *graph = xmalloc(sizeof(struct git_graph));\n+\n+\tif (!column_colors)\n+\t\tgraph_set_column_colors(column_colors_ansi,\n+\t\t\t\t\tCOLUMN_COLORS_ANSI_MAX);\n+\n \tgraph->commit = NULL;\n \tgraph->revs = opt;\n \tgraph->num_parents = 0;\n@@ -231,7 +246,7 @@ struct git_graph *graph_init(struct rev_info *opt)\n \t * always increment it for the first commit we output.\n \t * This way we start at 0 for the first commit.\n \t */\n-\tgraph->default_column_color = COLUMN_COLORS_MAX - 1;\n+\tgraph->default_column_color = column_colors_max - 1;\n \n \t/*\n \t * Allocate a reasonably large default number of columns\n@@ -354,7 +369,7 @@ static struct commit_list *first_interesting_parent(struct git_graph *graph)\n static unsigned short graph_get_current_column_color(const struct git_graph *graph)\n {\n \tif (!DIFF_OPT_TST(&graph->revs->diffopt, COLOR_DIFF))\n-\t\treturn COLUMN_COLORS_MAX;\n+\t\treturn column_colors_max;\n \treturn graph->default_column_color;\n }\n \n@@ -364,7 +379,7 @@ static unsigned short graph_get_current_column_color(const struct git_graph *gra\n static void graph_increment_column_color(struct git_graph *graph)\n {\n \tgraph->default_column_color = (graph->default_column_color + 1) %\n-\t\tCOLUMN_COLORS_MAX;\n+\t\tcolumn_colors_max;\n }\n \n static unsigned short graph_find_commit_color(const struct git_graph *graph,\ndiff --git a/graph.h b/graph.h\nindex f188168..aff960c 100644\n--- a/graph.h\n+++ b/graph.h\n@@ -5,6 +5,23 @@\n struct git_graph;\n \n /*\n+ * Set up a custom scheme for column colors.\n+ *\n+ * The default column color scheme inserts ANSI color escapes to colorize\n+ * the graph. The various color escapes are stored in an array of strings\n+ * where each entry corresponds to a color, except for the last entry,\n+ * which denotes the escape for resetting the color back to the default.\n+ * When generating the graph, strings from this array are inserted before\n+ * and after the various column characters.\n+ *\n+ * This function allows you to enable a custom array of color escapes.\n+ * The 'colors_max' argument is the index of the last \"reset\" entry.\n+ *\n+ * This functions must be called BEFORE graph_init() is called.\n+ */\n+void graph_set_column_colors(const char **colors, unsigned short colors_max);\n+\n+/*\n  * Create a new struct git_graph.\n  */\n struct git_graph *graph_init(struct rev_info *opt);\n-- \n1.7.0.4\n"},{"id":"145470","messageId":"1279057221-28036-1-git-send-email-johan@herland.net","threadId":"24385","inReplyTo":"1279056219-27096-1-git-send-email-johan@herland.net","subject":"[CGit RFC/PATCH 0/5] Commit graph on CGit's 'log' view","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2010-07-13T21:40:16Z","receivedAt":"2010-07-13T21:40:16Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"Hi,\n\nHere are some patches to implement an ASCII-art commit graph on CGit's\n'log' page. The patches reuse the graph-drawing code from Git's own\n'git log --graph'. As such, these patches depend on the two patches\nI just submitted to the Git list for extending the graph.h API.\n\nMore detailed: Patch #4 in this series (ui-log: Implement support for\ncommit graphs) depend on patch #1 in the other series (Make\ngraph_next_line() available in the graph.h API), while patch #5 in\nthis series (ui-log: Colorize commit graph) depends on patch #2 in the\nother series (Enable custom schemes for column colors in the graph\nAPI).\n\nOtherwise, the first patch in this series is a minor cleanup patch,\nwhile patches #2 and #3 prepare for the introduction of commit graphs\nin patch #4.\n\n\nHave fun!\n\n...Johan\n\n\nJohan Herland (5):\n  ui-stats: Remove unnecessary #include\n  ui-log: Move 'Age' column to the right of 'Author', like in gitk\n  ui-log: Refactor display of commit messages\n  ui-log: Implement support for commit graphs\n  ui-log: Colorize commit graph\n\n cgit.c       |    6 +++\n cgit.css     |   31 ++++++++++++-\n cgit.h       |    3 +\n cgitrc.5.txt |   15 ++++++-\n shared.c     |    1 +\n ui-log.c     |  140 +++++++++++++++++++++++++++++++++++++++++++++++-----------\n ui-stats.c   |    2 -\n 7 files changed, 168 insertions(+), 30 deletions(-)\n"},{"id":"145474","messageId":"1279057221-28036-2-git-send-email-johan@herland.net","threadId":"24385","inReplyTo":"1279056219-27096-1-git-send-email-johan@herland.net","subject":"[CGit RFC/PATCH 1/5] ui-stats: Remove unnecessary #include","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2010-07-13T21:40:17Z","receivedAt":"2010-07-13T21:40:17Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"<string-list.h> is already #included from cgit.h\n\nSigned-off-by: Johan Herland <johan@herland.net>\n---\n ui-stats.c |    2 --\n 1 files changed, 0 insertions(+), 2 deletions(-)\n\ndiff --git a/ui-stats.c b/ui-stats.c\nindex bdaf9cc..e8ea57a 100644\n--- a/ui-stats.c\n+++ b/ui-stats.c\n@@ -1,5 +1,3 @@\n-#include <string-list.h>\n-\n #include \"cgit.h\"\n #include \"html.h\"\n #include \"ui-shared.h\"\n-- \n1.7.0.4\n"},{"id":"145472","messageId":"1279057221-28036-3-git-send-email-johan@herland.net","threadId":"24385","inReplyTo":"1279056219-27096-1-git-send-email-johan@herland.net","subject":"[CGit RFC/PATCH 2/5] ui-log: Move 'Age' column to the right of 'Author', like in gitk","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2010-07-13T21:40:18Z","receivedAt":"2010-07-13T21:40:18Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"This is in preparation for putting the commit graph to the left of the\ncommit message. IMHO, it looks better when the commit message is right\nnext to the graph, than if the age is wedged in between.\n\nSigned-off-by: Johan Herland <johan@herland.net>\n---\n ui-log.c |   26 ++++++++++++--------------\n 1 files changed, 12 insertions(+), 14 deletions(-)\n\ndiff --git a/ui-log.c b/ui-log.c\nindex 33ec8a9..390c38b 100644\n--- a/ui-log.c\n+++ b/ui-log.c\n@@ -79,23 +79,22 @@ void print_commit(struct commit *commit)\n {\n \tstruct commitinfo *info;\n \tchar *tmp;\n-\tint cols = 2;\n+\tint cols = 3;\n \n \tinfo = cgit_parse_commit(commit);\n-\thtmlf(\"<tr%s><td>\",\n-\t\tctx.qry.showmsg ? \" class='logheader'\" : \"\");\n-\ttmp = fmt(\"id=%s\", sha1_to_hex(commit->object.sha1));\n-\ttmp = cgit_fileurl(ctx.repo->url, \"commit\", ctx.qry.vpath, tmp);\n-\thtml_link_open(tmp, NULL, NULL);\n-\tcgit_print_age(commit->date, TM_WEEK * 2, FMT_SHORTDATE);\n-\thtml_link_close();\n-\thtmlf(\"</td><td%s>\",\n-\t\tctx.qry.showmsg ? \" class='logsubject'\" : \"\");\n+\thtmlf(\"<tr%s>\", ctx.qry.showmsg ? \" class='logheader'\" : \"\");\n+\thtmlf(\"<td%s>\", ctx.qry.showmsg ? \" class='logsubject'\" : \"\");\n \tcgit_commit_link(info->subject, NULL, NULL, ctx.qry.head,\n \t\t\t sha1_to_hex(commit->object.sha1), ctx.qry.vpath, 0);\n \tshow_commit_decorations(commit);\n \thtml(\"</td><td>\");\n \thtml_txt(info->author);\n+\thtml(\"</td><td>\");\n+\ttmp = fmt(\"id=%s\", sha1_to_hex(commit->object.sha1));\n+\ttmp = cgit_fileurl(ctx.repo->url, \"commit\", ctx.qry.vpath, tmp);\n+\thtml_link_open(tmp, NULL, NULL);\n+\tcgit_print_age(commit->date, TM_WEEK * 2, FMT_SHORTDATE);\n+\thtml_link_close();\n \tif (ctx.repo->enable_log_filecount) {\n \t\tfiles = 0;\n \t\tadd_lines = 0;\n@@ -115,7 +114,7 @@ void print_commit(struct commit *commit)\n \t\t\tif (ctx.repo->enable_log_linecount)\n \t\t\t\tcols++;\n \t\t}\n-\t\thtmlf(\"<tr class='nohover'><td/><td colspan='%d' class='logmsg'>\",\n+\t\thtmlf(\"<tr class='nohover'><td colspan='%d' class='logmsg'>\",\n \t\t\tcols);\n \t\thtml_txt(info->msg);\n \t\thtml(\"</td></tr>\\n\");\n@@ -176,8 +175,7 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern\n \tif (pager)\n \t\thtml(\"<table class='list nowrap'>\");\n \n-\thtml(\"<tr class='nohover'><th class='left'>Age</th>\"\n-\t      \"<th class='left'>Commit message\");\n+\thtml(\"<tr class='nohover'><th class='left'>Commit message\");\n \tif (pager) {\n \t\thtml(\" (\");\n \t\tcgit_log_link(ctx.qry.showmsg ? \"Collapse\" : \"Expand\", NULL,\n@@ -186,7 +184,7 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern\n \t\t\t      ctx.qry.search, ctx.qry.showmsg ? 0 : 1);\n \t\thtml(\")\");\n \t}\n-\thtml(\"</th><th class='left'>Author</th>\");\n+\thtml(\"</th><th class='left'>Author</th><th class='left'>Age</th>\");\n \tif (ctx.repo->enable_log_filecount) {\n \t\thtml(\"<th class='left'>Files</th>\");\n \t\tcolumns++;\n-- \n1.7.0.4\n"},{"id":"145471","messageId":"1279057221-28036-4-git-send-email-johan@herland.net","threadId":"24385","inReplyTo":"1279056219-27096-1-git-send-email-johan@herland.net","subject":"[CGit RFC/PATCH 3/5] ui-log: Refactor display of commit messages","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2010-07-13T21:40:19Z","receivedAt":"2010-07-13T21:40:19Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"Split new function print_commit_line() out of print_commit(). The new\nfunction only prints the initial table cells containing commit metadata,\ni.e. the commit subject, author and date (and file/line-count if enabled).\n\nThe printing of the rest of the commit message (when showmsg is enabled)\nis still performed in print_commit(), but is slightly changed to use\nadditional newlines to achieve the vertical margins that were previously\nimplemented with CSS. This is in preparation for the commit graph which\nwill be printed to the left of the commit message as part of the same\ntable row, and therefore needs to minimize margins that would otherwise\ncause ugly gaps in the graph.\n\nSigned-off-by: Johan Herland <johan@herland.net>\n---\n cgit.css |    2 +-\n ui-log.c |   38 +++++++++++++++++++++++++-------------\n 2 files changed, 26 insertions(+), 14 deletions(-)\n\ndiff --git a/cgit.css b/cgit.css\nindex 6e47eb3..78f654e 100644\n--- a/cgit.css\n+++ b/cgit.css\n@@ -161,7 +161,7 @@ table.list td.logsubject {\n table.list td.logmsg {\n \tfont-family: monospace;\n \twhite-space: pre;\n-\tpadding: 1em 0.5em 2em 0.5em;\n+\tpadding: 0 0.5em;\n }\n \n table.list td a {\ndiff --git a/ui-log.c b/ui-log.c\nindex 390c38b..2cd0f19 100644\n--- a/ui-log.c\n+++ b/ui-log.c\n@@ -75,14 +75,10 @@ void show_commit_decorations(struct commit *commit)\n \t}\n }\n \n-void print_commit(struct commit *commit)\n+static void print_commit_line(struct commit *commit, struct commitinfo *info)\n {\n-\tstruct commitinfo *info;\n \tchar *tmp;\n-\tint cols = 3;\n \n-\tinfo = cgit_parse_commit(commit);\n-\thtmlf(\"<tr%s>\", ctx.qry.showmsg ? \" class='logheader'\" : \"\");\n \thtmlf(\"<td%s>\", ctx.qry.showmsg ? \" class='logsubject'\" : \"\");\n \tcgit_commit_link(info->subject, NULL, NULL, ctx.qry.head,\n \t\t\t sha1_to_hex(commit->object.sha1), ctx.qry.vpath, 0);\n@@ -107,18 +103,34 @@ void print_commit(struct commit *commit)\n \t\t\thtmlf(\"-%d/+%d\", rem_lines, add_lines);\n \t\t}\n \t}\n-\thtml(\"</td></tr>\\n\");\n-\tif (ctx.qry.showmsg) {\n-\t\tif (ctx.repo->enable_log_filecount) {\n+\thtml(\"</td>\");\n+}\n+\n+void print_commit(struct commit *commit)\n+{\n+\tstruct commitinfo *info = cgit_parse_commit(commit);\n+\tint cols = 3;\n+\n+\tif (ctx.repo->enable_log_filecount) {\n+\t\tcols++;\n+\t\tif (ctx.repo->enable_log_linecount)\n \t\t\tcols++;\n-\t\t\tif (ctx.repo->enable_log_linecount)\n-\t\t\t\tcols++;\n+\t}\n+\n+\thtmlf(\"<tr%s>\", ctx.qry.showmsg ? \" class='logheader'\" : \"\");\n+\tprint_commit_line(commit, info);\n+\thtml(\"</tr>\\n\");\n+\n+\tif (ctx.qry.showmsg) {\n+\t\thtml(\"<tr class='nohover'>\");\n+\t\thtmlf(\"<td colspan='%d' class='logmsg'>\\n\", cols);\n+\t\tif (*(info->msg)) {\n+\t\t\thtml_txt(info->msg);\n+\t\t\thtml(\"\\n\\n\");\n \t\t}\n-\t\thtmlf(\"<tr class='nohover'><td colspan='%d' class='logmsg'>\",\n-\t\t\tcols);\n-\t\thtml_txt(info->msg);\n \t\thtml(\"</td></tr>\\n\");\n \t}\n+\n \tcgit_free_commitinfo(info);\n }\n \n-- \n1.7.0.4\n"},{"id":"145475","messageId":"1279057221-28036-5-git-send-email-johan@herland.net","threadId":"24385","inReplyTo":"1279056219-27096-1-git-send-email-johan@herland.net","subject":"[CGit RFC/PATCH 4/5] ui-log: Implement support for commit graphs","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2010-07-13T21:40:20Z","receivedAt":"2010-07-13T21:40:20Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"Teach CGit to print an ASCII art commit graph to the left of the commit\nmessage, similar to 'git log --graph'. The graph adds extra lines (table\nrows) to the log when needed to add/remove/shuffle edges in the graph.\n\nWhen 'showmsg' is enabled, the graph auto-adjusts to the lines added by\nthe commit message.\n\nThis feature is controlled by a new config variable: \"enable-commit-graph\"\n(disabled by default), and individual repos can disable it by settign\n\"repo.enable-commit-graph\" to \"0\".\n\nSigned-off-by: Johan Herland <johan@herland.net>\n---\n cgit.c       |    6 +++++\n cgit.css     |    5 ++++\n cgit.h       |    3 ++\n cgitrc.5.txt |   15 +++++++++++-\n shared.c     |    1 +\n ui-log.c     |   71 +++++++++++++++++++++++++++++++++++++++++++++++++++++-----\n 6 files changed, 94 insertions(+), 7 deletions(-)\n\ndiff --git a/cgit.c b/cgit.c\nindex ab25b6a..29fb57f 100644\n--- a/cgit.c\n+++ b/cgit.c\n@@ -56,6 +56,8 @@ void repo_config(struct cgit_repo *repo, const char *name, const char *value)\n \t\trepo->defbranch = xstrdup(value);\n \telse if (!strcmp(name, \"snapshots\"))\n \t\trepo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value);\n+\telse if (!strcmp(name, \"enable-commit-graph\"))\n+\t\trepo->enable_commit_graph = ctx.cfg.enable_commit_graph * atoi(value);\n \telse if (!strcmp(name, \"enable-log-filecount\"))\n \t\trepo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value);\n \telse if (!strcmp(name, \"enable-log-linecount\"))\n@@ -137,6 +139,8 @@ void config_cb(const char *name, const char *value)\n \t\tctx.cfg.enable_filter_overrides = atoi(value);\n \telse if (!strcmp(name, \"enable-index-links\"))\n \t\tctx.cfg.enable_index_links = atoi(value);\n+\telse if (!strcmp(name, \"enable-commit-graph\"))\n+\t\tctx.cfg.enable_commit_graph = atoi(value);\n \telse if (!strcmp(name, \"enable-log-filecount\"))\n \t\tctx.cfg.enable_log_filecount = atoi(value);\n \telse if (!strcmp(name, \"enable-log-linecount\"))\n@@ -522,6 +526,8 @@ void print_repo(FILE *f, struct cgit_repo *repo)\n \t\tfprintf(f, \"repo.section=%s\\n\", repo->section);\n \tif (repo->clone_url)\n \t\tfprintf(f, \"repo.clone-url=%s\\n\", repo->clone_url);\n+\tfprintf(f, \"repo.enable-commit-graph=%d\\n\",\n+\t        repo->enable_commit_graph);\n \tfprintf(f, \"repo.enable-log-filecount=%d\\n\",\n \t        repo->enable_log_filecount);\n \tfprintf(f, \"repo.enable-log-linecount=%d\\n\",\ndiff --git a/cgit.css b/cgit.css\nindex 78f654e..65da960 100644\n--- a/cgit.css\n+++ b/cgit.css\n@@ -153,6 +153,11 @@ table.list td {\n \tpadding: 0.1em 0.5em 0.1em 0.5em;\n }\n \n+table.list td.commitgraph {\n+\tfont-family: monospace;\n+\twhite-space: pre;\n+}\n+\n table.list td.logsubject {\n \tfont-family: monospace;\n \tfont-weight: bold;\ndiff --git a/cgit.h b/cgit.h\nindex 2b28d63..402610b 100644\n--- a/cgit.h\n+++ b/cgit.h\n@@ -19,6 +19,7 @@\n #include <xdiff-interface.h>\n #include <xdiff/xdiff.h>\n #include <utf8.h>\n+#include <graph.h>\n \n \n /*\n@@ -70,6 +71,7 @@ struct cgit_repo {\n \tchar *section;\n \tchar *clone_url;\n \tint snapshots;\n+\tint enable_commit_graph;\n \tint enable_log_filecount;\n \tint enable_log_linecount;\n \tint enable_remote_branches;\n@@ -182,6 +184,7 @@ struct cgit_config {\n \tint embedded;\n \tint enable_filter_overrides;\n \tint enable_index_links;\n+\tint enable_commit_graph;\n \tint enable_log_filecount;\n \tint enable_log_linecount;\n \tint enable_remote_branches;\ndiff --git a/cgitrc.5.txt b/cgitrc.5.txt\nindex a853522..72fd2e1 100644\n--- a/cgitrc.5.txt\n+++ b/cgitrc.5.txt\n@@ -90,7 +90,12 @@ embedded::\n \tFlag which, when set to \"1\", will make cgit generate a html fragment\n \tsuitable for embedding in other html pages. Default value: none. See\n \talso: \"noheader\".\n-\t\n+\n+enable-commit-graph::\n+\tFlag which, when set to \"1\", will make cgit print an ASCII-art commit\n+\thistory graph to the left of the commit messages in the repository\n+\tlog page. Default value: \"0\".\n+\n enable-filter-overrides::\n \tFlag which, when set to \"1\", allows all filter settings to be\n \toverridden in repository-specific cgitrc files. Default value: none.\n@@ -319,6 +324,10 @@ repo.defbranch::\n repo.desc::\n \tThe value to show as repository description. Default value: none.\n \n+repo.enable-commit-graph::\n+\tA flag which can be used to disable the global setting\n+\t`enable-commit-graph'. Default value: none.\n+\n repo.enable-log-filecount::\n \tA flag which can be used to disable the global setting\n \t`enable-log-filecount'. Default value: none.\n@@ -404,6 +413,10 @@ css=/css/cgit.css\n enable-index-links=1\n \n \n+# Enable ASCII art commit history graph on the log pages\n+enable-commit-graph=1\n+\n+\n # Show number of affected files per commit on the log pages\n enable-log-filecount=1\n \ndiff --git a/shared.c b/shared.c\nindex 06f70bb..9c00a7d 100644\n--- a/shared.c\n+++ b/shared.c\n@@ -56,6 +56,7 @@ struct cgit_repo *cgit_add_repo(const char *url)\n \tret->section = ctx.cfg.section;\n \tret->defbranch = \"master\";\n \tret->snapshots = ctx.cfg.snapshots;\n+\tret->enable_commit_graph = ctx.cfg.enable_commit_graph;\n \tret->enable_log_filecount = ctx.cfg.enable_log_filecount;\n \tret->enable_log_linecount = ctx.cfg.enable_log_linecount;\n \tret->enable_remote_branches = ctx.cfg.enable_remote_branches;\ndiff --git a/ui-log.c b/ui-log.c\nindex 2cd0f19..3cfe3f9 100644\n--- a/ui-log.c\n+++ b/ui-log.c\n@@ -106,7 +106,7 @@ static void print_commit_line(struct commit *commit, struct commitinfo *info)\n \thtml(\"</td>\");\n }\n \n-void print_commit(struct commit *commit)\n+void print_commit(struct commit *commit, struct rev_info *revs)\n {\n \tstruct commitinfo *info = cgit_parse_commit(commit);\n \tint cols = 3;\n@@ -117,11 +117,65 @@ void print_commit(struct commit *commit)\n \t\t\tcols++;\n \t}\n \n-\thtmlf(\"<tr%s>\", ctx.qry.showmsg ? \" class='logheader'\" : \"\");\n+\tif (revs->graph) {\n+\t\tstruct strbuf msgbuf = STRBUF_INIT;\n+\n+\t\twhile (!graph_next_line(revs->graph, &msgbuf)) {\n+\t\t\t/* Create graph line + empty table row */\n+\t\t\thtml(\"<tr class='nohover'><td class='commitgraph'>\");\n+\t\t\thtml_txt(msgbuf.buf);\n+\t\t\thtmlf(\"</td><td colspan='%d' /></tr>\\n\", cols);\n+\t\t\tstrbuf_setlen(&msgbuf, 0);\n+\t\t}\n+\t\t/* Create graph line + commit info table row */\n+\t\thtmlf(\"<tr%s>\", ctx.qry.showmsg ? \" class='logheader'\" : \"\");\n+\t\thtml(\"<td class='commitgraph'>\");\n+\t\thtml_txt(msgbuf.buf);\n+\t\thtml(\"</td>\");\n+\t        strbuf_release(&msgbuf);\n+\t}\n+\telse\n+\t\thtmlf(\"<tr%s>\", ctx.qry.showmsg ? \" class='logheader'\" : \"\");\n+\n \tprint_commit_line(commit, info);\n \thtml(\"</tr>\\n\");\n \n-\tif (ctx.qry.showmsg) {\n+\tif (revs->graph) {\n+\t\tstruct strbuf msgbuf = STRBUF_INIT;\n+\t\tint lines = 0;\n+\n+\t\tif (ctx.qry.showmsg) {\n+\t\t\t/* Count #lines in commit message */\n+\t\t\tlines = 1;\n+\t\t\tif (*(info->msg)) {\n+\t\t\t\tconst char *p = info->msg;\n+\t\t\t\tlines += 3;\n+\t\t\t\twhile ((p = strchr(p, '\\n') + 1) > info->msg)\n+\t\t\t\t\tlines++;\n+\t\t\t}\n+\t\t}\n+\n+\t\t/* Print graph padding */\n+\t\thtml(\"<tr class='nohover'><td class='commitgraph'>\");\n+\t\twhile (lines > 0 || !graph_is_commit_finished(revs->graph)) {\n+\t\t\tif (msgbuf.len)\n+\t\t\t\thtml(\"\\n\");\n+\t\t\tstrbuf_setlen(&msgbuf, 0);\n+\t\t\tgraph_next_line(revs->graph, &msgbuf);\n+\t\t\thtml_txt(msgbuf.buf);\n+\t\t\tlines--;\n+\t\t}\n+\n+\t\t/* Print remainder of table row */\n+\t\thtmlf(\"</td><td colspan='%d'%s>\\n\", cols,\n+\t\t      ctx.qry.showmsg ? \" class='logmsg'\" : \"\");\n+\t\tif (ctx.qry.showmsg && *(info->msg)) {\n+\t\t\thtml_txt(info->msg);\n+\t\t\thtml(\"\\n\\n\");\n+\t\t}\n+\t\thtml(\"</td></tr>\\n\");\n+\t}\n+\telse if (ctx.qry.showmsg) {\n \t\thtml(\"<tr class='nohover'>\");\n \t\thtmlf(\"<td colspan='%d' class='logmsg'>\\n\", cols);\n \t\tif (*(info->msg)) {\n@@ -151,7 +205,7 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern\n {\n \tstruct rev_info rev;\n \tstruct commit *commit;\n-\tconst char *argv[] = {NULL, NULL, NULL, NULL, NULL};\n+\tconst char *argv[] = {NULL, NULL, NULL, NULL, NULL, NULL};\n \tint argc = 2;\n \tint i, columns = 3;\n \n@@ -167,6 +221,8 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern\n \t\tif (!strcmp(grep, \"range\"))\n \t\t\targv[1] = pattern;\n \t}\n+\tif (ctx.repo->enable_commit_graph)\n+\t\targv[argc++] = \"--graph\";\n \n \tif (path) {\n \t\targv[argc++] = \"--\";\n@@ -187,7 +243,10 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern\n \tif (pager)\n \t\thtml(\"<table class='list nowrap'>\");\n \n-\thtml(\"<tr class='nohover'><th class='left'>Commit message\");\n+\thtml(\"<tr class='nohover'>\");\n+\tif (ctx.repo->enable_commit_graph)\n+\t\thtml(\"<th></th>\");\n+\thtml(\"<th class='left'>Commit message\");\n \tif (pager) {\n \t\thtml(\" (\");\n \t\tcgit_log_link(ctx.qry.showmsg ? \"Collapse\" : \"Expand\", NULL,\n@@ -218,7 +277,7 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern\n \t}\n \n \tfor (i = 0; i < cnt && (commit = get_revision(&rev)) != NULL; i++) {\n-\t\tprint_commit(commit);\n+\t\tprint_commit(commit, &rev);\n \t\tfree(commit->buffer);\n \t\tcommit->buffer = NULL;\n \t\tfree_commit_list(commit->parents);\n-- \n1.7.0.4\n"},{"id":"145473","messageId":"1279057221-28036-6-git-send-email-johan@herland.net","threadId":"24385","inReplyTo":"1279056219-27096-1-git-send-email-johan@herland.net","subject":"[CGit RFC/PATCH 5/5] ui-log: Colorize commit graph","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2010-07-13T21:40:21Z","receivedAt":"2010-07-13T21:40:21Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"Use the existing coloring logic in Git's graph code to color the lines\nbetween commits in the commit graph.\n\nWhereas Git normally uses ANSI color escapes to produce colors, we here\nuse graph_set_column_colors() to replace those with \"HTML color escapes\"\nwhich embed the graph lines in <span> tags that apply the desired color\nusing CSS.\n\nSigned-off-by: Johan Herland <johan@herland.net>\n---\n cgit.css |   24 ++++++++++++++++++++++++\n ui-log.c |   29 ++++++++++++++++++++++++-----\n 2 files changed, 48 insertions(+), 5 deletions(-)\n\ndiff --git a/cgit.css b/cgit.css\nindex 65da960..e8be2b1 100644\n--- a/cgit.css\n+++ b/cgit.css\n@@ -158,6 +158,30 @@ table.list td.commitgraph {\n \twhite-space: pre;\n }\n \n+table.list td.commitgraph .column1 {\n+\tcolor: #a00;\n+}\n+\n+table.list td.commitgraph .column2 {\n+\tcolor: #0a0;\n+}\n+\n+table.list td.commitgraph .column3 {\n+\tcolor: #aa0;\n+}\n+\n+table.list td.commitgraph .column4 {\n+\tcolor: #00a;\n+}\n+\n+table.list td.commitgraph .column5 {\n+\tcolor: #a0a;\n+}\n+\n+table.list td.commitgraph .column6 {\n+\tcolor: #0aa;\n+}\n+\n table.list td.logsubject {\n \tfont-family: monospace;\n \tfont-weight: bold;\ndiff --git a/ui-log.c b/ui-log.c\nindex 3cfe3f9..2fc8c7b 100644\n--- a/ui-log.c\n+++ b/ui-log.c\n@@ -12,6 +12,21 @@\n \n int files, add_lines, rem_lines;\n \n+/*\n+ * The list of available column colors in the commit graph.\n+ */\n+static const char *column_colors_html[] = {\n+\t\"<span class='column1'>\",\n+\t\"<span class='column2'>\",\n+\t\"<span class='column3'>\",\n+\t\"<span class='column4'>\",\n+\t\"<span class='column5'>\",\n+\t\"<span class='column6'>\",\n+\t\"</span>\",\n+};\n+\n+#define COLUMN_COLORS_HTML_MAX (ARRAY_SIZE(column_colors_html) - 1)\n+\n void count_lines(char *line, int size)\n {\n \tif (size <= 0)\n@@ -123,14 +138,14 @@ void print_commit(struct commit *commit, struct rev_info *revs)\n \t\twhile (!graph_next_line(revs->graph, &msgbuf)) {\n \t\t\t/* Create graph line + empty table row */\n \t\t\thtml(\"<tr class='nohover'><td class='commitgraph'>\");\n-\t\t\thtml_txt(msgbuf.buf);\n+\t\t\thtml(msgbuf.buf);\n \t\t\thtmlf(\"</td><td colspan='%d' /></tr>\\n\", cols);\n \t\t\tstrbuf_setlen(&msgbuf, 0);\n \t\t}\n \t\t/* Create graph line + commit info table row */\n \t\thtmlf(\"<tr%s>\", ctx.qry.showmsg ? \" class='logheader'\" : \"\");\n \t\thtml(\"<td class='commitgraph'>\");\n-\t\thtml_txt(msgbuf.buf);\n+\t\thtml(msgbuf.buf);\n \t\thtml(\"</td>\");\n \t        strbuf_release(&msgbuf);\n \t}\n@@ -162,7 +177,7 @@ void print_commit(struct commit *commit, struct rev_info *revs)\n \t\t\t\thtml(\"\\n\");\n \t\t\tstrbuf_setlen(&msgbuf, 0);\n \t\t\tgraph_next_line(revs->graph, &msgbuf);\n-\t\t\thtml_txt(msgbuf.buf);\n+\t\t\thtml(msgbuf.buf);\n \t\t\tlines--;\n \t\t}\n \n@@ -205,7 +220,7 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern\n {\n \tstruct rev_info rev;\n \tstruct commit *commit;\n-\tconst char *argv[] = {NULL, NULL, NULL, NULL, NULL, NULL};\n+\tconst char *argv[] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL};\n \tint argc = 2;\n \tint i, columns = 3;\n \n@@ -221,8 +236,12 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern\n \t\tif (!strcmp(grep, \"range\"))\n \t\t\targv[1] = pattern;\n \t}\n-\tif (ctx.repo->enable_commit_graph)\n+\tif (ctx.repo->enable_commit_graph) {\n \t\targv[argc++] = \"--graph\";\n+\t\targv[argc++] = \"--color\";\n+\t\tgraph_set_column_colors(column_colors_html,\n+\t\t\t\t\tCOLUMN_COLORS_HTML_MAX);\n+\t}\n \n \tif (path) {\n \t\targv[argc++] = \"--\";\n-- \n1.7.0.4\n"},{"id":"145484","messageId":"AANLkTilWENrG8wf1P4EMlzLSj0CdG9s3M8WAwmAZTYUX@mail.gmail.com","threadId":"24385","inReplyTo":"1279057221-28036-1-git-send-email-johan@herland.net","subject":"Re: [CGit RFC/PATCH 0/5] Commit graph on CGit's 'log' view","fromName":"Lars Hjemli","fromEmail":"hjemli@gmail.com","sentAt":"2010-07-13T22:57:57Z","receivedAt":"2010-07-13T22:57:57Z","isPatch":true,"sender":{"key":"hjemli@gmail.com","avatar":null},"body":"On Tue, Jul 13, 2010 at 23:40, Johan Herland <johan@herland.net> wrote:\n> Here are some patches to implement an ASCII-art commit graph on CGit's\n> 'log' page. The patches reuse the graph-drawing code from Git's own\n> 'git log --graph'. As such, these patches depend on the two patches\n> I just submitted to the Git list for extending the graph.h API.\n\nThanks. I've applied the git patches to the jh/graph branch in\ngit://hjemli.net/pub/git/git (based on v1.7.1-rc2) and updated the\nsubmodule in cgit to point at the tip of this branch. The cgit patches\nare then applied on top of this and merged into the wip branch in\ngit://hjemli.net/pub/git/cgit.\n\nThe end result can be seen in action at http://hjemli.net/git/cgit/log\n[1] - it works, but I'll have to think about possible compromises\nbetween correctness and performance (i.e. the dependency on\n--topo-order).\n\n--\nlarsh\n\n[1] If the graph looks strange, you might have a cached cgit.css.\nPlease force a reload in your browser.\n"},{"id":"145514","messageId":"201007140759.02822.johan@herland.net","threadId":"24385","inReplyTo":"AANLkTilWENrG8wf1P4EMlzLSj0CdG9s3M8WAwmAZTYUX@mail.gmail.com","subject":"Re: [CGit RFC/PATCH 0/5] Commit graph on CGit's 'log' view","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2010-07-14T05:59:01Z","receivedAt":"2010-07-14T05:59:01Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"On Wednesday 14 July 2010, Lars Hjemli wrote:\n> On Tue, Jul 13, 2010 at 23:40, Johan Herland <johan@herland.net> wrote:\n> > Here are some patches to implement an ASCII-art commit graph on CGit's\n> > 'log' page. The patches reuse the graph-drawing code from Git's own\n> > 'git log --graph'. As such, these patches depend on the two patches\n> > I just submitted to the Git list for extending the graph.h API.\n> \n> Thanks. I've applied the git patches to the jh/graph branch in\n> git://hjemli.net/pub/git/git (based on v1.7.1-rc2) and updated the\n> submodule in cgit to point at the tip of this branch. The cgit patches\n> are then applied on top of this and merged into the wip branch in\n> git://hjemli.net/pub/git/cgit.\n\nThanks.\n\n> The end result can be seen in action at http://hjemli.net/git/cgit/log\n> [1] - it works, but I'll have to think about possible compromises\n> between correctness and performance (i.e. the dependency on\n> --topo-order).\n\nYes, this feature definitely introduces a performance tradeoff. IMHO it's up \nto the server admin to choose whether to enable this in the config or not. \nIf you're serving large repos from a small server, you might simply want to \nturn it off.\n\nWe might also want to consider adding a query (and cookie?) flag enabling \nvisitors to turn off graphs for faster browsing as well.\n\nBTW, have you had time to look at my previous patch series for ignoring \nwhitespace in diffs?\n\n\nHave fun! :)\n\n...Johan\n\n-- \nJohan Herland, <johan@herland.net>\nwww.herland.net\n"},{"id":"145749","messageId":"AANLkTimROxHdTKvjOIeWUMmQ_FmRD3igv5O06ySopKHW@mail.gmail.com","threadId":"24385","inReplyTo":"201007140759.02822.johan@herland.net","subject":"Re: [CGit RFC/PATCH 0/5] Commit graph on CGit's 'log' view","fromName":"Lars Hjemli","fromEmail":"hjemli@gmail.com","sentAt":"2010-07-18T13:26:09Z","receivedAt":"2010-07-18T13:26:09Z","isPatch":true,"sender":{"key":"hjemli@gmail.com","avatar":null},"body":"[Sorry for the late reply]\n\nOn Wed, Jul 14, 2010 at 07:59, Johan Herland <johan@herland.net> wrote:\n> BTW, have you had time to look at my previous patch series for ignoring\n> whitespace in diffs?\n\nIt took a while, but I've now merged all your patches (except the\ngraph series) into my master branch. Thanks.\n\n--\nlarsh\n"}]}