Hi, I'm playing around with some CGit patches for enabling an ASCII-art commit graph to be displayed on CGit's 'log' page. These patches reuse the ASCII-art commit graph that is produced by 'git log --graph'. However, in order to allow proper reuse by CGit, I need to make a couple of changes to the graph API: The first patch exposes graph_next_line() in the graph.h API. This function is needed to drive the graph generation from CGit. (Since the graph_show_* functions print directly to stdout, they can not be used by CGit.) The second patch allows CGit to use a different coloring mechanism than the default ANSI color escapes in graph.c. CGit replaces the column_colors array of ANSI escapes in graph.c with its own array that contains HTML <span> tags (which are then styled to the appropriate colors using CSS). For reference, the corresponding CGit patches that generate the commit graph on CGit's log page will follow as a separate patch series. Johan Herland (2): Make graph_next_line() available in the graph.h API Enable custom schemes for column colors in the graph API graph.c | 50 +++++++++++++++++++++++++++----------------------- graph.h | 28 ++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 23 deletions(-) --
In order to successfully use the graph API from a context other than the
stdout/command-line scenario (where the graph_show_* functions are
suitable), we need direct access to graph_next_line(), to drive the
graph drawing process.
Signed-off-by: Johan Herland <johan@herland.net>
---
graph.c | 13 +------------
graph.h | 11 +++++++++++
2 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/graph.c b/graph.c
index ac7c605..47397da 100644
--- a/graph.c
+++ b/graph.c
@@ -8,17 +8,6 @@
/* Internal API */
/*
- * Output the next line for a graph.
- * This formats the next graph line into the specified strbuf. It is not
- * terminated with a newline.
- *
- * Returns 1 if the line includes the current commit, and 0 otherwise.
- * graph_next_line() will return 1 exactly once for each time
- * graph_update() is called.
- */
-static int graph_next_line(struct git_graph *graph, struct strbuf *sb);
-
-/*
* Output a padding line in the graph.
* This is similar to graph_next_line(). However, it is guaranteed to
* never print the current commit line. Instead, if the commit line is
@@ -1143,7 +1132,7 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf
graph_update_state(graph, GRAPH_PADDING);
}
-static int graph_next_line(struct git_graph *graph, struct strbuf *sb)
+int graph_next_line(struct git_graph *graph, struct strbuf *sb)
{
switch (graph->state) {
case GRAPH_PADDING:
diff --git a/graph.h b/graph.h
index b82ae87..f188168 100644
--- a/graph.h
+++ b/graph.h
@@ -32,6 +32,17 @@ void graph_update(struct git_graph *graph, struct commit *commit);
*/
int graph_is_commit_finished(struct git_graph const *graph);
+/*
+ * Output the next line for a graph.
+ * This formats the next graph line into the specified strbuf. It is not
+ * terminated with a newline.
+ *
+ * Returns 1 if the line includes the current commit, and 0 otherwise.
+ * graph_next_line() will return 1 exactly once for each time
+ * ...Currently, the graph code is hardcoded to use ANSI color escapes for
coloring the column characters in the generated graphs. This patch
allows a custom scheme of colors to be set at runtime, allowing
different types of color escapes to be used.
A new function - graph_set_column_colors() - is added to the graph.h API,
which allows a custom column_colors array (and column_colors_max value)
to replace the builtin ANSI array (and _max value). The new function -
if used - must be called before graph_init() is called.
Signed-off-by: Johan Herland <johan@herland.net>
---
graph.c | 37 ++++++++++++++++++++++++++-----------
graph.h | 17 +++++++++++++++++
2 files changed, 43 insertions(+), 11 deletions(-)
diff --git a/graph.c b/graph.c
index 47397da..e2a5860 100644
--- a/graph.c
+++ b/graph.c
@@ -62,7 +62,7 @@ enum graph_state {
/*
* The list of available column colors.
*/
-static char column_colors[][COLOR_MAXLEN] = {
+static const char *column_colors_ansi[] = {
GIT_COLOR_RED,
GIT_COLOR_GREEN,
GIT_COLOR_YELLOW,
@@ -75,23 +75,33 @@ static char column_colors[][COLOR_MAXLEN] = {
GIT_COLOR_BOLD_BLUE,
GIT_COLOR_BOLD_MAGENTA,
GIT_COLOR_BOLD_CYAN,
+ GIT_COLOR_RESET,
};
-#define COLUMN_COLORS_MAX (ARRAY_SIZE(column_colors))
+#define COLUMN_COLORS_ANSI_MAX (ARRAY_SIZE(column_colors_ansi) - 1)
-static const char *column_get_color_code(const struct column *c)
+static const char **column_colors;
+static unsigned short column_colors_max;
+
+void graph_set_column_colors(const char **colors, unsigned short colors_max)
+{
+ column_colors = colors;
+ column_colors_max = colors_max;
+}
+
+static const char *column_get_color_code(unsigned short color)
{
- return column_colors[c->color];
+ return column_colors[color];
}
static void strbuf_write_column(struct strbuf *sb, const struct column *c,
char col_char)
{
- if (c->color < COLUMN_COLORS_MAX)
- strbuf_addstr(sb, column_get_color_code(c));
+ if (c->color < ...Hi, Here are some patches to implement an ASCII-art commit graph on CGit's 'log' page. The patches reuse the graph-drawing code from Git's own 'git log --graph'. As such, these patches depend on the two patches I just submitted to the Git list for extending the graph.h API. More detailed: Patch #4 in this series (ui-log: Implement support for commit graphs) depend on patch #1 in the other series (Make graph_next_line() available in the graph.h API), while patch #5 in this series (ui-log: Colorize commit graph) depends on patch #2 in the other series (Enable custom schemes for column colors in the graph API). Otherwise, the first patch in this series is a minor cleanup patch, while patches #2 and #3 prepare for the introduction of commit graphs in patch #4. Have fun! ...Johan Johan Herland (5): ui-stats: Remove unnecessary #include ui-log: Move 'Age' column to the right of 'Author', like in gitk ui-log: Refactor display of commit messages ui-log: Implement support for commit graphs ui-log: Colorize commit graph cgit.c | 6 +++ cgit.css | 31 ++++++++++++- cgit.h | 3 + cgitrc.5.txt | 15 ++++++- shared.c | 1 + ui-log.c | 140 +++++++++++++++++++++++++++++++++++++++++++++++----------- ui-stats.c | 2 - 7 files changed, 168 insertions(+), 30 deletions(-) --
Thanks. I've applied the git patches to the jh/graph branch in git://hjemli.net/pub/git/git (based on v1.7.1-rc2) and updated the submodule in cgit to point at the tip of this branch. The cgit patches are then applied on top of this and merged into the wip branch in git://hjemli.net/pub/git/cgit. The end result can be seen in action at http://hjemli.net/git/cgit/log [1] - it works, but I'll have to think about possible compromises between correctness and performance (i.e. the dependency on --topo-order). -- larsh [1] If the graph looks strange, you might have a cached cgit.css. Please force a reload in your browser. --
Yes, this feature definitely introduces a performance tradeoff. IMHO it's up to the server admin to choose whether to enable this in the config or not. If you're serving large repos from a small server, you might simply want to turn it off. We might also want to consider adding a query (and cookie?) flag enabling visitors to turn off graphs for faster browsing as well. BTW, have you had time to look at my previous patch series for ignoring whitespace in diffs? Have fun! :) ...Johan -- Johan Herland, <johan@herland.net> www.herland.net --
[Sorry for the late reply] It took a while, but I've now merged all your patches (except the graph series) into my master branch. Thanks. -- larsh --
This is in preparation for putting the commit graph to the left of the
commit message. IMHO, it looks better when the commit message is right
next to the graph, than if the age is wedged in between.
Signed-off-by: Johan Herland <johan@herland.net>
---
ui-log.c | 26 ++++++++++++--------------
1 files changed, 12 insertions(+), 14 deletions(-)
diff --git a/ui-log.c b/ui-log.c
index 33ec8a9..390c38b 100644
--- a/ui-log.c
+++ b/ui-log.c
@@ -79,23 +79,22 @@ void print_commit(struct commit *commit)
{
struct commitinfo *info;
char *tmp;
- int cols = 2;
+ int cols = 3;
info = cgit_parse_commit(commit);
- htmlf("<tr%s><td>",
- ctx.qry.showmsg ? " class='logheader'" : "");
- tmp = fmt("id=%s", sha1_to_hex(commit->object.sha1));
- tmp = cgit_fileurl(ctx.repo->url, "commit", ctx.qry.vpath, tmp);
- html_link_open(tmp, NULL, NULL);
- cgit_print_age(commit->date, TM_WEEK * 2, FMT_SHORTDATE);
- html_link_close();
- htmlf("</td><td%s>",
- ctx.qry.showmsg ? " class='logsubject'" : "");
+ htmlf("<tr%s>", ctx.qry.showmsg ? " class='logheader'" : "");
+ htmlf("<td%s>", ctx.qry.showmsg ? " class='logsubject'" : "");
cgit_commit_link(info->subject, NULL, NULL, ctx.qry.head,
sha1_to_hex(commit->object.sha1), ctx.qry.vpath, 0);
show_commit_decorations(commit);
html("</td><td>");
html_txt(info->author);
+ html("</td><td>");
+ tmp = fmt("id=%s", sha1_to_hex(commit->object.sha1));
+ tmp = cgit_fileurl(ctx.repo->url, "commit", ctx.qry.vpath, tmp);
+ html_link_open(tmp, NULL, NULL);
+ cgit_print_age(commit->date, TM_WEEK * 2, FMT_SHORTDATE);
+ html_link_close();
if (ctx.repo->enable_log_filecount) {
files = 0;
add_lines = 0;
@@ -115,7 +114,7 @@ void print_commit(struct commit *commit)
if (ctx.repo->enable_log_linecount)
cols++;
}
- htmlf("<tr class='nohover'><td/><td colspan='%d' class='logmsg'>",
+ htmlf("<tr class='nohover'><td colspan='%d' class='logmsg'>",
cols);
html_txt(info->msg);
html("</td></tr>\n");
@@ -176,8 ...<string-list.h> is already #included from cgit.h Signed-off-by: Johan Herland <johan@herland.net> --- ui-stats.c | 2 -- 1 files changed, 0 insertions(+), 2 deletions(-) diff --git a/ui-stats.c b/ui-stats.c index bdaf9cc..e8ea57a 100644 --- a/ui-stats.c +++ b/ui-stats.c @@ -1,5 +1,3 @@ -#include <string-list.h> - #include "cgit.h" #include "html.h" #include "ui-shared.h" -- 1.7.0.4 --
Split new function print_commit_line() out of print_commit(). The new
function only prints the initial table cells containing commit metadata,
i.e. the commit subject, author and date (and file/line-count if enabled).
The printing of the rest of the commit message (when showmsg is enabled)
is still performed in print_commit(), but is slightly changed to use
additional newlines to achieve the vertical margins that were previously
implemented with CSS. This is in preparation for the commit graph which
will be printed to the left of the commit message as part of the same
table row, and therefore needs to minimize margins that would otherwise
cause ugly gaps in the graph.
Signed-off-by: Johan Herland <johan@herland.net>
---
cgit.css | 2 +-
ui-log.c | 38 +++++++++++++++++++++++++-------------
2 files changed, 26 insertions(+), 14 deletions(-)
diff --git a/cgit.css b/cgit.css
index 6e47eb3..78f654e 100644
--- a/cgit.css
+++ b/cgit.css
@@ -161,7 +161,7 @@ table.list td.logsubject {
table.list td.logmsg {
font-family: monospace;
white-space: pre;
- padding: 1em 0.5em 2em 0.5em;
+ padding: 0 0.5em;
}
table.list td a {
diff --git a/ui-log.c b/ui-log.c
index 390c38b..2cd0f19 100644
--- a/ui-log.c
+++ b/ui-log.c
@@ -75,14 +75,10 @@ void show_commit_decorations(struct commit *commit)
}
}
-void print_commit(struct commit *commit)
+static void print_commit_line(struct commit *commit, struct commitinfo *info)
{
- struct commitinfo *info;
char *tmp;
- int cols = 3;
- info = cgit_parse_commit(commit);
- htmlf("<tr%s>", ctx.qry.showmsg ? " class='logheader'" : "");
htmlf("<td%s>", ctx.qry.showmsg ? " class='logsubject'" : "");
cgit_commit_link(info->subject, NULL, NULL, ctx.qry.head,
sha1_to_hex(commit->object.sha1), ctx.qry.vpath, 0);
@@ -107,18 +103,34 @@ void print_commit(struct commit *commit)
htmlf("-%d/+%d", rem_lines, add_lines);
}
}
- html("</td></tr>\n");
- if (ctx.qry.showmsg) {
- if ...Use the existing coloring logic in Git's graph code to color the lines
between commits in the commit graph.
Whereas Git normally uses ANSI color escapes to produce colors, we here
use graph_set_column_colors() to replace those with "HTML color escapes"
which embed the graph lines in <span> tags that apply the desired color
using CSS.
Signed-off-by: Johan Herland <johan@herland.net>
---
cgit.css | 24 ++++++++++++++++++++++++
ui-log.c | 29 ++++++++++++++++++++++++-----
2 files changed, 48 insertions(+), 5 deletions(-)
diff --git a/cgit.css b/cgit.css
index 65da960..e8be2b1 100644
--- a/cgit.css
+++ b/cgit.css
@@ -158,6 +158,30 @@ table.list td.commitgraph {
white-space: pre;
}
+table.list td.commitgraph .column1 {
+ color: #a00;
+}
+
+table.list td.commitgraph .column2 {
+ color: #0a0;
+}
+
+table.list td.commitgraph .column3 {
+ color: #aa0;
+}
+
+table.list td.commitgraph .column4 {
+ color: #00a;
+}
+
+table.list td.commitgraph .column5 {
+ color: #a0a;
+}
+
+table.list td.commitgraph .column6 {
+ color: #0aa;
+}
+
table.list td.logsubject {
font-family: monospace;
font-weight: bold;
diff --git a/ui-log.c b/ui-log.c
index 3cfe3f9..2fc8c7b 100644
--- a/ui-log.c
+++ b/ui-log.c
@@ -12,6 +12,21 @@
int files, add_lines, rem_lines;
+/*
+ * The list of available column colors in the commit graph.
+ */
+static const char *column_colors_html[] = {
+ "<span class='column1'>",
+ "<span class='column2'>",
+ "<span class='column3'>",
+ "<span class='column4'>",
+ "<span class='column5'>",
+ "<span class='column6'>",
+ "</span>",
+};
+
+#define COLUMN_COLORS_HTML_MAX (ARRAY_SIZE(column_colors_html) - 1)
+
void count_lines(char *line, int size)
{
if (size <= 0)
@@ -123,14 +138,14 @@ void print_commit(struct commit *commit, struct rev_info *revs)
while (!graph_next_line(revs->graph, &msgbuf)) {
/* Create graph line + empty table row */
html("<tr class='nohover'><td ...Teach CGit to print an ASCII art commit graph to the left of the commit message, similar to 'git log --graph'. The graph adds extra lines (table rows) to the log when needed to add/remove/shuffle edges in the graph. When 'showmsg' is enabled, the graph auto-adjusts to the lines added by the commit message. This feature is controlled by a new config variable: "enable-commit-graph" (disabled by default), and individual repos can disable it by settign "repo.enable-commit-graph" to "0". Signed-off-by: Johan Herland <johan@herland.net> --- cgit.c | 6 +++++ cgit.css | 5 ++++ cgit.h | 3 ++ cgitrc.5.txt | 15 +++++++++++- shared.c | 1 + ui-log.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- 6 files changed, 94 insertions(+), 7 deletions(-) diff --git a/cgit.c b/cgit.c index ab25b6a..29fb57f 100644 --- a/cgit.c +++ b/cgit.c @@ -56,6 +56,8 @@ void repo_config(struct cgit_repo *repo, const char *name, const char *value) repo->defbranch = xstrdup(value); else if (!strcmp(name, "snapshots")) repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); + else if (!strcmp(name, "enable-commit-graph")) + repo->enable_commit_graph = ctx.cfg.enable_commit_graph * atoi(value); else if (!strcmp(name, "enable-log-filecount")) repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value); else if (!strcmp(name, "enable-log-linecount")) @@ -137,6 +139,8 @@ void config_cb(const char *name, const char *value) ctx.cfg.enable_filter_overrides = atoi(value); else if (!strcmp(name, "enable-index-links")) ctx.cfg.enable_index_links = atoi(value); + else if (!strcmp(name, "enable-commit-graph")) + ctx.cfg.enable_commit_graph = atoi(value); else if (!strcmp(name, "enable-log-filecount")) ctx.cfg.enable_log_filecount = atoi(value); else if (!strcmp(name, "enable-log-linecount")) @@ -522,6 +526,8 @@ void print_repo(FILE *f, struct cgit_repo *repo) fprintf(f, ...
