diff options
Diffstat (limited to '')
| -rw-r--r-- | cmd.c | 5 | ||||
| -rw-r--r-- | ui-shared.c | 103 | ||||
| -rw-r--r-- | ui-shared.h | 3 | ||||
| -rw-r--r-- | ui-tree.c | 119 | ||||
| -rw-r--r-- | ui-tree.h | 1 | 
5 files changed, 223 insertions, 8 deletions
| @@ -127,7 +127,10 @@ static void tag_fn(struct cgit_context *ctx)  static void tree_fn(struct cgit_context *ctx)  { -	cgit_print_tree(ctx->qry.sha1, ctx->qry.path); +	if (ctx->qry.grep) +		cgit_grep(ctx->qry.sha1, ctx->qry.path, ctx->qry.grep); +	else +		cgit_print_tree(ctx->qry.sha1, ctx->qry.path);  }  #define def_cmd(name, want_repo, want_layout, want_vpath, is_clone) \ diff --git a/ui-shared.c b/ui-shared.c index 43166af..026c2cb 100644 --- a/ui-shared.c +++ b/ui-shared.c @@ -246,6 +246,61 @@ static char *repolink(const char *title, const char *class, const char *page,  	return fmt("%s", delim);  } +static char *repolink2(const char *title, const char *class, const char *page, +		       const char *head, const char *path, int lineno) +{ +	char *delim = "?"; + +	html("<a"); +	if (title) { +		html(" title='"); +		html_attr(title); +		html("'"); +	} +	if (class) { +		html(" class='"); +		html_attr(class); +		html("'"); +	} +	html(" href='"); +	if (ctx.cfg.virtual_root) { +		html_url_path(ctx.cfg.virtual_root); +		if (ctx.cfg.virtual_root[strlen(ctx.cfg.virtual_root) - 1] != '/') +			html("/"); +		html_url_path(ctx.repo->url); +		if (ctx.repo->url[strlen(ctx.repo->url) - 1] != '/') +			html("/"); +		if (page) { +			html_url_path(page); +			html("/"); +			if (path) +				html_url_path(path); +		} +	} else { +		html(ctx.cfg.script_name); +		html("?url="); +		html_url_arg(ctx.repo->url); +		if (ctx.repo->url[strlen(ctx.repo->url) - 1] != '/') +			html("/"); +		if (page) { +			html_url_arg(page); +			html("/"); +			if (path) +				html_url_arg(path); +		} +		delim = "&"; +	} +	if (head && strcmp(head, ctx.repo->defbranch)) { +		html(delim); +		html("h="); +		html_url_arg(head); +		delim = "&"; +	} +	if (lineno) +		htmlf("#n%d", lineno); +	return fmt("%s", delim); +} +  static void reporevlink(const char *page, const char *name, const char *title,  			const char *class, const char *head, const char *rev,  			const char *path) @@ -263,6 +318,23 @@ static void reporevlink(const char *page, const char *name, const char *title,  	html("</a>");  } +static void reporevlink2(const char *page, const char *name, const char *title, +			 const char *class, const char *head, const char *rev, +			 const char *path, int lineno) +{ +	char *delim; + +	delim = repolink2(title, class, page, head, path, lineno); +	if (rev && ctx.qry.head != NULL && strcmp(rev, ctx.qry.head)) { +		html(delim); +		html("id="); +		html_url_arg(rev); +	} +	html("'>"); +	html_txt(name); +	html("</a>"); +} +  void cgit_summary_link(const char *name, const char *title, const char *class,  		       const char *head)  { @@ -281,6 +353,13 @@ void cgit_tree_link(const char *name, const char *title, const char *class,  	reporevlink("tree", name, title, class, head, rev, path);  } +void cgit_tree_link2(const char *name, const char *title, const char *class, +		     const char *head, const char *rev, const char *path, +		     int lineno) +{ +	reporevlink2("tree", name, title, class, head, rev, path, lineno); +} +  void cgit_plain_link(const char *name, const char *title, const char *class,  		     const char *head, const char *rev, const char *path)  { @@ -875,6 +954,9 @@ static void print_header(struct cgit_context *ctx)  void cgit_print_pageheader(struct cgit_context *ctx)  { +	int tree; +	char *page; +  	html("<div id='cgit'>");  	if (!ctx->cfg.noheader)  		print_header(ctx); @@ -903,16 +985,23 @@ void cgit_print_pageheader(struct cgit_context *ctx)  				    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", +		if (ctx->cfg.virtual_root) { +			tree = !strcmp(ctx->qry.page, "tree"); +			page = tree ? "tree" : "log"; +			html_url_path(cgit_fileurl(ctx->qry.repo, page,  						   ctx->qry.vpath, NULL)); +		}  		html("'>\n"); -		cgit_add_hidden_formfields(1, 0, "log"); +		cgit_add_hidden_formfields(1, 0, page);  		html("<select name='qt'>\n"); -		html_option("grep", "log msg", ctx->qry.grep); -		html_option("author", "author", ctx->qry.grep); -		html_option("committer", "committer", ctx->qry.grep); -		html_option("range", "range", ctx->qry.grep); +		if (tree) { +			html_option("grep", "source", ctx->qry.grep); +		} else { +			html_option("grep", "log msg", ctx->qry.grep); +			html_option("author", "author", ctx->qry.grep); +			html_option("committer", "committer", ctx->qry.grep); +			html_option("range", "range", ctx->qry.grep); +		}  		html("</select>\n");  		html("<input class='txt' type='text' size='10' name='q' value='");  		html_attr(ctx->qry.search); diff --git a/ui-shared.h b/ui-shared.h index 87a7dac..35dca9c 100644 --- a/ui-shared.h +++ b/ui-shared.h @@ -20,6 +20,9 @@ extern void cgit_tag_link(const char *name, const char *title,  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_tree_link2(const char *name, const char *title, +			   const char *class, const char *head, +			   const char *rev, const char *path, int lno);  extern void cgit_plain_link(const char *name, const char *title,  			    const char *class, const char *head,  			    const char *rev, const char *path); @@ -277,3 +277,122 @@ void cgit_print_tree(const char *rev, char *path)  	read_tree_recursive(commit->tree, "", 0, 0, paths, walk_tree, NULL);  	ls_tail();  } + +struct grep_data { +	regex_t re; +	char *path; +	int max_hits; +}; + +static int grep_blob(const unsigned char *sha1, const char *base, int baselen, +		      const char *pathname, struct grep_data *grep) +{ +	enum object_type type; +	char *buf, *line, *lf, *fullpath; +	unsigned long size; +	int hits, lno, rc; + +	type = sha1_object_info(sha1, &size); +	if (type == OBJ_BAD) { +		cgit_print_error(fmt("Bad object name: %s", +				     sha1_to_hex(sha1))); +		return -1; +	} + +	buf = read_sha1_file(sha1, &type, &size); +	if (!buf) { +		cgit_print_error(fmt("Error reading object %s", +				     sha1_to_hex(sha1))); +		return -1; +	} +	hits = 0; +	line = buf; +	lno = 1; +	while (size) { +		lf = strchr(line, '\n'); +		if (lf) +			*lf = 0; +		rc = regexec(&grep->re, line, 0, NULL, 0); +		if (!rc) { +			if (!hits) { +				fullpath = fmt("%.*s%s", baselen, base, +					       pathname); +				htmlf("<strong>%s</strong><pre>", fullpath); +			} +			htmlf("%6d: ", lno); +			while (isspace(*line)) +				line++; +			cgit_tree_link2(line, NULL, NULL, ctx.qry.head, +					ctx.qry.sha1, fullpath, lno); +			html("\n"); +			++hits; +			if (!(--grep->max_hits)) +				break; +		} +		if (!lf) +			break; +		size -= (lf - line); +		*lf = '\n'; +		line = lf + 1; +		lno++; +	} +	if (hits) +		html("</pre>"); +	if (!grep->max_hits) { +		cgit_print_error("Too many matches found."); +		return -1; +	} +	return 0; +} + +static int grep_tree(const unsigned char *sha1, const char *base, int baselen, +		     const char *pathname, unsigned mode, int stage, +		     void *cbdata) +{ +	int rc; +	char *fullpath; +	struct grep_data *grep; + +	grep = cbdata; +	fullpath = fmt("%.*s%s", baselen, base, pathname); +	if (S_ISDIR(mode)) { +		rc = grep->path ? prefixcmp(grep->path, fullpath) : 0; +		if (!rc) +			return READ_TREE_RECURSIVE; +		return (rc > 0 ? -1 : 0); +	} else if (S_ISREG(mode)) { +		rc = grep->path ? prefixcmp(fullpath, grep->path) : 0; +		if (!rc) +			return grep_blob(sha1, base, baselen, pathname, grep); +		return (rc < 0 ? -1 : 0); +	} +	return 0; +} + +void cgit_grep(const char *rev, char *path, char *grep) +{ +	unsigned char sha1[20]; +	struct commit *commit; +	struct grep_data data; + +	if (!rev) +		rev = ctx.qry.head; + +	curr_rev = xstrdup(rev); +	if (get_sha1(rev, sha1)) { +		cgit_print_error(fmt("Invalid revision name: %s", rev)); +		return; +	} +	commit = lookup_commit_reference(sha1); +	if (!commit || parse_commit(commit)) { +		cgit_print_error(fmt("Invalid commit reference: %s", rev)); +		return; +	} +	data.path = path; +	data.max_hits = 100; +	if (regcomp(&data.re, ctx.qry.search, REG_EXTENDED | REG_ICASE | REG_NOSUB)) { +		cgit_print_error("Invalid regex"); +		return; +	} +	read_tree_recursive(commit->tree, "", 0, 0, NULL, grep_tree, &data); +} @@ -2,5 +2,6 @@  #define UI_TREE_H  extern void cgit_print_tree(const char *rev, char *path); +extern void cgit_grep(const char *rev, char *path, char *grep);  #endif /* UI_TREE_H */ | 
