mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 08:02:36 +09:00 
			
		
		
		
	Change all license headers to comply with REUSE specification. Fix #16132 Co-authored-by: flynnnnnnnnnn <flynnnnnnnnnn@github> Co-authored-by: John Olheiser <john.olheiser@gmail.com>
		
			
				
	
	
		
			189 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			189 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2022 The Gitea Authors. All rights reserved.
 | 
						|
// SPDX-License-Identifier: MIT
 | 
						|
 | 
						|
package main
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"flag"
 | 
						|
	"fmt"
 | 
						|
	"go/format"
 | 
						|
	"os"
 | 
						|
	"sort"
 | 
						|
	"text/template"
 | 
						|
	"unicode"
 | 
						|
 | 
						|
	"code.gitea.io/gitea/modules/json"
 | 
						|
 | 
						|
	"golang.org/x/text/unicode/rangetable"
 | 
						|
)
 | 
						|
 | 
						|
// ambiguous.json provides a one to one mapping of ambiguous characters to other characters
 | 
						|
// See https://github.com/hediet/vscode-unicode-data/blob/main/out/ambiguous.json
 | 
						|
 | 
						|
type AmbiguousTable struct {
 | 
						|
	Confusable []rune
 | 
						|
	With       []rune
 | 
						|
	Locale     string
 | 
						|
	RangeTable *unicode.RangeTable
 | 
						|
}
 | 
						|
 | 
						|
type RunePair struct {
 | 
						|
	Confusable rune
 | 
						|
	With       rune
 | 
						|
}
 | 
						|
 | 
						|
var verbose bool
 | 
						|
 | 
						|
