github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/misc/logos/misc.go (about) 1 package logos 2 3 import ( 4 "strings" 5 "unicode" 6 7 "github.com/gdamore/tcell/v2" 8 runewidth "github.com/mattn/go-runewidth" 9 ) 10 11 // splits a string into lines by newline. 12 func splitLines(s string) (ss []string) { 13 return strings.Split(s, "\n") 14 } 15 16 // splits a string according to unicode spaces. 17 func splitSpaces(s string) (ss []string) { 18 buf := []rune{} 19 for _, r := range s { 20 if unicode.IsSpace(r) { 21 // continue 22 if len(buf) > 0 { 23 ss = append(ss, string(buf)) 24 buf = nil 25 } 26 } else { 27 buf = append(buf, r) 28 } 29 } 30 if len(buf) > 0 { 31 ss = append(ss, string(buf)) 32 // buf = nil 33 } 34 return ss 35 } 36 37 func toRunes(s string) []rune { 38 runes := make([]rune, 0, len(s)) 39 for _, r := range s { 40 runes = append(runes, r) 41 } 42 return runes 43 } 44 45 // gets the terminal display width of a string. 46 // must be compatible with nextCharacter(). 47 // NOTE: must be kept in sync with nextCharacter(); see tests. 48 func widthOf(s string) (l int) { 49 zwj := false // zero width joiner '\u200d'. 50 for _, r := range s { 51 if r == '\u200d' { 52 zwj = true 53 continue 54 } 55 if zwj { 56 zwj = false 57 continue 58 } 59 switch runewidth.RuneWidth(r) { 60 case 0: 61 if isCombining(r) { 62 // combining characters have no length. 63 } else { 64 l++ // show a blank instead, weird. 65 } 66 case 1: 67 l++ 68 case 2: 69 l += 2 70 default: 71 panic("should not happen") 72 } 73 } 74 return l 75 } 76 77 // given runes of a valid utf8 string, 78 // return a string that represents 79 // the next single character (with any modifiers). 80 // w: width of character. n: number of runes read 81 func nextCharacter(rz []rune) (s string, w int, n int) { 82 for n = 0; n < len(rz); n++ { 83 r := rz[n] 84 if r == '\u200d' { 85 // special case: zero width joins. 86 s = s + string(r) 87 if n+1 < len(rz) { 88 s = s + string(rz[n+1]) 89 n++ 90 continue 91 } else { 92 // just continue, return invalid string s. 93 n++ 94 return 95 } 96 } else if 0 < len(s) { 97 return 98 } else { 99 // append r to s and inc w. 100 rw := runewidth.RuneWidth(r) 101 s = s + string(r) 102 if rw == 0 { 103 if isCombining(r) { 104 // no width 105 } else { 106 w += 1 107 } 108 } else { 109 w += rw 110 } 111 } 112 } 113 return 114 } 115 116 //---------------------------------------- 117 118 func AbsCoord(elem Elem) (crd Coord) { 119 for elem != nil { 120 crd = crd.Add(elem.GetCoord()) 121 elem = elem.GetParent() 122 } 123 return 124 } 125 126 var randColors []Color = []Color{ 127 tcell.ColorAliceBlue, 128 tcell.ColorAntiqueWhite, 129 tcell.ColorAquaMarine, 130 tcell.ColorAzure, 131 tcell.ColorBeige, 132 tcell.ColorBisque, 133 tcell.ColorBlanchedAlmond, 134 tcell.ColorBlueViolet, 135 tcell.ColorBrown, 136 tcell.ColorBurlyWood, 137 } 138 139 var rctr = 0 140 141 func RandColor() Color { 142 rctr++ 143 return randColors[rctr%len(randColors)] 144 } 145 146 func IsInBounds(x, y int, origin Coord, size Size) bool { 147 if x < origin.X || y < origin.Y { 148 return false 149 } 150 if origin.X+size.Width <= x || 151 origin.Y+size.Height <= y { 152 return false 153 } 154 return true 155 }