Verbatim-safe typography, ^-punctuation quoting, full-range ^UUUU^, polyglot html

Typographic transforms (---, quote pairs, ~) no longer touch verbatim
text: @c/@code/@source_listing content and ^'...'^ spans show exactly the
characters written. "^" before any punctuation character quotes it in
every target (the apostrophe excepted: ^' opens a literal span), with the
new :resolve option on @@@target declaring per-target renderings. The
^UUUU^ code-point form accepts 4-6 hex digits, the full Unicode range.
The html output and transform spellings are polyglot (XML-valid), in
preparation for an EPUB target. New suites: transform_test, character_test
(engine), typography_test (SKS).

(from dev 07ce5ea86a0a)
This commit is contained in:
2026-08-23 20:48:26 +02:00
parent d982c0d6cc
commit 37b6ba1c4f
77 changed files with 1665 additions and 1608 deletions

View File

@@ -14,7 +14,7 @@ std::string Target_registry::general_name = "*";
std::string Target_registry::optionset_name = "o";
Target_registry::Target_registry()
: m_parameters(Parameter_set("name | desc :after_apply :after_write :includes :escape | transforms.rest"))
: m_parameters(Parameter_set("name | desc :after_apply :after_write :includes :escape :resolve | transforms.rest"))
{
// Registration order is display order. The two that declare an interface
// come first -- "k" a klammer's, "o" an option set's -- and then "*", the
@@ -47,14 +47,25 @@ void Target_registry::add(std::vector<Katom>::iterator begin, std::vector<Katom>
Target target(values["name"], values["desc"], begin->m_loc);
target.add_transforms(values["transforms"]);
target.add_escapes(values["escape"]);
target.add_resolves(values["resolve"]);
target.add_after_apply(values["after_apply"]);
target.m_includes = word_split(values["includes"]);
// Inherit escapes from included targets
// Inherit escapes AND typographic transforms from included targets: an
// including target renders through the included one's syntax (pdf
// through tex), so both tables apply there too. Inherited entries are
// appended after the including target's own, so a declaration can
// override an inherited pair by declaring its source first.
for (const auto& included : target.m_includes) {
if (m_targets.count(included)) {
for (const auto& esc : m_targets[included].m_escapes) {
target.m_escapes.push_back(esc);
}
for (const auto& tr : m_targets[included].m_transforms) {
target.add_transform(tr.first, tr.second);
}
for (const auto& res : m_targets[included].m_resolves) {
target.m_resolves.push_back(res);
}
}
}
// Registration (and the previous-definition check) goes through
@@ -79,7 +90,7 @@ void Target_registry::check_for_previous_definition(const std::string& name, con
if (has(name)) {
const Target& current = m_targets.at(name);
throw Target_error("Target \"" + name + "\" is already defined:\n " + current.m_loc.desc(),
loc, false);
loc);
}
}