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

@@ -38,104 +38,6 @@ std::string levels_to_section(std::vector<unsigned int> levels)
int part_number = 1;
int unnumbered_id = 0;
/*
std::tuple<std::string, std::vector<Heading>, std::vector<unsigned int>, unsigned int>
add_section_numbers(const std::string& s, const std::string& basename, std::vector<unsigned int> levels, unsigned int initial_id,
std::map<std::string, std::string>& section_id_map)
{
(void)K::log(3);
auto depth { levels.size() };
std::vector<Heading> headings {};
std::string text { s };
std::regex section_rgx (R"((.*?)<h(\d)(.*?)>(.*?)</h\2>)");
std::regex part_rgx (R"((.*?)<kt-part(.*?)>Part (\d+)\s*<br>\s*(.*?)\s*</kt-part>)");
std::regex id_rgx(R"((.*?)id=\"([-\w]+)\"(.*))");
unsigned int id_number { initial_id };
//std::string result {};
std::stringstream result {};
for (std::string line : regex_split(s, std::regex(R"(\n)"), false)) {
std::smatch match {};
if (std::regex_match(line, match, part_rgx)) {
std::string pre { match[1] };
std::string attr { match[2] };
std::string level { match[3] };
std::string title { match[4] };
std::string id_prefix { "_part_"};
std::string id {};
std::smatch id_match {};
if (std::regex_match(attr, id_match, id_rgx)) {
id = id_match[2];
} else {
id = id_prefix + std::to_string(part_number);
}
//title = "Part " + std::to_string(part_number) + " - " + title;
//std::string section = "Part " + level;
std::string section = "Part " + std::to_string(part_number);
elements_t part_title
{ html::elt("kt-part",
{ html::elt("span", section).attr("class", "sectionnumber"),
html::elt("span", trim(title)).attr("class", "sectiontitle") })
.attr("id", id)
.attr("data-level", level) };
result << pre << part_title << "\n";
headings.push_back(Heading(0, basename, section, id, "0", title));
part_number += 1;
} else if (std::regex_match(line, match, section_rgx)) {
std::string pre { match[1] };
int level { std::stoi(match[2]) };
std::string attr { match[3] };
std::string title { match[4] };
bool numbered = attr.find("numbered") != std::string::npos;
std::string section {};
if (numbered) {
levels[level-1] = levels[level-1] + 1;
for (unsigned int li = level; li < depth; li++)
levels[li] = 0;
section = levels_to_section(levels);
}
std::string id {};
std::smatch id_match {};
if (std::regex_match(attr, id_match, id_rgx)) {
id = id_match[2];
} else {
if (section.size() == 0) {
id = "_su_" + std::to_string(unnumbered_id++);
} else {
id = "_s_" + string_replace(section, ".", "_");
}
}
std::string link_target = file_basename(basename) + link_delimiter + id;
section_id_map[title] = link_target;
//<h1 id="image-tests" style="clear:both;" class="headerlink">
// <span class="sectionnumber">1</span>Image tests</h1>
elements_t title_parts {};
if (numbered) {
title_parts.push_back(html::elt("span", trim(section)).attr("class", "sectionnumber"));
}
title_parts.push_back(html::elt("span", trim(title)).attr("class", "sectiontitle"));
// msg() << "title_parts: " << title_parts << "\n";
elements_t section_title
{ html::elt("h"+std::to_string(level), title_parts)
.attr("id", id)
.attr("data-level", std::to_string(level))};
// msg() << pre << section_title << "\n";
result << pre << section_title << "\n";
headings.push_back(Heading(level, basename, section, id, "0", title));
} else {
result << line << "\n";
}
}
//std::cout << "add_section_numbers: " << result.str() << " "
//<< headings.size() << " " << levels.size() << " " << id_number << "\n";
return std::tuple(result.str(), headings, levels, id_number);
}
*/
std::string make_html_table_of_contents(std::vector<Heading> headings)
{
elements_t toc { html::elt("h1", "Contents") };