feat: cycle through colors

resolves #3327
This commit is contained in:
Jan De Dobbeleer 2023-01-09 20:10:55 +01:00 committed by Jan De Dobbeleer
parent 6ca3d22b80
commit 86459f9a2f
13 changed files with 168 additions and 96 deletions

View file

@ -34,9 +34,9 @@ type style struct {
End string
}
type cachedColor struct {
Background string
Foreground string
type Colors struct {
Background string `json:"background"`
Foreground string `json:"foreground"`
}
const (
@ -75,9 +75,9 @@ const (
// Writer writes colorized ANSI strings
type Writer struct {
TerminalBackground string
Colors *cachedColor
ParentColors []*cachedColor
AnsiColors Colors
Colors *Colors
ParentColors []*Colors
AnsiColors ColorString
Plain bool
builder strings.Builder
@ -175,7 +175,7 @@ func (w *Writer) Init(shellName string) {
}
func (w *Writer) SetColors(background, foreground string) {
w.Colors = &cachedColor{
w.Colors = &Colors{
Background: background,
Foreground: foreground,
}
@ -183,9 +183,9 @@ func (w *Writer) SetColors(background, foreground string) {
func (w *Writer) SetParentColors(background, foreground string) {
if w.ParentColors == nil {
w.ParentColors = make([]*cachedColor, 0)
w.ParentColors = make([]*Colors, 0)
}
w.ParentColors = append([]*cachedColor{{
w.ParentColors = append([]*Colors{{
Background: background,
Foreground: foreground,
}}, w.ParentColors...)
@ -279,7 +279,7 @@ func (w *Writer) Write(background, foreground, text string) {
w.background, w.foreground = w.asAnsiColors(background, foreground)
// default to white foreground
if w.foreground.IsEmpty() {
w.foreground = w.AnsiColors.AnsiColorFromString("white", false)
w.foreground = w.AnsiColors.ToColor("white", false)
}
// validate if we start with a color override
match := regex.FindNamedRegexMatch(anchorRegex, text)
@ -361,7 +361,7 @@ func (w *Writer) writeEscapedAnsiString(text string) {
}
func (w *Writer) getAnsiFromColorString(colorString string, isBackground bool) Color {
return w.AnsiColors.AnsiColorFromString(colorString, isBackground)
return w.AnsiColors.ToColor(colorString, isBackground)
}
func (w *Writer) writeSegmentColors() {

View file

@ -13,187 +13,187 @@ func TestWriteANSIColors(t *testing.T) {
Case string
Expected string
Input string
Colors *cachedColor
Parent *cachedColor
Colors *Colors
Parent *Colors
TerminalBackground string
}{
{
Case: "Bold",
Input: "<b>test</b>",
Expected: "\x1b[1m\x1b[30mtest\x1b[22m\x1b[0m",
Colors: &cachedColor{Foreground: "black", Background: ParentBackground},
Colors: &Colors{Foreground: "black", Background: ParentBackground},
},
{
Case: "Bold with color override",
Input: "<b><#ffffff>test</></b>",
Expected: "\x1b[1m\x1b[30m\x1b[38;2;255;255;255mtest\x1b[0m\x1b[30m\x1b[22m\x1b[0m",
Colors: &cachedColor{Foreground: "black", Background: ParentBackground},
Colors: &Colors{Foreground: "black", Background: ParentBackground},
},
{
Case: "Bold with color override, flavor 2",
Input: "<#ffffff><b>test</b></>",
Expected: "\x1b[38;2;255;255;255m\x1b[1mtest\x1b[22m\x1b[0m",
Colors: &cachedColor{Foreground: "black", Background: ParentBackground},
Colors: &Colors{Foreground: "black", Background: ParentBackground},
},
{
Case: "Double override",
Input: "<#ffffff>jan</>@<#ffffff>Jans-MBP</>",
Expected: "\x1b[48;2;255;87;51m\x1b[38;2;255;255;255mjan\x1b[32m@\x1b[38;2;255;255;255mJans-MBP\x1b[0m",
Colors: &cachedColor{Foreground: "green", Background: "#FF5733"},
Colors: &Colors{Foreground: "green", Background: "#FF5733"},
},
{
Case: "No color override",
Input: "test",
Expected: "\x1b[47m\x1b[30mtest\x1b[0m",
Colors: &cachedColor{Foreground: "black", Background: "white"},
Parent: &cachedColor{Foreground: "black", Background: "white"},
Colors: &Colors{Foreground: "black", Background: "white"},
Parent: &Colors{Foreground: "black", Background: "white"},
},
{
Case: "Inherit foreground",
Input: "test",
Expected: "\x1b[47m\x1b[33mtest\x1b[0m",
Colors: &cachedColor{Foreground: ParentForeground, Background: "white"},
Parent: &cachedColor{Foreground: "yellow", Background: "white"},
Colors: &Colors{Foreground: ParentForeground, Background: "white"},
Parent: &Colors{Foreground: "yellow", Background: "white"},
},
{
Case: "Inherit background",
Input: "test",
Expected: "\x1b[41m\x1b[30mtest\x1b[0m",
Colors: &cachedColor{Foreground: "black", Background: ParentBackground},
Parent: &cachedColor{Foreground: "yellow", Background: "red"},
Colors: &Colors{Foreground: "black", Background: ParentBackground},
Parent: &Colors{Foreground: "yellow", Background: "red"},
},
{
Case: "No parent",
Input: "test",
Expected: "\x1b[30mtest\x1b[0m",
Colors: &cachedColor{Foreground: "black", Background: ParentBackground},
Colors: &Colors{Foreground: "black", Background: ParentBackground},
},
{
Case: "Inherit override foreground",
Input: "hello <parentForeground>world</>",
Expected: "\x1b[47m\x1b[30mhello \x1b[33mworld\x1b[0m",
Colors: &cachedColor{Foreground: "black", Background: "white"},
Parent: &cachedColor{Foreground: "yellow", Background: "red"},
Colors: &Colors{Foreground: "black", Background: "white"},
Parent: &Colors{Foreground: "yellow", Background: "red"},
},
{
Case: "Inherit override background",
Input: "hello <black,parentBackground>world</>",
Expected: "\x1b[47m\x1b[30mhello \x1b[41mworld\x1b[0m",
Colors: &cachedColor{Foreground: "black", Background: "white"},
Parent: &cachedColor{Foreground: "yellow", Background: "red"},
Colors: &Colors{Foreground: "black", Background: "white"},
Parent: &Colors{Foreground: "yellow", Background: "red"},
},
{
Case: "Inherit override background, no foreground specified",
Input: "hello <,parentBackground>world</>",
Expected: "\x1b[47m\x1b[30mhello \x1b[41mworld\x1b[0m",
Colors: &cachedColor{Foreground: "black", Background: "white"},
Parent: &cachedColor{Foreground: "yellow", Background: "red"},
Colors: &Colors{Foreground: "black", Background: "white"},
Parent: &Colors{Foreground: "yellow", Background: "red"},
},
{
Case: "Inherit no parent foreground",
Input: "hello <parentForeground>world</>",
Expected: "\x1b[47m\x1b[30mhello \x1b[0m\x1b[37;49m\x1b[7mworld\x1b[0m",
Colors: &cachedColor{Foreground: "black", Background: "white"},
Colors: &Colors{Foreground: "black", Background: "white"},
},
{
Case: "Inherit no parent background",
Input: "hello <,parentBackground>world</>",
Expected: "\x1b[47m\x1b[30mhello \x1b[0m\x1b[30mworld\x1b[0m",
Colors: &cachedColor{Foreground: "black", Background: "white"},
Colors: &Colors{Foreground: "black", Background: "white"},
},
{
Case: "Inherit override both",
Input: "hello <parentForeground,parentBackground>world</>",
Expected: "\x1b[47m\x1b[30mhello \x1b[41m\x1b[33mworld\x1b[0m",
Colors: &cachedColor{Foreground: "black", Background: "white"},
Parent: &cachedColor{Foreground: "yellow", Background: "red"},
Colors: &Colors{Foreground: "black", Background: "white"},
Parent: &Colors{Foreground: "yellow", Background: "red"},
},
{
Case: "Inherit override both inverted",
Input: "hello <parentBackground,parentForeground>world</>",
Expected: "\x1b[47m\x1b[30mhello \x1b[43m\x1b[31mworld\x1b[0m",
Colors: &cachedColor{Foreground: "black", Background: "white"},
Parent: &cachedColor{Foreground: "yellow", Background: "red"},
Colors: &Colors{Foreground: "black", Background: "white"},
Parent: &Colors{Foreground: "yellow", Background: "red"},
},
{
Case: "Inline override",
Input: "hello, <red>world</>, rabbit",
Expected: "\x1b[47m\x1b[30mhello, \x1b[31mworld\x1b[30m, rabbit\x1b[0m",
Colors: &cachedColor{Foreground: "black", Background: "white"},
Colors: &Colors{Foreground: "black", Background: "white"},
},
{
Case: "Transparent background",
Input: "hello world",
Expected: "\x1b[37mhello world\x1b[0m",
Colors: &cachedColor{Foreground: "white", Background: Transparent},
Colors: &Colors{Foreground: "white", Background: Transparent},
},
{
Case: "Transparent foreground override",
Input: "hello <#ffffff>world</>",
Expected: "\x1b[32mhello \x1b[38;2;255;255;255mworld\x1b[0m",
Colors: &cachedColor{Foreground: "green", Background: Transparent},
Colors: &Colors{Foreground: "green", Background: Transparent},
},
{
Case: "No foreground",
Input: "test",
Expected: "\x1b[48;2;255;87;51m\x1b[37mtest\x1b[0m",
Colors: &cachedColor{Foreground: "", Background: "#FF5733"},
Colors: &Colors{Foreground: "", Background: "#FF5733"},
},
{
Case: "Transparent foreground",
Input: "test",
Expected: "\x1b[0m\x1b[38;2;255;87;51;49m\x1b[7mtest\x1b[0m",
Colors: &cachedColor{Foreground: Transparent, Background: "#FF5733"},
Colors: &Colors{Foreground: Transparent, Background: "#FF5733"},
},
{
Case: "Transparent foreground, terminal background set",
Input: "test",
Expected: "\x1b[38;2;33;47;60m\x1b[48;2;255;87;51mtest\x1b[0m",
Colors: &cachedColor{Foreground: Transparent, Background: "#FF5733"},
Colors: &Colors{Foreground: Transparent, Background: "#FF5733"},
TerminalBackground: "#212F3C",
},
{
Case: "Foreground for foreground override",
Input: "<foreground>test</>",
Expected: "\x1b[47m\x1b[30mtest\x1b[0m",
Colors: &cachedColor{Foreground: "black", Background: "white"},
Colors: &Colors{Foreground: "black", Background: "white"},
},
{
Case: "Background for background override",
Input: "<,background>test</>",
Expected: "\x1b[47m\x1b[30mtest\x1b[0m",
Colors: &cachedColor{Foreground: "black", Background: "white"},
Colors: &Colors{Foreground: "black", Background: "white"},
},
{
Case: "Google",
Input: "<blue,white>G</><red,white>o</><yellow,white>o</><blue,white>g</><green,white>l</><red,white>e</>",
Expected: "\x1b[47m\x1b[34mG\x1b[40m\x1b[30m\x1b[47m\x1b[31mo\x1b[40m\x1b[30m\x1b[47m\x1b[33mo\x1b[40m\x1b[30m\x1b[47m\x1b[34mg\x1b[40m\x1b[30m\x1b[47m\x1b[32ml\x1b[40m\x1b[30m\x1b[47m\x1b[31me\x1b[0m", //nolint: lll
Colors: &cachedColor{Foreground: "black", Background: "black"},
Colors: &Colors{Foreground: "black", Background: "black"},
},
{
Case: "Foreground for background override",
Input: "<background>test</>",
Expected: "\x1b[47m\x1b[37mtest\x1b[0m",
Colors: &cachedColor{Foreground: "black", Background: "white"},
Colors: &Colors{Foreground: "black", Background: "white"},
},
{
Case: "Foreground for background vice versa override",
Input: "<background,foreground>test</>",
Expected: "\x1b[40m\x1b[37mtest\x1b[0m",
Colors: &cachedColor{Foreground: "black", Background: "white"},
Colors: &Colors{Foreground: "black", Background: "white"},
},
{
Case: "Background for foreground override",
Input: "<,foreground>test</>",
Expected: "\x1b[40m\x1b[30mtest\x1b[0m",
Colors: &cachedColor{Foreground: "black", Background: "white"},
Colors: &Colors{Foreground: "black", Background: "white"},
},
}
for _, tc := range cases {
renderer := &Writer{
ParentColors: []*cachedColor{tc.Parent},
ParentColors: []*Colors{tc.Parent},
Colors: tc.Colors,
TerminalBackground: tc.TerminalBackground,
AnsiColors: &DefaultColors{},
@ -210,37 +210,37 @@ func TestWriteLength(t *testing.T) {
Case string
Expected int
Input string
Colors *cachedColor
Colors *Colors
}{
{
Case: "Bold",
Input: "<b>test</b>",
Expected: 4,
Colors: &cachedColor{Foreground: "black", Background: ParentBackground},
Colors: &Colors{Foreground: "black", Background: ParentBackground},
},
{
Case: "Bold with color override",
Input: "<b><#ffffff>test</></b>",
Expected: 4,
Colors: &cachedColor{Foreground: "black", Background: ParentBackground},
Colors: &Colors{Foreground: "black", Background: ParentBackground},
},
{
Case: "Bold with color override and link",
Input: "<b><#ffffff>test</></b> [url](https://example.com)",
Expected: 8,
Colors: &cachedColor{Foreground: "black", Background: ParentBackground},
Colors: &Colors{Foreground: "black", Background: ParentBackground},
},
{
Case: "Bold with color override and link and leading/trailing spaces",
Input: " <b><#ffffff>test</></b> [url](https://example.com) ",
Expected: 10,
Colors: &cachedColor{Foreground: "black", Background: ParentBackground},
Colors: &Colors{Foreground: "black", Background: ParentBackground},
},
}
for _, tc := range cases {
renderer := &Writer{
ParentColors: []*cachedColor{},
ParentColors: []*Colors{},
Colors: tc.Colors,
AnsiColors: &DefaultColors{},
}

View file

@ -10,13 +10,13 @@ import (
"github.com/gookit/color"
)
// Colors is the interface that wraps AnsiColorFromString method.
// ColorString is the interface that wraps ToColor method.
//
// AnsiColorFromString gets the ANSI color code for a given color string.
// ToColor 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`.
type Colors interface {
AnsiColorFromString(colorString string, isBackground bool) Color
type ColorString interface {
ToColor(colorString string, isBackground bool) Color
}
// Color is an ANSI color code ready to be printed to the console.
@ -48,7 +48,7 @@ func (c Color) ToForeground() Color {
return c
}
func MakeColors(palette Palette, cacheEnabled bool, accentColor string, env platform.Environment) (colors Colors) {
func MakeColors(palette Palette, cacheEnabled bool, accentColor string, env platform.Environment) (colors ColorString) {
defaultColors := &DefaultColors{}
defaultColors.SetAccentColor(env, accentColor)
colors = defaultColors
@ -67,7 +67,7 @@ type RGB struct {
// DefaultColors is the default AnsiColors implementation.
type DefaultColors struct {
accent *cachedColor
accent *Colors
}
var (
@ -98,7 +98,7 @@ const (
backgroundIndex = 1
)
func (d *DefaultColors) AnsiColorFromString(colorString string, isBackground bool) Color {
func (d *DefaultColors) ToColor(colorString string, isBackground bool) Color {
if len(colorString) == 0 {
return emptyColor
}
@ -157,24 +157,24 @@ func IsAnsiColorName(colorString string) bool {
// PaletteColors is the AnsiColors Decorator that uses the Palette to do named color
// lookups before ANSI color code generation.
type PaletteColors struct {
ansiColors Colors
ansiColors ColorString
palette Palette
}
func (p *PaletteColors) AnsiColorFromString(colorString string, isBackground bool) Color {
func (p *PaletteColors) ToColor(colorString string, isBackground bool) Color {
paletteColor, err := p.palette.ResolveColor(colorString)
if err != nil {
return emptyColor
}
ansiColor := p.ansiColors.AnsiColorFromString(paletteColor, isBackground)
ansiColor := p.ansiColors.ToColor(paletteColor, isBackground)
return ansiColor
}
// CachedColors is the AnsiColors Decorator that does simple color lookup caching.
// AnsiColorFromString 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.
type CachedColors struct {
ansiColors Colors
ansiColors ColorString
colorCache map[cachedColorKey]Color
}
@ -183,7 +183,7 @@ type cachedColorKey struct {
isBackground bool
}
func (c *CachedColors) AnsiColorFromString(colorString string, isBackground bool) Color {
func (c *CachedColors) ToColor(colorString string, isBackground bool) Color {
if c.colorCache == nil {
c.colorCache = make(map[cachedColorKey]Color)
}
@ -191,7 +191,7 @@ func (c *CachedColors) AnsiColorFromString(colorString string, isBackground bool
if ansiColor, hit := c.colorCache[key]; hit {
return ansiColor
}
ansiColor := c.ansiColors.AnsiColorFromString(colorString, isBackground)
ansiColor := c.ansiColors.ToColor(colorString, isBackground)
c.colorCache[key] = ansiColor
return ansiColor
}

View file

@ -26,7 +26,7 @@ func TestGetAnsiFromColorString(t *testing.T) {
}
for _, tc := range cases {
ansiColors := &DefaultColors{}
ansiColor := ansiColors.AnsiColorFromString(tc.Color, tc.Background)
ansiColor := ansiColors.ToColor(tc.Color, tc.Background)
assert.Equal(t, tc.Expected, ansiColor, tc.Case)
}
}

View file

@ -12,8 +12,8 @@ func (d *DefaultColors) SetAccentColor(env platform.Environment, defaultColor st
if len(defaultColor) == 0 {
return
}
d.accent = &cachedColor{
Foreground: string(d.AnsiColorFromString(defaultColor, false)),
Background: string(d.AnsiColorFromString(defaultColor, true)),
d.accent = &Colors{
Foreground: string(d.ToColor(defaultColor, false)),
Background: string(d.ToColor(defaultColor, true)),
}
}

View file

@ -27,15 +27,15 @@ func GetAccentColor(env platform.Environment) (*RGB, error) {
func (d *DefaultColors) SetAccentColor(env platform.Environment, defaultColor string) {
rgb, err := GetAccentColor(env)
if err != nil {
d.accent = &cachedColor{
Foreground: string(d.AnsiColorFromString(defaultColor, false)),
Background: string(d.AnsiColorFromString(defaultColor, true)),
d.accent = &Colors{
Foreground: string(d.ToColor(defaultColor, false)),
Background: string(d.ToColor(defaultColor, true)),
}
return
}
foreground := color.RGB(rgb.R, rgb.G, rgb.B, false)
background := color.RGB(rgb.R, rgb.G, rgb.B, true)
d.accent = &cachedColor{
d.accent = &Colors{
Foreground: foreground.String(),
Background: background.String(),
}

10
src/ansi/cycle.go Normal file
View file

@ -0,0 +1,10 @@
package ansi
type Cycle []*Colors
func PopColors(array []*Colors) (*Colors, Cycle) {
if len(array) == 0 {
return nil, array
}
return array[0], array[1:]
}

View file

@ -55,11 +55,13 @@ type Block struct {
writer *ansi.Writer
activeSegment *Segment
previousActiveSegment *Segment
cycle *ansi.Cycle
}
func (b *Block) Init(env platform.Environment, writer *ansi.Writer) {
func (b *Block) Init(env platform.Environment, writer *ansi.Writer, cycle *ansi.Cycle) {
b.env = env
b.writer = writer
b.cycle = cycle
b.executeSegmentLogic()
}
@ -130,6 +132,11 @@ func (b *Block) RenderSegments() (string, int) {
if !segment.Enabled && segment.style() != Accordion {
continue
}
if b.cycle != nil && len(*b.cycle) > 0 {
colors, cycle := ansi.PopColors(*b.cycle)
b.cycle = &cycle
segment.colors = colors
}
b.setActiveSegment(segment)
b.renderActiveSegment()
}

View file

@ -47,6 +47,7 @@ type Config struct {
DebugPrompt *Segment `json:"debug_prompt,omitempty"`
Palette ansi.Palette `json:"palette,omitempty"`
Palettes *ansi.Palettes `json:"palettes,omitempty"`
Cycle ansi.Cycle `json:"cycle,omitempty"`
PWD string `json:"pwd,omitempty"`
// Deprecated
@ -63,7 +64,7 @@ type Config struct {
// MakeColors creates instance of AnsiColors to use in AnsiWriter according to
// environment and configuration.
func (cfg *Config) MakeColors() ansi.Colors {
func (cfg *Config) MakeColors() ansi.ColorString {
cacheDisabled := cfg.env.Getenv("OMP_CACHE_DISABLED") == "1"
return ansi.MakeColors(cfg.getPalette(), !cacheDisabled, cfg.AccentColor, cfg.env)
}

View file

@ -21,6 +21,7 @@ type Engine struct {
currentLineLength int
rprompt string
rpromptLength int
cycle *ansi.Cycle
}
func (e *Engine) write(text string) {
@ -57,6 +58,8 @@ func (e *Engine) canWriteRightBlock(rprompt bool) bool {
}
func (e *Engine) PrintPrimary() string {
// cache a pointer to the color cycle
e.cycle = &e.Config.Cycle
for _, block := range e.Config.Blocks {
e.renderBlock(block)
}
@ -156,7 +159,7 @@ func (e *Engine) renderBlock(block *Block) {
if e.Env.Shell() == shell.BASH && (block.Type == RPrompt || block.Alignment == Right) {
block.InitPlain(e.Env, e.Config)
} else {
block.Init(e.Env, e.Writer)
block.Init(e.Env, e.Writer, e.cycle)
}
if !block.Enabled() {
return
@ -243,9 +246,11 @@ func (e *Engine) PrintDebug(startTime time.Time, version string) string {
duration: time.Since(titleStartTime),
}
segmentTimings = append(segmentTimings, segmentTiming)
// cache a pointer to the color cycle
e.cycle = &e.Config.Cycle
// loop each segments of each blocks
for _, block := range e.Config.Blocks {
block.Init(e.Env, e.Writer)
block.Init(e.Env, e.Writer, e.cycle)
longestSegmentName, timings := block.Debug()
segmentTimings = append(segmentTimings, timings...)
if longestSegmentName > largestSegmentNameLength {
@ -344,7 +349,7 @@ func (e *Engine) PrintTooltip(tip string) string {
}
switch e.Env.Shell() {
case shell.ZSH, shell.CMD, shell.FISH, shell.GENERIC:
block.Init(e.Env, e.Writer)
block.Init(e.Env, e.Writer, nil)
if !block.Enabled() {
return ""
}
@ -453,7 +458,7 @@ func (e *Engine) PrintRPrompt() string {
if block == nil {
return ""
}
block.Init(e.Env, e.Writer)
block.Init(e.Env, e.Writer, e.cycle)
if !block.Enabled() {
return ""
}

View file

@ -7,6 +7,7 @@ import (
"strings"
"time"
"github.com/jandedobbeleer/oh-my-posh/src/ansi"
"github.com/jandedobbeleer/oh-my-posh/src/platform"
"github.com/jandedobbeleer/oh-my-posh/src/properties"
"github.com/jandedobbeleer/oh-my-posh/src/segments"
@ -39,13 +40,13 @@ type Segment struct {
MaxWidth int `json:"max_width,omitempty"`
MinWidth int `json:"min_width,omitempty"`
env platform.Environment
writer SegmentWriter
Enabled bool `json:"-"`
text string
backgroundCache string
foregroundCache string
styleCache SegmentStyle
Enabled bool `json:"-"`
colors *ansi.Colors
env platform.Environment
writer SegmentWriter
text string
styleCache SegmentStyle
}
// SegmentTiming holds the timing context for a segment
@ -360,17 +361,23 @@ func (segment *Segment) shouldInvokeWithTip(tip string) bool {
}
func (segment *Segment) foreground() string {
if len(segment.foregroundCache) == 0 {
segment.foregroundCache = segment.ForegroundTemplates.FirstMatch(segment.writer, segment.env, segment.Foreground)
if segment.colors == nil {
segment.colors = &ansi.Colors{}
}
return segment.foregroundCache
if len(segment.colors.Foreground) == 0 {
segment.colors.Foreground = segment.ForegroundTemplates.FirstMatch(segment.writer, segment.env, segment.Foreground)
}
return segment.colors.Foreground
}
func (segment *Segment) background() string {
if len(segment.backgroundCache) == 0 {
segment.backgroundCache = segment.BackgroundTemplates.FirstMatch(segment.writer, segment.env, segment.Background)
if segment.colors == nil {
segment.colors = &ansi.Colors{}
}
return segment.backgroundCache
if len(segment.colors.Background) == 0 {
segment.colors.Background = segment.BackgroundTemplates.FirstMatch(segment.writer, segment.env, segment.Background)
}
return segment.colors.Background
}
func (segment *Segment) mapSegmentWithWriter(env platform.Environment) error {

View file

@ -3063,6 +3063,22 @@
}
}
},
"cycle": {
"type": "array",
"title": "List of settings to cycle through segment by segment",
"description": "https://ohmyposh.dev/docs/configuration/cycle",
"default": [],
"items": {
"properties": {
"foreground": {
"$ref": "#/definitions/color"
},
"background": {
"$ref": "#/definitions/color"
}
}
}
},
"accent_color": {
"title": "Accent color",
"$ref": "#/definitions/color"

View file

@ -236,6 +236,32 @@ you could also add `frappe` as the default `palette`, given that one is used as
the `template` resolves to. In case no match is available and no `palette` is defined, it will also fallback to `transparent`
for any palette color reference in templates/colors.
## Cycle
When you want to display the same **sequence of colors** (background and foreground) regardless of which segments are active, you can
make use of the cycle property. This property is a list of colors which are used one after the other. If there's nothing in the list
anymore and your prompt would still render additional segments, the segment's colors are being used. A defined cycle always gets
precendence over everything else.
```json
...
"cycle": [
{
"background": "p:blue",
"foreground": "p:white"
},
{
"background": "p:green",
"foreground": "p:black"
},
{
"background": "p:orange",
"foreground": "p:white"
}
],
...
```
[hexcolors]: https://htmlcolorcodes.com/color-chart/material-design-color-chart/
[ansicolors]: https://htmlcolorcodes.com/color-chart/material-design-color-chart/
[git]: /docs/segments/git