use strings; export fn runewidth(r: rune) uint = { let ru = r: u32; // emoticons: https://en.wikipedia.org/wiki/Emoticons_(Unicode_block) if (ru >= '\U0001F600' && ru <= '\U0001F64F') { return 2; }; // hiragana: https://en.wikipedia.org/wiki/Hiragana_%28Unicode_block%29 if (ru >= '\U00003040' && ru <= '\U0000309F') { return 2; }; // katakana: https://en.wikipedia.org/wiki/Katakana_(Unicode_block) if (ru >= '\U000030A0' && ru <= '\U000030FF') { return 2; }; // CJK: https://en.wikipedia.org/wiki/CJK_Unified_Ideographs_(Unicode_block) if (ru >= '\U00004E00' && ru <= '\U00009FFF') { return 2; }; return 1; }; export fn strwidth(s: str) uint = { // TODO: handle tabs const runes = strings::torunes(s); defer free(runes); let sum = 0u; for (let r .. runes) { sum += runewidth(r); }; return sum; }; export fn subwidth(s: str, end: (size | strings::end)) str = { const runes = strings::torunes(s); defer free(runes); let sum = 0u; for (let i = 0z; i < len(runes); i += 1) { const r = runes[i]; sum += runewidth(r); if (sum > end: uint) { return strings::sub(s, 0, i - 1); }; }; return s; };