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>