[CGit RFC/PATCH 4/5] ui-log: Implement support for commit graphs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxxx>
---
 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, "repo.section=%s\n", repo->section);
 	if (repo->clone_url)
 		fprintf(f, "repo.clone-url=%s\n", repo->clone_url);
+	fprintf(f, "repo.enable-commit-graph=%d\n",
+	        repo->enable_commit_graph);
 	fprintf(f, "repo.enable-log-filecount=%d\n",
 	        repo->enable_log_filecount);
 	fprintf(f, "repo.enable-log-linecount=%d\n",
diff --git a/cgit.css b/cgit.css
index 78f654e..65da960 100644
--- a/cgit.css
+++ b/cgit.css
@@ -153,6 +153,11 @@ table.list td {
 	padding: 0.1em 0.5em 0.1em 0.5em;
 }
 
+table.list td.commitgraph {
+	font-family: monospace;
+	white-space: pre;
+}
+
 table.list td.logsubject {
 	font-family: monospace;
 	font-weight: bold;
diff --git a/cgit.h b/cgit.h
index 2b28d63..402610b 100644
--- a/cgit.h
+++ b/cgit.h
@@ -19,6 +19,7 @@
 #include <xdiff-interface.h>
 #include <xdiff/xdiff.h>
 #include <utf8.h>
+#include <graph.h>
 
 
 /*
@@ -70,6 +71,7 @@ struct cgit_repo {
 	char *section;
 	char *clone_url;
 	int snapshots;
+	int enable_commit_graph;
 	int enable_log_filecount;
 	int enable_log_linecount;
 	int enable_remote_branches;
@@ -182,6 +184,7 @@ struct cgit_config {
 	int embedded;
 	int enable_filter_overrides;
 	int enable_index_links;
+	int enable_commit_graph;
 	int enable_log_filecount;
 	int enable_log_linecount;
 	int enable_remote_branches;
diff --git a/cgitrc.5.txt b/cgitrc.5.txt
index a853522..72fd2e1 100644
--- a/cgitrc.5.txt
+++ b/cgitrc.5.txt
@@ -90,7 +90,12 @@ embedded::
 	Flag which, when set to "1", will make cgit generate a html fragment
 	suitable for embedding in other html pages. Default value: none. See
 	also: "noheader".
-	
+
+enable-commit-graph::
+	Flag which, when set to "1", will make cgit print an ASCII-art commit
+	history graph to the left of the commit messages in the repository
+	log page. Default value: "0".
+
 enable-filter-overrides::
 	Flag which, when set to "1", allows all filter settings to be
 	overridden in repository-specific cgitrc files. Default value: none.
@@ -319,6 +324,10 @@ repo.defbranch::
 repo.desc::
 	The value to show as repository description. Default value: none.
 
+repo.enable-commit-graph::
+	A flag which can be used to disable the global setting
+	`enable-commit-graph'. Default value: none.
+
 repo.enable-log-filecount::
 	A flag which can be used to disable the global setting
 	`enable-log-filecount'. Default value: none.
@@ -404,6 +413,10 @@ css=/css/cgit.css
 enable-index-links=1
 
 
+# Enable ASCII art commit history graph on the log pages
+enable-commit-graph=1
+
+
 # Show number of affected files per commit on the log pages
 enable-log-filecount=1
 
diff --git a/shared.c b/shared.c
index 06f70bb..9c00a7d 100644
--- a/shared.c
+++ b/shared.c
@@ -56,6 +56,7 @@ struct cgit_repo *cgit_add_repo(const char *url)
 	ret->section = ctx.cfg.section;
 	ret->defbranch = "master";
 	ret->snapshots = ctx.cfg.snapshots;
+	ret->enable_commit_graph = ctx.cfg.enable_commit_graph;
 	ret->enable_log_filecount = ctx.cfg.enable_log_filecount;
 	ret->enable_log_linecount = ctx.cfg.enable_log_linecount;
 	ret->enable_remote_branches = ctx.cfg.enable_remote_branches;
diff --git a/ui-log.c b/ui-log.c
index 2cd0f19..3cfe3f9 100644
--- a/ui-log.c
+++ b/ui-log.c
@@ -106,7 +106,7 @@ static void print_commit_line(struct commit *commit, struct commitinfo *info)
 	html("</td>");
 }
 
-void print_commit(struct commit *commit)
+void print_commit(struct commit *commit, struct rev_info *revs)
 {
 	struct commitinfo *info = cgit_parse_commit(commit);
 	int cols = 3;
@@ -117,11 +117,65 @@ void print_commit(struct commit *commit)
 			cols++;
 	}
 
-	htmlf("<tr%s>", ctx.qry.showmsg ? " class='logheader'" : "");
+	if (revs->graph) {
+		struct strbuf msgbuf = STRBUF_INIT;
+
+		while (!graph_next_line(revs->graph, &msgbuf)) {
+			/* Create graph line + empty table row */
+			html("<tr class='nohover'><td class='commitgraph'>");
+			html_txt(msgbuf.buf);
+			htmlf("</td><td colspan='%d' /></tr>\n", cols);
+			strbuf_setlen(&msgbuf, 0);
+		}
+		/* Create graph line + commit info table row */
+		htmlf("<tr%s>", ctx.qry.showmsg ? " class='logheader'" : "");
+		html("<td class='commitgraph'>");
+		html_txt(msgbuf.buf);
+		html("</td>");
+	        strbuf_release(&msgbuf);
+	}
+	else
+		htmlf("<tr%s>", ctx.qry.showmsg ? " class='logheader'" : "");
+
 	print_commit_line(commit, info);
 	html("</tr>\n");
 
