feat: enable/disable true color per terminal

This commit is contained in:
Jan De Dobbeleer 2023-03-23 09:59:54 +01:00 committed by Jan De Dobbeleer
parent 481f096878
commit 8c5c836f22
13 changed files with 48 additions and 20 deletions

View file

@ -80,6 +80,7 @@ type Writer struct {
ParentColors []*Colors ParentColors []*Colors
AnsiColors ColorString AnsiColors ColorString
Plain bool Plain bool
TrueColor bool
builder strings.Builder builder strings.Builder
length int length int
@ -283,7 +284,7 @@ func (w *Writer) Write(background, foreground, text string) {
w.background, w.foreground = w.asAnsiColors(background, foreground) w.background, w.foreground = w.asAnsiColors(background, foreground)
// default to white foreground // default to white foreground
if w.foreground.IsEmpty() { if w.foreground.IsEmpty() {
w.foreground = w.AnsiColors.ToColor("white", false) w.foreground = w.AnsiColors.ToColor("white", false, w.TrueColor)
} }
// validate if we start with a color override // validate if we start with a color override
match := regex.FindNamedRegexMatch(anchorRegex, text) match := regex.FindNamedRegexMatch(anchorRegex, text)
@ -365,7 +366,7 @@ func (w *Writer) writeEscapedAnsiString(text string) {
} }
func (w *Writer) getAnsiFromColorString(colorString string, isBackground bool) Color { func (w *Writer) getAnsiFromColorString(colorString string, isBackground bool) Color {
return w.AnsiColors.ToColor(colorString, isBackground) return w.AnsiColors.ToColor(colorString, isBackground, w.TrueColor)
} }
func (w *Writer) writeSegmentColors() { func (w *Writer) writeSegmentColors() {

View file

@ -203,6 +203,7 @@ func TestWriteANSIColors(t *testing.T) {
Colors: tc.Colors, Colors: tc.Colors,
TerminalBackground: tc.TerminalBackground, TerminalBackground: tc.TerminalBackground,
AnsiColors: &DefaultColors{}, AnsiColors: &DefaultColors{},
TrueColor: true,
} }
renderer.Init(shell.GENERIC) renderer.Init(shell.GENERIC)
renderer.Write(tc.Colors.Background, tc.Colors.Foreground, tc.Input) renderer.Write(tc.Colors.Background, tc.Colors.Foreground, tc.Input)

View file

@ -16,7 +16,7 @@ import (
// This can include a valid hex color in the format `#FFFFFF`, // This can include a valid hex color in the format `#FFFFFF`,
// 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 ColorString interface { type ColorString interface {
ToColor(colorString string, isBackground bool) Color ToColor(colorString string, isBackground bool, trueColor bool) Color
} }
// Color is an ANSI color code ready to be printed to the console. // Color is an ANSI color code ready to be printed to the console.
@ -98,7 +98,7 @@ const (
backgroundIndex = 1 backgroundIndex = 1
) )
func (d *DefaultColors) ToColor(colorString string, isBackground bool) Color { func (d *DefaultColors) ToColor(colorString string, isBackground, trueColor bool) Color {
if len(colorString) == 0 { if len(colorString) == 0 {
return emptyColor return emptyColor
} }
@ -128,7 +128,10 @@ func (d *DefaultColors) ToColor(colorString string, isBackground bool) Color {
} }
style := color.HEX(colorString, isBackground) style := color.HEX(colorString, isBackground)
if !style.IsEmpty() { if !style.IsEmpty() {
return Color(style.String()) if trueColor {
return Color(style.String())
}
return Color(style.C256().String())
} }
if colorInt, err := strconv.ParseInt(colorString, 10, 8); err == nil { if colorInt, err := strconv.ParseInt(colorString, 10, 8); err == nil {
c := color.C256(uint8(colorInt), isBackground) c := color.C256(uint8(colorInt), isBackground)
@ -161,12 +164,12 @@ type PaletteColors struct {
palette Palette palette Palette
} }
func (p *PaletteColors) ToColor(colorString string, isBackground bool) Color { func (p *PaletteColors) ToColor(colorString string, isBackground, trueColor bool) Color {
paletteColor, err := p.palette.ResolveColor(colorString) paletteColor, err := p.palette.ResolveColor(colorString)
if err != nil { if err != nil {
return emptyColor return emptyColor
} }
ansiColor := p.ansiColors.ToColor(paletteColor, isBackground) ansiColor := p.ansiColors.ToColor(paletteColor, isBackground, trueColor)
return ansiColor return ansiColor
} }
@ -183,7 +186,7 @@ type cachedColorKey struct {
isBackground bool isBackground bool
} }
func (c *CachedColors) ToColor(colorString string, isBackground bool) Color { func (c *CachedColors) ToColor(colorString string, isBackground, trueColor bool) Color {
if c.colorCache == nil { if c.colorCache == nil {
c.colorCache = make(map[cachedColorKey]Color) c.colorCache = make(map[cachedColorKey]Color)
} }
@ -191,7 +194,7 @@ func (c *CachedColors) ToColor(colorString string, isBackground bool) Color {
if ansiColor, hit := c.colorCache[key]; hit { if ansiColor, hit := c.colorCache[key]; hit {
return ansiColor return ansiColor
} }
ansiColor := c.ansiColors.ToColor(colorString, isBackground) ansiColor := c.ansiColors.ToColor(colorString, isBackground, trueColor)
c.colorCache[key] = ansiColor c.colorCache[key] = ansiColor
return ansiColor return ansiColor
} }

View file

@ -1,9 +1,12 @@
package ansi package ansi
import ( import (
"errors"
"testing" "testing"
"github.com/alecthomas/assert" "github.com/alecthomas/assert"
"github.com/jandedobbeleer/oh-my-posh/src/mock"
"github.com/jandedobbeleer/oh-my-posh/src/platform"
) )
func TestGetAnsiFromColorString(t *testing.T) { func TestGetAnsiFromColorString(t *testing.T) {
@ -12,6 +15,7 @@ func TestGetAnsiFromColorString(t *testing.T) {
Expected Color Expected Color
Color string Color string
Background bool Background bool
Color256 bool
}{ }{
{Case: "256 color", Expected: Color("38;5;99"), Color: "99", Background: false}, {Case: "256 color", Expected: Color("38;5;99"), Color: "99", Background: false},
{Case: "256 color", Expected: Color("38;5;122"), Color: "122", Background: false}, {Case: "256 color", Expected: Color("38;5;122"), Color: "122", Background: false},
@ -23,27 +27,33 @@ func TestGetAnsiFromColorString(t *testing.T) {
{Case: "Base 8 background", Expected: Color("41"), Color: "red", Background: true}, {Case: "Base 8 background", Expected: Color("41"), Color: "red", Background: true},
{Case: "Base 16 foreground", Expected: Color("91"), Color: "lightRed", Background: false}, {Case: "Base 16 foreground", Expected: Color("91"), Color: "lightRed", Background: false},
{Case: "Base 16 backround", Expected: Color("101"), Color: "lightRed", Background: true}, {Case: "Base 16 backround", Expected: Color("101"), Color: "lightRed", Background: true},
{Case: "Non true color TERM", Expected: Color("38;5;146"), Color: "#AABBCC", Color256: true},
} }
for _, tc := range cases { for _, tc := range cases {
ansiColors := &DefaultColors{} ansiColors := &DefaultColors{}
ansiColor := ansiColors.ToColor(tc.Color, tc.Background) ansiColor := ansiColors.ToColor(tc.Color, tc.Background, !tc.Color256)
assert.Equal(t, tc.Expected, ansiColor, tc.Case) assert.Equal(t, tc.Expected, ansiColor, tc.Case)
} }
} }
func TestMakeColors(t *testing.T) { func TestMakeColors(t *testing.T) {
colors := MakeColors(nil, false, "", nil) env := &mock.MockedEnvironment{}
env.On("Flags").Return(&platform.Flags{
TrueColor: true,
})
env.On("WindowsRegistryKeyValue", `HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM\ColorizationColor`).Return(&platform.WindowsRegistryValue{}, errors.New("err"))
colors := MakeColors(nil, false, "", env)
assert.IsType(t, &DefaultColors{}, colors) assert.IsType(t, &DefaultColors{}, colors)
colors = MakeColors(nil, true, "", nil) colors = MakeColors(nil, true, "", env)
assert.IsType(t, &CachedColors{}, colors) assert.IsType(t, &CachedColors{}, colors)
assert.IsType(t, &DefaultColors{}, colors.(*CachedColors).ansiColors) assert.IsType(t, &DefaultColors{}, colors.(*CachedColors).ansiColors)
colors = MakeColors(testPalette, false, "", nil) colors = MakeColors(testPalette, false, "", env)
assert.IsType(t, &PaletteColors{}, colors) assert.IsType(t, &PaletteColors{}, colors)
assert.IsType(t, &DefaultColors{}, colors.(*PaletteColors).ansiColors) assert.IsType(t, &DefaultColors{}, colors.(*PaletteColors).ansiColors)
colors = MakeColors(testPalette, true, "", nil) colors = MakeColors(testPalette, true, "", env)
assert.IsType(t, &CachedColors{}, colors) assert.IsType(t, &CachedColors{}, colors)
assert.IsType(t, &PaletteColors{}, colors.(*CachedColors).ansiColors) assert.IsType(t, &PaletteColors{}, colors.(*CachedColors).ansiColors)
assert.IsType(t, &DefaultColors{}, colors.(*CachedColors).ansiColors.(*PaletteColors).ansiColors) assert.IsType(t, &DefaultColors{}, colors.(*CachedColors).ansiColors.(*PaletteColors).ansiColors)

View file

@ -8,12 +8,12 @@ func GetAccentColor(_ platform.Environment) (*RGB, error) {
return nil, &platform.NotImplemented{} return nil, &platform.NotImplemented{}
} }
func (d *DefaultColors) SetAccentColor(_ platform.Environment, defaultColor string) { func (d *DefaultColors) SetAccentColor(env platform.Environment, defaultColor string) {
if len(defaultColor) == 0 { if len(defaultColor) == 0 {
return return
} }
d.accent = &Colors{ d.accent = &Colors{
Foreground: string(d.ToColor(defaultColor, false)), Foreground: string(d.ToColor(defaultColor, false, env.Flags().TrueColor)),
Background: string(d.ToColor(defaultColor, true)), Background: string(d.ToColor(defaultColor, true, env.Flags().TrueColor)),
} }
} }

View file

@ -28,8 +28,8 @@ func (d *DefaultColors) SetAccentColor(env platform.Environment, defaultColor st
rgb, err := GetAccentColor(env) rgb, err := GetAccentColor(env)
if err != nil { if err != nil {
d.accent = &Colors{ d.accent = &Colors{
Foreground: string(d.ToColor(defaultColor, false)), Foreground: string(d.ToColor(defaultColor, false, env.Flags().TrueColor)),
Background: string(d.ToColor(defaultColor, true)), Background: string(d.ToColor(defaultColor, true, env.Flags().TrueColor)),
} }
return return
} }

View file

@ -66,6 +66,7 @@ Exports the config to an image file using customized output options.`,
writer := &ansi.Writer{ writer := &ansi.Writer{
TerminalBackground: shell.ConsoleBackgroundColor(env, cfg.TerminalBackground), TerminalBackground: shell.ConsoleBackgroundColor(env, cfg.TerminalBackground),
AnsiColors: writerColors, AnsiColors: writerColors,
TrueColor: env.CmdFlags.TrueColor,
} }
writer.Init(shell.GENERIC) writer.Init(shell.GENERIC)
eng := &engine.Engine{ eng := &engine.Engine{

View file

@ -38,6 +38,7 @@ var debugCmd = &cobra.Command{
TerminalBackground: shell.ConsoleBackgroundColor(env, cfg.TerminalBackground), TerminalBackground: shell.ConsoleBackgroundColor(env, cfg.TerminalBackground),
AnsiColors: writerColors, AnsiColors: writerColors,
Plain: plain, Plain: plain,
TrueColor: env.CmdFlags.TrueColor,
} }
writer.Init(shell.GENERIC) writer.Init(shell.GENERIC)
eng := &engine.Engine{ eng := &engine.Engine{

View file

@ -67,6 +67,7 @@ func (b *Block) InitPlain(env platform.Environment, config *Config) {
b.writer = &ansi.Writer{ b.writer = &ansi.Writer{
TerminalBackground: shell.ConsoleBackgroundColor(env, config.TerminalBackground), TerminalBackground: shell.ConsoleBackgroundColor(env, config.TerminalBackground),
AnsiColors: config.MakeColors(), AnsiColors: config.MakeColors(),
TrueColor: env.Flags().TrueColor,
} }
b.writer.Init(shell.GENERIC) b.writer.Init(shell.GENERIC)
b.env = env b.env = env

View file

@ -337,7 +337,9 @@ func (e *Engine) print() string {
} }
// in bash, the entire rprompt needs to be escaped for the prompt to be interpreted correctly // in bash, the entire rprompt needs to be escaped for the prompt to be interpreted correctly
// see https://github.com/jandedobbeleer/oh-my-posh/pull/2398 // see https://github.com/jandedobbeleer/oh-my-posh/pull/2398
writer := &ansi.Writer{} writer := &ansi.Writer{
TrueColor: e.Env.Flags().TrueColor,
}
writer.Init(shell.GENERIC) writer.Init(shell.GENERIC)
prompt := writer.SaveCursorPosition() prompt := writer.SaveCursorPosition()
prompt += writer.CarriageForward() prompt += writer.CarriageForward()

View file

@ -105,6 +105,7 @@ func engineRender() {
writer := &ansi.Writer{ writer := &ansi.Writer{
TerminalBackground: shell.ConsoleBackgroundColor(env, cfg.TerminalBackground), TerminalBackground: shell.ConsoleBackgroundColor(env, cfg.TerminalBackground),
AnsiColors: writerColors, AnsiColors: writerColors,
TrueColor: env.CmdFlags.TrueColor,
} }
writer.Init(shell.GENERIC) writer.Init(shell.GENERIC)
engine := &Engine{ engine := &Engine{

View file

@ -22,6 +22,7 @@ func New(flags *platform.Flags) *Engine {
TerminalBackground: shell.ConsoleBackgroundColor(env, cfg.TerminalBackground), TerminalBackground: shell.ConsoleBackgroundColor(env, cfg.TerminalBackground),
AnsiColors: cfg.MakeColors(), AnsiColors: cfg.MakeColors(),
Plain: flags.Plain, Plain: flags.Plain,
TrueColor: env.CmdFlags.TrueColor,
} }
ansiWriter.Init(env.Shell()) ansiWriter.Init(env.Shell())

View file

@ -71,6 +71,7 @@ type Flags struct {
PromptCount int PromptCount int
Cleared bool Cleared bool
Version string Version string
TrueColor bool
} }
type CommandError struct { type CommandError struct {
@ -300,6 +301,11 @@ func (env *Shell) Init() {
if env.CmdFlags.Plain { if env.CmdFlags.Plain {
log.Plain() log.Plain()
} }
trueColor := true
if env.Getenv("TERM_PROGRAM") == "Apple_Terminal" {
trueColor = false
}
env.CmdFlags.TrueColor = trueColor
env.fileCache = &fileCache{} env.fileCache = &fileCache{}
env.fileCache.Init(env.CachePath()) env.fileCache.Init(env.CachePath())
env.resolveConfigPath() env.resolveConfigPath()