Skip to content

Commit

Permalink
feat: reference segments properties cross segment
Browse files Browse the repository at this point in the history
resolves #2208
  • Loading branch information
JanDeDobbeleer committed May 6, 2022
1 parent 88fb975 commit 482c997
Show file tree
Hide file tree
Showing 10 changed files with 89 additions and 60 deletions.
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"prompt",
"print",
"primary",
"--config=https://gist.githubusercontent.com/ehawman-rosenberg/50b3b695526f03690cfd396d02c2cca3/raw/c2e0bc78cdf551b0cc76f593e4fd70428f981c0e/eh-tea.omp.json",
"--config=~/.posh.omp.json",
"--shell=pwsh",
"--terminal-width=200",
]
Expand Down
4 changes: 3 additions & 1 deletion src/cli/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"oh-my-posh/engine"
"oh-my-posh/environment"
"oh-my-posh/shell"
"time"

"github.com/spf13/cobra"
)
Expand All @@ -18,6 +19,7 @@ var debugCmd = &cobra.Command{
Long: "Print the prompt in debug mode.",
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
startTime := time.Now()
env := &environment.ShellEnvironment{
CmdFlags: &environment.Flags{
Config: config,
Expand Down Expand Up @@ -47,7 +49,7 @@ var debugCmd = &cobra.Command{
Ansi: ansi,
Plain: plain,
}
fmt.Print(eng.PrintDebug(cliVersion))
fmt.Print(eng.PrintDebug(startTime, cliVersion))
},
}

Expand Down
52 changes: 36 additions & 16 deletions src/engine/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"oh-my-posh/color"
"oh-my-posh/environment"
"oh-my-posh/shell"
"strings"
"sync"
"time"
)
Expand Down Expand Up @@ -44,13 +45,15 @@ type Block struct {
previousActiveSegment *Segment
}

