forked from toolshed/abra
.gitea
cli
cmd
pkg
scripts
tests
vendor
coopcloud.tech
dario.cat
git.coopcloud.tech
github.com
go.opentelemetry.io
golang.org
x
crypto
exp
net
sync
sys
term
text
cases
internal
language
compact
common.go
compact.go
compose.go
coverage.go
language.go
lookup.go
match.go
parse.go
tables.go
tags.go
tag
internal.go
match.go
language
secure
transform
unicode
width
LICENSE
PATENTS
time
google.golang.org
gopkg.in
gotest.tools
modules.txt
.dockerignore
.drone.yml
.envrc.sample
.gitignore
.goreleaser.yml
AUTHORS.md
Dockerfile
LICENSE
Makefile
README.md
go.mod
go.sum
renovate.json
168 lines
3.8 KiB
Go
168 lines
3.8 KiB
Go
// Copyright 2018 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package language
|
|
|
|
import (
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// A Builder allows constructing a Tag from individual components.
|
|
// Its main user is Compose in the top-level language package.
|
|
type Builder struct {
|
|
Tag Tag
|
|
|
|
private string // the x extension
|
|
variants []string
|
|
extensions []string
|
|
}
|
|
|
|
// Make returns a new Tag from the current settings.
|
|
func (b *Builder) Make() Tag {
|
|
t := b.Tag
|
|
|
|
if len(b.extensions) > 0 || len(b.variants) > 0 {
|
|
sort.Sort(sortVariants(b.variants))
|
|
sort.Strings(b.extensions)
|
|
|
|
if b.private != "" {
|
|
b.extensions = append(b.extensions, b.private)
|
|
}
|
|
n := maxCoreSize + tokenLen(b.variants...) + tokenLen(b.extensions...)
|
|
buf := make([]byte, n)
|
|
p := t.genCoreBytes(buf)
|
|
t.pVariant = byte(p)
|
|
p += appendTokens(buf[p:], b.variants...)
|
|
t.pExt = uint16(p)
|
|
p += appendTokens(buf[p:], b.extensions...)
|
|
t.str = string(buf[:p])
|
|
// We may not always need to remake the string, but when or when not
|
|
// to do so is rather tricky.
|
|
scan := makeScanner(buf[:p])
|
|
t, _ = parse(&scan, "")
|
|
return t
|
|
|
|
} else if b.private != "" {
|
|
t.str = b.private
|
|
t.RemakeString()
|
|
}
|
|
return t
|
|
}
|
|
|
|
// SetTag copies all the settings from a given Tag. Any previously set values
|
|
// are discarded.
|
|
func (b *Builder) SetTag(t Tag) {
|
|
b.Tag.LangID = t.LangID
|
|
b.Tag.RegionID = t.RegionID
|
|
b.Tag.ScriptID = t.ScriptID
|
|
// TODO: optimize
|
|
b.variants = b.variants[:0]
|
|
if variants := t.Variants(); variants != "" {
|
|
for _, vr := range strings.Split(variants[1:], "-") {
|
|
b.variants = append(b.variants, vr)
|
|
}
|
|
}
|
|
b.extensions, b.private = b.extensions[:0], ""
|
|
for _, e := range t.Extensions() {
|
|
b.AddExt(e)
|
|
}
|
|
}
|
|
|
|
// AddExt adds extension e to the tag. e must be a valid extension as returned
|
|
// by Tag.Extension. If the extension already exists, it will be discarded,
|
|
// except for a -u extension, where non-existing key-type pairs will added.
|
|
func (b *Builder) AddExt(e string) {
|
|
if e[0] == 'x' {
|
|
if b.private == "" {
|
|
b.private = e
|
|
}
|
|
return
|
|
}
|
|
for i, s := range b.extensions {
|
|
if s[0] == e[0] {
|
|
if e[0] == 'u' {
|
|
b.extensions[i] += e[1:]
|
|
}
|
|
return
|
|
}
|
|
}
|
|
b.extensions = append(b.extensions, e)
|
|
}
|
|
|
|
// SetExt sets the extension e to the tag. e must be a valid extension as
|
|
// returned by Tag.Extension. If the extension already exists, it will be
|
|
// overwritten, except for a -u extension, where the individual key-type pairs
|
|
// will be set.
|
|
func (b *Builder) SetExt(e string) {
|
|
if e[0] == 'x' {
|
|
b.private = e
|
|
return
|
|
}
|
|
for i, s := range b.extensions {
|
|
if s[0] == e[0] {
|
|
if e[0] == 'u' {
|
|
b.extensions[i] = e + s[1:]
|
|
} else {
|
|
b.extensions[i] = e
|
|
}
|
|
return
|
|
}
|
|
}
|
|
b.extensions = append(b.extensions, e)
|
|
}
|
|
|
|
// AddVariant adds any number of variants.
|
|
func (b *Builder) AddVariant(v ...string) {
|
|
for _, v := range v {
|
|
if v != "" {
|
|
b.variants = append(b.variants, v)
|
|
}
|
|
}
|
|
}
|
|
|
|
// ClearVariants removes any variants previously added, including those
|
|
// copied from a Tag in SetTag.
|
|
func (b *Builder) ClearVariants() {
|
|
b.variants = b.variants[:0]
|
|
}
|
|
|
|
// ClearExtensions removes any extensions previously added, including those
|
|
// copied from a Tag in SetTag.
|
|
func (b *Builder) ClearExtensions() {
|
|
b.private = ""
|
|
b.extensions = b.extensions[:0]
|
|
}
|
|
|
|
func tokenLen(token ...string) (n int) {
|
|
for _, t := range token {
|
|
n += len(t) + 1
|
|
}
|
|
return
|
|
}
|
|
|
|
func appendTokens(b []byte, token ...string) int {
|
|
p := 0
|
|
for _, t := range token {
|
|
b[p] = '-'
|
|
copy(b[p+1:], t)
|
|
p += 1 + len(t)
|
|
}
|
|
return p
|
|
}
|
|
|
|
type sortVariants []string
|
|
|
|
func (s sortVariants) Len() int {
|
|
return len(s)
|
|
}
|
|
|
|
func (s sortVariants) Swap(i, j int) {
|
|
s[j], s[i] = s[i], s[j]
|
|
}
|
|
|
|
func (s sortVariants) Less(i, j int) bool {
|
|
return variantIndex[s[i]] < variantIndex[s[j]]
|
|
}
|