diff options
context:
space:
mode:
authorBryce Kwon <bryce@brycekwon.com>
committerBryce Kwon <bryce@brycekwon.com>
commit
parent
tree
download
Add `enable-tree-group-dirs` to list dirs first
Diffstat (limited to 'source/ui-tree.c')
-rw-r--r--source/ui-tree.c65
1 file changed, 60 insertions, 5 deletions
diff --git a/source/ui-tree.c b/source/ui-tree.c
index 5ac8c9a..cbaca38 100644
--- a/source/ui-tree.c
+++ b/source/ui-tree.c
@@ -13,10 +13,18 @@
#include "html.h"
#include "ui-shared.h"
+struct tree_ls_entry {
+ struct object_id oid;
+ char *name;
+ unsigned mode;
+};
+
struct walk_tree_context {
char *curr_rev;
char *match_path;
int state;
+ struct tree_ls_entry *entries;
+ size_t entries_nr, entries_alloc;
};
static void print_text_buffer(const char *name, char *buf, unsigned long size)
@@ -200,10 +208,9 @@ static void write_tree_link(const struct object_id *oid, char *name,
strbuf_setlen(fullpath, initial_length);
}
-static int ls_item(const struct object_id *oid, struct strbuf *base,
- const char *pathname, unsigned mode, void *cbdata)
+static void render_ls_item(const struct object_id *oid, const char *pathname,
+ unsigned mode, struct walk_tree_context *walk_tree_ctx)
{
- struct walk_tree_context *walk_tree_ctx = cbdata;
char *name;
struct strbuf fullpath = STRBUF_INIT;
struct strbuf linkpath = STRBUF_INIT;
@@ -278,9 +285,55 @@ cleanup:
free(name);
strbuf_release(&fullpath);
strbuf_release(&class);
+}
+
+static int ls_item(const struct object_id *oid, struct strbuf *base,
+ const char *pathname, unsigned mode, void *cbdata)
+{
+ struct walk_tree_context *walk_tree_ctx = cbdata;
+
+ /* When grouping directories first, collect the entries now and render
+ * them once the whole level has been read (see ls_flush). */
+ if (ctx.cfg.enable_tree_group_dirs) {
+ struct tree_ls_entry *e;
+ ALLOC_GROW(walk_tree_ctx->entries, walk_tree_ctx->entries_nr + 1,
+ walk_tree_ctx->entries_alloc);
+ e = &walk_tree_ctx->entries[walk_tree_ctx->entries_nr++];
+ oidcpy(&e->oid, oid);
+ e->name = xstrdup(pathname);
+ e->mode = mode;
+ return 0;
+ }
+
+ render_ls_item(oid, pathname, mode, walk_tree_ctx);
return 0;
}
+/* Render any entries collected by ls_item, directories first and then the
+ * rest, keeping git's ordering within each group. A no-op unless directory
+ * grouping is enabled, in which case nothing was collected. */
+static void ls_flush(struct walk_tree_context *walk_tree_ctx)
+{
+ size_t i;
+
+ for (i = 0; i < walk_tree_ctx->entries_nr; i++) {
+ struct tree_ls_entry *e = &walk_tree_ctx->entries[i];
+ if (S_ISDIR(e->mode))
+ render_ls_item(&e->oid, e->name, e->mode, walk_tree_ctx);
+ }
+ for (i = 0; i < walk_tree_ctx->entries_nr; i++) {
+ struct tree_ls_entry *e = &walk_tree_ctx->entries[i];
+ if (!S_ISDIR(e->mode))
+ render_ls_item(&e->oid, e->name, e->mode, walk_tree_ctx);
+ }
+
+ for (i = 0; i < walk_tree_ctx->entries_nr; i++)
+ free(walk_tree_ctx->entries[i].name);
+ free(walk_tree_ctx->entries);
+ walk_tree_ctx->entries = NULL;
+ walk_tree_ctx->entries_nr = walk_tree_ctx->entries_alloc = 0;
+}
+
static void ls_head(void)
{
cgit_print_layout_start();
@@ -315,6 +368,7 @@ static void ls_tree(const struct object_id *oid, const char *path, struct walk_t
ls_head();
read_tree(the_repository, tree, &paths, ls_item, walk_tree_ctx);
+ ls_flush(walk_tree_ctx);
ls_tail();
}
@@ -395,9 +449,10 @@ void cgit_print_tree(const char *rev, char *path)
read_tree(the_repository, repo_get_commit_tree(the_repository, commit),
&paths, walk_tree, &walk_tree_ctx);
- if (walk_tree_ctx.state == 1)
+ if (walk_tree_ctx.state == 1) {
+ ls_flush(&walk_tree_ctx);
ls_tail();
- else if (walk_tree_ctx.state == 2)
+ } else if (walk_tree_ctx.state == 2)
cgit_print_layout_end();
else
cgit_print_error_page(404, "Not found", "Path not found");