mirror of
https://github.com/JanDeDobbeleer/oh-my-posh.git
synced 2024-11-10 04:54:03 -08:00
fix: inherit parent colors in override
This commit is contained in:
parent
3781a43d01
commit
0bbc26d635
|
@ -47,6 +47,7 @@ type colorWriter interface {
|
|||
write(background, foreground, text string)
|
||||
string() string
|
||||
reset()
|
||||
setParentColors(background, foreground string)
|
||||
}
|
||||
|
||||
// AnsiColor writes colorized strings
|
||||
|
@ -54,6 +55,12 @@ type AnsiColor struct {
|
|||
builder strings.Builder
|
||||
ansi *ansiUtils
|
||||
terminalBackground string
|
||||
Parent *Color
|
||||
}
|
||||
|
||||
type Color struct {
|
||||
Background string
|
||||
Foreground string
|
||||
}
|
||||
|
||||
const (
|
||||
|
@ -63,6 +70,13 @@ const (
|
|||
Inherit = "inherit"
|
||||
)
|
||||
|
||||
func (a *AnsiColor) setParentColors(background, foreground string) {
|
||||
a.Parent = &Color{
|
||||
Background: background,
|
||||
Foreground: foreground,
|
||||
}
|
||||
}
|
||||
|
||||
// Gets the ANSI color code for a given color string.
|
||||
// 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`.
|
||||
|
@ -120,6 +134,12 @@ func (a *AnsiColor) write(background, foreground, text string) {
|
|||
}
|
||||
|
||||
getAnsiColors := func(background, foreground string) (string, string) {
|
||||
if background == Inherit && a.Parent != nil {
|
||||
background = a.Parent.Background
|
||||
}
|
||||
if foreground == Inherit && a.Parent != nil {
|
||||
foreground = a.Parent.Foreground
|
||||
}
|
||||
inverted := foreground == Transparent && len(background) != 0
|
||||
background = a.getAnsiFromColorString(background, !inverted)
|
||||
foreground = a.getAnsiFromColorString(foreground, false)
|
||||
|
|
|
@ -3,165 +3,150 @@ package main
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gookit/color"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const (
|
||||
inputText = "This is white, <#ff5733>this is orange</>, white again"
|
||||
)
|
||||
|
||||
func TestWriteAndRemoveText(t *testing.T) {
|
||||
ansi := &ansiUtils{}
|
||||
ansi.init("pwsh")
|
||||
renderer := &AnsiColor{
|
||||
ansi: ansi,
|
||||
func TestGetAnsiFromColorString(t *testing.T) {
|
||||
cases := []struct {
|
||||
Case string
|
||||
Expected string
|
||||
Color string
|
||||
Background bool
|
||||
}{
|
||||
{Case: "Invalid background", Expected: "", Color: "invalid", Background: true},
|
||||
{Case: "Invalid background", Expected: "", Color: "invalid", Background: false},
|
||||
{Case: "Hex foreground", Expected: "48;2;170;187;204", Color: "#AABBCC", Background: false},
|
||||
{Case: "Base 8 foreground", Expected: "41", Color: "red", Background: false},
|
||||
{Case: "Base 8 background", Expected: "41", Color: "red", Background: true},
|
||||
{Case: "Base 16 foreground", Expected: "101", Color: "lightRed", Background: false},
|
||||
{Case: "Base 16 backround", Expected: "101", Color: "lightRed", Background: true},
|
||||
}
|
||||
text := renderer.writeAndRemoveText("#193549", "#fff", "This is white, ", "This is white, ", inputText)
|
||||
assert.Equal(t, "<#ff5733>this is orange</>, white again", text)
|
||||
assert.NotContains(t, renderer.string(), "<#ff5733>")
|
||||
}
|
||||
|
||||
func TestWriteAndRemoveTextColored(t *testing.T) {
|
||||
ansi := &ansiUtils{}
|
||||
ansi.init("pwsh")
|
||||
renderer := &AnsiColor{
|
||||
ansi: ansi,
|
||||
for _, tc := range cases {
|
||||
renderer := &AnsiColor{}
|
||||
ansiColor := renderer.getAnsiFromColorString(tc.Color, true)
|
||||
assert.Equal(t, tc.Expected, ansiColor, tc.Case)
|
||||
}
|
||||
text := renderer.writeAndRemoveText("#193549", "#ff5733", "this is orange", "<#ff5733>this is orange</>", inputText)
|
||||
assert.Equal(t, "This is white, , white again", text)
|
||||
assert.NotContains(t, renderer.string(), "<#ff5733>")
|
||||
}
|
||||
|
||||
func TestWriteColorOverride(t *testing.T) {
|
||||
ansi := &ansiUtils{}
|
||||
ansi.init("pwsh")
|
||||
renderer := &AnsiColor{
|
||||
ansi: ansi,
|
||||
func TestWriteANSIColors(t *testing.T) {
|
||||
cases := []struct {
|
||||
Case string
|
||||
Expected string
|
||||
Input string
|
||||
Colors *Color
|
||||
Parent *Color
|
||||
TerminalBackground string
|
||||
}{
|
||||
{
|
||||
Case: "No color override",
|
||||
Input: "test",
|
||||
Expected: "\x1b[47m\x1b[30mtest\x1b[0m",
|
||||
Colors: &Color{Foreground: "black", Background: "white"},
|
||||
Parent: &Color{Foreground: "black", Background: "white"},
|
||||
},
|
||||
{
|
||||
Case: "Inherit foreground",
|
||||
Input: "test",
|
||||
Expected: "\x1b[47m\x1b[33mtest\x1b[0m",
|
||||
Colors: &Color{Foreground: Inherit, Background: "white"},
|
||||
Parent: &Color{Foreground: "yellow", Background: "white"},
|
||||
},
|
||||
{
|
||||
Case: "Inherit background",
|
||||
Input: "test",
|
||||
Expected: "\x1b[41m\x1b[30mtest\x1b[0m",
|
||||
Colors: &Color{Foreground: "black", Background: Inherit},
|
||||
Parent: &Color{Foreground: "yellow", Background: "red"},
|
||||
},
|
||||
{
|
||||
Case: "No parent",
|
||||
Input: "test",
|
||||
Expected: "\x1b[30mtest\x1b[0m",
|
||||
Colors: &Color{Foreground: "black", Background: Inherit},
|
||||
},
|
||||
{
|
||||
Case: "Inherit override foreground",
|
||||
Input: "hello <inherit>world</>",
|
||||
Expected: "\x1b[47m\x1b[30mhello \x1b[0m\x1b[47m\x1b[33mworld\x1b[0m",
|
||||
Colors: &Color{Foreground: "black", Background: "white"},
|
||||
Parent: &Color{Foreground: "yellow", Background: "red"},
|
||||
},
|
||||
{
|
||||
Case: "Inherit override background",
|
||||
Input: "hello <black,inherit>world</>",
|
||||
Expected: "\x1b[47m\x1b[30mhello \x1b[0m\x1b[41m\x1b[30mworld\x1b[0m",
|
||||
Colors: &Color{Foreground: "black", Background: "white"},
|
||||
Parent: &Color{Foreground: "yellow", Background: "red"},
|
||||
},
|
||||
{
|
||||
Case: "Inherit override background, no foreground specified",
|
||||
Input: "hello <,inherit>world</>",
|
||||
Expected: "\x1b[47m\x1b[30mhello \x1b[0m\x1b[41m\x1b[30mworld\x1b[0m",
|
||||
Colors: &Color{Foreground: "black", Background: "white"},
|
||||
Parent: &Color{Foreground: "yellow", Background: "red"},
|
||||
},
|
||||
{
|
||||
Case: "Inherit override both",
|
||||
Input: "hello <inherit,inherit>world</>",
|
||||
Expected: "\x1b[47m\x1b[30mhello \x1b[0m\x1b[41m\x1b[33mworld\x1b[0m",
|
||||
Colors: &Color{Foreground: "black", Background: "white"},
|
||||
Parent: &Color{Foreground: "yellow", Background: "red"},
|
||||
},
|
||||
{
|
||||
Case: "Inline override",
|
||||
Input: "hello, <red>world</>, rabbit",
|
||||
Expected: "\x1b[47m\x1b[30mhello, \x1b[0m\x1b[47m\x1b[31mworld\x1b[0m\x1b[47m\x1b[30m, rabbit\x1b[0m",
|
||||
Colors: &Color{Foreground: "black", Background: "white"},
|
||||
},
|
||||
{
|
||||
Case: "Transparent background",
|
||||
Input: "hello world",
|
||||
Expected: "\x1b[37mhello world\x1b[0m",
|
||||
Colors: &Color{Foreground: "white", Background: Transparent},
|
||||
},
|
||||
{
|
||||
Case: "Transparent foreground override",
|
||||
Input: "hello <#ffffff>world</>",
|
||||
Expected: "\x1b[32mhello \x1b[0m\x1b[38;2;255;255;255mworld\x1b[0m",
|
||||
Colors: &Color{Foreground: "green", Background: Transparent},
|
||||
},
|
||||
{
|
||||
Case: "Double override",
|
||||
Input: "<#ffffff>jan</>@<#ffffff>Jans-MBP</>",
|
||||
Expected: "\x1b[48;2;255;87;51m\x1b[38;2;255;255;255mjan\x1b[0m\x1b[48;2;255;87;51m\x1b[32m@\x1b[0m\x1b[48;2;255;87;51m\x1b[38;2;255;255;255mJans-MBP\x1b[0m",
|
||||
Colors: &Color{Foreground: "green", Background: "#FF5733"},
|
||||
},
|
||||
{
|
||||
Case: "No foreground",
|
||||
Input: "test",
|
||||
Expected: "\x1b[48;2;255;87;51m\x1b[37mtest\x1b[0m",
|
||||
Colors: &Color{Foreground: "", Background: "#FF5733"},
|
||||
},
|
||||
{
|
||||
Case: "Transparent foreground",
|
||||
Input: "test",
|
||||
Expected: "\x1b[38;2;255;87;51;49m\x1b[7mtest\x1b[0m",
|
||||
Colors: &Color{Foreground: Transparent, Background: "#FF5733"},
|
||||
},
|
||||
{
|
||||
Case: "Transparent foreground, terminal background set",
|
||||
Input: "test",
|
||||
Expected: "\x1b[38;2;255;87;51m\x1b[38;2;33;47;60mtest\x1b[0m",
|
||||
Colors: &Color{Foreground: Transparent, Background: "#FF5733"},
|
||||
TerminalBackground: "#212F3C",
|
||||
},
|
||||
}
|
||||
renderer.write("#193549", "#ff5733", inputText)
|
||||
assert.NotContains(t, renderer.string(), "<#ff5733>")
|
||||
}
|
||||
|
||||
func TestWriteColorOverrideBackground(t *testing.T) {
|
||||
ansi := &ansiUtils{}
|
||||
ansi.init("pwsh")
|
||||
renderer := &AnsiColor{
|
||||
ansi: ansi,
|
||||
for _, tc := range cases {
|
||||
ansi := &ansiUtils{}
|
||||
ansi.init("pwsh")
|
||||
renderer := &AnsiColor{
|
||||
ansi: ansi,
|
||||
Parent: tc.Parent,
|
||||
terminalBackground: tc.TerminalBackground,
|
||||
}
|
||||
renderer.write(tc.Colors.Background, tc.Colors.Foreground, tc.Input)
|
||||
got := renderer.string()
|
||||
assert.Equal(t, tc.Expected, got, tc.Case)
|
||||
}
|
||||
text := "This is white, <,#000000>this is black</>, white again"
|
||||
renderer.write("#193549", "#ff5733", text)
|
||||
assert.NotContains(t, renderer.string(), "000000")
|
||||
}
|
||||
|
||||
func TestWriteColorOverrideBackground16(t *testing.T) {
|
||||
ansi := &ansiUtils{}
|
||||
ansi.init("pwsh")
|
||||
renderer := &AnsiColor{
|
||||
ansi: ansi,
|
||||
}
|
||||
text := "This is default <,white> this background is changed</> default again"
|
||||
renderer.write("#193549", "#ff5733", text)
|
||||
assert.NotContains(t, renderer.string(), "white")
|
||||
assert.NotContains(t, renderer.string(), "</>")
|
||||
assert.NotContains(t, renderer.string(), "<,")
|
||||
}
|
||||
|
||||
func TestWriteColorOverrideBoth(t *testing.T) {
|
||||
ansi := &ansiUtils{}
|
||||
ansi.init("pwsh")
|
||||
renderer := &AnsiColor{
|
||||
ansi: ansi,
|
||||
}
|
||||
text := "This is white, <#000000,#ffffff>this is black</>, white again"
|
||||
renderer.write("#193549", "#ff5733", text)
|
||||
assert.NotContains(t, renderer.string(), "ffffff")
|
||||
assert.NotContains(t, renderer.string(), "000000")
|
||||
}
|
||||
|
||||
func TestWriteColorOverrideBoth16(t *testing.T) {
|
||||
ansi := &ansiUtils{}
|
||||
ansi.init("pwsh")
|
||||
renderer := &AnsiColor{
|
||||
ansi: ansi,
|
||||
}
|
||||
text := "This is white, <black,white>this is black</>, white again"
|
||||
renderer.write("#193549", "#ff5733", text)
|
||||
assert.NotContains(t, renderer.string(), "<black,white>")
|
||||
assert.NotContains(t, renderer.string(), "</>")
|
||||
}
|
||||
|
||||
func TestWriteColorOverrideDouble(t *testing.T) {
|
||||
ansi := &ansiUtils{}
|
||||
ansi.init("pwsh")
|
||||
renderer := &AnsiColor{
|
||||
ansi: ansi,
|
||||
}
|
||||
text := "<#ffffff>jan</>@<#ffffff>Jans-MBP</>"
|
||||
renderer.write("#193549", "#ff5733", text)
|
||||
assert.NotContains(t, renderer.string(), "<#ffffff>")
|
||||
assert.NotContains(t, renderer.string(), "</>")
|
||||
}
|
||||
|
||||
func TestWriteColorTransparent(t *testing.T) {
|
||||
ansi := &ansiUtils{}
|
||||
ansi.init("pwsh")
|
||||
renderer := &AnsiColor{
|
||||
ansi: ansi,
|
||||
}
|
||||
text := "This is white"
|
||||
renderer.writeColoredText("#193549", Transparent, text)
|
||||
t.Log(renderer.string())
|
||||
}
|
||||
|
||||
func TestWriteColorName(t *testing.T) {
|
||||
ansi := &ansiUtils{}
|
||||
ansi.init("pwsh")
|
||||
renderer := &AnsiColor{
|
||||
ansi: ansi,
|
||||
}
|
||||
text := "This is white, <red>this is red</>, white again"
|
||||
renderer.write("#193549", "red", text)
|
||||
assert.NotContains(t, renderer.string(), "<red>")
|
||||
}
|
||||
|
||||
func TestWriteColorInvalid(t *testing.T) {
|
||||
ansi := &ansiUtils{}
|
||||
ansi.init("pwsh")
|
||||
renderer := &AnsiColor{
|
||||
ansi: ansi,
|
||||
}
|
||||
text := "This is white, <invalid>this is orange</>, white again"
|
||||
renderer.write("#193549", "invalid", text)
|
||||
assert.NotContains(t, renderer.string(), "<invalid>")
|
||||
}
|
||||
|
||||
func TestGetAnsiFromColorStringBg(t *testing.T) {
|
||||
renderer := &AnsiColor{}
|
||||
colorCode := renderer.getAnsiFromColorString("blue", true)
|
||||
assert.Equal(t, color.BgBlue.String(), colorCode)
|
||||
}
|
||||
|
||||
func TestGetAnsiFromColorStringFg(t *testing.T) {
|
||||
renderer := &AnsiColor{}
|
||||
colorCode := renderer.getAnsiFromColorString("red", false)
|
||||
assert.Equal(t, color.FgRed.String(), colorCode)
|
||||
}
|
||||
|
||||
func TestGetAnsiFromColorStringHex(t *testing.T) {
|
||||
renderer := &AnsiColor{}
|
||||
colorCode := renderer.getAnsiFromColorString("#AABBCC", false)
|
||||
assert.Equal(t, color.HEX("#AABBCC").String(), colorCode)
|
||||
}
|
||||
|
||||
func TestGetAnsiFromColorStringInvalidFg(t *testing.T) {
|
||||
renderer := &AnsiColor{}
|
||||
colorCode := renderer.getAnsiFromColorString("invalid", false)
|
||||
assert.Equal(t, "", colorCode)
|
||||
}
|
||||
|
||||
func TestGetAnsiFromColorStringInvalidBg(t *testing.T) {
|
||||
renderer := &AnsiColor{}
|
||||
colorCode := renderer.getAnsiFromColorString("invalid", true)
|
||||
assert.Equal(t, "", colorCode)
|
||||
}
|
||||
|
|
29
src/block.go
29
src/block.go
|
@ -81,22 +81,6 @@ func (b *Block) setStringValues() {
|
|||
}
|
||||
}
|
||||
|
||||
func (b *Block) foreground() string {
|
||||
color := b.activeSegment.foreground()
|
||||
if b.previousActiveSegment != nil && color == Inherit {
|
||||
return b.previousActiveSegment.foreground()
|
||||
}
|
||||
return color
|
||||
}
|
||||
|
||||
func (b *Block) background() string {
|
||||
color := b.activeSegment.background()
|
||||
if b.previousActiveSegment != nil && color == Inherit {
|
||||
return b.previousActiveSegment.background()
|
||||
}
|
||||
return color
|
||||
}
|
||||
|
||||
func (b *Block) renderSegments() string {
|
||||
defer b.writer.reset()
|
||||
for _, segment := range b.Segments {
|
||||
|
@ -143,7 +127,7 @@ func (b *Block) getPowerlineColor(foreground bool) string {
|
|||
return b.previousActiveSegment.background()
|
||||
}
|
||||
if b.activeSegment.Style == Diamond && len(b.activeSegment.LeadingDiamond) == 0 {
|
||||
return b.background()
|
||||
return b.activeSegment.background()
|
||||
}
|
||||
if !foreground && b.activeSegment.Style != Powerline {
|
||||
return Transparent
|
||||
|
@ -164,10 +148,11 @@ func (b *Block) renderSegmentText(text string) {
|
|||
b.renderPowerLineSegment(text)
|
||||
}
|
||||
b.previousActiveSegment = b.activeSegment
|
||||
b.writer.setParentColors(b.activeSegment.background(), b.activeSegment.foreground())
|
||||
}
|
||||
|
||||
func (b *Block) renderPowerLineSegment(text string) {
|
||||
b.writePowerLineSeparator(b.background(), b.getPowerlineColor(true), false)
|
||||
b.writePowerLineSeparator(b.activeSegment.background(), b.getPowerlineColor(true), false)
|
||||
b.renderText(text)
|
||||
}
|
||||
|
||||
|
@ -176,14 +161,14 @@ func (b *Block) renderPlainSegment(text string) {
|
|||
}
|
||||
|
||||
func (b *Block) renderDiamondSegment(text string) {
|
||||
b.writer.write(Transparent, b.background(), b.activeSegment.LeadingDiamond)
|
||||
b.writer.write(Transparent, b.activeSegment.background(), b.activeSegment.LeadingDiamond)
|
||||
b.renderText(text)
|
||||
b.writer.write(Transparent, b.background(), b.activeSegment.TrailingDiamond)
|
||||
b.writer.write(Transparent, b.activeSegment.background(), b.activeSegment.TrailingDiamond)
|
||||
}
|
||||
|
||||
func (b *Block) renderText(text string) {
|
||||
bg := b.background()
|
||||
fg := b.foreground()
|
||||
bg := b.activeSegment.background()
|
||||
fg := b.activeSegment.foreground()
|
||||
defaultValue := " "
|
||||
b.writer.write(bg, fg, b.activeSegment.getValue(Prefix, defaultValue))
|
||||
b.writer.write(bg, fg, text)
|
||||
|
|
|
@ -28,42 +28,42 @@ func TestBlockEnabled(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestForegroundColor(t *testing.T) {
|
||||
cases := []struct {
|
||||
Case string
|
||||
Expected string
|
||||
PreviousSegment *Segment
|
||||
Segment *Segment
|
||||
}{
|
||||
{Case: "Standard", Expected: "black", Segment: &Segment{Foreground: "black"}},
|
||||
{Case: "Segment color override", Expected: "red", Segment: &Segment{Foreground: "black", props: &properties{foreground: "red"}}},
|
||||
{Case: "Inherit", Expected: "yellow", Segment: &Segment{Foreground: Inherit}, PreviousSegment: &Segment{Foreground: "yellow"}},
|
||||
}
|
||||
// func TestForegroundColor(t *testing.T) {
|
||||
// cases := []struct {
|
||||
// Case string
|
||||
// Expected string
|
||||
// PreviousSegment *Segment
|
||||
// Segment *Segment
|
||||
// }{
|
||||
// {Case: "Standard", Expected: "black", Segment: &Segment{Foreground: "black"}},
|
||||
// {Case: "Segment color override", Expected: "red", Segment: &Segment{Foreground: "black", props: &properties{foreground: "red"}}},
|
||||
// {Case: "Inherit", Expected: "yellow", Segment: &Segment{Foreground: Inherit}, PreviousSegment: &Segment{Foreground: "yellow"}},
|
||||
// }
|
||||
|
||||
for _, tc := range cases {
|
||||
block := &Block{}
|
||||
block.previousActiveSegment = tc.PreviousSegment
|
||||
block.activeSegment = tc.Segment
|
||||
assert.Equal(t, tc.Expected, block.foreground(), tc.Case)
|
||||
}
|
||||
}
|
||||
// for _, tc := range cases {
|
||||
// block := &Block{}
|
||||
// block.previousActiveSegment = tc.PreviousSegment
|
||||
// block.activeSegment = tc.Segment
|
||||
// assert.Equal(t, tc.Expected, block.foreground(), tc.Case)
|
||||
// }
|
||||
// }
|
||||
|
||||
func TestBackgroundColor(t *testing.T) {
|
||||
cases := []struct {
|
||||
Case string
|
||||
Expected string
|
||||
PreviousSegment *Segment
|
||||
Segment *Segment
|
||||
}{
|
||||
{Case: "Standard", Expected: "black", Segment: &Segment{Background: "black"}},
|
||||
{Case: "Segment color override", Expected: "red", Segment: &Segment{Background: "black", props: &properties{background: "red"}}},
|
||||
{Case: "Inherit", Expected: "yellow", Segment: &Segment{Background: Inherit}, PreviousSegment: &Segment{Background: "yellow"}},
|
||||
}
|
||||
// func TestBackgroundColor(t *testing.T) {
|
||||
// cases := []struct {
|
||||
// Case string
|
||||
// Expected string
|
||||
// PreviousSegment *Segment
|
||||
// Segment *Segment
|
||||
// }{
|
||||
// {Case: "Standard", Expected: "black", Segment: &Segment{Background: "black"}},
|
||||
// {Case: "Segment color override", Expected: "red", Segment: &Segment{Background: "black", props: &properties{background: "red"}}},
|
||||
// {Case: "Inherit", Expected: "yellow", Segment: &Segment{Background: Inherit}, PreviousSegment: &Segment{Background: "yellow"}},
|
||||
// }
|
||||
|
||||
for _, tc := range cases {
|
||||
block := &Block{}
|
||||
block.previousActiveSegment = tc.PreviousSegment
|
||||
block.activeSegment = tc.Segment
|
||||
assert.Equal(t, tc.Expected, block.background(), tc.Case)
|
||||
}
|
||||
}
|
||||
// for _, tc := range cases {
|
||||
// block := &Block{}
|
||||
// block.previousActiveSegment = tc.PreviousSegment
|
||||
// block.activeSegment = tc.Segment
|
||||
// assert.Equal(t, tc.Expected, block.background(), tc.Case)
|
||||
// }
|
||||
// }
|
||||
|
|
Loading…
Reference in a new issue