#include "text.hpp" namespace Nimbin { namespace Text { DynArray wrap_String(const std::string& text, size_t max_chars) { std::string word; std::string current_line; DynArray lines; auto flush_line = [&]() { while (!current_line.empty() && current_line.back() == ' ') current_line.pop_back(); lines.push_back(current_line); current_line.clear(); }; auto flush_word = [&]() { if (word.empty()) return; if (current_line.size() + word.size() + (current_line.empty() ? 0 : 1) > max_chars) { flush_line(); } if (!current_line.empty()) current_line += ' '; current_line += word; word.clear(); }; for (char c : text) { if (c == '\n') { flush_word(); flush_line(); } else if (c == ' ' || c == '\t') { flush_word(); } else { word += c; } } flush_word(); flush_line(); return lines; } std::string ascii_Sanitize(const std::string& in) { std::string out; out.reserve(in.size()); size_t i = 0; while (i < in.size()) { const unsigned char c = static_cast(in[i]); if (c < 0x80) { out += static_cast(c); ++i; continue; } // U+2000–U+20FF punctuation block: E2 80 xx if (c == 0xE2 && i + 2 < in.size() && static_cast(in[i + 1]) == 0x80) { const unsigned char c3 = static_cast(in[i + 2]); switch (c3) { case 0x98: case 0x99: out += '\''; break; // ‘ ’ case 0x9C: case 0x9D: out += '"'; break; // “ ” case 0x93: case 0x94: out += '-'; break; // – — default: out += '\''; break; } i += 3; continue; } // Any other multibyte sequence: one '?', skip continuation bytes. out += '?'; ++i; while (i < in.size() && (static_cast(in[i]) & 0xC0) == 0x80) ++i; } return out; } } // namespace Text } // namespace Nimbin