1package readline 2 3import ( 4 "bytes" 5 "unicode" 6 "unicode/utf8" 7) 8 9var runes = Runes{} 10var TabWidth = 4 11 12type Runes struct{} 13 14func (Runes) EqualRune(a, b rune, fold bool) bool { 15 if a == b { 16 return true 17 } 18 if !fold { 19 return false 20 } 21 if a > b { 22 a, b = b, a 23 } 24 if b < utf8.RuneSelf && 'A' <= a && a <= 'Z' { 25 if b == a+'a'-'A' { 26 return true 27 } 28 } 29 return false 30} 31 32func (r Runes) EqualRuneFold(a, b rune) bool { 33 return r.EqualRune(a, b, true) 34} 35 36func (r Runes) EqualFold(a, b []rune) bool { 37 if len(a) != len(b) { 38 return false 39 } 40 for i := 0; i < len(a); i++ { 41 if r.EqualRuneFold(a[i], b[i]) { 42 continue 43 } 44 return false 45 } 46 47 return true 48} 49 50func (Runes) Equal(a, b []rune) bool { 51 if len(a) != len(b) { 52 return false 53 } 54 for i := 0; i < len(a); i++ { 55 if a[i] != b[i] { 56 return false 57 } 58 } 59 return true 60} 61 62func (rs Runes) IndexAllBckEx(r, sub []rune, fold bool) int { 63 for i := len(r) - len(sub); i >= 0; i-- { 64 found := true 65 for j := 0; j < len(sub); j++ { 66 if !rs.EqualRune(r[i+j], sub[j], fold) { 67 found = false 68 break 69 } 70 } 71 if found { 72 return i 73 } 74 } 75 return -1 76} 77 78// Search in runes from end to front 79func (rs Runes) IndexAllBck(r, sub []rune) int { 80 return rs.IndexAllBckEx(r, sub, false) 81} 82 83// Search in runes from front to end 84func (rs Runes) IndexAll(r, sub []rune) int { 85 return rs.IndexAllEx(r, sub, false) 86} 87 88func (rs Runes) IndexAllEx(r, sub []rune, fold bool) int { 89 for i := 0; i < len(r); i++ { 90 found := true 91 if len(r[i:]) < len(sub) { 92 return -1 93 } 94 for j := 0; j < len(sub); j++ { 95 if !rs.EqualRune(r[i+j], sub[j], fold) { 96 found = false 97 break 98 } 99 } 100 if found { 101 return i 102 } 103 } 104 return -1 105} 106 107func (Runes) Index(r rune, rs []rune) int { 108 for i := 0; i < len(rs); i++ { 109 if rs[i] == r { 110 return i 111 } 112 } 113 return -1 114} 115 116func (Runes) ColorFilter(r []rune) []rune { 117 newr := make([]rune, 0, len(r)) 118 for pos := 0; pos < len(r); pos++ { 119 if r[pos] == '\033' && r[pos+1] == '[' { 120 idx := runes.Index('m', r[pos+2:]) 121 if idx == -1 { 122 continue 123 } 124 pos += idx + 2 125 continue 126 } 127 newr = append(newr, r[pos]) 128 } 129 return newr 130} 131 132var zeroWidth = []*unicode.RangeTable{ 133 unicode.Mn, 134 unicode.Me, 135 unicode.Cc, 136 unicode.Cf, 137} 138 139var doubleWidth = []*unicode.RangeTable{ 140 unicode.Han, 141 unicode.Hangul, 142 unicode.Hiragana, 143 unicode.Katakana, 144} 145 146func (Runes) Width(r rune) int { 147 if r == '\t' { 148 return TabWidth 149 } 150 if unicode.IsOneOf(zeroWidth, r) { 151 return 0 152 } 153 if unicode.IsOneOf(doubleWidth, r) { 154 return 2 155 } 156 return 1 157} 158 159func (Runes) WidthAll(r []rune) (length int) { 160 for i := 0; i < len(r); i++ { 161 length += runes.Width(r[i]) 162 } 163 return 164} 165 166func (Runes) Backspace(r []rune) []byte { 167 return bytes.Repeat([]byte{'\b'}, runes.WidthAll(r)) 168} 169 170func (Runes) Copy(r []rune) []rune { 171 n := make([]rune, len(r)) 172 copy(n, r) 173 return n 174} 175 176func (Runes) HasPrefixFold(r, prefix []rune) bool { 177 if len(r) < len(prefix) { 178 return false 179 } 180 return runes.EqualFold(r[:len(prefix)], prefix) 181} 182 183func (Runes) HasPrefix(r, prefix []rune) bool { 184 if len(r) < len(prefix) { 185 return false 186 } 187 return runes.Equal(r[:len(prefix)], prefix) 188} 189 190func (Runes) Aggregate(candicate [][]rune) (same []rune, size int) { 191 for i := 0; i < len(candicate[0]); i++ { 192 for j := 0; j < len(candicate)-1; j++ { 193 if i >= len(candicate[j]) || i >= len(candicate[j+1]) { 194 goto aggregate 195 } 196 if candicate[j][i] != candicate[j+1][i] { 197 goto aggregate 198 } 199 } 200 size = i + 1 201 } 202aggregate: 203 if size > 0 { 204 same = runes.Copy(candicate[0][:size]) 205 for i := 0; i < len(candicate); i++ { 206 n := runes.Copy(candicate[i]) 207 copy(n, n[size:]) 208 candicate[i] = n[:len(n)-size] 209 } 210 } 211 return 212} 213 214func (Runes) TrimSpaceLeft(in []rune) []rune { 215 firstIndex := len(in) 216 for i, r := range in { 217 if unicode.IsSpace(r) == false { 218 firstIndex = i 219 break 220 } 221 } 222 return in[firstIndex:] 223} 224