git / brickware / marrow.git - 9471250

(7 hours ago)commit 9471250: breadcrumb fixes

Summary | History | Files

commit 9471250

authorTanner Stenson <tanner@brickware.sh>
dateThu Jan 8 14:31:42 2026 -0500

message

breadcrumb fixes

diff

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);