diff -r 1c80ba4a0d62 -r 586dcd606e47 src/html.cpp --- a/src/html.cpp Fri Jun 20 17:15:18 2025 +0200 +++ b/src/html.cpp Sat Jun 28 11:32:08 2025 +0200 @@ -24,6 +24,7 @@ #include "html.h" +#include #include #include @@ -36,7 +37,6 @@ static const char *tabs = " "; static void indent(int change = 0) { indentation += change; - assert(indentation >= 0); assert(indentation <= max_indentation); fwrite(tabs, 4, indentation, stdout); } @@ -61,6 +61,9 @@ case '>': buffer.append(">"); break; + case '#': + buffer.append("#"); + break; default: buffer.append(&pos, 1); break; @@ -79,22 +82,30 @@ puts(R"( + +
)"); @@ -217,28 +326,58 @@ puts(""); } -void html::cell(year_month_day ymd, unsigned commits) { +void html::cell(year_month_day ymd, const fm::commits &commits) { const char *color_class; - if (commits == 0) { + if (commits.count() == 0) { color_class = "zero-commits"; - } else if (commits == 1) { + } else if (commits.count() == 1) { color_class = "one-commit"; - } else if (commits <= 5) { + } else if (commits.count() <= 5) { color_class = "up-to-5-commits"; - } else if (commits <= 10) { + } else if (commits.count() <= 10) { color_class = "up-to-10-commits"; - } else if (commits <= 20) { + } else if (commits.count() <= 20) { color_class = "up-to-20-commits"; } else { color_class = "commit-spam"; } - indent(); - printf("\n", - color_class, + + + // Format date for display + char date_str[32]; + sprintf(date_str, "%s, %d-%02u-%02u", weekdays[weekday(ymd).iso_encoding() - 1], static_cast(ymd.year()), static_cast(ymd.month()), - static_cast(ymd.day()), - commits, - commits == 1 ? "commit" : "commits"); + static_cast(ymd.day())); + + // Build a JSON array of commit summaries + // We have to iterate in reverse order to sort the summaries chronologically + std::string summaries_json = "["; + for (const auto &summary : commits.summaries | std::views::reverse) { + // Escape quotes in JSON + size_t pos = summary.find('\"'); + if (pos == std::string::npos) { + summaries_json += "\"" + summary + "\","; + } else { + std::string escaped = summary; + do { + escaped.replace(pos, 1, "\\\""); + pos += 2; + } while ((pos = escaped.find('\"', pos)) != std::string::npos); + summaries_json += "\"" + escaped + "\","; + } + } + summaries_json.pop_back(); + summaries_json += "]"; + + indent(); + printf("\n", + color_class, + date_str, + commits.count(), + commits.count() == 1 ? "commit" : "commits", + date_str, + encode(summaries_json).c_str() + ); }