commit 59ed33a4ee177fcff9ce9dfe8082778a772b1547
parent 245296de1a76e46d65ee8ba10ce155c0c4aa56c8
Author: Martin Kloeckner <mjkloeckner@gmail.com>
Date: Wed, 2 Sep 2026 20:50:52 -0300
Add markdown renderer for files other tha `README*`
Diffstat:
| M | stagit.c | | | 129 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------ |
1 file changed, 90 insertions(+), 39 deletions(-)
diff --git a/stagit.c b/stagit.c
@@ -556,7 +556,7 @@ writeheader(FILE *fp, const char *title)
fputs("</td></tr></table>", fp);
fputs("<div id=\"repo-top-buttons\">\n", fp);
- fprintf(fp, "<a <a href=\"https://git.kloeckner.com.ar\">Index</a> ", relpath);
+ // fprintf(fp, "<a <a href=\"https://git.kloeckner.com.ar\">Index</a> ", relpath);
fprintf(fp, "<a href=\"%slog.html\">Commits</a> ", relpath);
fprintf(fp, "<a href=\"%sfiles.html\">Files</a> ", relpath);
fprintf(fp, "<a href=\"%srefs.html\">Refs</a>", relpath);
@@ -1024,6 +1024,57 @@ writeblobraw(const git_blob *blob, const char *fpath, const char *filename, git_
fclose(fp);
}
+void
+process_output_md(const char* text, unsigned int size, void* fp)
+{
+ fprintf((FILE *)fp, "%.*s", size, text);
+}
+
+int
+ismarkdownfile(const char *name)
+{
+ const char *exts[] = { ".md", ".markdown" };
+ const char *dot;
+ size_t i, len;
+
+ if (!name)
+ return 0;
+ dot = strrchr(name, '.');
+ if (!dot)
+ return 0;
+ for (i = 0; i < LEN(exts); i++) {
+ len = strlen(exts[i]);
+ if (!strncasecmp(dot, exts[i], len))
+ return 1;
+ }
+ return 0;
+}
+
+void
+writeblobmd(FILE *fp, const git_blob *blob, const char *rawprefix)
+{
+ const char *s = git_blob_rawcontent(blob);
+ git_off_t len = git_blob_rawsize(blob);
+
+ fputs("<div id=\"md-content\">", fp);
+ if (md_html(s, len, process_output_md, fp,
+ MD_FLAG_TABLES |
+ MD_FLAG_TASKLISTS |
+ MD_FLAG_PERMISSIVEEMAILAUTOLINKS |
+ MD_FLAG_PERMISSIVEURLAUTOLINKS, 0))
+ err(1, "error parsing markdown");
+ fputs("</div>\n", fp);
+ fputs("<script>"
+ "document.querySelectorAll('#md-content img').forEach(img => {"
+ "const src = img.getAttribute('src');"
+ "if (src && !src.startsWith('/') && !src.startsWith('http'))"
+ "img.src = '", fp);
+ fputs(rawprefix, fp);
+ fputs("raw/' + src;"
+ "});"
+ "</script>\n", fp);
+}
+
size_t
writeblob(git_object *obj, const char *fpath, const char *rpath, const char *filename, const char *path, size_t filesize)
{
@@ -1087,9 +1138,9 @@ writeblob(git_object *obj, const char *fpath, const char *rpath, const char *fil
"</script>", fp);
fputs("<div id=\"open-file-header\"><div id=\"open-file-name\"><a id=\"file-parent-path\" href=\"", fp);
+ // xmlencode(fp, relpath, strlen(relpath));
// printf("relpath is '%s'\n", relpath);
- // fputs(relpath, fp);
- xmlencode(fp, relpath, strlen(relpath));
+ fputs(relpath, fp);
fputs("file/", fp);
xmlencode(fp, path, strlen(path));
fputs(".html\">", fp);
@@ -1102,6 +1153,12 @@ writeblob(git_object *obj, const char *fpath, const char *rpath, const char *fil
"id=\"line-checkbox\" onchange=\"toggleLineNumbers()\" checked>", fp);
fputs("<label for=\"line-checkbox\">Line numbers</label></div>", fp);
+ if (ismarkdownfile(filename)) {
+ fputs("<div id=\"md-checkbox-div\"><input type=\"checkbox\""
+ "id=\"md-checkbox\" onchange=\"toggleMdView()\" checked>", fp);
+ fputs("<label for=\"md-checkbox\">Render</label></div>", fp);
+ }
+
// fputs("<p id=\"openfile-name\"> ", fp);
// xmlencode(fp, filename, strlen(filename));
// fprintf(fp, " (%zuB)", filesize);
@@ -1111,7 +1168,34 @@ writeblob(git_object *obj, const char *fpath, const char *rpath, const char *fil
if (git_blob_is_binary((git_blob *)obj))
fputs("<p id=\"binary-file\">Binary file.</p>\n", fp);
- else
+ else if (ismarkdownfile(filename)) {
+ fputs("<div id=\"md-view\">", fp);
+ writeblobmd(fp, (git_blob *)obj, relpath);
+ fputs("</div>\n", fp);
+ fputs("<div id=\"source-view\">", fp);
+ lc = writeblobhtml(fp, (git_blob *)obj);
+ fputs("</div>\n", fp);
+ fputs("<script>"
+ "function toggleMdView() {"
+ " var mdCheckbox = document.getElementById('md-checkbox');"
+ " var mdView = document.getElementById('md-view');"
+ " var sourceView = document.getElementById('source-view');"
+ " if (mdView && sourceView) {"
+ " mdView.style.display = mdCheckbox.checked ? 'block' : 'none';"
+ " sourceView.style.display = mdCheckbox.checked ? 'none' : 'block';"
+ " }"
+ " localStorage.setItem('md-checkbox', mdCheckbox.checked);"
+ "}"
+ "document.addEventListener('DOMContentLoaded', function() {"
+ " var mdCheckbox = document.getElementById('md-checkbox');"
+ " var savedState = localStorage.getItem('md-checkbox');"
+ " if (savedState !== null) {"
+ " mdCheckbox.checked = savedState === 'true';"
+ " }"
+ " toggleMdView();"
+ "});"
+ "</script>", fp);
+ } else
lc = writeblobhtml(fp, (git_blob *)obj);
writefooter(fp);
@@ -1500,12 +1584,6 @@ usage(char *argv0)
exit(1);
}
-void
-process_output_md(const char* text, unsigned int size, void* fp)
-{
- fprintf((FILE *)fp, "%.*s", size, text);
-}
-
int
main(int argc, char *argv[])
{
@@ -1655,22 +1733,7 @@ main(int argc, char *argv[])
git_revparse_single(&obj, repo, readmefiles[r]);
const char *s = git_blob_rawcontent((git_blob *)obj);
if (r == 1) {
- git_off_t len = git_blob_rawsize((git_blob *)obj);
- fputs("<div id=\"readme\">", fp);
- if (md_html(s, len, process_output_md, fp,
- MD_FLAG_TABLES |
- MD_FLAG_TASKLISTS |
- MD_FLAG_PERMISSIVEEMAILAUTOLINKS |
- MD_FLAG_PERMISSIVEURLAUTOLINKS, 0))
- err(1, "error parsing markdown");
- fputs("</div>\n", fp);
- fputs("<script>"
- "document.querySelectorAll('#readme img').forEach(img => {"
- "const src = img.getAttribute('src');"
- "if (src && !src.startsWith('/') && !src.startsWith('http'))"
- "img.src = 'raw/' + src;"
- "});"
- "</script>\n", fp);
+ writeblobmd(fp, (git_blob *)obj, "");
} else {
fputs("<pre id=\"readme\">", fp);
xmlencode(fp, s, strlen(s));
@@ -1749,19 +1812,7 @@ main(int argc, char *argv[])
git_revparse_single(&obj, repo, readmefiles[r]);
const char *s = git_blob_rawcontent((git_blob *)obj);
if (r == 1) {
- git_off_t len = git_blob_rawsize((git_blob *)obj);
- fputs("<div id=\"readme\">", fp);
- if (md_html(s, len, process_output_md, fp, MD_FLAG_TABLES | MD_FLAG_TASKLISTS |
- MD_FLAG_PERMISSIVEEMAILAUTOLINKS | MD_FLAG_PERMISSIVEURLAUTOLINKS, 0))
- err(1, "error parsing markdown");
- fputs("</div>\n", fp);
- fputs("<script>"
- "document.querySelectorAll('#readme img').forEach(img => {"
- "const src = img.getAttribute('src');"
- "if (src && !src.startsWith('/') && !src.startsWith('http'))"
- "img.src = 'raw/' + src;"
- "});"
- "</script>\n", fp);
+ writeblobmd(fp, (git_blob *)obj, "");
} else {
fputs("<pre id=\"readme\">", fp);
xmlencode(fp, s, strlen(s));