oh-my-posh/src/color/palette.go
2022-02-03 10:44:18 +01:00

103 lines
2.7 KiB
Go

package color
import (
"fmt"
"sort"
"strings"
)
type Palette map[string]string
const (
paletteKeyPrefix = "p:"
paletteKeyError = "palette: requested color %s does not exist in palette of colors %s"
paletteMaxRecursionDepth = 3 // allows 3 or less recusive resolutions
paletteRecursiveKeyError = "palette: recursive resolution of color %s returned palette reference %s and reached recursion depth %d"
)
// ResolveColor gets a color value from the palette using given colorName.
// If colorName is not a palette reference, it is returned as is.
func (p Palette) ResolveColor(colorName string) (string, error) {
return p.resolveColor(colorName, 1, &colorName)
}
// originalColorName is a pointer to save allocations
func (p Palette) resolveColor(colorName string, depth int, originalColorName *string) (string, error) {
key, ok := asPaletteKey(colorName)
// colorName is not a palette key, return it as is
if !ok {
return colorName, nil
}
color, ok := p[key]
if !ok {
return "", &PaletteKeyError{Key: key, palette: p}
}
if _, isKey := isPaletteKey(color); isKey {
if depth > paletteMaxRecursionDepth {
return "", &PaletteRecursiveKeyError{Key: *originalColorName, Value: color, depth: depth}
}
return p.resolveColor(color, depth+1, originalColorName)
}
return color, nil
}
func asPaletteKey(colorName string) (string, bool) {
prefix, isKey := isPaletteKey(colorName)
if !isKey {
return "", false
}
key := strings.TrimPrefix(colorName, prefix)
return key, true
}
func isPaletteKey(colorName string) (string, bool) {
return paletteKeyPrefix, strings.HasPrefix(colorName, paletteKeyPrefix)
}
// PaletteKeyError records the missing Palette key.
type PaletteKeyError struct {
Key string
palette Palette
}
func (p *PaletteKeyError) Error() string {
keys := make([]string, 0, len(p.palette))
for key := range p.palette {
keys = append(keys, key)
}
sort.Strings(keys)
allColors := strings.Join(keys, ",")
errorStr := fmt.Sprintf(paletteKeyError, p.Key, allColors)
return errorStr
}
// PaletteRecursiveKeyError records the Palette key and resolved color value (which
// is also a Palette key)
type PaletteRecursiveKeyError struct {
Key string
Value string
depth int
}
func (p *PaletteRecursiveKeyError) Error() string {
errorStr := fmt.Sprintf(paletteRecursiveKeyError, p.Key, p.Value, p.depth)
return errorStr
}
// maybeResolveColor wraps resolveColor and silences possible errors, returning
// Transparent color by default, as a Block does not know how to handle color errors.
func (p Palette) MaybeResolveColor(colorName string) string {
color, err := p.ResolveColor(colorName)
if err != nil {
return ""
}
return color
}