-	if (ctx.qry.showmsg) {
+	if (revs->graph) {
+		struct strbuf msgbuf = STRBUF_INIT;
+		int lines = 0;
+
+		if (ctx.qry.showmsg) {
+			/* Count #lines in commit message */
+			lines = 1;
+			if (*(info->msg)) {
+				const char *p = info->msg;
+				lines += 3;
+				while ((p = strchr(p, '\n') + 1) > info->msg)
+					lines++;
+			}
+		}
+
+		/* Print graph padding */
+		html("<tr class='nohover'><td class='commitgraph'>");
+		while (lines > 0 || !graph_is_commit_finished(revs->graph)) {
+			if (msgbuf.len)
+				html("\n");
+			strbuf_setlen(&msgbuf, 0);
+			graph_next_line(revs->graph, &msgbuf);
+			html_txt(msgbuf.buf);
+			lines--;
+		}
+
+		/* Print remainder of table row */
+		htmlf("</td><td colspan='%d'%s>\n", cols,
+		      ctx.qry.showmsg ? " class='logmsg'" : "");
+		if (ctx.qry.showmsg && *(info->msg)) {
+			html_txt(info->msg);
+			html("\n\n");
+		}
+		html("</td></tr>\n");
+	}
+	else if (ctx.qry.showmsg) {
 		html("<tr class='nohover'>");
 		htmlf("<td colspan='%d' class='logmsg'>\n", cols);
 		if (*(info->msg)) {
@@ -151,7 +205,7 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern
 {
 	struct rev_info rev;
 	struct commit *commit;
-	const char *argv[] = {NULL, NULL, NULL, NULL, NULL};
+	const char *argv[] = {NULL, NULL, NULL, NULL, NULL, NULL};
 	int argc = 2;
 	int i, columns = 3;
 
@@ -167,6 +221,8 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern
 		if (!strcmp(grep, "range"))
 			argv[1] = pattern;
 	}
+	if (ctx.repo->enable_commit_graph)
+		argv[argc++] = "--graph";
 
 	if (path) {
 		argv[argc++] = "--";
@@ -187,7 +243,10 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern
 	if (pager)
 		html("<table class='list nowrap'>");
 
-	html("<tr class='nohover'><th class='left'>Commit message");
+	html("<tr class='nohover'>");
+	if (ctx.repo->enable_commit_graph)
+		html("<th></th>");
+	html("<th class='left'>Commit message");
 	if (pager) {
 		html(" (");
 		cgit_log_link(ctx.qry.showmsg ? "Collapse" : "Expand", NULL,
@@ -218,7 +277,7 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern
 	}
 
 	for (i = 0; i < cnt && (commit = get_revision(&rev)) != NULL; i++) {
-		print_commit(commit);
+		print_commit(commit, &rev);
 		free(commit->buffer);
 		commit->buffer = NULL;
 		free_commit_list(commit->parents);
-- 
1.7.0.4

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]