aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason A. Dönerfield <no-replay@sl0p.foo>2026-07-18 21:25:47 +0200
committerJason A. Dönerfield <no-replay@sl0p.foo>2026-07-18 21:31:00 +0200
commite207a823d2db8c99f47736c7c2d61709b8ef4cbd (patch)
tree9693e67ae364642284fc2ce2fb4015d244f8e9d8
parentbuild: fix empty version on tagless clones; mark version -sl0p (diff)
downloadcgit-e207a823d2db8c99f47736c7c2d61709b8ef4cbd.tar.gz
cgit-e207a823d2db8c99f47736c7c2d61709b8ef4cbd.tar.xz
cgit-e207a823d2db8c99f47736c7c2d61709b8ef4cbd.zip
ui-tree: render folder README under the directory listing
When browsing a tree, detect the best README (readme[.md/.markdown/.mkd/ .rst/.txt] or bare, case-insensitive, most-preferred extension wins) among the directory entries and render it through the about-filter beneath the file list, GitHub-style. The filter gets the readme path as argv[1] so the md2html relative-link rewriting resolves against the readme dir.
-rw-r--r--ui-tree.c58
1 files changed, 54 insertions, 4 deletions
diff --git a/ui-tree.c b/ui-tree.c
index 5ac8c9a..fd174b5 100644
--- a/ui-tree.c
+++ b/ui-tree.c
@@ -11,14 +11,51 @@
#include "cgit.h"
#include "ui-tree.h"
#include "html.h"
+#include "ui-blob.h"
#include "ui-shared.h"
struct walk_tree_context {
char *curr_rev;
char *match_path;
int state;
+ /* Best README found in the directory currently being listed, so we can
+ * render it (GitHub-style) under the file list. */
+ char *readme_path;
+ int readme_rank;
};
+/* Rank a directory entry as a renderable README: 0 = not a readme, higher =
+ * more preferred. "readme" + a known extension, case-insensitive. */
+static int readme_rank(const char *name)
+{
+ static const char * const exts[] = {
+ "", ".txt", ".rst", ".mkd", ".mdown", ".markdown", ".md"
+ };
+ const char *rest;
+ int i;
+
+ if (strncasecmp(name, "readme", 6))
+ return 0;
+ rest = name + 6;
+ for (i = ARRAY_SIZE(exts) - 1; i >= 0; i--)
+ if (!strcasecmp(rest, exts[i]))
+ return i + 1;
+ return 0;
+}
+
+/* Render the best README of the just-listed directory through the about-filter,
+ * so browsing a tree shows the folder's readme beneath the listing. */
+static void print_dir_readme(struct walk_tree_context *walk_tree_ctx)
+{
+ if (!walk_tree_ctx->readme_path || !ctx.repo->about_filter)
+ return;
+ html("<div id='summary' class='dir-readme'>");
+ cgit_open_filter(ctx.repo->about_filter, walk_tree_ctx->readme_path);
+ cgit_print_file(walk_tree_ctx->readme_path, walk_tree_ctx->curr_rev, 1);
+ cgit_close_filter(ctx.repo->about_filter);
+ html("</div>\n");
+}
+
static void print_text_buffer(const char *name, char *buf, unsigned long size)
{
unsigned long lineno, idx;
@@ -216,6 +253,15 @@ static int ls_item(const struct object_id *oid, struct strbuf *base,
strbuf_addf(&fullpath, "%s%s%s", ctx.qry.path ? ctx.qry.path : "",
ctx.qry.path ? "/" : "", name);
+ if (S_ISREG(mode)) {
+ int rank = readme_rank(name);
+ if (rank > walk_tree_ctx->readme_rank) {
+ walk_tree_ctx->readme_rank = rank;
+ free(walk_tree_ctx->readme_path);
+ walk_tree_ctx->readme_path = xstrdup(fullpath.buf);
+ }
+ }
+
if (!S_ISGITLINK(mode)) {
type = odb_read_object_info(the_repository->objects, oid, &size);
if (type == OBJ_BAD) {
@@ -293,9 +339,10 @@ static void ls_head(void)
html("</tr>\n");
}
-static void ls_tail(void)
+static void ls_tail(struct walk_tree_context *walk_tree_ctx)
{
html("</table>\n");
+ print_dir_readme(walk_tree_ctx);
cgit_print_layout_end();
}
@@ -315,7 +362,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_tail();
+ ls_tail(walk_tree_ctx);
}
@@ -368,7 +415,9 @@ void cgit_print_tree(const char *rev, char *path)
};
struct walk_tree_context walk_tree_ctx = {
.match_path = path,
- .state = 0
+ .state = 0,
+ .readme_path = NULL,
+ .readme_rank = 0
};
if (!rev)
@@ -396,7 +445,7 @@ 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)
- ls_tail();
+ ls_tail(&walk_tree_ctx);
else if (walk_tree_ctx.state == 2)
cgit_print_layout_end();
else
@@ -404,4 +453,5 @@ void cgit_print_tree(const char *rev, char *path)
cleanup:
free(walk_tree_ctx.curr_rev);
+ free(walk_tree_ctx.readme_path);
}