ui-log: Implement support for commit graphs
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 is automatically padded to account for the extra lines added by the commit message/notes. This feature is controlled by a new config variable: "enable-commit-graph" (disabled by default), and individual repos can control it by setting "repo.enable-commit-graph". Signed-off-by: Johan Herland <johan@herland.net> Signed-off-by: Lars Hjemli <hjemli@gmail.com>
这个提交包含在:
		
							
								
								
									
										6
									
								
								cgit.c
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								cgit.c
									
									
									
									
									
								
							| @@ -57,6 +57,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")) | ||||
| @@ -141,6 +143,8 @@ void config_cb(const char *name, const char *value) | ||||
| 		ctx.cfg.enable_gitweb_owner = 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")) | ||||
| @@ -540,6 +544,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", | ||||
|   | ||||
							
								
								
									
										7
									
								
								cgit.css
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								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; | ||||
| @@ -731,4 +736,4 @@ table.ssdiff td.space { | ||||
|  | ||||
| table.ssdiff td.space div { | ||||
| 	min-height: 3em; | ||||
| } | ||||
| } | ||||
|   | ||||
							
								
								
									
										3
									
								
								cgit.h
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								cgit.h
									
									
									
									
									
								
							| @@ -20,6 +20,7 @@ | ||||
| #include <xdiff/xdiff.h> | ||||
| #include <utf8.h> | ||||
| #include <notes.h> | ||||
| #include <graph.h> | ||||
|  | ||||
|  | ||||
| /* | ||||
| @@ -71,6 +72,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; | ||||
| @@ -188,6 +190,7 @@ struct cgit_config { | ||||
| 	int enable_filter_overrides; | ||||
| 	int enable_gitweb_owner; | ||||
| 	int enable_index_links; | ||||
| 	int enable_commit_graph; | ||||
| 	int enable_log_filecount; | ||||
| 	int enable_log_linecount; | ||||
| 	int enable_remote_branches; | ||||
|   | ||||
							
								
								
									
										15
									
								
								cgitrc.5.txt
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								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. | ||||
| @@ -354,6 +359,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. | ||||
| @@ -441,6 +450,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 | ||||
|  | ||||
|   | ||||
							
								
								
									
										1
									
								
								shared.c
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								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; | ||||
|   | ||||
							
								
								
									
										107
									
								
								ui-log.c
									
									
									
									
									
								
							
							
						
						
									
										107
									
								
								ui-log.c
									
									
									
									
									
								
							| @@ -77,11 +77,30 @@ void show_commit_decorations(struct commit *commit) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void print_commit(struct commit *commit) | ||||
| void print_commit(struct commit *commit, struct rev_info *revs) | ||||
| { | ||||
| 	struct commitinfo *info; | ||||
| 	char *tmp; | ||||
| 	int cols = 2; | ||||
| 	struct strbuf graphbuf = STRBUF_INIT; | ||||
|  | ||||
| 	if (ctx.repo->enable_log_filecount) { | ||||
| 		cols++; | ||||
| 		if (ctx.repo->enable_log_linecount) | ||||
| 			cols++; | ||||
| 	} | ||||
|  | ||||
| 	if (revs->graph) { | ||||
| 		/* Advance graph until current commit */ | ||||
| 		while (!graph_next_line(revs->graph, &graphbuf)) { | ||||
| 			/* Print graph segment in otherwise empty table row */ | ||||
| 			html("<tr class='nohover'><td/><td class='commitgraph'>"); | ||||
| 			html(graphbuf.buf); | ||||
| 			htmlf("</td><td colspan='%d' /></tr>\n", cols); | ||||
| 			strbuf_setlen(&graphbuf, 0); | ||||
| 		} | ||||
| 		/* Current commit's graph segment is now ready in graphbuf */ | ||||
| 	} | ||||
|  | ||||
| 	info = cgit_parse_commit(commit); | ||||
| 	htmlf("<tr%s><td>", | ||||
| @@ -91,8 +110,17 @@ void print_commit(struct commit *commit) | ||||
| 	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'" : ""); | ||||
| 	html("</td>"); | ||||
|  | ||||
| 	if (revs->graph) { | ||||
| 		/* Print graph segment for current commit */ | ||||
| 		html("<td class='commitgraph'>"); | ||||
| 		html(graphbuf.buf); | ||||
| 		html("</td>"); | ||||
| 		strbuf_setlen(&graphbuf, 0); | ||||
| 	} | ||||
|  | ||||
| 	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); | ||||
| @@ -112,32 +140,59 @@ void print_commit(struct commit *commit) | ||||
| 	} | ||||
| 	html("</td></tr>\n"); | ||||
|  | ||||
| 	if (ctx.qry.showmsg) { /* Print message + notes in a second table row */ | ||||
| 		/* Concatenate commit message and notes in msgbuf */ | ||||
| 	if (revs->graph || ctx.qry.showmsg) { /* Print a second table row */ | ||||
| 		struct strbuf msgbuf = STRBUF_INIT; | ||||
| 		if (info->msg && *(info->msg)) { | ||||
| 			strbuf_addstr(&msgbuf, info->msg); | ||||
| 		html("<tr class='nohover'><td/>"); /* Empty 'Age' column */ | ||||
|  | ||||
| 		if (ctx.qry.showmsg) { | ||||
| 			/* Concatenate commit message + notes in msgbuf */ | ||||
| 			if (info->msg && *(info->msg)) { | ||||
| 				strbuf_addstr(&msgbuf, info->msg); | ||||
| 				strbuf_addch(&msgbuf, '\n'); | ||||
| 			} | ||||
| 			format_note(NULL, commit->object.sha1, &msgbuf, | ||||
| 			            PAGE_ENCODING, | ||||
| 			            NOTES_SHOW_HEADER | NOTES_INDENT); | ||||
| 			strbuf_addch(&msgbuf, '\n'); | ||||
| 		} | ||||
| 		format_note(NULL, commit->object.sha1, &msgbuf, PAGE_ENCODING, | ||||
| 		            NOTES_SHOW_HEADER | NOTES_INDENT); | ||||
| 		strbuf_addch(&msgbuf, '\n'); | ||||
| 		strbuf_ltrim(&msgbuf); | ||||
|  | ||||
| 		if (ctx.repo->enable_log_filecount) { | ||||
| 			cols++; | ||||
| 			if (ctx.repo->enable_log_linecount) | ||||
| 				cols++; | ||||
| 			strbuf_ltrim(&msgbuf); | ||||
| 		} | ||||
|  | ||||
| 		/* Create second table row containing msgbuf */ | ||||
| 		htmlf("<tr class='nohover'><td/><td colspan='%d' class='logmsg'>", | ||||
| 			cols); | ||||
| 		if (revs->graph) { | ||||
| 			int lines = 0; | ||||
|  | ||||
| 			/* Calculate graph padding */ | ||||
| 			if (ctx.qry.showmsg) { | ||||
| 				/* Count #lines in commit message + notes */ | ||||
| 				const char *p = msgbuf.buf; | ||||
| 				lines = 1; | ||||
| 				while ((p = strchr(p, '\n'))) { | ||||
| 					p++; | ||||
| 					lines++; | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			/* Print graph padding */ | ||||
| 			html("<td class='commitgraph'>"); | ||||
| 			while (lines > 0 || !graph_is_commit_finished(revs->graph)) { | ||||
| 				if (graphbuf.len) | ||||
| 					html("\n"); | ||||
| 				strbuf_setlen(&graphbuf, 0); | ||||
| 				graph_next_line(revs->graph, &graphbuf); | ||||
| 				html(graphbuf.buf); | ||||
| 				lines--; | ||||
| 			} | ||||
| 			html("</td>\n"); | ||||
| 		} | ||||
|  | ||||
| 		/* Print msgbuf into remainder of table row */ | ||||
| 		htmlf("<td colspan='%d'%s>\n", cols, | ||||
| 			ctx.qry.showmsg ? " class='logmsg'" : ""); | ||||
| 		html_txt(msgbuf.buf); | ||||
| 		html("</td></tr>\n"); | ||||
| 		strbuf_release(&msgbuf); | ||||
| 	} | ||||
|  | ||||
| 	strbuf_release(&graphbuf); | ||||
| 	cgit_free_commitinfo(info); | ||||
| } | ||||
|  | ||||
| @@ -216,6 +271,10 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if (ctx.repo->enable_commit_graph) { | ||||
| 		static const char *graph_arg = "--graph"; | ||||
| 		vector_push(&vec, &graph_arg, 0); | ||||
| 	} | ||||
|  | ||||
| 	if (path) { | ||||
| 		arg = "--"; | ||||
| @@ -242,8 +301,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'>Age</th>" | ||||
| 	      "<th class='left'>Commit message"); | ||||
| 	html("<tr class='nohover'><th class='left'>Age</th>"); | ||||
| 	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, | ||||
| @@ -274,7 +335,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); | ||||
|   | ||||
		在新工单中引用
	
	屏蔽一个用户
	 Johan Herland
					Johan Herland