feat(transient): color template support

This commit is contained in:
Jan De Dobbeleer 2022-03-24 12:53:20 +01:00 committed by Jan De Dobbeleer
parent e1a1febc79
commit 8b5c2a35ca
9 changed files with 94 additions and 86 deletions

View file

@ -25,6 +25,34 @@ Oh My Posh supports multiple different color references, being:
`darkGray` `lightRed` `lightGreen` `lightYellow` `lightBlue` `lightMagenta` `lightCyan` `lightWhite`
## Color templates
Array of string templates to define the color based on the current context.
Under the hood this uses go's [text/template][go-text-template] feature extended with [sprig][sprig] and
offers a few standard properties to work with. For segments, you can look at the **Template Properties**
section in the documentation. The general template properties are listed [here][template-properties].
The following sample is based on the [AWS Segment][aws].
```json
{
"type": "aws",
"style": "powerline",
"powerline_symbol": "\uE0B0",
"foreground": "#ffffff",
"background": "#111111",
"foreground_templates": [
"{{if contains \"default\" .Profile}}#FFA400{{end}}",
"{{if contains \"jan\" .Profile}}#f1184c{{end}}"
]
}
```
The logic is as follows: when `foreground_templates` contains an array, we will check every template line until there's
one that returns a non-empty string. So, when the contents of `.Profile` contain the word `default`, the first template
returns `#FFA400` and that's the color that will be used. If it contains `jan`, it returns `#f1184c`. When none of the
templates returns a value, the foreground value `#ffffff` is used as a fallback value.
## Color overrides
You have the ability to override the foreground and/or background color for text in any property that accepts it.
@ -164,3 +192,5 @@ For example, `p:foreground` and `p:background` will be correctly set to "#CAF0F8
[ansicolors]: https://htmlcolorcodes.com/color-chart/material-design-color-chart/
[git]: /docs/segment-git
[battery]: /docs/segment-battery
[template-properties]: /docs/config-templates#global-properties
[aws]: /docs/aws

View file

