47QString InjaBridge::renderErrorText(
const RenderContext &context,
const QString &message)
49 const auto name = [](
const QString &value) {
return value.isEmpty() ? u"<unknown>"_s : value; };
50 return u"Failed to render page '"_s + name(context.page) + u"' with template '"_s
51 + name(context.templatePath) + u"' in format '"_s + name(context.format) + u"': "_s
156 if (!spans.is_array()) {
157 qWarning(
"render_signature_spans: expected JSON array, got %s",
162 const bool isMarkdown = format.contains(
"markdown"_L1, Qt::CaseInsensitive);
165 for (
const auto &s : spans) {
167 result += renderSpanMarkdown(s);
170 const auto role = s.value(
"role",
"");
171 const auto text = s.value(
"text",
"");
172 const bool hasHref = s.contains(
"href");
173 const auto href = s.value(
"href",
"");
175 if (role ==
"extra") {
176 result += R"(<code class="details extra" translate="no">)";
177 if (s.contains(
"children") && s[
"children"].is_array()) {
178 for (
const auto &c : s[
"children"]) {
179 if (c.value(
"role",
"") ==
"external-ref")
180 result +=
"<a href=\"" + c.value(
"href",
"") +
"\">"
181 + escapeHtml(c.value(
"text",
"")) +
"</a>";
183 result += escapeHtml(c.value(
"text",
""));
186 result += escapeHtml(text);
189 }
else if (role ==
"type") {
190 result += R"(<span class="type">)";
192 result +=
"<a href=\"" + href +
"\">";
193 result += escapeHtml(text);
197 }
else if (role ==
"name") {
198 result += R"(<span class="name">)";
200 result +=
"<a href=\"" + href +
"\">";
201 result += escapeHtml(text);
205 }
else if (role ==
"parameter") {
206 result +=
"<i>" + escapeHtml(text) +
"</i>";
207 }
else if (role ==
"external-ref") {
208 result +=
"<a href=\"" + href +
"\">" + escapeHtml(text) +
"</a>";
209 }
else if (role ==
"template-decl") {
210 result += R"(<span class="template-decl">)";
211 result += escapeHtml(text);
212 if (s.contains(
"children") && s[
"children"].is_array()) {
213 for (
const auto &c : s[
"children"]) {
214 const auto childRole = c.value(
"role",
"");
215 const auto childText = c.value(
"text",
"");
216 const bool childHasHref = c.contains(
"href");
217 const auto childHref = c.value(
"href",
"");
218 if (childRole ==
"type") {
219 result += R"(<span class="type">)" + escapeHtml(childText)
221 }
else if (childRole ==
"link") {
222 result += renderLinkSpan(childText, childHref, childHasHref, isMarkdown);
224 result += escapeHtml(childText);
229 }
else if (role ==
"link") {
230 result += renderLinkSpan(text, href, hasHref, isMarkdown);
232 result += escapeHtml(text);
240 env.add_callback(
"escape_html", 1, [](inja::Arguments &args) {
241 return escapeHtml(args.at(0)->get<std::string>());
244 env.add_callback(
"render_signature_spans", 1, [format](inja::Arguments &args) {
245 return renderSignatureSpans(*args.at(0), format);
255 env.add_callback(
"list_separator", 2, [](inja::Arguments &args) {
256 const auto pos = args.at(0)->get<qsizetype>();
257 const auto total = args.at(1)->get<qsizetype>();
258 return TextUtils::separator(pos, total).toStdString();
261 env.add_callback(
"escape_md_table", 1, [](inja::Arguments &args) {
262 auto input = args.at(0)->get<std::string>();
264 buffer.reserve(input.size() + input.size() / 8);
265 for (
char c : input) {
289 env.add_callback(
"is_odd", 1, [](inja::Arguments &args) {
290 return args.at(0)->get<qsizetype>() % 2 != 0;
420nlohmann::json InjaBridge::toInjaJson(
const QJsonObject &obj)
422 nlohmann::json result = nlohmann::json::object();
424 for (
const auto &[key, value] : obj.asKeyValueRange())
425 result[key.toString().toUtf8().toStdString()] = toInjaJson(value);
460InjaBridge::RenderResult InjaBridge::render(
const QString &templateStr,
const QJsonObject &data,
461 const RenderContext &context)
464 inja::Environment env;
469 env.set_line_statement(
"%!");
470 env.set_trim_blocks(
true);
471 env.set_lstrip_blocks(
true);
472 registerCallbacks(env, context.format);
473 nlohmann::json jsonData = toInjaJson(data);
474 std::string templateUtf8 = templateStr.toUtf8().toStdString();
475 return QString::fromUtf8(env.render(templateUtf8, jsonData).c_str());
477 return renderWithPolicy(context, render);
497InjaBridge::RenderResult InjaBridge::render(
const QString &templateStr,
const QJsonObject &data,
498 const IncludeCallback &includeCallback,
499 const RenderContext &context)
502 inja::Environment env;
503 env.set_line_statement(
"%!");
504 env.set_trim_blocks(
true);
505 env.set_lstrip_blocks(
true);
506 registerCallbacks(env, context.format);
507 env.set_search_included_templates_in_files(
false);
508 env.set_include_callback(
509 [&includeCallback, &env](
const std::filesystem::path & ,
510 const std::string &name) -> inja::Template {
511 const auto content = includeCallback(QString::fromStdString(name));
513 INJA_THROW(inja::FileError(
"include not found: '" + name +
"'"));
514 return env.parse(content->toUtf8().toStdString());
517 nlohmann::json jsonData = toInjaJson(data);
518 std::string templateUtf8 = templateStr.toUtf8().toStdString();
519 return QString::fromUtf8(env.render(templateUtf8, jsonData).c_str());
521 return renderWithPolicy(context, render);
535InjaBridge::RenderResult InjaBridge::renderFile(
const QString &templatePath,
536 const QJsonObject &data,
537 const RenderContext &context)
540 inja::Environment env;
541 env.set_line_statement(
"%!");
542 env.set_trim_blocks(
true);
543 env.set_lstrip_blocks(
true);
544 registerCallbacks(env, context.format);
545 nlohmann::json jsonData = toInjaJson(data);
546 std::string pathUtf8 = templatePath.toUtf8().toStdString();
547 return QString::fromUtf8(env.render_file(pathUtf8, jsonData).c_str());
549 return renderWithPolicy(context, render);