// Copyright (c) 2018-2022 Omar Al-Ithawi and The MathJax Consortium// SPDX-License-Identifier: Apache-2.0// Go translation and modification of MathJax 3.2.2 ColorUtil.ts.package colorimport ()var ( decimalPattern = regexp.MustCompile(`^(\d+(\.\d*)?|\.\d+)$`) integerPattern = regexp.MustCompile(`^\d+$`))// Error is the color extension's source-compatible TeX error. ID is the// localization key used by MathJax 3.2.2 and Message is its formatted English// fallback.typeErrorstruct { ID string Message string}func ( *Error) () string { return .Message }func texError(, string, ...any) error {return &Error{ID: , Message: fmt.Sprintf(, ...)}}// Model stores user-defined colors for one parser. A Model must not be shared// between parser instances; this preserves MathJax's packageData isolation.// The zero value is ready for use.typeModelstruct { userColors map[string]string}// NewModel creates an empty, parser-local color model.func () *Model { return &Model{userColors: make(map[string]string)} }// GetColor resolves def according to model. An empty model has MathJax's// special named-color semantics.func ( *Model) (, string) (string, error) {if == "" || == "named" {return .getColorByName(), nil }returnnormalizeColor(, )}// DefineColor creates or replaces one parser-local named color.func ( *Model) (, , string) error { , := normalizeColor(, )if != nil {return }if .userColors == nil { .userColors = make(map[string]string) } .userColors[] = returnnil}func ( *Model) ( string) string {if != nil && .userColors != nil {if , := .userColors[]; {return } }if , := NamedColors[]; {return }// MathJax v2 compatibility: unknown values pass through to CSS. This also // permits CSS literals such as #ff0 and browser-known color names.return}func normalizeColor(, string) (string, error) {if == "" || == "named" {return , nil }switch {case"rgb":returnnormalizeRGBDecimal()case"RGB":returnnormalizeRGBInteger()case"gray":returnnormalizeGray()default:return"", texError("UndefinedColorModel", "Color model '%s' not defined", ) }}func normalizeRGBDecimal( string) (string, error) { := splitComponents()iflen() != 3 {return"", texError("ModelArg1", "Color values for the %s model require 3 numbers", "rgb") }varstrings.Builder .WriteByte('#')for , := range {if !decimalPattern.MatchString() {return"", texError("InvalidDecimalNumber", "Invalid decimal number") } , := strconv.ParseFloat(, 64)if < 0 || > 1 {return"", texError("ModelArg2", "Color values for the %s model must be between %s and %s", "rgb", "0", "1") }writeHexByte(&, int(math.Floor(*255))) }return .String(), nil}func normalizeRGBInteger( string) (string, error) { := splitComponents()iflen() != 3 {return"", texError("ModelArg1", "Color values for the %s model require 3 numbers", "RGB") }varstrings.Builder .WriteByte('#')for , := range {if !integerPattern.MatchString() {return"", texError("InvalidNumber", "Invalid number") }// Avoid machine-integer overflow while retaining parseInt's behavior for // arbitrarily many leading zeroes. := strings.TrimLeft(, "0")if == "" { = "0" }iflen() > 3 {return"", texError("ModelArg2", "Color values for the %s model must be between %s and %s", "RGB", "0", "255") } , := strconv.Atoi()if > 255 {return"", texError("ModelArg2", "Color values for the %s model must be between %s and %s", "RGB", "0", "255") }writeHexByte(&, ) }return .String(), nil}func normalizeGray( string) (string, error) { = trimECMAScriptSpace()if !decimalPattern.MatchString() {return"", texError("InvalidDecimalNumber", "Invalid decimal number") } , := strconv.ParseFloat(, 64)if < 0 || > 1 {return"", texError("ModelArg2", "Color values for the %s model must be between %s and %s", "gray", "0", "1") } := int(math.Floor( * 255))returnfmt.Sprintf("#%02x%02x%02x", , , ), nil}func splitComponents( string) []string { := strings.Split(trimECMAScriptSpace(), ",")for := range { [] = trimECMAScriptSpace([]) }return}// trimECMAScriptSpace matches the WhiteSpace and LineTerminator code points// recognized by JavaScript's String.trim() and regular-expression \s in the// MathJax 3.2.2 implementation. In particular, Go's strings.TrimSpace does not// include U+FEFF.func trimECMAScriptSpace( string) string {returnstrings.TrimFunc(, func( rune) bool {switch {case'\u0009', '\u000A', '\u000B', '\u000C', '\u000D', '\u0020','\u00A0', '\u1680', '\u2028', '\u2029', '\u202F', '\u205F','\u3000', '\uFEFF':returntruedefault:return >= '\u2000' && <= '\u200A' } })}func writeHexByte( *strings.Builder, int) {fmt.Fprintf(, "%02x", )}
The pages are generated with Goldsv0.8.7. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.