fix(segment): evaluate all needs

This commit is contained in:
Jan De Dobbeleer 2024-11-05 20:54:34 +01:00 committed by Jan De Dobbeleer
parent 472bd6fba7
commit 7de2809187
4 changed files with 90 additions and 25 deletions

View file

@ -3,12 +3,14 @@ package config
import (
"encoding/json"
"fmt"
"slices"
"strings"
"time"
"github.com/jandedobbeleer/oh-my-posh/src/cache"
"github.com/jandedobbeleer/oh-my-posh/src/color"
"github.com/jandedobbeleer/oh-my-posh/src/properties"
"github.com/jandedobbeleer/oh-my-posh/src/regex"
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
"github.com/jandedobbeleer/oh-my-posh/src/template"
@ -40,7 +42,7 @@ type Segment struct {
env runtime.Environment
Properties properties.Map `json:"properties,omitempty" toml:"properties,omitempty"`
Cache *cache.Config `json:"cache,omitempty" toml:"cache,omitempty"`
Style SegmentStyle `json:"style,omitempty" toml:"style,omitempty"`
Alias string `json:"alias,omitempty" toml:"alias,omitempty"`
styleCache SegmentStyle
name string
LeadingDiamond string `json:"leading_diamond,omitempty" toml:"leading_diamond,omitempty"`
@ -52,18 +54,19 @@ type Segment struct {
Background color.Ansi `json:"background,omitempty" toml:"background,omitempty"`
Filler string `json:"filler,omitempty" toml:"filler,omitempty"`
Type SegmentType `json:"type,omitempty" toml:"type,omitempty"`
Alias string `json:"alias,omitempty" toml:"alias,omitempty"`
Style SegmentStyle `json:"style,omitempty" toml:"style,omitempty"`
LeadingPowerlineSymbol string `json:"leading_powerline_symbol,omitempty" toml:"leading_powerline_symbol,omitempty"`
ForegroundTemplates template.List `json:"foreground_templates,omitempty" toml:"foreground_templates,omitempty"`
Tips []string `json:"tips,omitempty" toml:"tips,omitempty"`
ForegroundTemplates template.List `json:"foreground_templates,omitempty" toml:"foreground_templates,omitempty"`
BackgroundTemplates template.List `json:"background_templates,omitempty" toml:"background_templates,omitempty"`
Templates template.List `json:"templates,omitempty" toml:"templates,omitempty"`
ExcludeFolders []string `json:"exclude_folders,omitempty" toml:"exclude_folders,omitempty"`
IncludeFolders []string `json:"include_folders,omitempty" toml:"include_folders,omitempty"`
Duration time.Duration `json:"-" toml:"-"`
Needs []string `json:"-" toml:"-"`
NameLength int `json:"-" toml:"-"`
MaxWidth int `json:"max_width,omitempty" toml:"max_width,omitempty"`
MinWidth int `json:"min_width,omitempty" toml:"min_width,omitempty"`
Duration time.Duration `json:"-" toml:"-"`
Interactive bool `json:"interactive,omitempty" toml:"interactive,omitempty"`
Enabled bool `json:"-" toml:"-"`
Newline bool `json:"newline,omitempty" toml:"newline,omitempty"`
@ -95,6 +98,8 @@ func (segment *Segment) Execute(env runtime.Environment) {
}()
}
defer segment.evaluateNeeds()
err := segment.MapSegmentWithWriter(env)
if err != nil || !segment.shouldIncludeFolder() {
return
@ -311,3 +316,30 @@ func (segment *Segment) cwdIncluded() bool {
func (segment *Segment) cwdExcluded() bool {
return segment.env.DirMatchesOneOf(segment.env.Pwd(), segment.ExcludeFolders)
}
func (segment *Segment) evaluateNeeds() {
value := segment.Template
if len(segment.ForegroundTemplates) != 0 {
value += strings.Join(segment.ForegroundTemplates, "")
}
if len(segment.BackgroundTemplates) != 0 {
value += strings.Join(segment.BackgroundTemplates, "")
}
if !strings.Contains(value, ".Segments.") {
return
}
matches := regex.FindAllNamedRegexMatch(`\.Segments\.(?P<NAME>[a-zA-Z0-9]+)`, value)
for _, name := range matches {
segmentName := name["NAME"]
if len(name) == 0 || slices.Contains(segment.Needs, segmentName) {
continue
}
segment.Needs = append(segment.Needs, segmentName)
}
}

View file

@ -160,3 +160,46 @@ func TestGetColors(t *testing.T) {
assert.Equal(t, tc.Expected, fgColor, tc.Case)
}
}
func TestEvaluateNeeds(t *testing.T) {
cases := []struct {
Segment *Segment
Case string
Needs []string
}{
{
Case: "No needs",
Segment: &Segment{
Template: "foo",
},
},
{
Case: "Template needs",
Segment: &Segment{
Template: "{{ .Segments.Git.URL }}",
},
Needs: []string{"Git"},
},
{
Case: "Template & Foreground needs",
Segment: &Segment{
Template: "{{ .Segments.Git.URL }}",
ForegroundTemplates: []string{"foo", "{{ .Segments.Os.Icon }}"},
},
Needs: []string{"Git", "Os"},
},
{
Case: "Template & Foreground & Background needs",
Segment: &Segment{
Template: "{{ .Segments.Git.URL }}",
ForegroundTemplates: []string{"foo", "{{ .Segments.Os.Icon }}"},
BackgroundTemplates: []string{"bar", "{{ .Segments.Exit.Icon }}"},
},
Needs: []string{"Git", "Os", "Exit"},
},
}
for _, tc := range cases {
tc.Segment.evaluateNeeds()
assert.Equal(t, tc.Needs, tc.Segment.Needs, tc.Case)
}
}

View file

@ -3,10 +3,8 @@ package prompt
import (
"runtime"
"slices"
"strings"
"github.com/jandedobbeleer/oh-my-posh/src/config"
"github.com/jandedobbeleer/oh-my-posh/src/regex"
"github.com/jandedobbeleer/oh-my-posh/src/terminal"
)
@ -113,12 +111,7 @@ func (e *Engine) writeSegment(index int, block *config.Block, segment *config.Se
}
func (e *Engine) canRenderSegment(segment *config.Segment, executed []string) bool {
if !strings.Contains(segment.Template, ".Segments.") {
return true
}
matches := regex.FindNamedRegexMatch(`\.Segments\.(?P<NAME>[a-zA-Z0-9]+)`, segment.Template)
for _, name := range matches {
for _, name := range segment.Needs {
if slices.Contains(executed, name) {
continue
}

View file

@ -35,38 +35,35 @@ func TestRenderBlock(t *testing.T) {
func TestCanRenderSegment(t *testing.T) {
cases := []struct {
Case string
Template string
ExecutedSegments []string
Expected bool
Case string
Executed []string
Needs []string
Expected bool
}{
{
Case: "No cross segment dependencies",
Expected: true,
Template: "Hello",
},
{
Case: "Cross segment dependencies, nothing executed",
Expected: false,
Template: "Hello {{ .Segments.Foo.World }} {{ .Segments.Foo.Bar }}",
Needs: []string{"Foo"},
},
{
Case: "Cross segment dependencies, available",
Expected: true,
Template: "Hello {{ .Segments.Foo.World }}",
ExecutedSegments: []string{
"Foo",
},
Executed: []string{"Foo"},
Needs: []string{"Foo"},
},
}
for _, c := range cases {
segment := &config.Segment{
Type: "text",
Template: c.Template,
Type: "text",
Needs: c.Needs,
}
engine := &Engine{}
got := engine.canRenderSegment(segment, c.ExecutedSegments)
got := engine.canRenderSegment(segment, c.Executed)
assert.Equal(t, c.Expected, got, c.Case)
}