gitee.com/quant1x/gox@v1.21.2/text/runewidth/script/generate.go (about) 1 //go:build ignore 2 // +build ignore 3 4 // Generate runewidth_table.go from data at https://unicode.org/ 5 6 package main 7 8 import ( 9 "bufio" 10 "bytes" 11 "fmt" 12 "go/format" 13 "io" 14 "io/ioutil" 15 "log" 16 "net/http" 17 "strings" 18 ) 19 20 type rrange struct { 21 lo rune 22 hi rune 23 } 24 25 func generate(out io.Writer, v string, arr []rrange) { 26 fmt.Fprintf(out, "var %s = table{\n\t", v) 27 for i := 0; i < len(arr); i++ { 28 fmt.Fprintf(out, "{0x%04X, 0x%04X},", arr[i].lo, arr[i].hi) 29 if i < len(arr)-1 { 30 if i%3 == 2 { 31 fmt.Fprint(out, "\n\t") 32 } else { 33 fmt.Fprint(out, " ") 34 } 35 } 36 } 37 fmt.Fprintln(out, "\n}") 38 } 39 40 func shapeup(p *[]rrange) { 41 arr := *p 42 for i := 0; i < len(arr)-1; i++ { 43 if arr[i].hi+1 == arr[i+1].lo { 44 lo := arr[i].lo 45 arr = append(arr[:i], arr[i+1:]...) 46 arr[i].lo = lo 47 i-- 48 } 49 } 50 *p = arr 51 } 52 53 func eastasian(out io.Writer, in io.Reader) error { 54 scanner := bufio.NewScanner(in) 55 56 dbl := []rrange{} 57 amb := []rrange{} 58 cmb := []rrange{} 59 na := []rrange{} 60 nu := []rrange{} 61 for scanner.Scan() { 62 line := scanner.Text() 63 if strings.HasPrefix(line, "#") { 64 continue 65 } 66 var r1, r2 rune 67 var ss string 68 n, err := fmt.Sscanf(line, "%x..%x;%s ", &r1, &r2, &ss) 69 if err != nil || n == 2 { 70 n, err = fmt.Sscanf(line, "%x;%s ", &r1, &ss) 71 if err != nil || n != 2 { 72 continue 73 } 74 r2 = r1 75 } 76 77 if strings.Index(line, "COMBINING") != -1 { 78 cmb = append(cmb, rrange{ 79 lo: r1, 80 hi: r2, 81 }) 82 } 83 84 switch ss { 85 case "W", "F": 86 dbl = append(dbl, rrange{ 87 lo: r1, 88 hi: r2, 89 }) 90 case "A": 91 amb = append(amb, rrange{ 92 lo: r1, 93 hi: r2, 94 }) 95 case "Na": 96 na = append(na, rrange{ 97 lo: r1, 98 hi: r2, 99 }) 100 case "N": 101 nu = append(nu, rrange{ 102 lo: r1, 103 hi: r2, 104 }) 105 } 106 } 107 108 shapeup(&cmb) 109 generate(out, "combining", cmb) 110 fmt.Fprintln(out) 111 112 shapeup(&dbl) 113 generate(out, "doublewidth", dbl) 114 fmt.Fprintln(out) 115 116 shapeup(&amb) 117 generate(out, "ambiguous", amb) 118 fmt.Fprint(out) 119 120 shapeup(&na) 121 generate(out, "narrow", na) 122 fmt.Fprintln(out) 123 124 shapeup(&nu) 125 generate(out, "neutral", nu) 126 fmt.Fprintln(out) 127 128 return nil 129 } 130 131 func emoji(out io.Writer, in io.Reader) error { 132 scanner := bufio.NewScanner(in) 133 134 for scanner.Scan() { 135 line := scanner.Text() 136 if strings.Index(line, "Extended_Pictographic ; No") != -1 { 137 break 138 } 139 } 140 141 if scanner.Err() != nil { 142 return scanner.Err() 143 } 144 145 arr := []rrange{} 146 for scanner.Scan() { 147 line := scanner.Text() 148 if strings.HasPrefix(line, "#") { 149 continue 150 } 151 var r1, r2 rune 152 n, err := fmt.Sscanf(line, "%x..%x ", &r1, &r2) 153 if err != nil || n == 1 { 154 n, err = fmt.Sscanf(line, "%x ", &r1) 155 if err != nil || n != 1 { 156 continue 157 } 158 r2 = r1 159 } 160 if r2 < 0xFF { 161 continue 162 } 163 164 arr = append(arr, rrange{ 165 lo: r1, 166 hi: r2, 167 }) 168 } 169 170 shapeup(&arr) 171 generate(out, "emoji", arr) 172 173 return nil 174 } 175 176 func main() { 177 var buf bytes.Buffer 178 f := &buf 179 fmt.Fprint(f, "// Code generated by script/generate.go. DO NOT EDIT.\n\n") 180 181 fmt.Fprint(f, "package runewidth\n\n") 182 183 resp, err := http.Get("https://unicode.org/Public/13.0.0/ucd/EastAsianWidth.txt") 184 if err != nil { 185 log.Fatal(err) 186 } 187 defer resp.Body.Close() 188 189 eastasian(f, resp.Body) 190 191 resp, err = http.Get("https://unicode.org/Public/13.0.0/ucd/emoji/emoji-data.txt") 192 if err != nil { 193 log.Fatal(err) 194 } 195 defer resp.Body.Close() 196 197 emoji(f, resp.Body) 198 199 out, err := format.Source(f.Bytes()) 200 if err != nil { 201 log.Fatal(err) 202 } 203 err = ioutil.WriteFile("runewidth_table.go", out, 0666) 204 if err != nil { 205 log.Fatal(err) 206 } 207 }