fix(color): resolve palette before ANSI conversion

resolves #5790
This commit is contained in:
Jan De Dobbeleer 2024-11-03 16:41:48 +01:00 committed by Jan De Dobbeleer
parent 4ac1033706
commit 6a8cecb73b
2 changed files with 29 additions and 9 deletions

View file

@ -21,6 +21,7 @@ var TrueColor = true
// but also a name of one of the first 16 ANSI colors like `lightBlue`. // but also a name of one of the first 16 ANSI colors like `lightBlue`.
type String interface { type String interface {
ToAnsi(colorString Ansi, isBackground bool) Ansi ToAnsi(colorString Ansi, isBackground bool) Ansi
Resolve(colorString Ansi) (Ansi, error)
} }
type Set struct { type Set struct {
@ -150,12 +151,15 @@ func MakeColors(palette Palette, cacheEnabled bool, accentColor Ansi, env runtim
defaultColors := &Defaults{} defaultColors := &Defaults{}
defaultColors.SetAccentColor(env, accentColor) defaultColors.SetAccentColor(env, accentColor)
colors = defaultColors colors = defaultColors
if palette != nil { if palette != nil {
colors = &PaletteColors{ansiColors: colors, palette: palette} colors = &PaletteColors{ansiColors: colors, palette: palette}
} }
if cacheEnabled { if cacheEnabled {
colors = &Cached{ansiColors: colors} colors = &Cached{ansiColors: colors}
} }
return return
} }
@ -288,6 +292,10 @@ func (d *Defaults) ToAnsi(ansiColor Ansi, isBackground bool) Ansi {
return emptyColor return emptyColor
} }
func (d *Defaults) Resolve(colorString Ansi) (Ansi, error) {
return colorString, nil
}
// getAnsiColorFromName returns the color code for a given color name if the name is // getAnsiColorFromName returns the color code for a given color name if the name is
// known ANSI color name. // known ANSI color name.
func getAnsiColorFromName(colorValue Ansi, isBackground bool) (Ansi, error) { func getAnsiColorFromName(colorValue Ansi, isBackground bool) (Ansi, error) {
@ -325,6 +333,10 @@ func (p *PaletteColors) ToAnsi(colorString Ansi, isBackground bool) Ansi {
return ansiColor return ansiColor
} }
func (p *PaletteColors) Resolve(colorString Ansi) (Ansi, error) {
return p.palette.ResolveColor(colorString)
}
// Cached is the AnsiColors Decorator that does simple color lookup caching. // Cached is the AnsiColors Decorator that does simple color lookup caching.
// ToColor calls are cheap, but not free, and having a simple cache in // ToColor calls are cheap, but not free, and having a simple cache in
// has measurable positive effect on performance. // has measurable positive effect on performance.
@ -350,3 +362,7 @@ func (c *Cached) ToAnsi(colorString Ansi, isBackground bool) Ansi {
c.colorCache[key] = ansiColor c.colorCache[key] = ansiColor
return ansiColor return ansiColor
} }
func (c *Cached) Resolve(colorString Ansi) (Ansi, error) {
return c.ansiColors.Resolve(colorString)
}

View file

@ -382,10 +382,6 @@ func writeEscapedAnsiString(text string) {
builder.WriteString(text) builder.WriteString(text)
} }
func getAnsiFromColorString(colorString color.Ansi, isBackground bool) color.Ansi {
return Colors.ToAnsi(colorString, isBackground)
}
func write(s rune) { func write(s rune) {
if isInvisible { if isInvisible {
return return
@ -430,7 +426,7 @@ func writeSegmentColors() {
switch { switch {
case fg.IsTransparent() && len(BackgroundColor) != 0: case fg.IsTransparent() && len(BackgroundColor) != 0:
background := getAnsiFromColorString(BackgroundColor, false) background := Colors.ToAnsi(BackgroundColor, false)
writeEscapedAnsiString(fmt.Sprintf(colorise, background)) writeEscapedAnsiString(fmt.Sprintf(colorise, background))
writeEscapedAnsiString(fmt.Sprintf(colorise, bg.ToForeground())) writeEscapedAnsiString(fmt.Sprintf(colorise, bg.ToForeground()))
case fg.IsTransparent() && !bg.IsEmpty(): case fg.IsTransparent() && !bg.IsEmpty():
@ -496,7 +492,7 @@ func writeArchorOverride(match map[string]string, background color.Ansi, i int)
currentColor.Add(bg, fg) currentColor.Add(bg, fg)
if currentColor.Foreground().IsTransparent() && len(BackgroundColor) != 0 { if currentColor.Foreground().IsTransparent() && len(BackgroundColor) != 0 {
background := getAnsiFromColorString(BackgroundColor, false) background := Colors.ToAnsi(BackgroundColor, false)
writeEscapedAnsiString(fmt.Sprintf(colorise, background)) writeEscapedAnsiString(fmt.Sprintf(colorise, background))
writeEscapedAnsiString(fmt.Sprintf(colorise, currentColor.Background().ToForeground())) writeEscapedAnsiString(fmt.Sprintf(colorise, currentColor.Background().ToForeground()))
return position return position
@ -606,12 +602,20 @@ func asAnsiColors(background, foreground color.Ansi) (color.Ansi, color.Ansi) {
background = background.Resolve(CurrentColors, ParentColors) background = background.Resolve(CurrentColors, ParentColors)
foreground = foreground.Resolve(CurrentColors, ParentColors) foreground = foreground.Resolve(CurrentColors, ParentColors)
if bg, err := Colors.Resolve(background); err == nil {
background = bg
}
if fg, err := Colors.Resolve(foreground); err == nil {
foreground = fg
}
inverted := foreground == color.Transparent && len(background) != 0 inverted := foreground == color.Transparent && len(background) != 0
backgroundAnsi := getAnsiFromColorString(background, !inverted) background = Colors.ToAnsi(background, !inverted)
foregroundAnsi := getAnsiFromColorString(foreground, false) foreground = Colors.ToAnsi(foreground, false)
return backgroundAnsi, foregroundAnsi return background, foreground
} }
func trimAnsi(text string) string { func trimAnsi(text string) string {