about summary refs log tree commit
path: root/ui-tree.c
diff options
context:
space:
mode:
Diffstat (limited to 'ui-tree.c')
-rw-r--r--ui-tree.c70
1 files changed, 68 insertions, 2 deletions
diff --git a/ui-tree.c b/ui-tree.c
index 120066c..5c31e6a 100644
--- a/ui-tree.c
+++ b/ui-tree.c
@@ -155,6 +155,72 @@ static void print_object(const unsigned char *sha1, char *path, const char *base
                 print_text_buffer(basename, buf, size);
 }
 
+struct single_tree_ctx {
+        struct strbuf *path;
+        unsigned char sha1[GIT_SHA1_RAWSZ];
+        char *name;
+        size_t count;
+};
+
+static int single_tree_cb(const unsigned char *sha1, struct strbuf *base,
+                          const char *pathname, unsigned mode, int stage,
+                          void *cbdata)
+{
+        struct single_tree_ctx *ctx = cbdata;
+
+        if (++ctx->count > 1)
+                return -1;
+
+        if (!S_ISDIR(mode)) {
+                ctx->count = 2;
+                return -1;
+        }
+
+        ctx->name = xstrdup(pathname);
+        hashcpy(ctx->sha1, sha1);
+        strbuf_addf(ctx->path, "/%s", pathname);
+        return 0;
+}
+
+static void write_tree_link(const unsigned char *sha1, char *name,
+                            char *rev, struct strbuf *fullpath)
+{
+        size_t initial_length = fullpath->len;
+        struct tree *tree;
+        struct single_tree_ctx tree_ctx = {
+                .path = fullpath,
+                .count = 1,
+        };
+        struct pathspec paths = {
+                .nr = 0
+        };
+
+        hashcpy(tree_ctx.sha1, sha1);
+
+        while (tree_ctx.count == 1) {
+                cgit_tree_link(name, NULL, "ls-dir", ctx.qry.head, rev,
+                               fullpath->buf);
+
+                tree = lookup_tree(tree_ctx.sha1);
+                if (!tree)
+                        return;
+
+                free(tree_ctx.name);
+                tree_ctx.name = NULL;
+                tree_ctx.count = 0;
+
+                read_tree_recursive(tree, "", 0, 1, &paths, single_tree_cb,
+                                    &tree_ctx);
+
+                if (tree_ctx.count != 1)
+                        break;
+
+                html(" / ");
+                name = tree_ctx.name;
+        }
+
+        strbuf_setlen(fullpath, initial_length);
+}
 
 static int ls_item(const unsigned char *sha1, struct strbuf *base,
                 const char *pathname, unsigned mode, int stage, void *cbdata)
@@ -187,8 +253,8 @@ static int ls_item(const unsigned char *sha1, struct strbuf *base,
         if (S_ISGITLINK(mode)) {
                 cgit_submodule_link("ls-mod", fullpath.buf, sha1_to_hex(sha1));
         } else if (S_ISDIR(mode)) {
-                cgit_tree_link(name, NULL, "ls-dir", ctx.qry.head,
-                               walk_tree_ctx->curr_rev, fullpath.buf);
+                write_tree_link(sha1, name, walk_tree_ctx->curr_rev,
+                                &fullpath);
         } else {
                 char *ext = strrchr(name, '.');
                 strbuf_addstr(&class, "ls-blob");