Escaping, table layout, and document fixes
Quoted Klammertext specials (^@ ^| ^# ^^ ^: ^*) and ^'...'^ regions now survive re-processing (held as escape markers until final output); :after_apply phase functions receive and return raw target text. Tables: :hpos element position (center|left|right|<length>) replaces the unimplemented :center/:indent; the ranged cell override is renamed :justify; :column_width works in html (colgroup widths) and gains 'fill' -- the remaining width, capped at the column's widest entry, in both targets; a table wider than the text column warns on the console; table edges without an outer line set their text flush on the margins. @document: no empty title bar for untitled documents; @vfill fills to the bottom of the window in html (pure CSS); @vspace in plain text; new @dot klammer; monospace email links.
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
||||
#include "target.h"
|
||||
#include "log.h"
|
||||
#include "show.h"
|
||||
@@ -85,20 +88,60 @@ std::string Target::escape_text(std::string text) const
|
||||
std::string Target::unescape_text(std::string text) const
|
||||
{
|
||||
// Restore KTESC markers to original characters (for programmatic use)
|
||||
for (const auto& [ch, repl] : m_escapes) {
|
||||
text = string_replace(text, escape_marker(ch), ch);
|
||||
}
|
||||
return text;
|
||||
return ktesc_resolve(text);
|
||||
}
|
||||
|
||||
std::string Target::resolve_escapes(std::string text) const
|
||||
{
|
||||
// Target-declared escapes first (marker -> declared replacement), then
|
||||
// the generic decode for the remaining markers (marker -> the character
|
||||
// itself: quoted Klammertext specials and literal-span content).
|
||||
for (const auto& [ch, repl] : m_escapes) {
|
||||
text = string_replace(text, escape_marker(ch), repl);
|
||||
}
|
||||
return ktesc_resolve(text);
|
||||
}
|
||||
|
||||
std::string ktesc_resolve(std::string text)
|
||||
{
|
||||
// Hand-rolled scan: no std::regex here, this runs over document-sized
|
||||
// strings.
|
||||
static const std::string tag = "KTESC";
|
||||
size_t pos = 0;
|
||||
while ((pos = text.find(tag, pos)) != std::string::npos) {
|
||||
size_t start = pos + tag.size();
|
||||
size_t close = text.find(tag, start);
|
||||
if (close == std::string::npos) break;
|
||||
size_t len = close - start;
|
||||
bool is_hex = len > 0 && len % 4 == 0 &&
|
||||
std::all_of(text.begin() + start, text.begin() + close,
|
||||
[](unsigned char c) { return std::isxdigit(c) != 0; });
|
||||
if (!is_hex) {
|
||||
// Not a marker body; the closing tag may open a real marker.
|
||||
pos = start;
|
||||
continue;
|
||||
}
|
||||
std::string chars {};
|
||||
for (size_t i = start; i < close; i += 4)
|
||||
chars += (char)std::stoi(text.substr(i, 4), nullptr, 16);
|
||||
text.replace(pos, close + tag.size() - pos, chars);
|
||||
pos += chars.size();
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
std::string hide_structural_characters(const std::string& s)
|
||||
{
|
||||
std::string result {};
|
||||
for (char c : s) {
|
||||
if (c == '@' || c == '|' || c == '#' || c == '^' || c == ':' || c == '*')
|
||||
result += Target::escape_marker(std::string(1, c));
|
||||
else
|
||||
result += c;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void Target::add_after_apply(std::string function_specs)
|
||||
{
|
||||
for (auto f : regex_split(function_specs, std::regex(R"(\s+;\s+)"), true)) {
|
||||
|
||||
Reference in New Issue
Block a user