commit 952baf777eb0b9dafd69967af166c1df4c001279
parent 76340912c8aa23b13a3f4893f93d2bd7430b1beb
Author: Nathaniel Chappelle <nathaniel@chappelle.dev>
Date: Thu, 29 Jan 2026 23:30:22 -0800
Details and summaries working well to provide threading and dropdowns
Diffstat:
3 files changed, 58 insertions(+), 35 deletions(-)
diff --git a/setup-mock-maildir b/setup-mock-maildir
@@ -333,5 +333,5 @@ echo " - Standalone announcements"
echo " - Very deep thread (10 levels)"
echo ""
echo "To index with notmuch:"
-echo " notmuch new --maildir=$MAILDIR"
-echo " notmuch show --format=json '*' | ./stamail -o archive"
+echo " notmuch new "
+echo " notmuch show --format=sexp '*' | ./stamail "
diff --git a/stamail.c b/stamail.c
@@ -380,43 +380,57 @@ static int write_message(const char *output_dir, struct message *m) {
return 0;
}
+static void render_message_line(FILE *fp,
+ struct message *m) {
+ unsigned long hash = hash_msgid(m->id, m->id_len);
+
+ /* subject link */
+ fprintf(fp, "<a href=\"msg-%08lx.html\">", hash);
+ fprinthtml(fp, m->subject, m->subject_len);
+ fprinthtml(fp, " <", 2);
+ fprinthtml(fp, m->from, m->from_len);
+ fprinthtml(fp, ">", 1);
+ fprintf(fp, "</a>");
+
+ /* inline details for body */
+ if (m->body && m->body_len > 0) {
+ fprintf(fp, " ");
+ fprintf(fp, "<details>");
+ fprintf(fp, "<summary>+</summary>");
+ fprintf(fp, "<div class=\"body\">");
+ fprinthtml(fp, m->body, m->body_len);
+ fprintf(fp, "</div>");
+ fprintf(fp, "</details>");
+ }
+}
+
static void render_thread_ascii(FILE *fp,
struct thread_node *n,
const char *prefix,
- int is_last)
-{
+ int is_last) {
char next_prefix[1024];
- /* branch marker */
- fprintf(fp, "%s%s ", prefix, is_last ? "\\-" : "+-");
-
- /* link to message */
- unsigned long hash =
- hash_msgid(n->msg->id, n->msg->id_len);
+ fprintf(fp, "%s%s ",
+ prefix,
+ is_last ? "└─" : "├─");
- fprintf(fp, "<a href=\"msg-%08lx.html\">", hash);
- fprinthtml(fp,
- n->msg->subject,
- n->msg->subject_len);
- fprintf(fp, "</a>\n");
+ render_message_line(fp, n->msg);
+ fputc('\n', fp);
- /* extend prefix */
snprintf(next_prefix, sizeof(next_prefix),
- "%s%s ",
+ "%s%s",
prefix,
- is_last ? " " : "| ");
+ is_last ? " " : "│ ");
- /* walk children */
- struct thread_node *c = n->child;
- while (c) {
+ for (struct thread_node *c = n->child; c; c = c->sibling) {
render_thread_ascii(fp,
c,
next_prefix,
c->sibling == NULL);
- c = c->sibling;
}
}
+
static int write_threads(const char *output_dir,
const char *archive_name,
struct thread_node **threads,
@@ -441,8 +455,7 @@ static int write_threads(const char *output_dir,
fprintf(fp, "</nav>\n");
fprintf(fp,
- "<pre style=\"font-family: monospace;"
- "white-space: pre; line-height: 1.3;\">\n");
+ "<pre class=\"threads\">\n");
for (int i = 0; i < num_threads; i++) {
struct thread_node *r = *threads++;
@@ -451,22 +464,26 @@ static int write_threads(const char *output_dir,
unsigned long hash =
hash_msgid(r->msg->id, r->msg->id_len);
- fprintf(fp, "<a href=\"msg-%08lx.html\">", hash);
- fprinthtml(fp,
- r->msg->subject,
- r->msg->subject_len);
- fprintf(fp, "</a>\n");
-
- /* children */
- struct thread_node *c = r->child;
- while (c) {
+ fprintf(fp, "<details open class=\"threads\">\n");
+ fprintf(fp, "<summary>");
+
+ /* root rendered as tree head */
+ fprintf(fp, "└─ ");
+ render_message_line(fp, r->msg);
+
+ fprintf(fp, "</summary>\n");
+
+ /* children share the same tree */
+ for (struct thread_node *c = r->child; c; c = c->sibling) {
render_thread_ascii(fp,
c,
- "",
+ " ",
c->sibling == NULL);
- c = c->sibling;
}
+ fprintf(fp, "</details>\n");
+
+
fprintf(fp, "\n");
}
diff --git a/style.css b/style.css
@@ -12,3 +12,9 @@ td.from { width: 250px; }
td.subject a { color: #0066cc; text-decoration: none; }
td.subject a:hover { text-decoration: underline; }
tr:hover { background: #f5f5f5; }
+details { display: inline; }
+summary { display: inline; cursor: pointer; color: #666; }
+summary::marker { display: none; }
+.body { margin-top: 0.5em; margin-left: 4ch; white-space: pre-wrap; color: #222; }
+pre.threads { font-family: monospace; white-space: pre; line-height: 1.0; margin: 0; }
+