func main() {
 | 
						|
	flag.Usage = func() {
 | 
						|
		fmt.Fprintf(os.Stderr, `%s: Generate AmbiguousCharacter
 | 
						|
 | 
						|
Usage: %[1]s [-v] [-o output.go] ambiguous.json
 | 
						|
`, os.Args[0])
 | 
						|
		flag.PrintDefaults()
 | 
						|
	}
 | 
						|
 | 
						|
	output := ""
 | 
						|
	flag.BoolVar(&verbose, "v", false, "verbose output")
 | 
						|
	flag.StringVar(&output, "o", "ambiguous_gen.go", "file to output to")
 | 
						|
	flag.Parse()
 | 
						|
	input := flag.Arg(0)
 | 
						|
	if input == "" {
 | 
						|
		input = "ambiguous.json"
 | 
						|
	}
 | 
						|
 | 
						|
	bs, err := os.ReadFile(input)
 | 
						|
	if err != nil {
 | 
						|
		fatalf("Unable to read: %s Err: %v", input, err)
 | 
						|
	}
 | 
						|
 | 
						|
	var unwrapped string
 | 
						|
	if err := json.Unmarshal(bs, &unwrapped); err != nil {
 | 
						|
		fatalf("Unable to unwrap content in: %s Err: %v", input, err)
 | 
						|
	}
 | 
						|
 | 
						|
	fromJSON := map[string][]uint32{}
 | 
						|
	if err := json.Unmarshal([]byte(unwrapped), &fromJSON); err != nil {
 | 
						|
		fatalf("Unable to unmarshal content in: %s Err: %v", input, err)
 | 
						|
	}
 | 
						|
 | 
						|
	tables := make([]*AmbiguousTable, 0, len(fromJSON))
 | 
						|
	for locale, chars := range fromJSON {
 | 
						|
		table := &AmbiguousTable{Locale: locale}
 | 
						|
		table.Confusable = make([]rune, 0, len(chars)/2)
 | 
						|
		table.With = make([]rune, 0, len(chars)/2)
 | 
						|
		pairs := make([]RunePair, len(chars)/2)
 | 
						|
		for i := 0; i < len(chars); i += 2 {
 | 
						|
			pairs[i/2].Confusable, pairs[i/2].With = rune(chars[i]), rune(chars[i+1])
 | 
						|
		}
 | 
						|
		sort.Slice(pairs, func(i, j int) bool {
 | 
						|
			return pairs[i].Confusable < pairs[j].Confusable
 | 
						|
		})
 | 
						|
		for _, pair := range pairs {
 | 
						|
			table.Confusable = append(table.Confusable, pair.Confusable)
 | 
						|
			table.With = append(table.With, pair.With)
 | 
						|
		}
 | 
						|
		table.RangeTable = rangetable.New(table.Confusable...)
 | 
						|
		tables = append(tables, table)
 | 
						|
	}
 | 
						|
	sort.Slice(tables, func(i, j int) bool {
 | 
						|
		return tables[i].Locale < tables[j].Locale
 | 
						|
	})
 | 
						|
	data := map[string]interface{}{
 | 
						|
		"Tables": tables,
 | 
						|
	}
 | 
						|
 | 
						|
	if err := runTemplate(generatorTemplate, output, &data); err != nil {
 | 
						|
		fatalf("Unable to run template: %v", err)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func runTemplate(t *template.Template, filename string, data interface{}) error {
 | 
						|
	buf := bytes.NewBuffer(nil)
 | 
						|
	if err := t.Execute(buf, data); err != nil {
 | 
						|
		return fmt.Errorf("unable to execute template: %w", err)
 | 
						|
	}
 | 
						|
	bs, err := format.Source(buf.Bytes())
 | 
						|
	if err != nil {
 | 
						|
		verbosef("Bad source:\n%s", buf.String())
 | 
						|
		return fmt.Errorf("unable to format source: %w", err)
 | 
						|
	}
 | 
						|
 | 
						|
	old, err := os.ReadFile(filename)
 | 
						|
	if err != nil && !os.IsNotExist(err) {
 | 
						|
		return fmt.Errorf("failed to read old file %s because %w", filename, err)
 | 
						|
	} else if err == nil {
 | 
						|
		if bytes.Equal(bs, old) {
 | 
						|
			// files are the same don't rewrite it.
 | 
						|
			return nil
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	file, err := os.Create(filename)
 | 
						|
	if err != nil {
 | 
						|
		return fmt.Errorf("failed to create file %s because %w", filename, err)
 | 
						|
	}
 | 
						|
	defer file.Close()
 | 
						|
	_, err = file.Write(bs)
 | 
						|
	if err != nil {
 | 
						|
		return fmt.Errorf("unable to write generated source: %w", err)
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
var generatorTemplate = template.Must(template.New("ambiguousTemplate").Parse(`// This file is generated by modules/charset/ambiguous/generate.go DO NOT EDIT
 | 
						|
// Copyright 2022 The Gitea Authors. All rights reserved.
 | 
						|
// SPDX-License-Identifier: MIT
 | 
						|
 | 
						|
 | 
						|
package charset
 | 
						|
 | 
						|
import "unicode"
 | 
						|
 | 
						|
// This file is generated from https://github.com/hediet/vscode-unicode-data/blob/main/out/ambiguous.json
 | 
						|
 | 
						|
// AmbiguousTable matches a confusable rune with its partner for the Locale
 | 
						|
type AmbiguousTable struct {
 | 
						|
	Confusable []rune
 | 
						|
	With       []rune
 | 
						|
	Locale     string
 | 
						|
	RangeTable *unicode.RangeTable
 | 
						|
}
 | 
						|
 | 
						|
// AmbiguousCharacters provides a map by locale name to the confusable characters in that locale
 | 
						|
var AmbiguousCharacters = map[string]*AmbiguousTable{
 | 
						|
	{{range .Tables}}{{printf "%q:" .Locale}} {
 | 
						|
			Confusable: []rune{ {{range .Confusable}}{{.}},{{end}} },
 | 
						|
			With: []rune{ {{range .With}}{{.}},{{end}} },
 | 
						|
			Locale: {{printf "%q" .Locale}},
 | 
						|
			RangeTable: &unicode.RangeTable{
 | 
						|
				R16: []unicode.Range16{
 | 
						|
			{{range .RangeTable.R16 }}		{Lo:{{.Lo}}, Hi:{{.Hi}}, Stride: {{.Stride}}},
 | 
						|
			{{end}}	},
 | 
						|
				R32: []unicode.Range32{
 | 
						|
			{{range .RangeTable.R32}}		{Lo:{{.Lo}}, Hi:{{.Hi}}, Stride: {{.Stride}}},
 | 
						|
			{{end}}	},
 | 
						|
				LatinOffset: {{.RangeTable.LatinOffset}},
 | 
						|
			},
 | 
						|
		},
 | 
						|
	{{end}}
 | 
						|
}
 | 
						|
 | 
						|
`))
 | 
						|
 | 
						|
func logf(format string, args ...interface{}) {
 | 
						|
	fmt.Fprintf(os.Stderr, format+"\n", args...)
 | 
						|
}
 | 
						|
 | 
						|
func verbosef(format string, args ...interface{}) {
 | 
						|
	if verbose {
 | 
						|
		logf(format, args...)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func fatalf(format string, args ...interface{}) {
 | 
						|
	logf("fatal: "+format+"\n", args...)
 | 
						|
	os.Exit(1)
 | 
						|
}
 |