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  }