(7 hours ago)commit 9471250: breadcrumb fixes
| author | Tanner Stenson <tanner@brickware.sh> |
| date | Thu Jan 8 14:31:42 2026 -0500 |
breadcrumb fixes
commit 94712501b79ca46d9cdbb65b28b96f6db56b001a
Author: Tanner Stenson <tanner@brickware.sh>
Date: Thu Jan 8 14:31:42 2026 -0500
breadcrumb fixes
diff --git a/marrow-static.c b/marrow-static.c
index ab15d32..e8823a7 100644
--- a/marrow-static.c
+++ b/marrow-static.c
@@ -745,6 +745,9 @@ generate_branch_tree_page(FILE *out, const char *repo_path, const char *repo_nam
fprintf(out, "</small></p>\n");
}
+ /* Display tree path breadcrumb */
+ fprintf(out, "<p><small>tree</small></p>\n");
+
/* Navigation */
fprintf(out, "<p><strong>Files</strong> | <a href=\"../history/\">History</a></p>\n");
@@ -865,132 +868,10 @@ generate_branch_tree_page(FILE *out, const char *repo_path, const char *repo_nam
return 1;
}
-static void
-generate_tree_path_header(FILE *out, const char *repo_name, const char *ref,
- const char *tree_path) {
- fprintf(out, "<!DOCTYPE html>\n");
- fprintf(out, "<html>\n<head>\n");
- fprintf(out, "<meta charset=\"utf-8\">\n");
- fprintf(out, "<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n");
- fprintf(out, "<title>%s - %s - %s</title>\n", repo_name, ref, tree_path);
- fprintf(out, "<style>\n");
- fprintf(out, "body{font-family:monospace;max-width:900px;margin:40px auto;padding:0 20px;line-height:1.6;}\n");
- fprintf(out, "a{color:#00f;text-decoration:none;}\n");
- fprintf(out, "a:hover{text-decoration:underline;}\n");
- fprintf(out, "table{border-collapse:collapse;width:100%%;}\n");
- fprintf(out, "th,td{text-align:left;padding:8px 12px;border-bottom:1px solid #ddd;}\n");
- fprintf(out, "th{font-weight:bold;}\n");
- fprintf(out, "pre{background:#f5f5f5;padding:10px;overflow-x:auto;}\n");
- fprintf(out, "code{background:#f5f5f5;padding:2px 4px;}\n");
- fprintf(out, ".header{border-bottom:2px solid #000;margin-bottom:20px;padding-bottom:10px;}\n");
- fprintf(out, ".footer{margin-top:40px;padding-top:20px;border-top:1px solid #ddd;font-size:0.9em;color:#666;}\n");
- fprintf(out, "</style>\n");
- fprintf(out, "</head>\n<body>\n");
-
- /* Generate breadcrumb with full path including tree path */
- fprintf(out, "<div class=\"header\"><h1>");
-
- /* Count segments in repo_name and tree_path */
- int32_t repo_segments = 1;
- for (const char *p = repo_name; *p; p++) {
- if ('/' == *p) repo_segments++;
- }
-
- int32_t tree_segments = 0;
- if (tree_path && tree_path[0]) {
- tree_segments = 1;
- for (const char *p = tree_path; *p; p++) {
- if ('/' == *p) tree_segments++;
- }
- }
-
- /* Root "git" link */
- fprintf(out, "<a href=\"");
- /* From tree/path/to/file: up tree_segments, then up 3 (tree/, ref/, branch/), then repo_segments */
- for (int32_t i = 0; i < tree_segments + 3 + repo_segments; i++) {
- fprintf(out, "../");
- }
- fprintf(out, "\">git</a>");
-
- /* Repository path segments */
- if (repo_name && repo_name[0]) {
- char path_copy[PATH_MAX];
- snprintf(path_copy, sizeof(path_copy), "%s", repo_name);
- char *token = strtok(path_copy, "/");
- int32_t current_segment = 0;
-
- while (token) {
- fprintf(out, " / ");
- fprintf(out, "<a href=\"");
- int32_t levels_up = tree_segments + 3 + (repo_segments - current_segment - 1);
- for (int32_t i = 0; i < levels_up; i++) {
- fprintf(out, "../");
- }
- fprintf(out, "\">");
- html_escape(out, token);
- fprintf(out, "</a>");
-
- current_segment++;
- token = strtok(NULL, "/");
- }
- }
-
- /* Branch/commit reference */
- fprintf(out, " / <a href=\"");
- for (int32_t i = 0; i < tree_segments + 2; i++) { /* Up to branch/ref level */
- fprintf(out, "../");
- }
- fprintf(out, "\">");
- html_escape(out, ref);
- fprintf(out, "</a>");
-
- /* Tree root link */
- fprintf(out, " / <a href=\"");
- for (int32_t i = 0; i < tree_segments + 1; i++) { /* Up to tree/ level */
- fprintf(out, "../");
- }
- fprintf(out, "\">tree</a>");
-
- /* Tree path segments */
- if (tree_path && tree_path[0]) {
- char tree_copy[PATH_MAX];
- snprintf(tree_copy, sizeof(tree_copy), "%s", tree_path);
- char *token = strtok(tree_copy, "/");
-
- while (token) {
- fprintf(out, " / ");
-
- char *next = strtok(NULL, "/");
- if (next) {
- /* Not last segment - make it a link */
- fprintf(out, "<a href=\"");
- int32_t remaining = 1;
- for (char *p = next; *p; p++) {
- if ('/' == *p) remaining++;
- }
- for (int32_t i = 0; i < remaining + 1; i++) {
- fprintf(out, "../");
- }
- fprintf(out, "\">");
- html_escape(out, token);
- fprintf(out, "</a>");
- token = next;
- } else {
- /* Last segment - no link */
- html_escape(out, token);
- token = NULL;
- }
- }
- }
-
- fprintf(out, "</h1></div>\n");
-}
-
static int32_t
generate_tree_path_page(FILE *out, const char *repo_path, const char *repo_name,
const char *ref, const char *tree_path, const char *page_title) {
- (void)page_title; /* Unused - kept for function signature compatibility */
- generate_tree_path_header(out, repo_name, ref, tree_path);
+ generate_html_header(out, repo_name, page_title);
/* Get latest commit for this path */
char cmd[MAX_CMD_LEN];
@@ -1030,6 +911,43 @@ generate_tree_path_page(FILE *out, const char *repo_path, const char *repo_name,
fprintf(out, "</small></p>\n");
}
+ /* Display tree path breadcrumb */
+ if (tree_path && tree_path[0]) {
+ fprintf(out, "<p><small>");
+ fprintf(out, "<a href=\"../\">tree</a>");
+
+ char path_copy[PATH_MAX];
+ snprintf(path_copy, sizeof(path_copy), "%s", tree_path);
+ char *token = strtok(path_copy, "/");
+
+ while (token) {
+ fprintf(out, " / ");
+
+ char *next = strtok(NULL, "/");
+ if (next) {
+ /* Not last segment - make it a link */
+ fprintf(out, "<a href=\"");
+ int32_t remaining = 1;
+ for (char *p = next; *p; p++) {
+ if ('/' == *p) remaining++;
+ }
+ for (int32_t i = 0; i < remaining + 1; i++) {
+ fprintf(out, "../");
+ }
+ fprintf(out, "\">");
+ html_escape(out, token);
+ fprintf(out, "</a>");
+ token = next;
+ } else {
+ /* Last segment - no link */
+ html_escape(out, token);
+ token = NULL;
+ }
+ }
+
+ fprintf(out, "</small></p>\n");
+ }
+
/* Check if path is tree or blob */
snprintf(cmd, sizeof(cmd),
"cd '%s' && git cat-file -t %s:'%s' 2>/dev/null",
@@ -1052,6 +970,56 @@ generate_tree_path_page(FILE *out, const char *repo_path, const char *repo_name,
fprintf(out, "<h2>%s/</h2>\n", tree_path);
fprintf(out, "<h3>files</h3>\n");
+ /* Display repository structure breadcrumb */
+ fprintf(out, "<p><small>");
+
+ /* Count depth to calculate relative paths */
+ int32_t depth = 1;
+ for (const char *p = tree_path; *p; p++) {
+ if ('/' == *p) depth++;
+ }
+
+ /* Link to root tree */
+ fprintf(out, "<a href=\"");
+ for (int32_t i = 0; i < depth; i++) {
+ fprintf(out, "../");
+ }
+ fprintf(out, "\">");
+ html_escape(out, repo_name);
+ fprintf(out, "</a>");
+
+ /* Parse and link path segments */
+ char path_copy[PATH_MAX];
+ snprintf(path_copy, sizeof(path_copy), "%s", tree_path);
+ char *token = strtok(path_copy, "/");
+
+ while (token) {
+ fprintf(out, " / ");
+
+ char *next = strtok(NULL, "/");
+ if (next) {
+ /* Not last segment - make it a link */
+ fprintf(out, "<a href=\"");
+ int32_t remaining = 1;
+ for (char *p = next; *p; p++) {
+ if ('/' == *p) remaining++;
+ }
+ for (int32_t i = 0; i < remaining; i++) {
+ fprintf(out, "../");
+ }
+ fprintf(out, "\">");
+ html_escape(out, token);
+ fprintf(out, "</a>");
+ token = next;
+ } else {
+ /* Last segment - no link */
+ html_escape(out, token);
+ token = NULL;
+ }
+ }
+
+ fprintf(out, "</small></p>\n");
+
snprintf(cmd, sizeof(cmd),
"cd '%s' && git ls-tree -l %s:'%s' 2>/dev/null",
repo_path, ref, tree_path);