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