diff options
| -rw-r--r-- | cgit.c | 8 | ||||
| -rw-r--r-- | cgit.css | 10 | ||||
| -rw-r--r-- | cgit.h | 4 | ||||
| -rw-r--r-- | cgitrc.5.txt | 2 | ||||
| -rw-r--r-- | cmd.c | 46 | ||||
| -rw-r--r-- | cmd.h | 3 | ||||
| -rw-r--r-- | shared.c | 6 | ||||
| -rw-r--r-- | ui-commit.c | 20 | ||||
| -rw-r--r-- | ui-commit.h | 2 | ||||
| -rw-r--r-- | ui-diff.c | 22 | ||||
| -rw-r--r-- | ui-log.c | 29 | ||||
| -rw-r--r-- | ui-patch.c | 8 | ||||
| -rw-r--r-- | ui-patch.h | 2 | ||||
| -rw-r--r-- | ui-refs.c | 2 | ||||
| -rw-r--r-- | ui-shared.c | 230 | ||||
| -rw-r--r-- | ui-shared.h | 72 | ||||
| -rw-r--r-- | ui-tree.c | 15 | 
17 files changed, 309 insertions, 172 deletions
| @@ -258,6 +258,8 @@ static void querystring_cb(const char *name, const char *value)  		ctx.qry.ssdiff = atoi(value);  	} else if (!strcmp(name, "all")) {  		ctx.qry.show_all = atoi(value); +	} else if (!strcmp(name, "context")) { +		ctx.qry.context = atoi(value);  	}  } @@ -433,6 +435,12 @@ static void process_request(void *cbdata)  		return;  	} +	/* If cmd->want_vpath is set, assume ctx->qry.path contains a "virtual" +	 * in-project path limit to be made available at ctx->qry.vpath. +	 * Otherwise, no path limit is in effect (ctx->qry.vpath = NULL). +	 */ +	ctx->qry.vpath = cmd->want_vpath ? ctx->qry.path : NULL; +  	if (cmd->want_repo && !ctx->repo) {  		cgit_print_http_headers(ctx);  		cgit_print_docstart(ctx); @@ -64,7 +64,7 @@ table#header td.sub {  }  table.tabs { -	/* border-bottom: solid 2px #ccc; */ +	border-bottom: solid 3px #ccc;  	border-collapse: collapse;  	margin-top: 2em;  	margin-bottom: 0px; @@ -102,10 +102,16 @@ table.tabs td.form select {  	font-size: 90%;  } +div.path { +	margin: 0px; +	padding: 5px 2em 2px 2em; +	color: #000; +	background-color: #eee; +} +  div.content {  	margin: 0px;  	padding: 2em; -	border-top: solid 3px #ccc;  	border-bottom: solid 3px #ccc;  } @@ -147,6 +147,8 @@ struct cgit_query {  	int showmsg;  	int ssdiff;  	int show_all; +	int context; +	char *vpath;  };  struct cgit_config { @@ -277,7 +279,7 @@ extern void *cgit_free_commitinfo(struct commitinfo *info);  extern int cgit_diff_files(const unsigned char *old_sha1,  			   const unsigned char *new_sha1,  			   unsigned long *old_size, unsigned long *new_size, -			   int *binary, linediff_fn fn); +			   int *binary, int context, linediff_fn fn);  extern void cgit_diff_tree(const unsigned char *old_sha1,  			   const unsigned char *new_sha1, diff --git a/cgitrc.5.txt b/cgitrc.5.txt index 5c24381..a853522 100644 --- a/cgitrc.5.txt +++ b/cgitrc.5.txt @@ -444,7 +444,7 @@ snapshots=tar.gz tar.bz2 zip  ## List of common mimetypes  ## -mimetype.git=image/git +mimetype.gif=image/gif  mimetype.html=text/html  mimetype.jpg=image/jpeg  mimetype.jpeg=image/jpeg @@ -51,7 +51,7 @@ static void blob_fn(struct cgit_context *ctx)  static void commit_fn(struct cgit_context *ctx)  { -	cgit_print_commit(ctx->qry.sha1); +	cgit_print_commit(ctx->qry.sha1, ctx->qry.path);  }  static void diff_fn(struct cgit_context *ctx) @@ -90,7 +90,7 @@ static void repolist_fn(struct cgit_context *ctx)  static void patch_fn(struct cgit_context *ctx)  { -	cgit_print_patch(ctx->qry.sha1); +	cgit_print_patch(ctx->qry.sha1, ctx->qry.path);  }  static void plain_fn(struct cgit_context *ctx) @@ -129,31 +129,31 @@ static void tree_fn(struct cgit_context *ctx)  	cgit_print_tree(ctx->qry.sha1, ctx->qry.path);  } -#define def_cmd(name, want_repo, want_layout) \ -	{#name, name##_fn, want_repo, want_layout} +#define def_cmd(name, want_repo, want_layout, want_vpath) \ +	{#name, name##_fn, want_repo, want_layout, want_vpath}  struct cgit_cmd *cgit_get_cmd(struct cgit_context *ctx)  {  	static struct cgit_cmd cmds[] = { -		def_cmd(HEAD, 1, 0), -		def_cmd(atom, 1, 0), -		def_cmd(about, 0, 1), -		def_cmd(blob, 1, 0), -		def_cmd(commit, 1, 1), -		def_cmd(diff, 1, 1), -		def_cmd(info, 1, 0), -		def_cmd(log, 1, 1), -		def_cmd(ls_cache, 0, 0), -		def_cmd(objects, 1, 0), -		def_cmd(patch, 1, 0), -		def_cmd(plain, 1, 0), -		def_cmd(refs, 1, 1), -		def_cmd(repolist, 0, 0), -		def_cmd(snapshot, 1, 0), -		def_cmd(stats, 1, 1), -		def_cmd(summary, 1, 1), -		def_cmd(tag, 1, 1), -		def_cmd(tree, 1, 1), +		def_cmd(HEAD, 1, 0, 0), +		def_cmd(atom, 1, 0, 0), +		def_cmd(about, 0, 1, 0), +		def_cmd(blob, 1, 0, 0), +		def_cmd(commit, 1, 1, 1), +		def_cmd(diff, 1, 1, 1), +		def_cmd(info, 1, 0, 0), +		def_cmd(log, 1, 1, 1), +		def_cmd(ls_cache, 0, 0, 0), +		def_cmd(objects, 1, 0, 0), +		def_cmd(patch, 1, 0, 1), +		def_cmd(plain, 1, 0, 0), +		def_cmd(refs, 1, 1, 0), +		def_cmd(repolist, 0, 0, 0), +		def_cmd(snapshot, 1, 0, 0), +		def_cmd(stats, 1, 1, 1), +		def_cmd(summary, 1, 1, 0), +		def_cmd(tag, 1, 1, 0), +		def_cmd(tree, 1, 1, 1),  	};  	int i; @@ -7,7 +7,8 @@ struct cgit_cmd {  	const char *name;  	cgit_cmd_fn fn;  	unsigned int want_repo:1, -		want_layout:1; +		want_layout:1, +		want_vpath:1;  };  extern struct cgit_cmd *cgit_get_cmd(struct cgit_context *ctx); @@ -10,7 +10,6 @@  struct cgit_repolist cgit_repolist;  struct cgit_context ctx; -int cgit_cmd;  int chk_zero(int result, char *msg)  { @@ -264,7 +263,8 @@ int filediff_cb(void *priv, mmbuffer_t *mb, int nbuf)  int cgit_diff_files(const unsigned char *old_sha1,  		    const unsigned char *new_sha1, unsigned long *old_size, -		    unsigned long *new_size, int *binary, linediff_fn fn) +		    unsigned long *new_size, int *binary, int context, +		    linediff_fn fn)  {  	mmfile_t file1, file2;  	xpparam_t diff_params; @@ -291,7 +291,7 @@ int cgit_diff_files(const unsigned char *old_sha1,  	memset(&emit_params, 0, sizeof(emit_params));  	memset(&emit_cb, 0, sizeof(emit_cb));  	diff_params.flags = XDF_NEED_MINIMAL; -	emit_params.ctxlen = 3; +	emit_params.ctxlen = context > 0 ? context : 3;  	emit_params.flags = XDL_EMIT_FUNCNAMES;  	emit_cb.outf = filediff_cb;  	emit_cb.priv = fn; diff --git a/ui-commit.c b/ui-commit.c index 41313b9..a11bc5f 100644 --- a/ui-commit.c +++ b/ui-commit.c @@ -12,7 +12,7 @@  #include "ui-diff.h"  #include "ui-log.h" -void cgit_print_commit(char *hex) +void cgit_print_commit(char *hex, const char *prefix)  {  	struct commit *commit, *parent;  	struct commitinfo *info, *parent_info; @@ -58,19 +58,23 @@ void cgit_print_commit(char *hex)  	html("</td></tr>\n");  	html("<tr><th>commit</th><td colspan='2' class='sha1'>");  	tmp = sha1_to_hex(commit->object.sha1); -	cgit_commit_link(tmp, NULL, NULL, ctx.qry.head, tmp, 0); +	cgit_commit_link(tmp, NULL, NULL, ctx.qry.head, tmp, prefix, 0);  	html(" ("); -	cgit_patch_link("patch", NULL, NULL, NULL, tmp); +	cgit_patch_link("patch", NULL, NULL, NULL, tmp, prefix);  	html(") (");  	if ((ctx.qry.ssdiff && !ctx.cfg.ssdiff) || (!ctx.qry.ssdiff && ctx.cfg.ssdiff)) -		cgit_commit_link("unidiff", NULL, NULL, ctx.qry.head, tmp, 1); +		cgit_commit_link("unidiff", NULL, NULL, ctx.qry.head, tmp, prefix, 1);  	else -		cgit_commit_link("side-by-side diff", NULL, NULL, ctx.qry.head, tmp, 1); +		cgit_commit_link("side-by-side diff", NULL, NULL, ctx.qry.head, tmp, prefix, 1);  	html(")</td></tr>\n");  	html("<tr><th>tree</th><td colspan='2' class='sha1'>");  	tmp = xstrdup(hex);  	cgit_tree_link(sha1_to_hex(commit->tree->object.sha1), NULL, NULL,  		       ctx.qry.head, tmp, NULL); +	if (prefix) { +		html(" /"); +		cgit_tree_link(prefix, NULL, NULL, ctx.qry.head, tmp, prefix); +	}  	html("</td></tr>\n");        	for (p = commit->parents; p ; p = p->next) {  		parent = lookup_commit_reference(p->item->object.sha1); @@ -87,10 +91,10 @@ void cgit_print_commit(char *hex)  			parent_info = cgit_parse_commit(parent);  			tmp2 = parent_info->subject;  		} -		cgit_commit_link(tmp2, NULL, NULL, ctx.qry.head, tmp, 0); +		cgit_commit_link(tmp2, NULL, NULL, ctx.qry.head, tmp, prefix, 0);  		html(" (");  		cgit_diff_link("diff", NULL, NULL, ctx.qry.head, hex, -			       sha1_to_hex(p->item->object.sha1), NULL, 0); +			       sha1_to_hex(p->item->object.sha1), prefix, 0);  		html(")</td></tr>");  		parents++;  	} @@ -121,7 +125,7 @@ void cgit_print_commit(char *hex)  			tmp = sha1_to_hex(commit->parents->item->object.sha1);  		else  			tmp = NULL; -		cgit_print_diff(ctx.qry.sha1, tmp, NULL); +		cgit_print_diff(ctx.qry.sha1, tmp, prefix);  	}  	cgit_free_commitinfo(info);  } diff --git a/ui-commit.h b/ui-commit.h index 40bcb31..8198b4b 100644 --- a/ui-commit.h +++ b/ui-commit.h @@ -1,6 +1,6 @@  #ifndef UI_COMMIT_H  #define UI_COMMIT_H -extern void cgit_print_commit(char *hex); +extern void cgit_print_commit(char *hex, const char *prefix);  #endif /* UI_COMMIT_H */ @@ -127,7 +127,7 @@ static void inspect_filepair(struct diff_filepair *pair)  	lines_added = 0;  	lines_removed = 0;  	cgit_diff_files(pair->one->sha1, pair->two->sha1, &old_size, &new_size, -			&binary, count_diff_lines); +			&binary, 0, count_diff_lines);  	if (files >= slots) {  		if (slots == 0)  			slots = 4; @@ -154,17 +154,27 @@ static void inspect_filepair(struct diff_filepair *pair)  }  void cgit_print_diffstat(const unsigned char *old_sha1, -			 const unsigned char *new_sha1) +			 const unsigned char *new_sha1, const char *prefix)  { -	int i; +	int i, save_context = ctx.qry.context;  	html("<div class='diffstat-header'>");  	cgit_diff_link("Diffstat", NULL, NULL, ctx.qry.head, ctx.qry.sha1,  		       ctx.qry.sha2, NULL, 0); +	if (prefix) +		htmlf(" (limited to '%s')", prefix); +	html(" ("); +	ctx.qry.context = (save_context > 0 ? save_context : 3) << 1; +	cgit_self_link("more", NULL, NULL, &ctx); +	html("/"); +	ctx.qry.context = (save_context > 3 ? save_context : 3) >> 1; +	cgit_self_link("less", NULL, NULL, &ctx); +	ctx.qry.context = save_context; +	html(" context)");  	html("</div>");  	html("<table summary='diffstat' class='diffstat'>");  	max_changes = 0; -	cgit_diff_tree(old_sha1, new_sha1, inspect_filepair, NULL); +	cgit_diff_tree(old_sha1, new_sha1, inspect_filepair, prefix);  	for(i = 0; i<files; i++)  		print_fileinfo(&items[i]);  	html("</table>"); @@ -286,7 +296,7 @@ static void filepair_cb(struct diff_filepair *pair)  		return;  	}  	if (cgit_diff_files(pair->one->sha1, pair->two->sha1, &old_size, -			    &new_size, &binary, print_line_fn)) +			    &new_size, &binary, ctx.qry.context, print_line_fn))  		cgit_print_error("Error running diff");  	if (binary) {  		if (use_ssdiff) @@ -338,7 +348,7 @@ void cgit_print_diff(const char *new_rev, const char *old_rev, const char *prefi  		use_ssdiff = 1;  	print_ssdiff_link(); -	cgit_print_diffstat(old_rev_sha1, new_rev_sha1); +	cgit_print_diffstat(old_rev_sha1, new_rev_sha1, prefix);  	if (use_ssdiff) {  		html("<table summary='ssdiff' class='ssdiff'>"); @@ -33,7 +33,7 @@ void inspect_files(struct diff_filepair *pair)  	files++;  	if (ctx.repo->enable_log_linecount)  		cgit_diff_files(pair->one->sha1, pair->two->sha1, &old_size, -				&new_size, &binary, count_lines); +				&new_size, &binary, 0, count_lines);  }  void show_commit_decorations(struct commit *commit) @@ -46,8 +46,9 @@ void show_commit_decorations(struct commit *commit)  	while (deco) {  		if (!prefixcmp(deco->name, "refs/heads/")) {  			strncpy(buf, deco->name + 11, sizeof(buf) - 1); -			cgit_log_link(buf, NULL, "branch-deco", buf, NULL, NULL, -				0, NULL, NULL, ctx.qry.showmsg); +			cgit_log_link(buf, NULL, "branch-deco", buf, NULL, +				      ctx.qry.vpath, 0, NULL, NULL, +				      ctx.qry.showmsg);  		}  		else if (!prefixcmp(deco->name, "tag: refs/tags/")) {  			strncpy(buf, deco->name + 15, sizeof(buf) - 1); @@ -60,13 +61,15 @@ void show_commit_decorations(struct commit *commit)  		else if (!prefixcmp(deco->name, "refs/remotes/")) {  			strncpy(buf, deco->name + 13, sizeof(buf) - 1);  			cgit_log_link(buf, NULL, "remote-deco", NULL, -				sha1_to_hex(commit->object.sha1), NULL, -				0, NULL, NULL, ctx.qry.showmsg); +				      sha1_to_hex(commit->object.sha1), +				      ctx.qry.vpath, 0, NULL, NULL, +				      ctx.qry.showmsg);  		}  		else {  			strncpy(buf, deco->name, sizeof(buf) - 1);  			cgit_commit_link(buf, NULL, "deco", ctx.qry.head, -				sha1_to_hex(commit->object.sha1), 0); +					 sha1_to_hex(commit->object.sha1), +					 ctx.qry.vpath, 0);  		}  		deco = deco->next;  	} @@ -82,14 +85,14 @@ void print_commit(struct commit *commit)  	htmlf("<tr%s><td>",  		ctx.qry.showmsg ? " class='logheader'" : "");  	tmp = fmt("id=%s", sha1_to_hex(commit->object.sha1)); -	tmp = cgit_pageurl(ctx.repo->url, "commit", tmp); +	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'" : "");  	cgit_commit_link(info->subject, NULL, NULL, ctx.qry.head, -			 sha1_to_hex(commit->object.sha1), 0); +			 sha1_to_hex(commit->object.sha1), ctx.qry.vpath, 0);  	show_commit_decorations(commit);  	html("</td><td>");  	html_txt(info->author); @@ -179,7 +182,7 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern  		html(" (");  		cgit_log_link(ctx.qry.showmsg ? "Collapse" : "Expand", NULL,  			      NULL, ctx.qry.head, ctx.qry.sha1, -			      ctx.qry.path, ctx.qry.ofs, ctx.qry.grep, +			      ctx.qry.vpath, ctx.qry.ofs, ctx.qry.grep,  			      ctx.qry.search, ctx.qry.showmsg ? 0 : 1);  		html(")");  	} @@ -216,22 +219,22 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern  		     columns);  		if (ofs > 0) {  			cgit_log_link("[prev]", NULL, NULL, ctx.qry.head, -				      ctx.qry.sha1, ctx.qry.path, +				      ctx.qry.sha1, ctx.qry.vpath,  				      ofs - cnt, ctx.qry.grep,  				      ctx.qry.search, ctx.qry.showmsg);  			html(" ");  		}  		if ((commit = get_revision(&rev)) != NULL) {  			cgit_log_link("[next]", NULL, NULL, ctx.qry.head, -				      ctx.qry.sha1, ctx.qry.path, +				      ctx.qry.sha1, ctx.qry.vpath,  				      ofs + cnt, ctx.qry.grep,  				      ctx.qry.search, ctx.qry.showmsg);  		}  		html("</div>");  	} else if ((commit = get_revision(&rev)) != NULL) {  		html("<tr class='nohover'><td colspan='3'>"); -		cgit_log_link("[...]", NULL, NULL, ctx.qry.head, NULL, NULL, 0, -			      NULL, NULL, ctx.qry.showmsg); +		cgit_log_link("[...]", NULL, NULL, ctx.qry.head, NULL, +			      ctx.qry.vpath, 0, NULL, NULL, ctx.qry.showmsg);  		html("</td></tr>\n");  	}  } @@ -71,13 +71,13 @@ static void filepair_cb(struct diff_filepair *pair)  		return;  	}  	if (cgit_diff_files(pair->one->sha1, pair->two->sha1, &old_size, -			    &new_size, &binary, print_line)) +			    &new_size, &binary, 0, print_line))  		html("Error running diff");  	if (binary)  		html("Binary files differ\n");  } -void cgit_print_patch(char *hex) +void cgit_print_patch(char *hex, const char *prefix)  {  	struct commit *commit;  	struct commitinfo *info; @@ -122,7 +122,9 @@ void cgit_print_patch(char *hex)  			html("\n");  	}  	html("---\n"); -	cgit_diff_tree(old_sha1, sha1, filepair_cb, NULL); +	if (prefix) +		htmlf("(limited to '%s')\n\n", prefix); +	cgit_diff_tree(old_sha1, sha1, filepair_cb, prefix);  	html("--\n");  	htmlf("cgit %s\n", CGIT_VERSION);  	cgit_free_commitinfo(info); @@ -1,6 +1,6 @@  #ifndef UI_PATCH_H  #define UI_PATCH_H -extern void cgit_print_patch(char *hex); +extern void cgit_print_patch(char *hex, const char *prefix);  #endif /* UI_PATCH_H */ @@ -74,7 +74,7 @@ static int print_branch(struct refinfo *ref)  	html("</td><td>");  	if (ref->object->type == OBJ_COMMIT) { -		cgit_commit_link(info->subject, NULL, NULL, name, NULL, 0); +		cgit_commit_link(info->subject, NULL, NULL, name, NULL, NULL, 0);  		html("</td><td>");  		html_txt(info->author);  		html("</td><td colspan='2'>"); diff --git a/ui-shared.c b/ui-shared.c index 0f65474..c398d7a 100644 --- a/ui-shared.c +++ b/ui-shared.c @@ -27,7 +27,7 @@ static char *http_date(time_t t)  		   tm->tm_hour, tm->tm_min, tm->tm_sec);  } -void cgit_print_error(char *msg) +void cgit_print_error(const char *msg)  {  	html("<div class='error'>");  	html_txt(msg); @@ -133,7 +133,7 @@ char *cgit_currurl()  		return fmt("%s/", ctx.cfg.virtual_root);  } -static void site_url(char *page, char *search, int ofs) +static void site_url(const char *page, const char *search, int ofs)  {  	char *delim = "?"; @@ -160,8 +160,8 @@ static void site_url(char *page, char *search, int ofs)  	}  } -static void site_link(char *page, char *name, char *title, char *class, -		      char *search, int ofs) +static void site_link(const char *page, const char *name, const char *title, +		      const char *class, const char *search, int ofs)  {  	html("<a");  	if (title) { @@ -181,14 +181,14 @@ static void site_link(char *page, char *name, char *title, char *class,  	html("</a>");  } -void cgit_index_link(char *name, char *title, char *class, char *pattern, -		     int ofs) +void cgit_index_link(const char *name, const char *title, const char *class, +		     const char *pattern, int ofs)  {  	site_link(NULL, name, title, class, pattern, ofs);  } -static char *repolink(char *title, char *class, char *page, char *head, -		      char *path) +static char *repolink(const char *title, const char *class, const char *page, +		      const char *head, const char *path)  {  	char *delim = "?"; @@ -240,8 +240,9 @@ static char *repolink(char *title, char *class, char *page, char *head,  	return fmt("%s", delim);  } -static void reporevlink(char *page, char *name, char *title, char *class, -			char *head, char *rev, char *path) +static void reporevlink(const char *page, const char *name, const char *title, +			const char *class, const char *head, const char *rev, +			const char *path)  {  	char *delim; @@ -256,32 +257,33 @@ static void reporevlink(char *page, char *name, char *title, char *class,  	html("</a>");  } -void cgit_summary_link(char *name, char *title, char *class, char *head) +void cgit_summary_link(const char *name, const char *title, const char *class, +		       const char *head)  {  	reporevlink(NULL, name, title, class, head, NULL, NULL);  } -void cgit_tag_link(char *name, char *title, char *class, char *head, -		   char *rev) +void cgit_tag_link(const char *name, const char *title, const char *class, +		   const char *head, const char *rev)  {  	reporevlink("tag", name, title, class, head, rev, NULL);  } -void cgit_tree_link(char *name, char *title, char *class, char *head, -		    char *rev, char *path) +void cgit_tree_link(const char *name, const char *title, const char *class, +		    const char *head, const char *rev, const char *path)  {  	reporevlink("tree", name, title, class, head, rev, path);  } -void cgit_plain_link(char *name, char *title, char *class, char *head, -		     char *rev, char *path) +void cgit_plain_link(const char *name, const char *title, const char *class, +		     const char *head, const char *rev, const char *path)  {  	reporevlink("plain", name, title, class, head, rev, path);  } -void cgit_log_link(char *name, char *title, char *class, char *head, -		   char *rev, char *path, int ofs, char *grep, char *pattern, -		   int showmsg) +void cgit_log_link(const char *name, const char *title, const char *class, +		   const char *head, const char *rev, const char *path, +		   int ofs, const char *grep, const char *pattern, int showmsg)  {  	char *delim; @@ -316,8 +318,9 @@ void cgit_log_link(char *name, char *title, char *class, char *head,  	html("</a>");  } -void cgit_commit_link(char *name, char *title, char *class, char *head, -		      char *rev, int toggle_ssdiff) +void cgit_commit_link(char *name, const char *title, const char *class, +		      const char *head, const char *rev, const char *path, +		      int toggle_ssdiff)  {  	if (strlen(name) > ctx.cfg.max_msg_len && ctx.cfg.max_msg_len >= 15) {  		name[ctx.cfg.max_msg_len] = '\0'; @@ -328,7 +331,7 @@ void cgit_commit_link(char *name, char *title, char *class, char *head,  	char *delim; -	delim = repolink(title, class, "commit", head, NULL); +	delim = repolink(title, class, "commit", head, path);  	if (rev && strcmp(rev, ctx.qry.head)) {  		html(delim);  		html("id="); @@ -338,27 +341,35 @@ void cgit_commit_link(char *name, char *title, char *class, char *head,  	if ((ctx.qry.ssdiff && !toggle_ssdiff) || (!ctx.qry.ssdiff && toggle_ssdiff)) {  		html(delim);  		html("ss=1"); +		delim = "&"; +	} +	if (ctx.qry.context > 0 && ctx.qry.context != 3) { +		html(delim); +		html("context="); +		htmlf("%d", ctx.qry.context); +		delim = "&";  	}  	html("'>");  	html_txt(name);  	html("</a>");  } -void cgit_refs_link(char *name, char *title, char *class, char *head, -		    char *rev, char *path) +void cgit_refs_link(const char *name, const char *title, const char *class, +		    const char *head, const char *rev, const char *path)  {  	reporevlink("refs", name, title, class, head, rev, path);  } -void cgit_snapshot_link(char *name, char *title, char *class, char *head, -			char *rev, char *archivename) +void cgit_snapshot_link(const char *name, const char *title, const char *class, +			const char *head, const char *rev, +			const char *archivename)  {  	reporevlink("snapshot", name, title, class, head, rev, archivename);  } -void cgit_diff_link(char *name, char *title, char *class, char *head, -		    char *new_rev, char *old_rev, char *path, -		    int toggle_ssdiff) +void cgit_diff_link(const char *name, const char *title, const char *class, +		    const char *head, const char *new_rev, const char *old_rev, +		    const char *path, int toggle_ssdiff)  {  	char *delim; @@ -378,24 +389,89 @@ void cgit_diff_link(char *name, char *title, char *class, char *head,  	if ((ctx.qry.ssdiff && !toggle_ssdiff) || (!ctx.qry.ssdiff && toggle_ssdiff)) {  		html(delim);  		html("ss=1"); +		delim = "&"; +	} +	if (ctx.qry.context > 0 && ctx.qry.context != 3) { +		html(delim); +		html("context="); +		htmlf("%d", ctx.qry.context); +		delim = "&";  	}  	html("'>");  	html_txt(name);  	html("</a>");  } -void cgit_patch_link(char *name, char *title, char *class, char *head, -		     char *rev) +void cgit_patch_link(const char *name, const char *title, const char *class, +		     const char *head, const char *rev, const char *path)  { -	reporevlink("patch", name, title, class, head, rev, NULL); +	reporevlink("patch", name, title, class, head, rev, path);  } -void cgit_stats_link(char *name, char *title, char *class, char *head, -		     char *path) +void cgit_stats_link(const char *name, const char *title, const char *class, +		     const char *head, const char *path)  {  	reporevlink("stats", name, title, class, head, NULL, path);  } +void cgit_self_link(char *name, const char *title, const char *class, +		    struct cgit_context *ctx) +{ +	if (!strcmp(ctx->qry.page, "repolist")) +		return cgit_index_link(name, title, class, ctx->qry.search, +				       ctx->qry.ofs); +	else if (!strcmp(ctx->qry.page, "summary")) +		return cgit_summary_link(name, title, class, ctx->qry.head); +	else if (!strcmp(ctx->qry.page, "tag")) +		return cgit_tag_link(name, title, class, ctx->qry.head, +				     ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL); +	else if (!strcmp(ctx->qry.page, "tree")) +		return cgit_tree_link(name, title, class, ctx->qry.head, +				      ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, +				      ctx->qry.path); +	else if (!strcmp(ctx->qry.page, "plain")) +		return cgit_plain_link(name, title, class, ctx->qry.head, +				      ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, +				      ctx->qry.path); +	else if (!strcmp(ctx->qry.page, "log")) +		return cgit_log_link(name, title, class, ctx->qry.head, +				      ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, +				      ctx->qry.path, ctx->qry.ofs, +				      ctx->qry.grep, ctx->qry.search, +				      ctx->qry.showmsg); +	else if (!strcmp(ctx->qry.page, "commit")) +		return cgit_commit_link(name, title, class, ctx->qry.head, +				      ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, +				      ctx->qry.path, 0); +	else if (!strcmp(ctx->qry.page, "patch")) +		return cgit_patch_link(name, title, class, ctx->qry.head, +				      ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, +				      ctx->qry.path); +	else if (!strcmp(ctx->qry.page, "refs")) +		return cgit_refs_link(name, title, class, ctx->qry.head, +				      ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, +				      ctx->qry.path); +	else if (!strcmp(ctx->qry.page, "snapshot")) +		return cgit_snapshot_link(name, title, class, ctx->qry.head, +				      ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, +				      ctx->qry.path); +	else if (!strcmp(ctx->qry.page, "diff")) +		return cgit_diff_link(name, title, class, ctx->qry.head, +				      ctx->qry.sha1, ctx->qry.sha2, +				      ctx->qry.path, 0); +	else if (!strcmp(ctx->qry.page, "stats")) +		return cgit_stats_link(name, title, class, ctx->qry.head, +				      ctx->qry.path); + +	/* Don't known how to make link for this page */ +	repolink(title, class, ctx->qry.page, ctx->qry.head, ctx->qry.path); +	html("><!-- cgit_self_link() doesn't know how to make link for page '"); +	html_txt(ctx->qry.page); +	html("' -->"); +	html_txt(name); +	html("</a>"); +} +  void cgit_object_link(struct object *obj)  {  	char *page, *shortrev, *fullrev, *name; @@ -405,7 +481,7 @@ void cgit_object_link(struct object *obj)  	shortrev[10] = '\0';  	if (obj->type == OBJ_COMMIT) {                  cgit_commit_link(fmt("commit %s...", shortrev), NULL, NULL, -				 ctx.qry.head, fullrev, 0); +				 ctx.qry.head, fullrev, NULL, 0);  		return;  	} else if (obj->type == OBJ_TREE)  		page = "tree"; @@ -417,7 +493,7 @@ void cgit_object_link(struct object *obj)  	reporevlink(page, name, NULL, NULL, ctx.qry.head, fullrev, NULL);  } -void cgit_print_date(time_t secs, char *format, int local_time) +void cgit_print_date(time_t secs, const char *format, int local_time)  {  	char buf[64];  	struct tm *time; @@ -432,7 +508,7 @@ void cgit_print_date(time_t secs, char *format, int local_time)  	html_txt(buf);  } -void cgit_print_age(time_t t, time_t max_relative, char *format) +void cgit_print_age(time_t t, time_t max_relative, const char *format)  {  	time_t now, secs; @@ -531,7 +607,7 @@ void cgit_print_docstart(struct cgit_context *ctx)  		html("<link rel='alternate' title='Atom feed' href='");  		html(cgit_httpscheme());  		html_attr(cgit_hosturl()); -		html_attr(cgit_fileurl(ctx->repo->url, "atom", ctx->qry.path, +		html_attr(cgit_fileurl(ctx->repo->url, "atom", ctx->qry.vpath,  				       fmt("h=%s", ctx->qry.head)));  		html("' type='application/atom+xml'/>\n");  	} @@ -611,14 +687,15 @@ int print_archive_ref(const char *refname, const unsigned char *sha1,  	return 0;  } -void cgit_add_hidden_formfields(int incl_head, int incl_search, char *page) +void cgit_add_hidden_formfields(int incl_head, int incl_search, +				const char *page)  {  	char *url;  	if (!ctx.cfg.virtual_root) {  		url = fmt("%s/%s", ctx.qry.repo, page); -		if (ctx.qry.path) -			url = fmt("%s/%s", url, ctx.qry.path); +		if (ctx.qry.vpath) +			url = fmt("%s/%s", url, ctx.qry.vpath);  		html_hidden("url", url);  	} @@ -641,11 +718,30 @@ void cgit_add_hidden_formfields(int incl_head, int incl_search, char *page)  	}  } -const char *fallback_cmd = "repolist"; +static const char *hc(struct cgit_context *ctx, const char *page) +{ +	return strcmp(ctx->qry.page, page) ? NULL : "active"; +} -char *hc(struct cgit_cmd *cmd, const char *page) +static void cgit_print_path_crumbs(struct cgit_context *ctx, char *path)  { -	return (strcmp(cmd ? cmd->name : fallback_cmd, page) ? NULL : "active"); +	char *old_path = ctx->qry.path; +	char *p = path, *q, *end = path + strlen(path); + +	ctx->qry.path = NULL; +	cgit_self_link("root", NULL, NULL, ctx); +	ctx->qry.path = p = path; +	while (p < end) { +		if (!(q = strchr(p, '/'))) +			q = end; +		*q = '\0'; +		html_txt("/"); +		cgit_self_link(p, NULL, NULL, ctx); +		if (q < end) +			*q = '/'; +		p = q + 1; +	} +	ctx->qry.path = old_path;  }  static void print_header(struct cgit_context *ctx) @@ -697,41 +793,37 @@ static void print_header(struct cgit_context *ctx)  void cgit_print_pageheader(struct cgit_context *ctx)  { -	struct cgit_cmd *cmd = cgit_get_cmd(ctx); - -	if (!cmd && ctx->repo) -		fallback_cmd = "summary"; -  	html("<div id='cgit'>");  	if (!ctx->cfg.noheader)  		print_header(ctx);  	html("<table class='tabs'><tr><td>\n");  	if (ctx->repo) { -		cgit_summary_link("summary", NULL, hc(cmd, "summary"), +		cgit_summary_link("summary", NULL, hc(ctx, "summary"),  				  ctx->qry.head); -		cgit_refs_link("refs", NULL, hc(cmd, "refs"), ctx->qry.head, +		cgit_refs_link("refs", NULL, hc(ctx, "refs"), ctx->qry.head,  			       ctx->qry.sha1, NULL); -		cgit_log_link("log", NULL, hc(cmd, "log"), ctx->qry.head, -			      NULL, NULL, 0, NULL, NULL, ctx->qry.showmsg); -		cgit_tree_link("tree", NULL, hc(cmd, "tree"), ctx->qry.head, -			       ctx->qry.sha1, NULL); -		cgit_commit_link("commit", NULL, hc(cmd, "commit"), -				 ctx->qry.head, ctx->qry.sha1, 0); -		cgit_diff_link("diff", NULL, hc(cmd, "diff"), ctx->qry.head, -			       ctx->qry.sha1, ctx->qry.sha2, NULL, 0); +		cgit_log_link("log", NULL, hc(ctx, "log"), ctx->qry.head, +			      NULL, ctx->qry.vpath, 0, NULL, NULL, +			      ctx->qry.showmsg); +		cgit_tree_link("tree", NULL, hc(ctx, "tree"), ctx->qry.head, +			       ctx->qry.sha1, ctx->qry.vpath); +		cgit_commit_link("commit", NULL, hc(ctx, "commit"), +				 ctx->qry.head, ctx->qry.sha1, ctx->qry.vpath, 0); +		cgit_diff_link("diff", NULL, hc(ctx, "diff"), ctx->qry.head, +			       ctx->qry.sha1, ctx->qry.sha2, ctx->qry.vpath, 0);  		if (ctx->repo->max_stats) -			cgit_stats_link("stats", NULL, hc(cmd, "stats"), -					ctx->qry.head, NULL); +			cgit_stats_link("stats", NULL, hc(ctx, "stats"), +					ctx->qry.head, ctx->qry.vpath);  		if (ctx->repo->readme)  			reporevlink("about", "about", NULL, -				    hc(cmd, "about"), ctx->qry.head, NULL, +				    hc(ctx, "about"), ctx->qry.head, NULL,  				    NULL);  		html("</td><td class='form'>");  		html("<form class='right' method='get' action='");  		if (ctx->cfg.virtual_root)  			html_url_path(cgit_fileurl(ctx->qry.repo, "log", -						   ctx->qry.path, NULL)); +						   ctx->qry.vpath, NULL));  		html("'>\n");  		cgit_add_hidden_formfields(1, 0, "log");  		html("<select name='qt'>\n"); @@ -746,9 +838,9 @@ void cgit_print_pageheader(struct cgit_context *ctx)  		html("<input type='submit' value='search'/>\n");  		html("</form>\n");  	} else { -		site_link(NULL, "index", NULL, hc(cmd, "repolist"), NULL, 0); +		site_link(NULL, "index", NULL, hc(ctx, "repolist"), NULL, 0);  		if (ctx->cfg.root_readme) -			site_link("about", "about", NULL, hc(cmd, "about"), +			site_link("about", "about", NULL, hc(ctx, "about"),  				  NULL, 0);  		html("</td><td class='form'>");  		html("<form method='get' action='"); @@ -761,6 +853,12 @@ void cgit_print_pageheader(struct cgit_context *ctx)  		html("</form>");  	}  	html("</td></tr></table>\n"); +	if (ctx->qry.vpath) { +		html("<div class='path'>"); +		html("path: "); +		cgit_print_path_crumbs(ctx, ctx->qry.vpath); +		html("</div>"); +	}  	html("<div class='content'>");  } diff --git a/ui-shared.h b/ui-shared.h index 9ebc1f9..3cc1258 100644 --- a/ui-shared.h +++ b/ui-shared.h @@ -10,36 +10,50 @@ extern char *cgit_fileurl(const char *reponame, const char *pagename,  extern char *cgit_pageurl(const char *reponame, const char *pagename,  			  const char *query); -extern void cgit_index_link(char *name, char *title, char *class, -			    char *pattern, int ofs); -extern void cgit_summary_link(char *name, char *title, char *class, char *head); -extern void cgit_tag_link(char *name, char *title, char *class, char *head, -			  char *rev); -extern void cgit_tree_link(char *name, char *title, char *class, char *head, -			   char *rev, char *path); -extern void cgit_plain_link(char *name, char *title, char *class, char *head, -			    char *rev, char *path); -extern void cgit_log_link(char *name, char *title, char *class, char *head, -			  char *rev, char *path, int ofs, char *grep, -			  char *pattern, int showmsg); -extern void cgit_commit_link(char *name, char *title, char *class, char *head, -			     char *rev, int toggle_ssdiff); -extern void cgit_patch_link(char *name, char *title, char *class, char *head, -			    char *rev); -extern void cgit_refs_link(char *name, char *title, char *class, char *head, -			   char *rev, char *path); -extern void cgit_snapshot_link(char *name, char *title, char *class, -			       char *head, char *rev, char *archivename); -extern void cgit_diff_link(char *name, char *title, char *class, char *head, -			   char *new_rev, char *old_rev, char *path, -			   int toggle_ssdiff); -extern void cgit_stats_link(char *name, char *title, char *class, char *head, -			    char *path); +extern void cgit_index_link(const char *name, const char *title, +			    const char *class, const char *pattern, int ofs); +extern void cgit_summary_link(const char *name, const char *title, +			      const char *class, const char *head); +extern void cgit_tag_link(const char *name, const char *title, +			  const char *class, const char *head, +			  const char *rev); +extern void cgit_tree_link(const char *name, const char *title, +			   const char *class, const char *head, +			   const char *rev, const char *path); +extern void cgit_plain_link(const char *name, const char *title, +			    const char *class, const char *head, +			    const char *rev, const char *path); +extern void cgit_log_link(const char *name, const char *title, +			  const char *class, const char *head, const char *rev, +			  const char *path, int ofs, const char *grep, +			  const char *pattern, int showmsg); +extern void cgit_commit_link(char *name, const char *title, +			     const char *class, const char *head, +			     const char *rev, const char *path, +			     int toggle_ssdiff); +extern void cgit_patch_link(const char *name, const char *title, +			    const char *class, const char *head, +			    const char *rev, const char *path); +extern void cgit_refs_link(const char *name, const char *title, +			   const char *class, const char *head, +			   const char *rev, const char *path); +extern void cgit_snapshot_link(const char *name, const char *title, +			       const char *class, const char *head, +			       const char *rev, const char *archivename); +extern void cgit_diff_link(const char *name, const char *title, +			   const char *class, const char *head, +			   const char *new_rev, const char *old_rev, +			   const char *path, int toggle_ssdiff); +extern void cgit_stats_link(const char *name, const char *title, +			    const char *class, const char *head, +			    const char *path); +extern void cgit_self_link(char *name, const char *title, +			   const char *class, struct cgit_context *ctx);  extern void cgit_object_link(struct object *obj); -extern void cgit_print_error(char *msg); -extern void cgit_print_date(time_t secs, char *format, int local_time); -extern void cgit_print_age(time_t t, time_t max_relative, char *format); +extern void cgit_print_error(const char *msg); +extern void cgit_print_date(time_t secs, const char *format, int local_time); +extern void cgit_print_age(time_t t, time_t max_relative, const char *format);  extern void cgit_print_http_headers(struct cgit_context *ctx);  extern void cgit_print_docstart(struct cgit_context *ctx);  extern void cgit_print_docend(); @@ -48,5 +62,5 @@ extern void cgit_print_filemode(unsigned short mode);  extern void cgit_print_snapshot_links(const char *repo, const char *head,  				      const char *hex, int snapshots);  extern void cgit_add_hidden_formfields(int incl_head, int incl_search, -				       char *page); +				       const char *page);  #endif /* UI_SHARED_H */ @@ -102,10 +102,10 @@ static void print_object(const unsigned char *sha1, char *path, const char *base  		return;  	} -	html(" ("); +	htmlf("blob: %s (", sha1_to_hex(sha1));  	cgit_plain_link("plain", NULL, NULL, ctx.qry.head,  		        curr_rev, path); -	htmlf(")<br/>blob: %s\n", sha1_to_hex(sha1)); +	html(")\n");  	if (ctx.cfg.max_blob_size && size / 1024 > ctx.cfg.max_blob_size) {  		htmlf("<div class='error'>blob size (%dKB) exceeds display size limit (%dKB).</div>", @@ -225,17 +225,10 @@ static int walk_tree(const unsigned char *sha1, const char *base, int baselen,  {  	static int state;  	static char buffer[PATH_MAX]; -	char *url;  	if (state == 0) {  		memcpy(buffer, base, baselen);  		strcpy(buffer+baselen, pathname); -		url = cgit_pageurl(ctx.qry.repo, "tree", -				   fmt("h=%s&path=%s", curr_rev, buffer)); -		html("/"); -		cgit_tree_link(xstrdup(pathname), NULL, NULL, ctx.qry.head, -			       curr_rev, buffer); -  		if (strcmp(match_path, buffer))  			return READ_TREE_RECURSIVE; @@ -278,10 +271,6 @@ void cgit_print_tree(const char *rev, char *path)  		return;  	} -	html("path: <a href='"); -	html_attr(cgit_pageurl(ctx.qry.repo, "tree", fmt("h=%s", rev))); -	html("'>root</a>"); -  	if (path == NULL) {  		ls_tree(commit->tree->object.sha1, NULL);  		return; | 
