summaryrefslogtreecommitdiff
path: root/tui/width.ha
blob: f6d6078dd8ffefa11e9c49b1c776c0ea39814166 (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
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;
};