use strings; //https://unicodeplus.com/ 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; }; // CJK Symbols and Punctuation: https://en.wikipedia.org/wiki/CJK_Symbols_and_Punctuation if (ru >= '\U00003000' && ru <= '\U0000303F') { return 2; }; // Hangul Syllables: https://en.wikipedia.org/wiki/Hangul_Syllables if (ru >= '\U0000AC00' && ru <= '\U0000D7AF') { return 2; }; // Miscellaneous Symbols: https://en.wikipedia.org/wiki/Miscellaneous_Symbols_and_Pictographs if (ru >= '\U00002600' && ru <= '\U000026FF') { return 2; }; // Miscellaneous Symbols and Pictographs: https://en.wikipedia.org/wiki/Miscellaneous_Symbols_and_Pictographs if (ru >= '\U0001F300' && ru <= '\U0001F5FF') { return 2; }; // Dingbats: https://en.wikipedia.org/wiki/Dingbats_(Unicode_block) if (ru >= '\U00002700' && ru <= '\U000027BF') { return 2; }; // Transport and Map symbols: https://en.wikipedia.org/wiki/Transport_and_Map_Symbols if (ru >= '\U0001F680' && ru <= '\U0001F6FF') { return 2; }; // Supplemental Symbols and Pictographs: https://en.wikipedia.org/wiki/Supplemental_Symbols_and_Pictographs if (ru >= '\U0001F900' && ru <= '\U0001F9FF') { return 2; }; // Miscellaneous Symbols and Arrows: https://en.wikipedia.org/wiki/Miscellaneous_Symbols_and_Arrows if (ru >= '\U00002B00' && ru <= '\U00002BFF') { return 2; }; // Symbols and Pictographs Extended-A: https://en.wikipedia.org/wiki/Symbols_and_Pictographs_Extended-A if (ru >= '\U0001FA70' && ru <= '\U0001FAFF') { 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; };