2021-11-22 16:05:02 +00:00

209 lines
3.4 KiB
Go

// +build ignore
// Generate runewidth_table.go from data at https://unicode.org/
package main
import (
"bufio"
"bytes"
"fmt"
"go/format"
"io"
"io/ioutil"
"log"
"net/http"
"strings"
)
type rrange struct {
lo rune
hi rune
}
func generate(out io.Writer, v string, arr []rrange) {
fmt.Fprintf(out, "var %s = table{\n\t", v)
for i := 0; i < len(arr); i++ {
fmt.Fprintf(out, "{0x%04X, 0x%04X},", arr[i].lo, arr[i].hi)
if i < len(arr)-1 {
if i%3 == 2 {
fmt.Fprint(out, "\n\t")
} else {
fmt.Fprint(out, " ")
}
}
}
fmt.Fprintln(out, "\n}")
}
func shapeup(p *[]rrange) {
arr := *p
for i := 0; i < len(arr)-1; i++ {
if arr[i].hi+1 == arr[i+1].lo {
lo := arr[i].lo
arr = append(arr[:i], arr[i+1:]...)
arr[i].lo = lo
i--
}
}
*p = arr
}
func eastasian(out io.Writer, in io.Reader) error {
scanner := bufio.NewScanner(in)
dbl := []rrange{}
amb := []rrange{}
cmb := []rrange{}
na := []rrange{}
nu := []rrange{}
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, "#") {
continue
}
var r1, r2 rune
var ss string
n, err := fmt.Sscanf(line, "%x..%x;%s ", &r1, &r2, &ss)
if err != nil || n == 2 {
n, err = fmt.Sscanf(line, "%x;%s ", &r1, &ss)
if err != nil || n != 2 {
continue
}
r2 = r1
}
if strings.Index(line, "COMBINING") != -1 {
cmb = append(cmb, rrange{
lo: r1,
hi: r2,
})
}
switch ss {
case "W", "F":
dbl = append(dbl, rrange{
lo: r1,
hi: r2,
})
case "A":
amb = append(amb, rrange{
lo: r1,
hi: r2,
})
case "Na":
if r1 > 0xFF {
na = append(na, rrange{
lo: r1,
hi: r2,
})
}
case "N":
nu = append(nu, rrange{
lo: r1,
hi: r2,
})
}
}
shapeup(&cmb)
generate(out, "combining", cmb)
fmt.Fprintln(out)
shapeup(&dbl)
generate(out, "doublewidth", dbl)
fmt.Fprintln(out)
shapeup(&amb)
generate(out, "ambiguous", amb)
fmt.Fprint(out)
shapeup(&na)
generate(out, "notassigned", na)
fmt.Fprintln(out)
shapeup(&nu)
generate(out, "neutral", nu)
fmt.Fprintln(out)
return nil
}
func emoji(out io.Writer, in io.Reader) error {
scanner := bufio.NewScanner(in)
for scanner.Scan() {
line := scanner.Text()
if strings.Index(line, "Extended_Pictographic ; No") != -1 {
break
}
}
if scanner.Err() != nil {
return scanner.Err()
}
arr := []rrange{}
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, "#") {
continue
}
var r1, r2 rune
n, err := fmt.Sscanf(line, "%x..%x ", &r1, &r2)
if err != nil || n == 1 {
n, err = fmt.Sscanf(line, "%x ", &r1)
if err != nil || n != 1 {
continue
}
r2 = r1
}
if r2 < 0xFF {
continue
}
arr = append(arr, rrange{
lo: r1,
hi: r2,
})
}
shapeup(&arr)
generate(out, "emoji", arr)
return nil
}
func main() {
var buf bytes.Buffer
f := &buf
fmt.Fprint(f, "// Code generated by script/generate.go. DO NOT EDIT.\n\n")
fmt.Fprint(f, "package runewidth\n\n")
resp, err := http.Get("https://unicode.org/Public/13.0.0/ucd/EastAsianWidth.txt")
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
eastasian(f, resp.Body)
resp, err = http.Get("https://unicode.org/Public/13.0.0/ucd/emoji/emoji-data.txt")
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
emoji(f, resp.Body)
out, err := format.Source(f.Bytes())
if err != nil {
log.Fatal(err)
}
err = ioutil.WriteFile("runewidth_table.go", out, 0666)
if err != nil {
log.Fatal(err)
}
}