feat(palette): conditional palettes

This commit is contained in:
Jan De Dobbeleer 2022-10-13 20:01:51 +02:00 committed by Jan De Dobbeleer
parent b533a27f21
commit 3efa4df088
10 changed files with 192 additions and 22 deletions

View file

@ -59,7 +59,7 @@ Exports the config to an image file using customized output options.`,
cfg := engine.LoadConfig(env)
ansi := &color.Ansi{}
ansi.InitPlain()
writerColors := cfg.MakeColors(env)
writerColors := cfg.MakeColors()
writer := &color.AnsiWriter{
Ansi: ansi,
TerminalBackground: shell.ConsoleBackgroundColor(env, cfg.TerminalBackground),

View file

@ -32,7 +32,7 @@ var debugCmd = &cobra.Command{
cfg := engine.LoadConfig(env)
ansi := &color.Ansi{}
ansi.InitPlain()
writerColors := cfg.MakeColors(env)
writerColors := cfg.MakeColors()
writer := &color.AnsiWriter{
Ansi: ansi,
TerminalBackground: shell.ConsoleBackgroundColor(env, cfg.TerminalBackground),

View file

@ -73,7 +73,7 @@ var printCmd = &cobra.Command{
Ansi: ansi,
}
} else {
writerColors := cfg.MakeColors(env)
writerColors := cfg.MakeColors()
writer = &color.AnsiWriter{
Ansi: ansi,
TerminalBackground: shell.ConsoleBackgroundColor(env, cfg.TerminalBackground),

6
src/color/palettes.go Normal file
View file

@ -0,0 +1,6 @@
package color
type Palettes struct {
Template string `json:"template,omitempty"`
List map[string]Palette `json:"list,omitempty"`
}

View file

@ -67,7 +67,7 @@ func (b *Block) InitPlain(env environment.Environment, config *Config) {
b.writer = &color.AnsiWriter{
Ansi: b.ansi,
TerminalBackground: shell.ConsoleBackgroundColor(env, config.TerminalBackground),
AnsiColors: config.MakeColors(env),
AnsiColors: config.MakeColors(),
}
b.env = env
b.executeSegmentLogic()

View file

@ -9,6 +9,7 @@ import (
"oh-my-posh/environment"
"oh-my-posh/properties"
"oh-my-posh/segments"
"oh-my-posh/template"
"os"
"path/filepath"
"strings"
@ -31,20 +32,21 @@ const (
// Config holds all the theme for rendering the prompt
type Config struct {
Version int `json:"version"`
FinalSpace bool `json:"final_space,omitempty"`
ConsoleTitleTemplate string `json:"console_title_template,omitempty"`
TerminalBackground string `json:"terminal_background,omitempty"`
AccentColor string `json:"accent_color,omitempty"`
Blocks []*Block `json:"blocks,omitempty"`
Tooltips []*Segment `json:"tooltips,omitempty"`
TransientPrompt *Segment `json:"transient_prompt,omitempty"`
ValidLine *Segment `json:"valid_line,omitempty"`
ErrorLine *Segment `json:"error_line,omitempty"`
SecondaryPrompt *Segment `json:"secondary_prompt,omitempty"`
DebugPrompt *Segment `json:"debug_prompt,omitempty"`
Palette color.Palette `json:"palette,omitempty"`
PWD string `json:"pwd,omitempty"`
Version int `json:"version"`
FinalSpace bool `json:"final_space,omitempty"`
ConsoleTitleTemplate string `json:"console_title_template,omitempty"`
TerminalBackground string `json:"terminal_background,omitempty"`
AccentColor string `json:"accent_color,omitempty"`
Blocks []*Block `json:"blocks,omitempty"`
Tooltips []*Segment `json:"tooltips,omitempty"`
TransientPrompt *Segment `json:"transient_prompt,omitempty"`
ValidLine *Segment `json:"valid_line,omitempty"`
ErrorLine *Segment `json:"error_line,omitempty"`
SecondaryPrompt *Segment `json:"secondary_prompt,omitempty"`
DebugPrompt *Segment `json:"debug_prompt,omitempty"`
Palette color.Palette `json:"palette,omitempty"`
Palettes *color.Palettes `json:"palettes,omitempty"`
PWD string `json:"pwd,omitempty"`
// Deprecated
OSC99 bool `json:"osc99,omitempty"`
@ -55,13 +57,30 @@ type Config struct {
origin string
eval bool
updated bool
env environment.Environment
}
// MakeColors creates instance of AnsiColors to use in AnsiWriter according to
// environment and configuration.
func (cfg *Config) MakeColors(env environment.Environment) color.AnsiColors {
cacheDisabled := env.Getenv("OMP_CACHE_DISABLED") == "1"
return color.MakeColors(cfg.Palette, !cacheDisabled, cfg.AccentColor, env)
func (cfg *Config) MakeColors() color.AnsiColors {
cacheDisabled := cfg.env.Getenv("OMP_CACHE_DISABLED") == "1"
return color.MakeColors(cfg.getPalette(), !cacheDisabled, cfg.AccentColor, cfg.env)
}
func (cfg *Config) getPalette() color.Palette {
if cfg.Palettes == nil {
return cfg.Palette
}
tmpl := &template.Text{
Template: cfg.Palettes.Template,
Env: cfg.env,
}
if palette, err := tmpl.Render(); err == nil {
if p, ok := cfg.Palettes.List[palette]; ok {
return p
}
}
return cfg.Palette
}
func (cfg *Config) print(message string) {
@ -88,6 +107,7 @@ func (cfg *Config) exitWithError(err error) {
// LoadConfig returns the default configuration including possible user overrides
func LoadConfig(env environment.Environment) *Config {
cfg := loadConfig(env)
cfg.env = env
// only migrate automatically when the switch isn't set
if !env.Flags().Migrate && cfg.Version < configVersion {
cfg.BackupAndMigrate(env)

View file

@ -1,6 +1,9 @@
package engine
import (
"oh-my-posh/color"
"oh-my-posh/environment"
"oh-my-posh/mock"
"oh-my-posh/segments"
"testing"
@ -55,3 +58,77 @@ func TestEscapeGlyphs(t *testing.T) {
assert.Equal(t, tc.Expected, escapeGlyphs(tc.Input), tc.Input)
}
}
func TestGetPalette(t *testing.T) {
palette := color.Palette{
"red": "#ff0000",
"blue": "#0000ff",
}
cases := []struct {
Case string
Palettes *color.Palettes
Palette color.Palette
ExpectedPalette color.Palette
}{
{
Case: "match",
Palettes: &color.Palettes{
Template: "{{ .Shell }}",
List: map[string]color.Palette{
"bash": palette,
"zsh": {
"red": "#ff0001",
"blue": "#0000fb",
},
},
},
ExpectedPalette: palette,
},
{
Case: "no match, no fallback",
Palettes: &color.Palettes{
Template: "{{ .Shell }}",
List: map[string]color.Palette{
"fish": palette,
"zsh": {
"red": "#ff0001",
"blue": "#0000fb",
},
},
},
ExpectedPalette: nil,
},
{
Case: "no match, default",
Palettes: &color.Palettes{
Template: "{{ .Shell }}",
List: map[string]color.Palette{
"zsh": {
"red": "#ff0001",
"blue": "#0000fb",
},
},
},
Palette: palette,
ExpectedPalette: palette,
},
{
Case: "no palettes",
ExpectedPalette: nil,
},
}
for _, tc := range cases {
env := &mock.MockedEnvironment{}
env.On("TemplateCache").Return(&environment.TemplateCache{
Env: map[string]string{},
Shell: "bash",
})
cfg := &Config{
env: env,
Palette: tc.Palette,
Palettes: tc.Palettes,
}
got := cfg.getPalette()
assert.Equal(t, tc.ExpectedPalette, got, tc.Case)
}
}

View file

@ -100,7 +100,7 @@ func engineRender() {
ansi := &color.Ansi{}
ansi.InitPlain()
writerColors := cfg.MakeColors(env)
writerColors := cfg.MakeColors()
writer := &color.AnsiWriter{
Ansi: ansi,
TerminalBackground: shell.ConsoleBackgroundColor(env, cfg.TerminalBackground),

View file

@ -2900,6 +2900,27 @@
}
}
},
"palettes": {
"type": "object",
"title": "Palettes",
"description": "https://ohmyposh.dev/docs/configuration/colors#palettes",
"default": {},
"properties": {
"template": {
"type": "string",
"title": "Prompt Template"
},
"list": {
"type": "object",
"title": "List of palettes",
"patternProperties": {
".*": {
"$ref": "#/definitions/palette"
}
}
}
}
},
"accent_color": {
"title": "Accent color",
"$ref": "#/definitions/color"

View file

@ -17,6 +17,7 @@ Oh My Posh supports multiple different color references, being:
as well as 8 extended ANSI colors:
`darkGray` `lightRed` `lightGreen` `lightYellow` `lightBlue` `lightMagenta` `lightCyan` `lightWhite`
- 256 color palette using their number representation.
For example `0` is black, `1` is red, `2` is green, etc.
- The `transparent` keyword which can be used to create either a transparent foreground override
@ -190,6 +191,51 @@ For example, `p:foreground` and `p:background` will be correctly set to "#CAF0F8
}
```
## Palettes
If you want to use a `palette` conditionally, for example for **light or dark mode**, you can define multiple
`palettes` and a [template][templates] that resolves to the `palette` key. The `template` is evaluated at
runtime so your prompt can change at any time based on the outcome of the `template`.
Take the following configuration:
```json
{
"$schema": "https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json",
"palettes": {
"template": "{{ if eq .Shell \"pwsh\" }}latte{{ else }}frappe{{ end }}",
"list": {
"latte": {
"black": "#262B44",
"green": "#59C9A5",
"orange": "#F07623",
"red": "#e64553",
"white": "#E0DEF4",
"yellow": "#df8e1d",
"blue": "#7287fd"
},
"frappe": {
"black": "#262B44",
"green": "#59C9A5",
"orange": "#F07623",
"red": "#D81E5B",
"white": "#E0DEF4",
"yellow": "#F3AE35",
"blue": "#4B95E9"
}
}
},
"blocks": [
...
]
}
```
In this case, when the shell is `pwsh`, the `latte` palette will be used, otherwise it uses the `frappe` palette. If you want,
you could also add `frappe` as the default `palette`, given that one is used as a fallback when not match can be found based on what
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.
[hexcolors]: https://htmlcolorcodes.com/color-chart/material-design-color-chart/
[ansicolors]: https://htmlcolorcodes.com/color-chart/material-design-color-chart/
[git]: /docs/segments/git