From 7de28091874648c96f177738f9b72c641c526334 Mon Sep 17 00:00:00 2001 From: Jan De Dobbeleer Date: Tue, 5 Nov 2024 20:54:34 +0100 Subject: [PATCH] fix(segment): evaluate all needs --- src/config/segment.go | 40 ++++++++++++++++++++++++++++++---- src/config/segment_test.go | 43 +++++++++++++++++++++++++++++++++++++ src/prompt/segments.go | 9 +------- src/prompt/segments_test.go | 23 +++++++++----------- 4 files changed, 90 insertions(+), 25 deletions(-) diff --git a/src/config/segment.go b/src/config/segment.go index 2169cfd1..2010cbea 100644 --- a/src/config/segment.go +++ b/src/config/segment.go @@ -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[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) + } +} diff --git a/src/config/segment_test.go b/src/config/segment_test.go index 14c41723..3dcb0b28 100644 --- a/src/config/segment_test.go +++ b/src/config/segment_test.go @@ -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) + } +} diff --git a/src/prompt/segments.go b/src/prompt/segments.go index a0814db7..5d01912e 100644 --- a/src/prompt/segments.go +++ b/src/prompt/segments.go @@ -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[a-zA-Z0-9]+)`, segment.Template) - for _, name := range matches { + for _, name := range segment.Needs { if slices.Contains(executed, name) { continue } diff --git a/src/prompt/segments_test.go b/src/prompt/segments_test.go index 787cf903..eae4e022 100644 --- a/src/prompt/segments_test.go +++ b/src/prompt/segments_test.go @@ -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) }