@ -39,9 +39,9 @@ understand how to configure a segment.
- leading_diamond: `string`
- trailing_diamond: `string`
- foreground: `string` [color][colors]
- foreground_templates: `array` of `string` values
- foreground_templates: foreground [color templates][color-templates]
- background: `string` [color][colors]
- background_templates: `array` of `string` values
- background_templates: background [color templates][color-templates]
- properties: `array` of `Property`: `string`
## Type
@ -89,46 +89,6 @@ its foreground color.
Text character to use at the end of the segment. Will take the background color of the segment as its foreground color.
## Foreground
[Color][colors] to use as the segment text foreground color. Also supports transparency using the `transparent` keyword.
## Foreground Templates
Array if string templates to define the foreground color for the given Segment based on the Segment's Template Properties.
Under the hood this uses go's [text/template][go-text-template] feature extended with [sprig][sprig] and
offers a few standard properties to work with. For supported Segments, look for the **Template Properties** section in
the documentation.
The following sample is based on the [AWS Segment][aws].
```json
{
"type": "aws",
"style": "powerline",
"powerline_symbol": "\uE0B0",
"foreground": "#ffffff",
"background": "#111111",
"foreground_templates": [
"{{if contains \"default\" .Profile}}#FFA400{{end}}",
"{{if contains \"jan\" .Profile}}#f1184c{{end}}"
]
}
```
The logic is as follows: when `background_templates` contains an array, we will check every template line until there's
one that returns a non-empty string. So, when the contents of `.Profile` contain the word `default`, the first template
returns `#FFA400` and that's the color that will be used. If it contains `jan`, it returns `#f1184c`. When none of the
templates returns a value, the foreground value `#ffffff` is used.
## Background
[Color][colors] to use as the segment text background color. Also supports transparency using the `transparent` keyword.
## Background Templates
Same as [Foreground Templates][fg-templ] but for the background color.
## Properties
An array of **Properties** with a value. This is used inside of the segment logic to tweak what the output of the segment
@ -198,7 +158,6 @@ This means that for user Bill, who has a user account `Bill` on Windows and `bil
[colors]: /docs/config-colors
[go-text-template]: https://golang.org/pkg/text/template/
[sprig]: https://masterminds.github.io/sprig/
[fg-templ]: /docs/config-overview#foreground-templates
[regex]: https://www.regular-expressions.info/tutorial.html
[aws]: /docs/aws
[templates]: /docs/config-templates
[color-templates]: /docs/config-colors#color-templates

View file

@ -44,8 +44,10 @@ You need to extend or create a custom theme with your transient prompt. For exam
The configuration has the following properties:
- background: `string` [color][colors]
- foreground: `string` [color][colors]
- foreground_templates: foreground [color templates][color-templates]
- background: `string` [color][colors]
- background_templates: background [color templates][color-templates]
- template: `string` - A go [text/template][go-text-template] template extended with [sprig][sprig] utilizing the
properties below - defaults to `{{ .Shell }}> `
@ -131,3 +133,4 @@ Restart your shell or reload fish using `exec fish` for the changes to take effe
[sprig]: https://masterminds.github.io/sprig/
[clink]: https://chrisant996.github.io/clink/
[templates]: /docs/config-templates
[color-templates]: /docs/config-colors#color-templates

27
src/color/templates.go Normal file
View file

@ -0,0 +1,27 @@
package color
import (
"oh-my-posh/environment"
"oh-my-posh/template"
)
type Templates []string
func (t Templates) Resolve(context interface{}, env environment.Environment, defaultColor string) string {
if len(t) == 0 {
return defaultColor
}
txtTemplate := &template.Text{
Context: context,
Env: env,
}
for _, tmpl := range t {
txtTemplate.Template = tmpl
value, err := txtTemplate.Render()
if err != nil || value == "" {
continue
}
return value
}
return defaultColor
}

View file

@ -59,9 +59,11 @@ func (cfg *Config) MakeColors(env environment.Environment) color.AnsiColors {
}
type ExtraPrompt struct {
Template string `json:"template,omitempty"`
Background string `json:"background,omitempty"`
Foreground string `json:"foreground,omitempty"`
Template string `json:"template,omitempty"`
Foreground string `json:"foreground,omitempty"`
ForegroundTemplates color.Templates `json:"foreground_templates,omitempty"`
Background string `json:"background,omitempty"`
BackgroundTemplates color.Templates `json:"background_templates,omitempty"`
}
func (cfg *Config) print(message string) {

View file

@ -319,8 +319,10 @@ func (e *Engine) PrintExtraPrompt(promptType ExtraPromptType) string {
if err != nil {
promptText = err.Error()
}
e.Writer.SetColors(prompt.Background, prompt.Foreground)
e.Writer.Write(prompt.Background, prompt.Foreground, promptText)
foreground := prompt.ForegroundTemplates.Resolve(nil, e.Env, prompt.Foreground)
background := prompt.BackgroundTemplates.Resolve(nil, e.Env, prompt.Background)
e.Writer.SetColors(background, foreground)
e.Writer.Write(background, foreground, promptText)
switch e.Env.Shell() {
case shell.ZSH:
// escape double quotes contained in the prompt

View file

@ -3,6 +3,7 @@ package engine
import (
"errors"
"fmt"
"oh-my-posh/color"
"oh-my-posh/environment"
"oh-my-posh/properties"
"oh-my-posh/segments"
@ -14,18 +15,18 @@ import (
// Segment represent a single segment and it's configuration
type Segment struct {
Type SegmentType `json:"type,omitempty"`
Tips []string `json:"tips,omitempty"`
Style SegmentStyle `json:"style,omitempty"`
PowerlineSymbol string `json:"powerline_symbol,omitempty"`
InvertPowerline bool `json:"invert_powerline,omitempty"`
Foreground string `json:"foreground,omitempty"`
ForegroundTemplates []string `json:"foreground_templates,omitempty"`
Background string `json:"background,omitempty"`
BackgroundTemplates []string `json:"background_templates,omitempty"`
LeadingDiamond string `json:"leading_diamond,omitempty"`
TrailingDiamond string `json:"trailing_diamond,omitempty"`
Properties properties.Map `json:"properties,omitempty"`
Type SegmentType `json:"type,omitempty"`
Tips []string `json:"tips,omitempty"`
Style SegmentStyle `json:"style,omitempty"`
PowerlineSymbol string `json:"powerline_symbol,omitempty"`
InvertPowerline bool `json:"invert_powerline,omitempty"`
Foreground string `json:"foreground,omitempty"`
ForegroundTemplates color.Templates `json:"foreground_templates,omitempty"`
Background string `json:"background,omitempty"`
BackgroundTemplates color.Templates `json:"background_templates,omitempty"`
LeadingDiamond string `json:"leading_diamond,omitempty"`
TrailingDiamond string `json:"trailing_diamond,omitempty"`
Properties properties.Map `json:"properties,omitempty"`
writer SegmentWriter
text string
@ -207,25 +208,6 @@ func (segment *Segment) cwdExcluded() bool {
return environment.DirMatchesOneOf(segment.env, segment.env.Pwd(), list)
}
func (segment *Segment) getColor(templates []string, defaultColor string) string {
if len(templates) == 0 {
return defaultColor
}
txtTemplate := &template.Text{
Context: segment.writer,
Env: segment.env,
}
for _, tmpl := range templates {
txtTemplate.Template = tmpl
value, err := txtTemplate.Render()
if err != nil || value == "" {
continue
}
return value
}
return defaultColor
}
func (segment *Segment) shouldInvokeWithTip(tip string) bool {
for _, t := range segment.Tips {
if t == tip {
@ -237,14 +219,14 @@ func (segment *Segment) shouldInvokeWithTip(tip string) bool {
func (segment *Segment) foreground() string {
if len(segment.foregroundCache) == 0 {
segment.foregroundCache = segment.getColor(segment.ForegroundTemplates, segment.Foreground)
segment.foregroundCache = segment.ForegroundTemplates.Resolve(segment.writer, segment.env, segment.Foreground)
}
return segment.foregroundCache
}
func (segment *Segment) background() string {
if len(segment.backgroundCache) == 0 {
segment.backgroundCache = segment.getColor(segment.BackgroundTemplates, segment.Background)
segment.backgroundCache = segment.BackgroundTemplates.Resolve(segment.writer, segment.env, segment.Background)
}
return segment.backgroundCache
}

View file

@ -5,11 +5,12 @@ set --global omp_tooltip_command ""
set --global omp_transient 0
function fish_prompt
set --local omp_status_cache_temp $status
if test "$omp_transient" = "1"
::OMP:: prompt print transient --config $POSH_THEME --shell fish
::OMP:: prompt print transient --config $POSH_THEME --shell fish --error $omp_status_cache --execution-time $omp_duration --stack-count $omp_stack_count
return
end
set --global omp_status_cache $status
set --global omp_status_cache $omp_status_cache_temp
set --global omp_stack_count (count $dirstack)
set --global omp_duration "$CMD_DURATION$cmd_duration"
# check if variable set, < 3.2 case

View file

@ -72,8 +72,10 @@
"type": "string",
"title": "Prompt Template"
},
"foreground": { "$ref": "#/definitions/color" },
"foreground_templates": { "$ref": "#/definitions/color_templates" },
"background": { "$ref": "#/definitions/color" },
"foreground": { "$ref": "#/definitions/color" }
"background_templates": { "$ref": "#/definitions/color_templates" }
}
},
"block": {