...

Source file src/github.com/mattn/go-runewidth/script/generate.go

Documentation: github.com/mattn/go-runewidth/script

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

View as plain text