summaryrefslogtreecommitdiff
path: root/tui/width.ha
blob: b7ac99322eb20ac1de77a850e307470ef43b1679 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
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);
		};
	};
	return s;
};