1package liner
2
3import "unicode"
4
5// These character classes are mostly zero width (when combined).
6// A few might not be, depending on the user's font. Fixing this
7// is non-trivial, given that some terminals don't support
8// ANSI DSR/CPR
9var zeroWidth = []*unicode.RangeTable{
10	unicode.Mn,
11	unicode.Me,
12	unicode.Cc,
13	unicode.Cf,
14}
15
16var doubleWidth = []*unicode.RangeTable{
17	unicode.Han,
18	unicode.Hangul,
19	unicode.Hiragana,
20	unicode.Katakana,
21}
22
23// countGlyphs considers zero-width characters to be zero glyphs wide,
24// and members of Chinese, Japanese, and Korean scripts to be 2 glyphs wide.
25func countGlyphs(s []rune) int {
26	n := 0
27	for _, r := range s {
28		// speed up the common case
29		if r < 127 {
30			n++
31			continue
32		}
33
34		switch {
35		case unicode.IsOneOf(zeroWidth, r):
36		case unicode.IsOneOf(doubleWidth, r):
37			n += 2
38		default:
39			n++
40		}
41	}
42	return n
43}
44
45func countMultiLineGlyphs(s []rune, columns int, start int) int {
46	n := start
47	for _, r := range s {
48		if r < 127 {
49			n++
50			continue
51		}
52		switch {
53		case unicode.IsOneOf(zeroWidth, r):
54		case unicode.IsOneOf(doubleWidth, r):
55			n += 2
56			// no room for a 2-glyphs-wide char in the ending
57			// so skip a column and display it at the beginning
58			if n%columns == 1 {
59				n++
60			}
61		default:
62			n++
63		}
64	}
65	return n
66}
67
68func getPrefixGlyphs(s []rune, num int) []rune {
69	p := 0
70	for n := 0; n < num && p < len(s); p++ {
71		// speed up the common case
72		if s[p] < 127 {
73			n++
74			continue
75		}
76		if !unicode.IsOneOf(zeroWidth, s[p]) {
77			n++
78		}
79	}
80	for p < len(s) && unicode.IsOneOf(zeroWidth, s[p]) {
81		p++
82	}
83	return s[:p]
84}
85
86func getSuffixGlyphs(s []rune, num int) []rune {
87	p := len(s)
88	for n := 0; n < num && p > 0; p-- {
89		// speed up the common case
90		if s[p-1] < 127 {
91			n++
92			continue
93		}
94		if !unicode.IsOneOf(zeroWidth, s[p-1]) {
95			n++
96		}
97	}
98	return s[p:]
99}
100