func (b *Block) init(env environment.Environment, writer color.Writer, ansi *color.Ansi) {
func (b *Block) Init(env environment.Environment, writer color.Writer, ansi *color.Ansi) {
b.env = env
b.writer = writer
b.ansi = ansi
b.setEnabledSegments()
b.setSegmentsText()
}

func (b *Block) initPlain(env environment.Environment, config *Config) {
func (b *Block) InitPlain(env environment.Environment, config *Config) {
b.ansi = &color.Ansi{}
b.ansi.InitPlain(env.Shell())
b.writer = &color.AnsiWriter{
Expand All @@ -59,14 +62,16 @@ func (b *Block) initPlain(env environment.Environment, config *Config) {
AnsiColors: config.MakeColors(env),
}
b.env = env
b.setEnabledSegments()
b.setSegmentsText()
}

func (b *Block) setActiveSegment(segment *Segment) {
b.activeSegment = segment
b.writer.SetColors(segment.background(), segment.foreground())
}

func (b *Block) enabled() bool {
func (b *Block) Enabled() bool {
if b.Type == LineBreak {
return true
}
Expand All @@ -78,14 +83,30 @@ func (b *Block) enabled() bool {
return false
}

func (b *Block) renderSegmentsText() {
func (b *Block) setEnabledSegments() {
wg := sync.WaitGroup{}
wg.Add(len(b.Segments))
defer wg.Wait()
for _, segment := range b.Segments {
go func(s *Segment) {
defer wg.Done()
s.renderText(b.env)
s.setEnabled(b.env)
}(segment)
}
}

func (b *Block) setSegmentsText() {
wg := sync.WaitGroup{}
wg.Add(len(b.Segments))
defer wg.Wait()
for _, segment := range b.Segments {
go func(s *Segment) {
defer wg.Done()
if !s.enabled {
return
}
s.text = s.string()
s.enabled = len(strings.ReplaceAll(s.text, " ", "")) > 0
}(segment)
}
}
Expand All @@ -96,26 +117,26 @@ func (b *Block) renderSegments() (string, int) {
if !segment.enabled && segment.Style != Accordion {
continue
}
b.renderSegment(segment)
b.setActiveSegment(segment)
b.renderActiveSegment()
}
b.writePowerline(true)
b.writer.ClearParentColors()
return b.writer.String()
}

func (b *Block) renderSegment(segment *Segment) {
b.setActiveSegment(segment)
func (b *Block) renderActiveSegment() {
b.writePowerline(false)
switch b.activeSegment.Style {
case Plain, Powerline:
b.writer.Write(color.Background, color.Foreground, segment.text)
b.writer.Write(color.Background, color.Foreground, b.activeSegment.text)
case Diamond:
b.writer.Write(color.Transparent, color.Background, b.activeSegment.LeadingDiamond)
b.writer.Write(color.Background, color.Foreground, segment.text)
b.writer.Write(color.Background, color.Foreground, b.activeSegment.text)
b.writer.Write(color.Transparent, color.Background, b.activeSegment.TrailingDiamond)
case Accordion:
if segment.enabled {
b.writer.Write(color.Background, color.Foreground, segment.text)
if b.activeSegment.enabled {
b.writer.Write(color.Background, color.Foreground, b.activeSegment.text)
}
}
b.previousActiveSegment = b.activeSegment
Expand Down Expand Up @@ -177,11 +198,10 @@ func (b *Block) debug() (int, []*SegmentTiming) {
largestSegmentNameLength = segmentTiming.nameLength
}
start := time.Now()
segment.renderText(b.env)
segmentTiming.active = segment.enabled
segmentTiming.text = segment.text
if segmentTiming.active {
b.renderSegment(segment)
if segmentTiming.active || segment.Style == Accordion {
b.setActiveSegment(segment)
b.renderActiveSegment()
segmentTiming.text, _ = b.writer.String()
b.writer.Reset()
}
Expand Down
2 changes: 1 addition & 1 deletion src/engine/block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ func TestBlockEnabled(t *testing.T) {
Type: tc.Type,
Segments: tc.Segments,
}
assert.Equal(t, tc.Expected, block.enabled(), tc.Case)
assert.Equal(t, tc.Expected, block.Enabled(), tc.Case)
}
}
26 changes: 11 additions & 15 deletions src/engine/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,11 @@ func (e *Engine) renderBlock(block *Block) {
// when in bash, for rprompt blocks we need to write plain
// and wrap in escaped mode or the prompt will not render correctly
if block.Type == RPrompt && e.Env.Shell() == shell.BASH {
block.initPlain(e.Env, e.Config)
block.InitPlain(e.Env, e.Config)
} else {
block.init(e.Env, e.Writer, e.Ansi)
block.Init(e.Env, e.Writer, e.Ansi)
}
block.renderSegmentsText()
if !block.enabled() {
if !block.Enabled() {
return
}
if block.Newline {
Expand Down Expand Up @@ -161,17 +160,16 @@ func (e *Engine) renderBlock(block *Block) {
}

// debug will loop through your config file and output the timings for each segments
func (e *Engine) PrintDebug(version string) string {
func (e *Engine) PrintDebug(startTime time.Time, version string) string {
var segmentTimings []*SegmentTiming
largestSegmentNameLength := 0
e.write(fmt.Sprintf("\n\x1b[1mVersion:\x1b[0m %s\n", version))
e.write("\n\x1b[1mSegments:\x1b[0m\n\n")
// console title timing
start := time.Now()
title := e.ConsoleTitle.GetTitle()
title = strings.TrimPrefix(title, "\x1b]0;")
title = strings.TrimSuffix(title, "\a")
duration := time.Since(start)
duration := time.Since(startTime)
segmentTiming := &SegmentTiming{
name: "ConsoleTitle",
nameLength: 12,
Expand All @@ -182,7 +180,7 @@ func (e *Engine) PrintDebug(version string) string {
segmentTimings = append(segmentTimings, segmentTiming)
// loop each segments of each blocks
for _, block := range e.Config.Blocks {
block.init(e.Env, e.Writer, e.Ansi)
block.Init(e.Env, e.Writer, e.Ansi)
longestSegmentName, timings := block.debug()
segmentTimings = append(segmentTimings, timings...)
if longestSegmentName > largestSegmentNameLength {
Expand All @@ -197,7 +195,7 @@ func (e *Engine) PrintDebug(version string) string {
segmentName := fmt.Sprintf("%s(%t)", segment.name, segment.active)
e.write(fmt.Sprintf("%-*s - %3d ms - %s\n", largestSegmentNameLength, segmentName, duration, segment.text))
}
e.write(fmt.Sprintf("\n\x1b[1mRun duration:\x1b[0m %s\n", time.Since(start)))
e.write(fmt.Sprintf("\n\x1b[1mRun duration:\x1b[0m %s\n", time.Since(startTime)))
e.write(fmt.Sprintf("\n\x1b[1mCache path:\x1b[0m %s\n", e.Env.CachePath()))
e.write("\n\x1b[1mLogs:\x1b[0m\n\n")
e.write(e.Env.Logs())
Expand Down Expand Up @@ -245,7 +243,6 @@ func (e *Engine) PrintTooltip(tip string) string {
if !tooltip.writer.Enabled() {
return ""
}
tooltip.text = tooltip.string()
tooltip.enabled = true
// little hack to reuse the current logic
block := &Block{
Expand All @@ -254,11 +251,11 @@ func (e *Engine) PrintTooltip(tip string) string {
}
switch e.Env.Shell() {
case shell.ZSH, shell.CMD, shell.FISH:
block.init(e.Env, e.Writer, e.Ansi)
block.Init(e.Env, e.Writer, e.Ansi)
text, _ := block.renderSegments()
return text
case shell.PWSH, shell.PWSH5:
block.initPlain(e.Env, e.Config)
block.InitPlain(e.Env, e.Config)
text, length := block.renderSegments()
e.write(e.Ansi.ClearAfter())
e.write(e.Ansi.CarriageForward())
Expand Down Expand Up @@ -354,9 +351,8 @@ func (e *Engine) PrintRPrompt() string {
if block == nil {
return ""
}
block.init(e.Env, e.Writer, e.Ansi)
block.renderSegmentsText()
if !block.enabled() {
block.Init(e.Env, e.Writer, e.Ansi)
if !block.Enabled() {
return ""
}
text, length := block.renderSegments()
Expand Down
10 changes: 4 additions & 6 deletions src/engine/segment.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"oh-my-posh/segments"
"oh-my-posh/template"
"runtime/debug"
"strings"
"time"
)

Expand All @@ -30,8 +29,8 @@ type Segment struct {
Properties properties.Map `json:"properties,omitempty"`

writer SegmentWriter
text string
enabled bool
text string
env environment.Environment
backgroundCache string
foregroundCache string
Expand Down Expand Up @@ -326,7 +325,7 @@ func (segment *Segment) string() string {
return text
}

func (segment *Segment) renderText(env environment.Environment) {
func (segment *Segment) setEnabled(env environment.Environment) {
defer func() {
err := recover()
if err == nil {
Expand All @@ -335,15 +334,14 @@ func (segment *Segment) renderText(env environment.Environment) {
// display a message explaining omp failed(with the err)
message := fmt.Sprintf("\noh-my-posh fatal error rendering %s segment:%s\n\n%s\n", segment.Type, err, debug.Stack())
fmt.Println(message)
segment.text = "error"
segment.enabled = true
}()
err := segment.mapSegmentWithWriter(env)
if err != nil || !segment.shouldIncludeFolder() {
return
}
if segment.writer.Enabled() {
segment.text = segment.string()
segment.enabled = len(strings.ReplaceAll(segment.text, " ", "")) > 0
segment.enabled = true
env.TemplateCache().AddSegmentData(string(segment.Type), segment.writer)
}
}
16 changes: 6 additions & 10 deletions src/environment/concurrent_map.go
Original file line number Diff line number Diff line change
@@ -1,37 +1,33 @@
package environment

import "sync"

type concurrentMap struct {
values map[string]interface{}
lock sync.RWMutex
}

func newConcurrentMap() *concurrentMap {
return &concurrentMap{
values: make(map[string]interface{}),
lock: sync.RWMutex{},
}
}

func (c *concurrentMap) set(key string, value interface{}) {
c.lock.Lock()
defer c.lock.Unlock()
lock.Lock()
defer lock.Unlock()
c.values[key] = value
}

func (c *concurrentMap) get(key string) (interface{}, bool) {
c.lock.RLock()
defer c.lock.RUnlock()
lock.RLock()
defer lock.RUnlock()
if val, ok := c.values[key]; ok {
return val, true
}
return "", false
}

func (c *concurrentMap) remove(key string) {
c.lock.RLock()
defer c.lock.RUnlock()
lock.RLock()
defer lock.RUnlock()
delete(c.values, key)
}

Expand Down

0 comments on commit 482c997

Please sign in to comment.