Was working on a solution when this came in. However, this looks much better than what I was trying to attempt.<div><br></div><div><span></span>Gave it a spin. Works great.<br><br>On Wednesday, 13 July 2016, John Keeping <<a href="mailto:john@keeping.me.uk">john@keeping.me.uk</a>> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On Wed, Jul 13, 2016 at 07:57:23PM +0200, Erik Brangs wrote:<br>
> I use cgit via websites that use it to provide a repository browser,<br>
> i.e. I don't have my own deployment. IMHO it would be nice to get a<br>
> more comfortable navigation for directories that only contain one<br>
> subdirectory. For example, for a path like "contrib/hooks" at<br>
> <a href="https://git.zx2c4.com/cgit/tree/" target="_blank">https://git.zx2c4.com/cgit/tree/</a> , you first need to click on<br>
> "contrib" and then again on "hooks". Navigation could be simplified by<br>
> providing a link for "contrib/hooks" that points directly to the<br>
> "contrib/hooks" path.<br>
><br>
> GitHub's repository browser implements this feature. For example, at<br>
> <a href="https://github.com/torvalds/linux/tree/master/tools" target="_blank">https://github.com/torvalds/linux/tree/master/tools</a> , there's a link<br>
> for "kvm/kvm_stat" that points directly to<br>
> "<a href="https://github.com/torvalds/linux/tree/master/tools/kvm/kvm_stat" target="_blank">https://github.com/torvalds/linux/tree/master/tools/kvm/kvm_stat</a>" .<br>
><br>
> I looked at cgitrc.5.txt and didn't find any evidence that this<br>
> feature was already implemented for cgit. Assuming I didn't miss<br>
> anything, would someone be interested in implementing it?<br>
<br>
It turns out it's not too difficult, patch below. This is slightly<br>
different from Github's behaviour because it allows clicking on<br>
intermediate directories; it wouldn't be hard to collect the full path<br>
instead but I actually prefer this way of doing things.<br>
<br>
-- >8 --<br>
Subject: [PATCH] tree: allow skipping through single-child trees<br>
<br>
If we have only a single element in a directory (for example in Java<br>
package paths), display multiple directories in one go so that it is<br>
possible to navigate directly to the first directory that contains<br>
either files or multiple directories.<br>
<br>
Signed-off-by: John Keeping <<a href="javascript:;" onclick="_e(event, 'cvml', 'john@keeping.me.uk')">john@keeping.me.uk</a>><br>
---<br>
ui-tree.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--<br>
1 file changed, 68 insertions(+), 2 deletions(-)<br>
<br>
diff --git a/ui-tree.c b/ui-tree.c<br>
index 120066c..2252490 100644<br>
--- a/ui-tree.c<br>
+++ b/ui-tree.c<br>
@@ -155,6 +155,72 @@ static void print_object(const unsigned char *sha1, char *path, const char *base<br>
print_text_buffer(basename, buf, size);<br>
}<br>
<br>
+struct single_tree_ctx {<br>
+ struct strbuf *path;<br>
+ unsigned char sha1[GIT_SHA1_RAWSZ];<br>
+ char *name;<br>
+ size_t count;<br>
+};<br>
+<br>
+static int single_tree_cb(const unsigned char *sha1, struct strbuf *base,<br>
+ const char *pathname, unsigned mode, int stage,<br>
+ void *cbdata)<br>
+{<br>
+ struct single_tree_ctx *ctx = cbdata;<br>
+<br>
+ if (++ctx->count > 1)<br>
+ return -1;<br>
+<br>
+ if (!S_ISDIR(mode)) {<br>
+ ctx->count = 2;<br>
+ return -1;<br>
+ }<br>
+<br>
+ ctx->name = xstrdup(pathname);<br>
+ memcpy(ctx->sha1, sha1, GIT_SHA1_RAWSZ);<br>
+ strbuf_addf(ctx->path, "/%s", pathname);<br>
+ return 0;<br>
+}<br>
+<br>
+static void write_tree_link(const unsigned char *sha1, char *name,<br>
+ char *rev, struct strbuf *fullpath)<br>
+{<br>
+ size_t initial_length = fullpath->len;<br>
+ struct tree *tree;<br>
+ struct single_tree_ctx tree_ctx = {<br>
+ .path = fullpath,<br>
+ .count = 1,<br>
+ };<br>
+ struct pathspec paths = {<br>
+ .nr = 0<br>
+ };<br>
+<br>
+ memcpy(tree_ctx.sha1, sha1, GIT_SHA1_RAWSZ);<br>
+<br>
+ while (tree_ctx.count == 1) {<br>
+ cgit_tree_link(name, NULL, "ls-dir", ctx.qry.head, rev,<br>
+ fullpath->buf);<br>
+<br>
+ tree = lookup_tree(tree_ctx.sha1);<br>
+ if (!tree)<br>
+ return;<br>
+<br>
+ free(<a href="http://tree_ctx.name" target="_blank">tree_ctx.name</a>);<br>
+ <a href="http://tree_ctx.name" target="_blank">tree_ctx.name</a> = NULL;<br>
+ tree_ctx.count = 0;<br>
+<br>
+ read_tree_recursive(tree, "", 0, 1, &paths, single_tree_cb,<br>
+ &tree_ctx);<br>
+<br>
+ if (tree_ctx.count != 1)<br>
+ break;<br>
+<br>
+ html(" / ");<br>
+ name = <a href="http://tree_ctx.name" target="_blank">tree_ctx.name</a>;<br>
+ }<br>
+<br>
+ strbuf_setlen(fullpath, initial_length);<br>
+}<br>
<br>
static int ls_item(const unsigned char *sha1, struct strbuf *base,<br>
const char *pathname, unsigned mode, int stage, void *cbdata)<br>
@@ -187,8 +253,8 @@ static int ls_item(const unsigned char *sha1, struct strbuf *base,<br>
if (S_ISGITLINK(mode)) {<br>
cgit_submodule_link("ls-mod", fullpath.buf, sha1_to_hex(sha1));<br>
} else if (S_ISDIR(mode)) {<br>
- cgit_tree_link(name, NULL, "ls-dir", ctx.qry.head,<br>
- walk_tree_ctx->curr_rev, fullpath.buf);<br>
+ write_tree_link(sha1, name, walk_tree_ctx->curr_rev,<br>
+ &fullpath);<br>
} else {<br>
char *ext = strrchr(name, '.');<br>
strbuf_addstr(&class, "ls-blob");<br>
--<br>
2.9.0.465.g8850cbc<br>
<br>
_______________________________________________<br>
CGit mailing list<br>
<a href="javascript:;" onclick="_e(event, 'cvml', 'CGit@lists.zx2c4.com')">CGit@lists.zx2c4.com</a><br>
<a href="http://lists.zx2c4.com/mailman/listinfo/cgit" target="_blank">http://lists.zx2c4.com/mailman/listinfo/cgit</a><br>
</blockquote></div>