33struct WordBreakPropertyInterval {
44constexpr auto g_extend_characters{[]()
constexpr {
46 constexpr size_t size = []()
constexpr {
49 if (interval.property == WBP::Extend) {
57 std::array<Interval, size> result{};
60 if (interval.property == WBP::Extend) {
61 result[index++] = {interval.first, interval.last};
69bool Bisearch(uint32_t ucs,
const std::array<Interval, N>& table) {
70 if (ucs < table.front().first || ucs > table.back().last) {
77 const int mid = (min + max) / 2;
78 if (ucs > table[mid].last) {
80 }
else if (ucs < table[mid].first) {
91template <
class C,
size_t N>
92bool Bisearch(uint32_t ucs,
const std::array<C, N>& table, C* out) {
93 if (ucs < table.front().first || ucs > table.back().last) {
100 const int mid = (min + max) / 2;
101 if (ucs > table[mid].last) {
103 }
else if (ucs < table[mid].first) {
116constexpr uint32_t kEmojiPresentationSelector = 0xFE0F;
118int codepoint_width(uint32_t ucs) {
146 if (start >= input.size()) {
150 const uint8_t C0 = input[start];
153 if ((C0 & 0b1000'0000) == 0b0000'0000) {
154 *ucs = C0 & 0b0111'1111;
160 if ((C0 & 0b1110'0000) == 0b1100'0000 &&
161 start + 1 < input.size()) {
162 const uint8_t C1 = input[start + 1];
164 *ucs += C0 & 0b0001'1111;
166 *ucs += C1 & 0b0011'1111;
172 if ((C0 & 0b1111'0000) == 0b1110'0000 &&
173 start + 2 < input.size()) {
174 const uint8_t C1 = input[start + 1];
175 const uint8_t C2 = input[start + 2];
177 *ucs += C0 & 0b0000'1111;
179 *ucs += C1 & 0b0011'1111;
181 *ucs += C2 & 0b0011'1111;
187 if ((C0 & 0b1111'1000) == 0b1111'0000 &&
188 start + 3 < input.size()) {
189 const uint8_t C1 = input[start + 1];
190 const uint8_t C2 = input[start + 2];
191 const uint8_t C3 = input[start + 3];
193 *ucs += C0 & 0b0000'0111;
195 *ucs += C1 & 0b0011'1111;
197 *ucs += C2 & 0b0011'1111;
199 *ucs += C3 & 0b0011'1111;
216 if (start >= input.size()) {
222 if constexpr (
sizeof(wchar_t) == 4) {
229 int32_t C0 = input[start];
232 if (C0 < 0xd800 || C0 >= 0xdc00) {
239 if (start + 1 >= input.size()) {
244 int32_t C1 = input[start + 1];
245 *ucs = ((C0 & 0x3ff) << 10) + (C1 & 0x3ff) + 0x10000;
251 return Bisearch(ucs, g_extend_characters);
267 const uint32_t LINE_FEED = 10;
268 return ucs != LINE_FEED;
270 if (ucs >= 0x7f && ucs < 0xa0) {
277 WordBreakPropertyInterval interval = {0, 0, WBP::ALetter};
279 return interval.property;
283 return codepoint_width(uint32_t(ucs));
289 for (
const wchar_t& it : text) {
307 if (input.size() == 1) {
308 const char c = input[0];
309 if (c >= 32 && c < 127) {
317 bool is_pure_ascii =
true;
318 for (
const char c : input) {
319 if (c < 31 || c >= 127) {
320 is_pure_ascii =
false;
325 return static_cast<int>(input.size());
329 bool previous_narrow =
false;
331 while (start < input.size()) {
332 uint32_t codepoint = 0;
342 if (codepoint == kEmojiPresentationSelector && previous_narrow) {
343 previous_narrow =
false;
350 previous_narrow =
false;
355 previous_narrow =
true;
362 std::vector<std::string> out;
363 out.reserve(input.size());
364 size_t last_glyph = 0;
365 bool last_glyph_narrow =
false;
368 while (start < input.size()) {
369 uint32_t codepoint = 0;
375 const auto append = input.substr(start, end - start);
386 out[last_glyph] += append;
389 if (codepoint == kEmojiPresentationSelector && last_glyph_narrow) {
390 last_glyph_narrow =
false;
391 out.emplace_back(
"");
396 last_glyph = out.size();
401 last_glyph_narrow =
false;
402 out.emplace_back(append);
403 out.emplace_back(
"");
408 last_glyph_narrow =
true;
409 out.emplace_back(append);
422 if ((input[start] & 0b1100'0000) == 0b1000'0000) {
426 uint32_t codepoint = 0;
428 const bool eaten =
EatCodePoint(input, start, &end, &codepoint);
440 bool glyph_found =
false;
441 while (start < input.size()) {
443 uint32_t codepoint = 0;
444 const bool eaten =
EatCodePoint(input, start, &end, &codepoint);
455 return static_cast<int>(start);
462 return static_cast<int>(input.size());
465size_t GlyphIterate(std::string_view input,
int glyph_offset,
size_t start) {
466 if (glyph_offset >= 0) {
467 for (
int i = 0; i < glyph_offset; ++i) {
472 for (
int i = 0; i < -glyph_offset; ++i) {
481 bool last_glyph_narrow =
false;
482 std::vector<int> out;
483 out.reserve(input.size());
486 while (start < input.size()) {
487 uint32_t codepoint = 0;
488 const bool eaten =
EatCodePoint(input, start, &end, &codepoint);
503 if (codepoint == kEmojiPresentationSelector && last_glyph_narrow) {
504 last_glyph_narrow =
false;
513 last_glyph_narrow =
false;
521 last_glyph_narrow =
true;
532 while (start < input.size()) {
533 uint32_t codepoint = 0;
534 const bool eaten =
EatCodePoint(input, start, &end, &codepoint);
557 std::vector<WordBreakProperty> out;
558 out.reserve(input.size());
561 while (start < input.size()) {
562 uint32_t codepoint = 0;
579 WordBreakPropertyInterval interval = {0, 0, WBP::ALetter};
581 out.push_back(interval.property);
591 uint32_t codepoint = 0;
608 if (codepoint <= 0b000'0000'0111'1111) {
609 const uint8_t p1 = codepoint;
615 if (codepoint <= 0b000'0111'1111'1111) {
616 uint8_t p2 = codepoint & 0b111111;
618 uint8_t p1 = codepoint;
619 out.push_back(0b11000000 + p1);
620 out.push_back(0b10000000 + p2);
625 if (codepoint <= 0b1111'1111'1111'1111) {
626 uint8_t p3 = codepoint & 0b111111;
628 uint8_t p2 = codepoint & 0b111111;
630 uint8_t p1 = codepoint;
631 out.push_back(0b11100000 + p1);
632 out.push_back(0b10000000 + p2);
633 out.push_back(0b10000000 + p3);
638 if (codepoint <= 0b1'0000'1111'1111'1111'1111) {
639 uint8_t p4 = codepoint & 0b111111;
641 uint8_t p3 = codepoint & 0b111111;
643 uint8_t p2 = codepoint & 0b111111;
645 uint8_t p1 = codepoint;
646 out.push_back(0b11110000 + p1);
647 out.push_back(0b10000000 + p2);
648 out.push_back(0b10000000 + p3);
649 out.push_back(0b10000000 + p4);
663 uint32_t codepoint = 0;
666 if constexpr (
sizeof(wchar_t) == 4) {
667 out.push_back(codepoint);
675 if (codepoint < 0xD800 || (codepoint > 0xDFFF && codepoint < 0x10000)) {
676 uint16_t p0 = codepoint;
682 codepoint -= 0x010000;
683 uint16_t p0 = (((codepoint << 12) >> 22) + 0xD800);
684 uint16_t p1 = (((codepoint << 22) >> 22) + 0xDC00);
The FTXUI ftxui:: namespace.
bool IsControl(uint32_t ucs)
WordBreakProperty CodepointToWordBreakProperty(uint32_t codepoint)
size_t GlyphPrevious(std::string_view input, size_t start)
FTXUI_EXPORT(SCREEN) int string_width(std std::vector< std::string > Utf8ToGlyphs(std::string_view input)
int string_width(std::string_view input)
bool IsCombining(uint32_t ucs)
int wchar_width(wchar_t ucs)
bool EatCodePoint(std::string_view input, size_t start, size_t *end, uint32_t *ucs)
std::string to_string(std::wstring_view s)
Convert a std::wstring into a UTF8 std::string.
int GlyphCount(std::string_view input)
std::vector< WordBreakProperty > Utf8ToWordBreakProperty(std::string_view input)
int wstring_width(const std::wstring &text)
std::vector< int > CellToGlyphIndex(std::string_view input)
FTXUI_EXPORT(SCREEN) std FTXUI_EXPORT(SCREEN) std std::wstring to_wstring(T s)
size_t GlyphIterate(std::string_view input, int glyph_offset, size_t start)
bool IsFullWidth(uint32_t ucs)
size_t GlyphNext(std::string_view input, size_t start)
constexpr std::array< Interval, 126 > g_full_width_characters
constexpr std::array< WordBreakPropertyInterval, 1114 > g_word_break_intervals