src/html.cpp

changeset 84
7c9dfe5b49b5
parent 81
1ff88eb9555c
equal deleted inserted replaced
83:bb0fc7994d2f 84:7c9dfe5b49b5
94 } 94 }
95 } 95 }
96 return buffer; 96 return buffer;
97 } 97 }
98 98
99 static std::string escape_json(const std::string &raw) {
100 using std::string_view_literals::operator ""sv;
101 auto replace_all = [](std::string str, char chr, std::string_view repl) static {
102 size_t pos = str.find(chr);
103 if (pos == std::string::npos) return str;
104 std::string result = std::move(str);
105 do {
106 result.replace(pos, 1, repl);
107 pos += repl.length();
108 } while ((pos = result.find(chr, pos)) != std::string::npos);
109 return result;
110 };
111 return replace_all(replace_all(raw, '\\', "\\\\"), '\"', "\\\""sv);
112 }
113
114 static std::string build_tag_list(fm::tag_lists tags, bool hide_repo_names) { 99 static std::string build_tag_list(fm::tag_lists tags, bool hide_repo_names) {
115 std::string tags_json; 100 std::string tags_json;
116 if (hide_repo_names) { 101 if (hide_repo_names) {
117 for (const auto &tags_vector: tags | std::views::values) { 102 for (const auto &tags_vector: tags | std::views::values) {
118 for (const auto &tag: tags_vector) { 103 for (const auto &tag: tags_vector) {
119 tags_json += escape_json(tag.message); 104 tags_json += encode(tag.message);
120 tags_json += ' '; 105 tags_json += ' ';
121 } 106 }
122 } 107 }
123 if (!tags_json.empty()) { 108 if (!tags_json.empty()) {
124 tags_json.pop_back(); 109 tags_json.pop_back();
125 } 110 }
126 } else { 111 } else {
127 tags_json += '{'; 112 tags_json += '{';
128 for (const auto &[repo, tags_vector] : tags) { 113 for (const auto &[repo, tags_vector] : tags) {
129 tags_json += "\"" + escape_json(repo) + "\":\""; 114 tags_json += "\"" + encode(repo) + "\":\"";
130 for (const auto &tag: tags_vector) { 115 for (const auto &tag: tags_vector) {
131 tags_json += escape_json(tag.message); 116 tags_json += encode(tag.message);
132 tags_json += ' '; 117 tags_json += ' ';
133 } 118 }
134 if (!tags_vector.empty()) { 119 if (!tags_vector.empty()) {
135 tags_json.pop_back(); 120 tags_json.pop_back();
136 } 121 }
149 if (hide_repo_names) { 134 if (hide_repo_names) {
150 tags_json += '['; 135 tags_json += '[';
151 for (const auto &tags_vector: tags | std::views::values) { 136 for (const auto &tags_vector: tags | std::views::values) {
152 for (const auto &tag: tags_vector) { 137 for (const auto &tag: tags_vector) {
153 tags_json += '"'; 138 tags_json += '"';
154 tags_json += escape_json(tag); 139 tags_json += encode(tag);
155 tags_json += "\","; 140 tags_json += "\",";
156 } 141 }
157 } 142 }
158 if (!tags.empty()) { 143 if (!tags.empty()) {
159 tags_json.pop_back(); 144 tags_json.pop_back();
160 } 145 }
161 tags_json += ']'; 146 tags_json += ']';
162 } else { 147 } else {
163 tags_json += '{'; 148 tags_json += '{';
164 for (const auto &[repo, tags_vector] : tags) { 149 for (const auto &[repo, tags_vector] : tags) {
165 tags_json += "\"" + escape_json(repo) + "\":["; 150 tags_json += "\"" + encode(repo) + "\":[";
166 for (const auto &tag: tags_vector) { 151 for (const auto &tag: tags_vector) {
167 tags_json += '"'; 152 tags_json += '"';
168 tags_json += escape_json(tag); 153 tags_json += encode(tag);
169 tags_json += "\","; 154 tags_json += "\",";
170 } 155 }
171 if (!tags_vector.empty()) { 156 if (!tags_vector.empty()) {
172 tags_json.pop_back(); 157 tags_json.pop_back();
173 } 158 }
514 std::string commit_summary; 499 std::string commit_summary;
515 if (!hide_repo_names) { 500 if (!hide_repo_names) {
516 std::string commit_summary_json; 501 std::string commit_summary_json;
517 commit_summary_json += '{'; 502 commit_summary_json += '{';
518 for (const auto &[repo, count] : summary.commits) { 503 for (const auto &[repo, count] : summary.commits) {
519 commit_summary_json += std::format("\"{}\": {},", escape_json(repo), count); 504 commit_summary_json += std::format("\"{}\": {},", encode(repo), count);
520 } 505 }
521 if (!summary.commits.empty()) { 506 if (!summary.commits.empty()) {
522 commit_summary_json.pop_back(); 507 commit_summary_json.pop_back();
523 } 508 }
524 commit_summary_json += '}'; 509 commit_summary_json += '}';
580 565
581 // Build a JSON object of commit summaries 566 // Build a JSON object of commit summaries
582 auto add_summaries = [](std::string &json, const std::vector<fm::commit_info> &summaries) static { 567 auto add_summaries = [](std::string &json, const std::vector<fm::commit_info> &summaries) static {
583 // We have to iterate in reverse order to sort the summaries chronologically 568 // We have to iterate in reverse order to sort the summaries chronologically
584 for (const auto &summary : summaries | std::views::reverse) { 569 for (const auto &summary : summaries | std::views::reverse) {
585 json += "\"" + escape_json(summary.message) + "\","; 570 json += "\"" + encode(summary.message) + "\",";
586 } 571 }
587 json.pop_back(); 572 json.pop_back();
588 }; 573 };
589 std::string summaries_json; 574 std::string summaries_json;
590 if (hide_repo_names) { 575 if (hide_repo_names) {
594 } 579 }
595 summaries_json += ']'; 580 summaries_json += ']';
596 } else { 581 } else {
597 summaries_json += '{'; 582 summaries_json += '{';
598 for (const auto &[repo, summaries] : commits.summaries) { 583 for (const auto &[repo, summaries] : commits.summaries) {
599 summaries_json += "\"" + escape_json(repo) + "\":["; 584 summaries_json += "\"" + encode(repo) + "\":[";
600 add_summaries(summaries_json, summaries); 585 add_summaries(summaries_json, summaries);
601 summaries_json += "],"; 586 summaries_json += "],";
602 } 587 }
603 if (!commits.summaries.empty()) { 588 if (!commits.summaries.empty()) {
604 summaries_json.pop_back(); 589 summaries_json.pop_back();

mercurial