refactor: move color logic to module

This commit is contained in:
Jan De Dobbeleer 2022-01-26 13:09:21 +01:00 committed by Jan De Dobbeleer
parent 906ece2af9
commit c86b7b62bc
50 changed files with 452 additions and 413 deletions

View file

@ -1,6 +1,7 @@
package main package main
import ( import (
"oh-my-posh/color"
"oh-my-posh/environment" "oh-my-posh/environment"
"sync" "sync"
"time" "time"
@ -35,27 +36,27 @@ type Block struct {
Newline bool `config:"newline"` Newline bool `config:"newline"`
env environment.Environment env environment.Environment
writer promptWriter writer color.Writer
ansi *ansiUtils ansi *color.Ansi
activeSegment *Segment activeSegment *Segment
previousActiveSegment *Segment previousActiveSegment *Segment
activeBackground string activeBackground string
activeForeground string activeForeground string
} }
func (b *Block) init(env environment.Environment, writer promptWriter, ansi *ansiUtils) { func (b *Block) init(env environment.Environment, writer color.Writer, ansi *color.Ansi) {
b.env = env b.env = env
b.writer = writer b.writer = writer
b.ansi = ansi b.ansi = ansi
} }
func (b *Block) initPlain(env environment.Environment, config *Config) { func (b *Block) initPlain(env environment.Environment, config *Config) {
b.ansi = &ansiUtils{} b.ansi = &color.Ansi{}
b.ansi.init(plain) b.ansi.Init(plain)
b.writer = &AnsiWriter{ b.writer = &color.AnsiWriter{
ansi: b.ansi, Ansi: b.ansi,
terminalBackground: getConsoleBackgroundColor(env, config.TerminalBackground), TerminalBackground: getConsoleBackgroundColor(env, config.TerminalBackground),
ansiColors: MakeColors(env, config), AnsiColors: config.MakeColors(env),
} }
b.env = env b.env = env
} }
@ -64,7 +65,7 @@ func (b *Block) setActiveSegment(segment *Segment) {
b.activeSegment = segment b.activeSegment = segment
b.activeBackground = segment.background() b.activeBackground = segment.background()
b.activeForeground = segment.foreground() b.activeForeground = segment.foreground()
b.writer.setColors(b.activeBackground, b.activeForeground) b.writer.SetColors(b.activeBackground, b.activeForeground)
} }
func (b *Block) enabled() bool { func (b *Block) enabled() bool {
@ -92,7 +93,7 @@ func (b *Block) setStringValues() {
} }
func (b *Block) renderSegments() string { func (b *Block) renderSegments() string {
defer b.writer.reset() defer b.writer.Reset()
for _, segment := range b.Segments { for _, segment := range b.Segments {
if !segment.active { if !segment.active {
continue continue
@ -100,8 +101,8 @@ func (b *Block) renderSegments() string {
b.renderSegment(segment) b.renderSegment(segment)
} }
b.writePowerline(true) b.writePowerline(true)
b.writer.clearParentColors() b.writer.ClearParentColors()
return b.writer.string() return b.writer.String()
} }
func (b *Block) renderSegment(segment *Segment) { func (b *Block) renderSegment(segment *Segment) {
@ -111,19 +112,19 @@ func (b *Block) renderSegment(segment *Segment) {
case Plain, Powerline: case Plain, Powerline:
b.renderText(segment.stringValue) b.renderText(segment.stringValue)
case Diamond: case Diamond:
b.writer.write(Transparent, b.activeBackground, b.activeSegment.LeadingDiamond) b.writer.Write(color.Transparent, b.activeBackground, b.activeSegment.LeadingDiamond)
b.renderText(segment.stringValue) b.renderText(segment.stringValue)
b.writer.write(Transparent, b.activeBackground, b.activeSegment.TrailingDiamond) b.writer.Write(color.Transparent, b.activeBackground, b.activeSegment.TrailingDiamond)
} }
b.previousActiveSegment = b.activeSegment b.previousActiveSegment = b.activeSegment
b.writer.setParentColors(b.activeBackground, b.activeForeground) b.writer.SetParentColors(b.activeBackground, b.activeForeground)
} }
func (b *Block) renderText(text string) { func (b *Block) renderText(text string) {
defaultValue := " " defaultValue := " "
b.writer.write(b.activeBackground, b.activeForeground, b.activeSegment.getValue(Prefix, defaultValue)) b.writer.Write(b.activeBackground, b.activeForeground, b.activeSegment.getValue(Prefix, defaultValue))
b.writer.write(b.activeBackground, b.activeForeground, text) b.writer.Write(b.activeBackground, b.activeForeground, text)
b.writer.write(b.activeBackground, b.activeForeground, b.activeSegment.getValue(Postfix, defaultValue)) b.writer.Write(b.activeBackground, b.activeForeground, b.activeSegment.getValue(Postfix, defaultValue))
} }
func (b *Block) writePowerline(final bool) { func (b *Block) writePowerline(final bool) {
@ -142,21 +143,21 @@ func (b *Block) writePowerline(final bool) {
} }
background := b.activeSegment.background() background := b.activeSegment.background()
if final || b.activeSegment.Style != Powerline { if final || b.activeSegment.Style != Powerline {
background = Transparent background = color.Transparent
} }
if b.activeSegment.Style == Diamond && len(b.activeSegment.LeadingDiamond) == 0 { if b.activeSegment.Style == Diamond && len(b.activeSegment.LeadingDiamond) == 0 {
background = b.activeSegment.background() background = b.activeSegment.background()
} }
if b.activeSegment.InvertPowerline { if b.activeSegment.InvertPowerline {
b.writer.write(b.getPowerlineColor(), background, symbol) b.writer.Write(b.getPowerlineColor(), background, symbol)
return return
} }
b.writer.write(background, b.getPowerlineColor(), symbol) b.writer.Write(background, b.getPowerlineColor(), symbol)
} }
func (b *Block) getPowerlineColor() string { func (b *Block) getPowerlineColor() string {
if b.previousActiveSegment == nil { if b.previousActiveSegment == nil {
return Transparent return color.Transparent
} }
if b.previousActiveSegment.Style == Diamond && len(b.previousActiveSegment.TrailingDiamond) == 0 { if b.previousActiveSegment.Style == Diamond && len(b.previousActiveSegment.TrailingDiamond) == 0 {
return b.previousActiveSegment.background() return b.previousActiveSegment.background()
@ -165,7 +166,7 @@ func (b *Block) getPowerlineColor() string {
return b.previousActiveSegment.background() return b.previousActiveSegment.background()
} }
if b.previousActiveSegment.Style != Powerline { if b.previousActiveSegment.Style != Powerline {
return Transparent return color.Transparent
} }
return b.previousActiveSegment.background() return b.previousActiveSegment.background()
} }
@ -195,8 +196,8 @@ func (b *Block) debug() (int, []*SegmentTiming) {
segmentTiming.stringDuration = time.Since(start) segmentTiming.stringDuration = time.Since(start)
b.renderSegment(segment) b.renderSegment(segment)
b.writePowerline(true) b.writePowerline(true)
segmentTiming.stringValue = b.writer.string() segmentTiming.stringValue = b.writer.String()
b.writer.reset() b.writer.Reset()
} }
segmentTimings = append(segmentTimings, &segmentTiming) segmentTimings = append(segmentTimings, &segmentTiming)
} }

View file

@ -1,4 +1,4 @@
package main package color
import ( import (
"fmt" "fmt"
@ -8,9 +8,17 @@ import (
const ( const (
ansiRegex = "[\u001B\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))" ansiRegex = "[\u001B\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))"
zsh = "zsh"
bash = "bash"
pwsh = "pwsh"
str = "STR"
url = "URL"
) )
type ansiUtils struct { type Ansi struct {
title string
shell string shell string
linechange string linechange string
left string left string
@ -20,7 +28,6 @@ type ansiUtils struct {
clearLine string clearLine string
saveCursorPosition string saveCursorPosition string
restoreCursorPosition string restoreCursorPosition string
title string
colorSingle string colorSingle string
colorFull string colorFull string
colorTransparent string colorTransparent string
@ -32,7 +39,7 @@ type ansiUtils struct {
italic string italic string
underline string underline string
strikethrough string strikethrough string
bashFormat string format string
shellReservedKeywords []shellKeyWordReplacement shellReservedKeywords []shellKeyWordReplacement
} }
@ -41,11 +48,11 @@ type shellKeyWordReplacement struct {
replacement string replacement string
} }
func (a *ansiUtils) init(shell string) { func (a *Ansi) Init(shell string) {
a.shell = shell a.shell = shell
a.bashFormat = "\\[%s\\]"
switch shell { switch shell {
case zsh: case zsh:
a.format = "%%{%s%%}"
a.linechange = "%%{\x1b[%d%s%%}" a.linechange = "%%{\x1b[%d%s%%}"
a.right = "%%{\x1b[%dC%%}" a.right = "%%{\x1b[%dC%%}"
a.left = "%%{\x1b[%dD%%}" a.left = "%%{\x1b[%dD%%}"
@ -69,6 +76,7 @@ func (a *ansiUtils) init(shell string) {
// escape double quotes and variable expansion // escape double quotes and variable expansion
a.shellReservedKeywords = append(a.shellReservedKeywords, shellKeyWordReplacement{"\\", "\\\\"}, shellKeyWordReplacement{"%", "%%"}) a.shellReservedKeywords = append(a.shellReservedKeywords, shellKeyWordReplacement{"\\", "\\\\"}, shellKeyWordReplacement{"%", "%%"})
case bash: case bash:
a.format = "\\[%s\\]"
a.linechange = "\\[\x1b[%d%s\\]" a.linechange = "\\[\x1b[%d%s\\]"
a.right = "\\[\x1b[%dC\\]" a.right = "\\[\x1b[%dC\\]"
a.left = "\\[\x1b[%dD\\]" a.left = "\\[\x1b[%dD\\]"
@ -93,6 +101,7 @@ func (a *ansiUtils) init(shell string) {
// https://tldp.org/HOWTO/Bash-Prompt-HOWTO/bash-prompt-escape-sequences.html // https://tldp.org/HOWTO/Bash-Prompt-HOWTO/bash-prompt-escape-sequences.html
a.shellReservedKeywords = append(a.shellReservedKeywords, shellKeyWordReplacement{"\\", "\\\\"}) a.shellReservedKeywords = append(a.shellReservedKeywords, shellKeyWordReplacement{"\\", "\\\\"})
default: default:
a.format = "%s"
a.linechange = "\x1b[%d%s" a.linechange = "\x1b[%d%s"
a.right = "\x1b[%dC" a.right = "\x1b[%dC"
a.left = "\x1b[%dD" a.left = "\x1b[%dD"
@ -118,7 +127,7 @@ func (a *ansiUtils) init(shell string) {
a.shellReservedKeywords = append(a.shellReservedKeywords, shellKeyWordReplacement{"`", "'"}) a.shellReservedKeywords = append(a.shellReservedKeywords, shellKeyWordReplacement{"`", "'"})
} }
func (a *ansiUtils) lenWithoutANSI(text string) int { func (a *Ansi) LenWithoutANSI(text string) int {
if len(text) == 0 { if len(text) == 0 {
return 0 return 0
} }
@ -139,7 +148,7 @@ func (a *ansiUtils) lenWithoutANSI(text string) int {
return len(runeText) return len(runeText)
} }
func (a *ansiUtils) generateHyperlink(text string) string { func (a *Ansi) generateHyperlink(text string) string {
// hyperlink matching // hyperlink matching
results := regex.FindNamedRegexMatch("(?P<all>(?:\\[(?P<name>.+)\\])(?:\\((?P<url>.*)\\)))", text) results := regex.FindNamedRegexMatch("(?P<all>(?:\\[(?P<name>.+)\\])(?:\\((?P<url>.*)\\)))", text)
if len(results) != 3 { if len(results) != 3 {
@ -151,7 +160,7 @@ func (a *ansiUtils) generateHyperlink(text string) string {
return strings.Replace(text, results["all"], hyperlink, 1) return strings.Replace(text, results["all"], hyperlink, 1)
} }
func (a *ansiUtils) formatText(text string) string { func (a *Ansi) formatText(text string) string {
results := regex.FindAllNamedRegexMatch("(?P<context><(?P<format>[buis])>(?P<text>[^<]+)</[buis]>)", text) results := regex.FindAllNamedRegexMatch("(?P<context><(?P<format>[buis])>(?P<text>[^<]+)</[buis]>)", text)
for _, result := range results { for _, result := range results {
var formatted string var formatted string
@ -170,16 +179,16 @@ func (a *ansiUtils) formatText(text string) string {
return text return text
} }
func (a *ansiUtils) carriageForward() string { func (a *Ansi) CarriageForward() string {
return fmt.Sprintf(a.right, 1000) return fmt.Sprintf(a.right, 1000)
} }
func (a *ansiUtils) getCursorForRightWrite(text string, offset int) string { func (a *Ansi) GetCursorForRightWrite(text string, offset int) string {
strippedLen := a.lenWithoutANSI(text) + -offset strippedLen := a.LenWithoutANSI(text) + -offset
return fmt.Sprintf(a.left, strippedLen) return fmt.Sprintf(a.left, strippedLen)
} }
func (a *ansiUtils) changeLine(numberOfLines int) string { func (a *Ansi) ChangeLine(numberOfLines int) string {
position := "B" position := "B"
if numberOfLines < 0 { if numberOfLines < 0 {
position = "F" position = "F"
@ -188,21 +197,41 @@ func (a *ansiUtils) changeLine(numberOfLines int) string {
return fmt.Sprintf(a.linechange, numberOfLines, position) return fmt.Sprintf(a.linechange, numberOfLines, position)
} }
func (a *ansiUtils) consolePwd(pwd string) string { func (a *Ansi) ConsolePwd(pwd string) string {
if strings.HasSuffix(pwd, ":") { if strings.HasSuffix(pwd, ":") {
pwd += "\\" pwd += "\\"
} }
return fmt.Sprintf(a.osc99, pwd) return fmt.Sprintf(a.osc99, pwd)
} }
func (a *ansiUtils) clearAfter() string { func (a *Ansi) ClearAfter() string {
return a.clearLine + a.clearBelow return a.clearLine + a.clearBelow
} }
func (a *ansiUtils) escapeText(text string) string { func (a *Ansi) EscapeText(text string) string {
// what to escape/replace is different per shell // what to escape/replace is different per shell
for _, s := range a.shellReservedKeywords { for _, s := range a.shellReservedKeywords {
text = strings.ReplaceAll(text, s.text, s.replacement) text = strings.ReplaceAll(text, s.text, s.replacement)
} }
return text return text
} }
func (a *Ansi) Title(title string) string {
return fmt.Sprintf(a.title, title)
}
func (a *Ansi) ColorReset() string {
return a.creset
}
func (a *Ansi) FormatText(text string) string {
return fmt.Sprintf(a.format, text)
}
func (a *Ansi) SaveCursorPosition() string {
return a.saveCursorPosition
}
func (a *Ansi) RestoreCursorPosition() string {
return a.restoreCursorPosition
}

View file

@ -1,4 +1,4 @@
package main package color
import ( import (
"testing" "testing"
@ -17,9 +17,9 @@ func TestLenWithoutAnsi(t *testing.T) {
{Text: "\\[\x1b[44m\\]hello\\[\x1b[0m\\]", ShellName: bash, Expected: 5}, {Text: "\\[\x1b[44m\\]hello\\[\x1b[0m\\]", ShellName: bash, Expected: 5},
} }
for _, tc := range cases { for _, tc := range cases {
a := ansiUtils{} a := Ansi{}
a.init(tc.ShellName) a.Init(tc.ShellName)
strippedLength := a.lenWithoutANSI(tc.Text) strippedLength := a.LenWithoutANSI(tc.Text)
assert.Equal(t, 5, strippedLength) assert.Equal(t, 5, strippedLength)
} }
} }
@ -35,8 +35,8 @@ func TestGenerateHyperlinkNoUrl(t *testing.T) {
{Text: "sample text with no url", ShellName: bash, Expected: "sample text with no url"}, {Text: "sample text with no url", ShellName: bash, Expected: "sample text with no url"},
} }
for _, tc := range cases { for _, tc := range cases {
a := ansiUtils{} a := Ansi{}
a.init(tc.ShellName) a.Init(tc.ShellName)
hyperlinkText := a.generateHyperlink(tc.Text) hyperlinkText := a.generateHyperlink(tc.Text)
assert.Equal(t, tc.Expected, hyperlinkText) assert.Equal(t, tc.Expected, hyperlinkText)
} }
@ -53,8 +53,8 @@ func TestGenerateHyperlinkWithUrl(t *testing.T) {
{Text: "[google](http://www.google.be)", ShellName: bash, Expected: "\\[\x1b]8;;http://www.google.be\x1b\\\\\\]google\\[\x1b]8;;\x1b\\\\\\]"}, {Text: "[google](http://www.google.be)", ShellName: bash, Expected: "\\[\x1b]8;;http://www.google.be\x1b\\\\\\]google\\[\x1b]8;;\x1b\\\\\\]"},
} }
for _, tc := range cases { for _, tc := range cases {
a := ansiUtils{} a := Ansi{}
a.init(tc.ShellName) a.Init(tc.ShellName)
hyperlinkText := a.generateHyperlink(tc.Text) hyperlinkText := a.generateHyperlink(tc.Text)
assert.Equal(t, tc.Expected, hyperlinkText) assert.Equal(t, tc.Expected, hyperlinkText)
} }
@ -71,8 +71,8 @@ func TestGenerateHyperlinkWithUrlNoName(t *testing.T) {
{Text: "[](http://www.google.be)", ShellName: bash, Expected: "[](http://www.google.be)"}, {Text: "[](http://www.google.be)", ShellName: bash, Expected: "[](http://www.google.be)"},
} }
for _, tc := range cases { for _, tc := range cases {
a := ansiUtils{} a := Ansi{}
a.init(tc.ShellName) a.Init(tc.ShellName)
hyperlinkText := a.generateHyperlink(tc.Text) hyperlinkText := a.generateHyperlink(tc.Text)
assert.Equal(t, tc.Expected, hyperlinkText) assert.Equal(t, tc.Expected, hyperlinkText)
} }
@ -91,8 +91,8 @@ func TestFormatText(t *testing.T) {
{Case: "strikethrough", Text: "This <s>is</s> white", Expected: "This \x1b[9mis\x1b[29m white"}, {Case: "strikethrough", Text: "This <s>is</s> white", Expected: "This \x1b[9mis\x1b[29m white"},
} }
for _, tc := range cases { for _, tc := range cases {
a := ansiUtils{} a := Ansi{}
a.init("") a.Init("")
formattedText := a.formatText(tc.Text) formattedText := a.formatText(tc.Text)
assert.Equal(t, tc.Expected, formattedText, tc.Case) assert.Equal(t, tc.Expected, formattedText, tc.Case)
} }

View file

@ -1,20 +1,12 @@
package main package color
import ( import (
"fmt" "fmt"
"oh-my-posh/environment"
"github.com/gookit/color" "github.com/gookit/color"
) )
// MakeColors creates instance of AnsiColors to use in AnsiWriter according to func MakeColors(palette Palette, cacheEnabled bool) (colors AnsiColors) {
// environment and configuration.
func MakeColors(env environment.Environment, cfg *Config) AnsiColors {
cacheDisabled := env.Getenv("OMP_CACHE_DISABLED") == "1"
return makeColors(cfg.Palette, !cacheDisabled)
}
func makeColors(palette Palette, cacheEnabled bool) (colors AnsiColors) {
colors = &DefaultColors{} colors = &DefaultColors{}
if palette != nil { if palette != nil {
colors = &PaletteColors{ansiColors: colors, palette: palette} colors = &PaletteColors{ansiColors: colors, palette: palette}

View file

@ -1,4 +1,4 @@
package main package color
import ( import (
"testing" "testing"
@ -30,29 +30,19 @@ func TestGetAnsiFromColorString(t *testing.T) {
} }
func TestMakeColors(t *testing.T) { func TestMakeColors(t *testing.T) {
colors := makeColors(nil, false) colors := MakeColors(nil, false)
assert.IsType(t, &DefaultColors{}, colors) assert.IsType(t, &DefaultColors{}, colors)
colors = makeColors(nil, true) colors = MakeColors(nil, true)
assert.IsType(t, &CachedColors{}, colors) assert.IsType(t, &CachedColors{}, colors)
assert.IsType(t, &DefaultColors{}, colors.(*CachedColors).ansiColors) assert.IsType(t, &DefaultColors{}, colors.(*CachedColors).ansiColors)
colors = makeColors(testPalette, false) colors = MakeColors(testPalette, false)
assert.IsType(t, &PaletteColors{}, colors) assert.IsType(t, &PaletteColors{}, colors)
assert.IsType(t, &DefaultColors{}, colors.(*PaletteColors).ansiColors) assert.IsType(t, &DefaultColors{}, colors.(*PaletteColors).ansiColors)
colors = makeColors(testPalette, true) colors = MakeColors(testPalette, true)
assert.IsType(t, &CachedColors{}, colors) assert.IsType(t, &CachedColors{}, colors)
assert.IsType(t, &PaletteColors{}, colors.(*CachedColors).ansiColors) assert.IsType(t, &PaletteColors{}, colors.(*CachedColors).ansiColors)
assert.IsType(t, &DefaultColors{}, colors.(*CachedColors).ansiColors.(*PaletteColors).ansiColors) assert.IsType(t, &DefaultColors{}, colors.(*CachedColors).ansiColors.(*PaletteColors).ansiColors)
} }
func BenchmarkEngineRenderPalette(b *testing.B) {
var err error
for i := 0; i < b.N; i++ {
err = engineRender("jandedobbeleer-palette.omp.json")
if err != nil {
b.Fatal(err)
}
}
}

View file

@ -1,4 +1,4 @@
package main package color
import ( import (
"fmt" "fmt"

View file

@ -1,4 +1,4 @@
package main package color
import ( import (
"testing" "testing"

View file

@ -1,4 +1,4 @@
package main package color
import ( import (
"oh-my-posh/regex" "oh-my-posh/regex"
@ -10,11 +10,11 @@ type PlainWriter struct {
builder strings.Builder builder strings.Builder
} }
func (a *PlainWriter) setColors(background, foreground string) {} func (a *PlainWriter) SetColors(background, foreground string) {}
func (a *PlainWriter) setParentColors(background, foreground string) {} func (a *PlainWriter) SetParentColors(background, foreground string) {}
func (a *PlainWriter) clearParentColors() {} func (a *PlainWriter) ClearParentColors() {}
func (a *PlainWriter) write(background, foreground, text string) { func (a *PlainWriter) Write(background, foreground, text string) {
if len(text) == 0 { if len(text) == 0 {
return return
} }
@ -33,10 +33,10 @@ func (a *PlainWriter) write(background, foreground, text string) {
a.builder.WriteString(text) a.builder.WriteString(text)
} }
func (a *PlainWriter) string() string { func (a *PlainWriter) String() string {
return a.builder.String() return a.builder.String()
} }
func (a *PlainWriter) reset() { func (a *PlainWriter) Reset() {
a.builder.Reset() a.builder.Reset()
} }

View file

@ -1,4 +1,4 @@
package main package color
import ( import (
"fmt" "fmt"
@ -10,23 +10,24 @@ const (
colorRegex = `<(?P<foreground>[^,>]+)?,?(?P<background>[^>]+)?>(?P<content>[^<]*)<\/>` colorRegex = `<(?P<foreground>[^,>]+)?,?(?P<background>[^>]+)?>(?P<content>[^<]*)<\/>`
) )
type promptWriter interface { type Writer interface {
write(background, foreground, text string) Write(background, foreground, text string)
string() string String() string
reset() Reset()
setColors(background, foreground string) SetColors(background, foreground string)
setParentColors(background, foreground string) SetParentColors(background, foreground string)
clearParentColors() ClearParentColors()
} }
// AnsiWriter writes colorized strings // AnsiWriter writes colorized ANSI strings
type AnsiWriter struct { type AnsiWriter struct {
builder strings.Builder Ansi *Ansi
ansi *ansiUtils TerminalBackground string
terminalBackground string
Colors *Color Colors *Color
ParentColors []*Color ParentColors []*Color
ansiColors AnsiColors AnsiColors AnsiColors
builder strings.Builder
} }
type Color struct { type Color struct {
@ -73,14 +74,14 @@ const (
Foreground = "foreground" Foreground = "foreground"
) )
func (a *AnsiWriter) setColors(background, foreground string) { func (a *AnsiWriter) SetColors(background, foreground string) {
a.Colors = &Color{ a.Colors = &Color{
Background: background, Background: background,
Foreground: foreground, Foreground: foreground,
} }
} }
func (a *AnsiWriter) setParentColors(background, foreground string) { func (a *AnsiWriter) SetParentColors(background, foreground string) {
if a.ParentColors == nil { if a.ParentColors == nil {
a.ParentColors = make([]*Color, 0) a.ParentColors = make([]*Color, 0)
} }
@ -90,12 +91,12 @@ func (a *AnsiWriter) setParentColors(background, foreground string) {
}}, a.ParentColors...) }}, a.ParentColors...)
} }
func (a *AnsiWriter) clearParentColors() { func (a *AnsiWriter) ClearParentColors() {
a.ParentColors = nil a.ParentColors = nil
} }
func (a *AnsiWriter) getAnsiFromColorString(colorString string, isBackground bool) AnsiColor { func (a *AnsiWriter) getAnsiFromColorString(colorString string, isBackground bool) AnsiColor {
return a.ansiColors.AnsiColorFromString(colorString, isBackground) return a.AnsiColors.AnsiColorFromString(colorString, isBackground)
} }
func (a *AnsiWriter) writeColoredText(background, foreground AnsiColor, text string) { func (a *AnsiWriter) writeColoredText(background, foreground AnsiColor, text string) {
@ -107,22 +108,22 @@ func (a *AnsiWriter) writeColoredText(background, foreground AnsiColor, text str
if foreground.IsEmpty() { if foreground.IsEmpty() {
foreground = a.getAnsiFromColorString("white", false) foreground = a.getAnsiFromColorString("white", false)
} }
if foreground.IsTransparent() && !background.IsEmpty() && len(a.terminalBackground) != 0 { if foreground.IsTransparent() && !background.IsEmpty() && len(a.TerminalBackground) != 0 {
fgAnsiColor := a.getAnsiFromColorString(a.terminalBackground, false) fgAnsiColor := a.getAnsiFromColorString(a.TerminalBackground, false)
coloredText := fmt.Sprintf(a.ansi.colorFull, background, fgAnsiColor, text) coloredText := fmt.Sprintf(a.Ansi.colorFull, background, fgAnsiColor, text)
a.builder.WriteString(coloredText) a.builder.WriteString(coloredText)
return return
} }
if foreground.IsTransparent() && !background.IsEmpty() { if foreground.IsTransparent() && !background.IsEmpty() {
coloredText := fmt.Sprintf(a.ansi.colorTransparent, background, text) coloredText := fmt.Sprintf(a.Ansi.colorTransparent, background, text)
a.builder.WriteString(coloredText) a.builder.WriteString(coloredText)
return return
} else if background.IsEmpty() || background.IsTransparent() { } else if background.IsEmpty() || background.IsTransparent() {
coloredText := fmt.Sprintf(a.ansi.colorSingle, foreground, text) coloredText := fmt.Sprintf(a.Ansi.colorSingle, foreground, text)
a.builder.WriteString(coloredText) a.builder.WriteString(coloredText)
return return
} }
coloredText := fmt.Sprintf(a.ansi.colorFull, background, foreground, text) coloredText := fmt.Sprintf(a.Ansi.colorFull, background, foreground, text)
a.builder.WriteString(coloredText) a.builder.WriteString(coloredText)
} }
@ -131,15 +132,15 @@ func (a *AnsiWriter) writeAndRemoveText(background, foreground AnsiColor, text,
return strings.Replace(parentText, textToRemove, "", 1) return strings.Replace(parentText, textToRemove, "", 1)
} }
func (a *AnsiWriter) write(background, foreground, text string) { func (a *AnsiWriter) Write(background, foreground, text string) {
if len(text) == 0 { if len(text) == 0 {
return return
} }
bgAnsi, fgAnsi := a.asAnsiColors(background, foreground) bgAnsi, fgAnsi := a.asAnsiColors(background, foreground)
text = a.ansi.escapeText(text) text = a.Ansi.EscapeText(text)
text = a.ansi.formatText(text) text = a.Ansi.formatText(text)
text = a.ansi.generateHyperlink(text) text = a.Ansi.generateHyperlink(text)
// first we match for any potentially valid colors enclosed in <> // first we match for any potentially valid colors enclosed in <>
// i.e., find color overrides // i.e., find color overrides
@ -225,10 +226,10 @@ func (a *AnsiWriter) expandKeyword(keyword string) string {
return keyword return keyword
} }
func (a *AnsiWriter) string() string { func (a *AnsiWriter) String() string {
return a.builder.String() return a.builder.String()
} }
func (a *AnsiWriter) reset() { func (a *AnsiWriter) Reset() {
a.builder.Reset() a.builder.Reset()
} }

View file

@ -1,4 +1,4 @@
package main package color
import ( import (
"testing" "testing"
@ -171,17 +171,17 @@ func TestWriteANSIColors(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
ansi := &ansiUtils{} ansi := &Ansi{}
ansi.init("pwsh") ansi.Init("pwsh")
renderer := &AnsiWriter{ renderer := &AnsiWriter{
ansi: ansi, Ansi: ansi,
ParentColors: []*Color{tc.Parent}, ParentColors: []*Color{tc.Parent},
Colors: tc.Colors, Colors: tc.Colors,
terminalBackground: tc.TerminalBackground, TerminalBackground: tc.TerminalBackground,
ansiColors: &DefaultColors{}, AnsiColors: &DefaultColors{},
} }
renderer.write(tc.Colors.Background, tc.Colors.Foreground, tc.Input) renderer.Write(tc.Colors.Background, tc.Colors.Foreground, tc.Input)
got := renderer.string() got := renderer.String()
assert.Equal(t, tc.Expected, got, tc.Case) assert.Equal(t, tc.Expected, got, tc.Case)
} }
} }

View file

@ -7,6 +7,7 @@ import (
json2 "encoding/json" json2 "encoding/json"
"errors" "errors"
"fmt" "fmt"
"oh-my-posh/color"
"oh-my-posh/environment" "oh-my-posh/environment"
"os" "os"
"strconv" "strconv"
@ -30,7 +31,14 @@ type Config struct {
Blocks []*Block `config:"blocks"` Blocks []*Block `config:"blocks"`
Tooltips []*Segment `config:"tooltips"` Tooltips []*Segment `config:"tooltips"`
TransientPrompt *TransientPrompt `config:"transient_prompt"` TransientPrompt *TransientPrompt `config:"transient_prompt"`
Palette Palette `config:"palette"` Palette color.Palette `config:"palette"`
}
// 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)
} }
type TransientPrompt struct { type TransientPrompt struct {

View file

@ -1,7 +1,7 @@
package main package main
import ( import (
"fmt" "oh-my-posh/color"
"oh-my-posh/environment" "oh-my-posh/environment"
"strings" "strings"
) )
@ -9,7 +9,7 @@ import (
type consoleTitle struct { type consoleTitle struct {
env environment.Environment env environment.Environment
config *Config config *Config
ansi *ansiUtils ansi *color.Ansi
} }
// ConsoleTitleStyle defines how to show the title in the console window // ConsoleTitleStyle defines how to show the title in the console window
@ -36,8 +36,8 @@ func (t *consoleTitle) getConsoleTitle() string {
default: default:
title = environment.Base(t.env, t.getPwd()) title = environment.Base(t.env, t.getPwd())
} }
title = t.ansi.escapeText(title) title = t.ansi.EscapeText(title)
return fmt.Sprintf(t.ansi.title, title) return t.ansi.Title(title)
} }
func (t *consoleTitle) getTemplateText() string { func (t *consoleTitle) getTemplateText() string {

View file

@ -1,6 +1,7 @@
package main package main
import ( import (
"oh-my-posh/color"
"oh-my-posh/environment" "oh-my-posh/environment"
"oh-my-posh/mock" "oh-my-posh/mock"
"testing" "testing"
@ -69,8 +70,8 @@ func TestGetConsoleTitle(t *testing.T) {
PWD: tc.Cwd, PWD: tc.Cwd,
Folder: "vagrant", Folder: "vagrant",
}) })
ansi := &ansiUtils{} ansi := &color.Ansi{}
ansi.init(tc.ShellName) ansi.Init(tc.ShellName)
ct := &consoleTitle{ ct := &consoleTitle{
env: env, env: env,
config: config, config: config,
@ -127,8 +128,8 @@ func TestGetConsoleTitleIfGethostnameReturnsError(t *testing.T) {
Root: tc.Root, Root: tc.Root,
HostName: "", HostName: "",
}) })
ansi := &ansiUtils{} ansi := &color.Ansi{}
ansi.init(tc.ShellName) ansi.Init(tc.ShellName)
ct := &consoleTitle{ ct := &consoleTitle{
env: env, env: env,
config: config, config: config,

View file

@ -2,6 +2,7 @@ package main
import ( import (
"fmt" "fmt"
"oh-my-posh/color"
"oh-my-posh/environment" "oh-my-posh/environment"
"strings" "strings"
"time" "time"
@ -10,8 +11,8 @@ import (
type engine struct { type engine struct {
config *Config config *Config
env environment.Environment env environment.Environment
writer promptWriter writer color.Writer
ansi *ansiUtils ansi *color.Ansi
consoleTitle *consoleTitle consoleTitle *consoleTitle
plain bool plain bool
@ -40,7 +41,7 @@ func (e *engine) canWriteRPrompt() bool {
if err != nil || consoleWidth == 0 { if err != nil || consoleWidth == 0 {
return true return true
} }
promptWidth := e.ansi.lenWithoutANSI(prompt) promptWidth := e.ansi.LenWithoutANSI(prompt)
availableSpace := consoleWidth - promptWidth availableSpace := consoleWidth - promptWidth
// spanning multiple lines // spanning multiple lines
if availableSpace < 0 { if availableSpace < 0 {
@ -48,7 +49,7 @@ func (e *engine) canWriteRPrompt() bool {
availableSpace = consoleWidth - overflow availableSpace = consoleWidth - overflow
} }
promptBreathingRoom := 30 promptBreathingRoom := 30
canWrite := (availableSpace - e.ansi.lenWithoutANSI(e.rprompt)) >= promptBreathingRoom canWrite := (availableSpace - e.ansi.LenWithoutANSI(e.rprompt)) >= promptBreathingRoom
return canWrite return canWrite
} }
@ -59,7 +60,7 @@ func (e *engine) render() string {
if e.config.ConsoleTitle { if e.config.ConsoleTitle {
e.writeANSI(e.consoleTitle.getConsoleTitle()) e.writeANSI(e.consoleTitle.getConsoleTitle())
} }
e.writeANSI(e.ansi.creset) e.writeANSI(e.ansi.ColorReset())
if e.config.FinalSpace { if e.config.FinalSpace {
e.write(" ") e.write(" ")
} }
@ -68,7 +69,7 @@ func (e *engine) render() string {
return e.print() return e.print()
} }
cwd := e.env.Pwd() cwd := e.env.Pwd()
e.writeANSI(e.ansi.consolePwd(cwd)) e.writeANSI(e.ansi.ConsolePwd(cwd))
return e.print() return e.print()
} }
@ -95,13 +96,13 @@ func (e *engine) renderBlock(block *Block) {
e.write("\n") e.write("\n")
case Prompt: case Prompt:
if block.VerticalOffset != 0 { if block.VerticalOffset != 0 {
e.writeANSI(e.ansi.changeLine(block.VerticalOffset)) e.writeANSI(e.ansi.ChangeLine(block.VerticalOffset))
} }
switch block.Alignment { switch block.Alignment {
case Right: case Right:
e.writeANSI(e.ansi.carriageForward()) e.writeANSI(e.ansi.CarriageForward())
blockText := block.renderSegments() blockText := block.renderSegments()
e.writeANSI(e.ansi.getCursorForRightWrite(blockText, block.HorizontalOffset)) e.writeANSI(e.ansi.GetCursorForRightWrite(blockText, block.HorizontalOffset))
e.write(blockText) e.write(blockText)
case Left: case Left:
e.write(block.renderSegments()) e.write(block.renderSegments())
@ -109,7 +110,7 @@ func (e *engine) renderBlock(block *Block) {
case RPrompt: case RPrompt:
blockText := block.renderSegments() blockText := block.renderSegments()
if e.env.Shell() == bash { if e.env.Shell() == bash {
blockText = fmt.Sprintf(e.ansi.bashFormat, blockText) blockText = e.ansi.FormatText(blockText)
} }
e.rprompt = blockText e.rprompt = blockText
} }
@ -117,8 +118,8 @@ func (e *engine) renderBlock(block *Block) {
// If this doesn't happen, the portion after the prompt gets colored in the background // If this doesn't happen, the portion after the prompt gets colored in the background
// color of the line above the new input line. Clearing the line fixes this, // color of the line above the new input line. Clearing the line fixes this,
// but can hopefully one day be removed when this is resolved natively. // but can hopefully one day be removed when this is resolved natively.
if e.ansi.shell == pwsh || e.ansi.shell == powershell5 { if e.env.Shell() == pwsh || e.env.Shell() == powershell5 {
e.writeANSI(e.ansi.clearAfter()) e.writeANSI(e.ansi.ClearAfter())
} }
} }
@ -182,11 +183,11 @@ func (e *engine) print() string {
if e.rprompt == "" || !e.canWriteRPrompt() || e.plain { if e.rprompt == "" || !e.canWriteRPrompt() || e.plain {
break break
} }
e.write(e.ansi.saveCursorPosition) e.write(e.ansi.SaveCursorPosition())
e.write(e.ansi.carriageForward()) e.write(e.ansi.CarriageForward())
e.write(e.ansi.getCursorForRightWrite(e.rprompt, 0)) e.write(e.ansi.GetCursorForRightWrite(e.rprompt, 0))
e.write(e.rprompt) e.write(e.rprompt)
e.write(e.ansi.restoreCursorPosition) e.write(e.ansi.RestoreCursorPosition())
} }
return e.string() return e.string()
} }
@ -222,9 +223,9 @@ func (e *engine) renderTooltip(tip string) string {
case pwsh, powershell5: case pwsh, powershell5:
block.initPlain(e.env, e.config) block.initPlain(e.env, e.config)
tooltipText := block.renderSegments() tooltipText := block.renderSegments()
e.write(e.ansi.clearAfter()) e.write(e.ansi.ClearAfter())
e.write(e.ansi.carriageForward()) e.write(e.ansi.CarriageForward())
e.write(e.ansi.getCursorForRightWrite(tooltipText, 0)) e.write(e.ansi.GetCursorForRightWrite(tooltipText, 0))
e.write(tooltipText) e.write(tooltipText)
return e.string() return e.string()
} }
@ -247,16 +248,16 @@ func (e *engine) renderTransientPrompt() string {
if err != nil { if err != nil {
prompt = err.Error() prompt = err.Error()
} }
e.writer.setColors(e.config.TransientPrompt.Background, e.config.TransientPrompt.Foreground) e.writer.SetColors(e.config.TransientPrompt.Background, e.config.TransientPrompt.Foreground)
e.writer.write(e.config.TransientPrompt.Background, e.config.TransientPrompt.Foreground, prompt) e.writer.Write(e.config.TransientPrompt.Background, e.config.TransientPrompt.Foreground, prompt)
switch e.env.Shell() { switch e.env.Shell() {
case zsh: case zsh:
// escape double quotes contained in the prompt // escape double quotes contained in the prompt
prompt := fmt.Sprintf("PS1=\"%s\"", strings.ReplaceAll(e.writer.string(), "\"", "\"\"")) prompt := fmt.Sprintf("PS1=\"%s\"", strings.ReplaceAll(e.writer.String(), "\"", "\"\""))
prompt += "\nRPROMPT=\"\"" prompt += "\nRPROMPT=\"\""
return prompt return prompt
case pwsh, powershell5, winCMD: case pwsh, powershell5, winCMD:
return e.writer.string() return e.writer.String()
} }
return "" return ""
} }

View file

@ -2,6 +2,7 @@ package main
import ( import (
"errors" "errors"
"oh-my-posh/color"
"oh-my-posh/environment" "oh-my-posh/environment"
"oh-my-posh/mock" "oh-my-posh/mock"
"os" "os"
@ -33,8 +34,8 @@ func TestCanWriteRPrompt(t *testing.T) {
for _, tc := range cases { for _, tc := range cases {
env := new(mock.MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("TerminalWidth").Return(tc.TerminalWidth, tc.TerminalWidthError) env.On("TerminalWidth").Return(tc.TerminalWidth, tc.TerminalWidthError)
ansi := &ansiUtils{} ansi := &color.Ansi{}
ansi.init(plain) ansi.Init(plain)
engine := &engine{ engine := &engine{
env: env, env: env,
ansi: ansi, ansi: ansi,
@ -94,13 +95,13 @@ func engineRender(configPath string) error {
cfg := GetConfig(env) cfg := GetConfig(env)
defer testClearDefaultConfig() defer testClearDefaultConfig()
ansi := &ansiUtils{} ansi := &color.Ansi{}
ansi.init(env.Shell()) ansi.Init(env.Shell())
writerColors := MakeColors(env, cfg) writerColors := cfg.MakeColors(env)
writer := &AnsiWriter{ writer := &color.AnsiWriter{
ansi: ansi, Ansi: ansi,
terminalBackground: getConsoleBackgroundColor(env, cfg.TerminalBackground), TerminalBackground: getConsoleBackgroundColor(env, cfg.TerminalBackground),
ansiColors: writerColors, AnsiColors: writerColors,
} }
title := &consoleTitle{ title := &consoleTitle{
env: env, env: env,
@ -120,3 +121,13 @@ func engineRender(configPath string) error {
return nil return nil
} }
func BenchmarkEngineRenderPalette(b *testing.B) {
var err error
for i := 0; i < b.N; i++ {
err = engineRender("jandedobbeleer-palette.omp.json")
if err != nil {
b.Fatal(err)
}
}
}

View file

@ -26,6 +26,7 @@ import (
_ "embed" _ "embed"
"fmt" "fmt"
"math" "math"
"oh-my-posh/color"
"oh-my-posh/regex" "oh-my-posh/regex"
"strconv" "strconv"
"strings" "strings"
@ -98,7 +99,7 @@ func NewRGBColor(ansiColor string) *RGB {
type ImageRenderer struct { type ImageRenderer struct {
ansiString string ansiString string
author string author string
ansi *ansiUtils ansi *color.Ansi
bgColor string bgColor string
factor float64 factor float64
@ -244,7 +245,7 @@ func (ir *ImageRenderer) runeAdditionalWidth(r rune) int {
func (ir *ImageRenderer) calculateWidth() int { func (ir *ImageRenderer) calculateWidth() int {
longest := 0 longest := 0
for _, line := range strings.Split(ir.ansiString, "\n") { for _, line := range strings.Split(ir.ansiString, "\n") {
length := ir.ansi.lenWithoutANSI(line) length := ir.ansi.LenWithoutANSI(line)
for _, char := range line { for _, char := range line {
length += ir.runeAdditionalWidth(char) length += ir.runeAdditionalWidth(char)
} }
@ -435,9 +436,9 @@ func (ir *ImageRenderer) shouldPrint() bool {
return false return false
case invertedColorSingle: case invertedColorSingle:
ir.foregroundColor = ir.defaultBackgroundColor ir.foregroundColor = ir.defaultBackgroundColor
color, _ := strconv.Atoi(match[bg]) bgColor, _ := strconv.Atoi(match[bg])
color += 10 bgColor += 10
ir.setBase16Color(fmt.Sprint(color)) ir.setBase16Color(fmt.Sprint(bgColor))
return false return false
case fullColor: case fullColor:
ir.foregroundColor = NewRGBColor(match[fg]) ir.foregroundColor = NewRGBColor(match[fg])
@ -469,48 +470,48 @@ func (ir *ImageRenderer) shouldPrint() bool {
} }
func (ir *ImageRenderer) setBase16Color(colorStr string) { func (ir *ImageRenderer) setBase16Color(colorStr string) {
color := ir.defaultForegroundColor tempColor := ir.defaultForegroundColor
colorInt, err := strconv.Atoi(colorStr) colorInt, err := strconv.Atoi(colorStr)
if err != nil { if err != nil {
ir.foregroundColor = color ir.foregroundColor = tempColor
} }
switch colorInt { switch colorInt {
case 30, 40: // Black case 30, 40: // Black
color = &RGB{1, 1, 1} tempColor = &RGB{1, 1, 1}
case 31, 41: // Red case 31, 41: // Red
color = &RGB{222, 56, 43} tempColor = &RGB{222, 56, 43}
case 32, 42: // Green case 32, 42: // Green
color = &RGB{57, 181, 74} tempColor = &RGB{57, 181, 74}
case 33, 43: // Yellow case 33, 43: // Yellow
color = &RGB{255, 199, 6} tempColor = &RGB{255, 199, 6}
case 34, 44: // Blue case 34, 44: // Blue
color = &RGB{0, 111, 184} tempColor = &RGB{0, 111, 184}
case 35, 45: // Magenta case 35, 45: // Magenta
color = &RGB{118, 38, 113} tempColor = &RGB{118, 38, 113}
case 36, 46: // Cyan case 36, 46: // Cyan
color = &RGB{44, 181, 233} tempColor = &RGB{44, 181, 233}
case 37, 47: // White case 37, 47: // White
color = &RGB{204, 204, 204} tempColor = &RGB{204, 204, 204}
case 90, 100: // Bright Black (Gray) case 90, 100: // Bright Black (Gray)
color = &RGB{128, 128, 128} tempColor = &RGB{128, 128, 128}
case 91, 101: // Bright Red case 91, 101: // Bright Red
color = &RGB{255, 0, 0} tempColor = &RGB{255, 0, 0}
case 92, 102: // Bright Green case 92, 102: // Bright Green
color = &RGB{0, 255, 0} tempColor = &RGB{0, 255, 0}
case 93, 103: // Bright Yellow case 93, 103: // Bright Yellow
color = &RGB{255, 255, 0} tempColor = &RGB{255, 255, 0}
case 94, 104: // Bright Blue case 94, 104: // Bright Blue
color = &RGB{0, 0, 255} tempColor = &RGB{0, 0, 255}
case 95, 105: // Bright Magenta case 95, 105: // Bright Magenta
color = &RGB{255, 0, 255} tempColor = &RGB{255, 0, 255}
case 96, 106: // Bright Cyan case 96, 106: // Bright Cyan
color = &RGB{101, 194, 205} tempColor = &RGB{101, 194, 205}
case 97, 107: // Bright White case 97, 107: // Bright White
color = &RGB{255, 255, 255} tempColor = &RGB{255, 255, 255}
} }
if colorInt < 40 || (colorInt >= 90 && colorInt < 100) { if colorInt < 40 || (colorInt >= 90 && colorInt < 100) {
ir.foregroundColor = color ir.foregroundColor = tempColor
return return
} }
ir.backgroundColor = color ir.backgroundColor = tempColor
} }

View file

@ -2,6 +2,7 @@ package main
import ( import (
"io/ioutil" "io/ioutil"
"oh-my-posh/color"
"os" "os"
"testing" "testing"
@ -15,8 +16,8 @@ func runImageTest(content string) error {
return err return err
} }
defer os.Remove(file.Name()) defer os.Remove(file.Name())
ansi := &ansiUtils{} ansi := &color.Ansi{}
ansi.init(plain) ansi.Init(plain)
image := &ImageRenderer{ image := &ImageRenderer{
ansiString: content, ansiString: content,
ansi: ansi, ansi: ansi,

View file

@ -4,6 +4,7 @@ import (
_ "embed" _ "embed"
"flag" "flag"
"fmt" "fmt"
"oh-my-posh/color"
"oh-my-posh/environment" "oh-my-posh/environment"
"oh-my-posh/regex" "oh-my-posh/regex"
"os" "os"
@ -32,7 +33,8 @@ var zshInit string
var cmdInit string var cmdInit string
const ( const (
noExe = "echo \"Unable to find Oh My Posh executable\"" noExe = "echo \"Unable to find Oh My Posh executable\""
zsh = "zsh" zsh = "zsh"
bash = "bash" bash = "bash"
pwsh = "pwsh" pwsh = "pwsh"
@ -184,17 +186,17 @@ func main() {
return return
} }
cfg := GetConfig(env) cfg := GetConfig(env)
ansi := &ansiUtils{} ansi := &color.Ansi{}
ansi.init(env.Shell()) ansi.Init(env.Shell())
var writer promptWriter var writer color.Writer
if *args.Plain { if *args.Plain {
writer = &PlainWriter{} writer = &color.PlainWriter{}
} else { } else {
writerColors := MakeColors(env, cfg) writerColors := cfg.MakeColors(env)
writer = &AnsiWriter{ writer = &color.AnsiWriter{
ansi: ansi, Ansi: ansi,
terminalBackground: getConsoleBackgroundColor(env, cfg.TerminalBackground), TerminalBackground: getConsoleBackgroundColor(env, cfg.TerminalBackground),
ansiColors: writerColors, AnsiColors: writerColors,
} }
} }
title := &consoleTitle{ title := &consoleTitle{

View file

@ -2,9 +2,20 @@ package main
import ( import (
"fmt" "fmt"
"oh-my-posh/color"
"oh-my-posh/regex" "oh-my-posh/regex"
) )
type Properties interface {
GetColor(property Property, defaultColor string) string
GetBool(property Property, defaultValue bool) bool
GetString(property Property, defaultValue string) string
GetFloat64(property Property, defaultValue float64) float64
GetInt(property Property, defaultValue int) int
GetKeyValueMap(property Property, defaultValue map[string]string) map[string]string
GetStringArray(property Property, defaultValue []string) []string
}
// Property defines one property of a segment for context // Property defines one property of a segment for context
type Property string type Property string
@ -42,7 +53,7 @@ const (
type properties map[Property]interface{} type properties map[Property]interface{}
func (p properties) getString(property Property, defaultValue string) string { func (p properties) GetString(property Property, defaultValue string) string {
val, found := p[property] val, found := p[property]
if !found { if !found {
return defaultValue return defaultValue
@ -58,13 +69,13 @@ func parseString(value interface{}, defaultValue string) string {
return stringValue return stringValue
} }
func (p properties) getColor(property Property, defaultValue string) string { func (p properties) GetColor(property Property, defaultValue string) string {
val, found := p[property] val, found := p[property]
if !found { if !found {
return defaultValue return defaultValue
} }
colorString := parseString(val, defaultValue) colorString := parseString(val, defaultValue)
if IsAnsiColorName(colorString) { if color.IsAnsiColorName(colorString) {
return colorString return colorString
} }
values := regex.FindNamedRegexMatch(`(?P<color>#[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}|p:.*)`, colorString) values := regex.FindNamedRegexMatch(`(?P<color>#[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}|p:.*)`, colorString)
@ -74,7 +85,7 @@ func (p properties) getColor(property Property, defaultValue string) string {
return defaultValue return defaultValue
} }
func (p properties) getBool(property Property, defaultValue bool) bool { func (p properties) GetBool(property Property, defaultValue bool) bool {
val, found := p[property] val, found := p[property]
if !found { if !found {
return defaultValue return defaultValue
@ -86,7 +97,7 @@ func (p properties) getBool(property Property, defaultValue bool) bool {
return boolValue return boolValue
} }
func (p properties) getFloat64(property Property, defaultValue float64) float64 { func (p properties) GetFloat64(property Property, defaultValue float64) float64 {
val, found := p[property] val, found := p[property]
if !found { if !found {
return defaultValue return defaultValue
@ -105,7 +116,7 @@ func (p properties) getFloat64(property Property, defaultValue float64) float64
return float64(intValue) return float64(intValue)
} }
func (p properties) getInt(property Property, defaultValue int) int { func (p properties) GetInt(property Property, defaultValue int) int {
val, found := p[property] val, found := p[property]
if !found { if !found {
return defaultValue return defaultValue
@ -124,7 +135,7 @@ func (p properties) getInt(property Property, defaultValue int) int {
return int(intValue) return int(intValue)
} }
func (p properties) getKeyValueMap(property Property, defaultValue map[string]string) map[string]string { func (p properties) GetKeyValueMap(property Property, defaultValue map[string]string) map[string]string {
val, found := p[property] val, found := p[property]
if !found { if !found {
return defaultValue return defaultValue
@ -135,7 +146,7 @@ func (p properties) getKeyValueMap(property Property, defaultValue map[string]st
return keyValues return keyValues
} }
func (p properties) getStringArray(property Property, defaultValue []string) []string { func (p properties) GetStringArray(property Property, defaultValue []string) []string {
val, found := p[property] val, found := p[property]
if !found { if !found {
return defaultValue return defaultValue

View file

@ -15,100 +15,100 @@ const (
func TestGetString(t *testing.T) { func TestGetString(t *testing.T) {
var properties properties = properties{Foo: expected} var properties properties = properties{Foo: expected}
value := properties.getString(Foo, "err") value := properties.GetString(Foo, "err")
assert.Equal(t, expected, value) assert.Equal(t, expected, value)
} }
func TestGetStringNoEntry(t *testing.T) { func TestGetStringNoEntry(t *testing.T) {
var properties properties = properties{} var properties properties = properties{}
value := properties.getString(Foo, expected) value := properties.GetString(Foo, expected)
assert.Equal(t, expected, value) assert.Equal(t, expected, value)
} }
func TestGetStringNoTextEntry(t *testing.T) { func TestGetStringNoTextEntry(t *testing.T) {
var properties properties = properties{Foo: true} var properties properties = properties{Foo: true}
value := properties.getString(Foo, expected) value := properties.GetString(Foo, expected)
assert.Equal(t, expected, value) assert.Equal(t, expected, value)
} }
func TestGetHexColor(t *testing.T) { func TestGetHexColor(t *testing.T) {
expected := expectedColor expected := expectedColor
var properties properties = properties{Foo: expected} var properties properties = properties{Foo: expected}
value := properties.getColor(Foo, "#789123") value := properties.GetColor(Foo, "#789123")
assert.Equal(t, expected, value) assert.Equal(t, expected, value)
} }
func TestGetColor(t *testing.T) { func TestGetColor(t *testing.T) {
expected := "yellow" expected := "yellow"
var properties properties = properties{Foo: expected} var properties properties = properties{Foo: expected}
value := properties.getColor(Foo, "#789123") value := properties.GetColor(Foo, "#789123")
assert.Equal(t, expected, value) assert.Equal(t, expected, value)
} }
func TestDefaultColorWithInvalidColorCode(t *testing.T) { func TestDefaultColorWithInvalidColorCode(t *testing.T) {
expected := expectedColor expected := expectedColor
var properties properties = properties{Foo: "invalid"} var properties properties = properties{Foo: "invalid"}
value := properties.getColor(Foo, expected) value := properties.GetColor(Foo, expected)
assert.Equal(t, expected, value) assert.Equal(t, expected, value)
} }
func TestDefaultColorWithUnavailableProperty(t *testing.T) { func TestDefaultColorWithUnavailableProperty(t *testing.T) {
expected := expectedColor expected := expectedColor
var properties properties = properties{} var properties properties = properties{}
value := properties.getColor(Foo, expected) value := properties.GetColor(Foo, expected)
assert.Equal(t, expected, value) assert.Equal(t, expected, value)
} }
func TestGetPaletteColor(t *testing.T) { func TestGetPaletteColor(t *testing.T) {
expected := "p:red" expected := "p:red"
var properties properties = properties{Foo: expected} var properties properties = properties{Foo: expected}
value := properties.getColor(Foo, "white") value := properties.GetColor(Foo, "white")
assert.Equal(t, expected, value) assert.Equal(t, expected, value)
} }
func TestGetBool(t *testing.T) { func TestGetBool(t *testing.T) {
expected := true expected := true
var properties properties = properties{Foo: expected} var properties properties = properties{Foo: expected}
value := properties.getBool(Foo, false) value := properties.GetBool(Foo, false)
assert.True(t, value) assert.True(t, value)
} }
func TestGetBoolPropertyNotInMap(t *testing.T) { func TestGetBoolPropertyNotInMap(t *testing.T) {
var properties properties = properties{} var properties properties = properties{}
value := properties.getBool(Foo, false) value := properties.GetBool(Foo, false)
assert.False(t, value) assert.False(t, value)
} }
func TestGetBoolInvalidProperty(t *testing.T) { func TestGetBoolInvalidProperty(t *testing.T) {
var properties properties = properties{Foo: "borked"} var properties properties = properties{Foo: "borked"}
value := properties.getBool(Foo, false) value := properties.GetBool(Foo, false)
assert.False(t, value) assert.False(t, value)
} }
func TestGetFloat64(t *testing.T) { func TestGetFloat64(t *testing.T) {
expected := float64(1337) expected := float64(1337)
var properties properties = properties{Foo: expected} var properties properties = properties{Foo: expected}
value := properties.getFloat64(Foo, 9001) value := properties.GetFloat64(Foo, 9001)
assert.Equal(t, expected, value) assert.Equal(t, expected, value)
} }
func TestGetFloat64PropertyNotInMap(t *testing.T) { func TestGetFloat64PropertyNotInMap(t *testing.T) {
expected := float64(1337) expected := float64(1337)
var properties properties = properties{} var properties properties = properties{}
value := properties.getFloat64(Foo, expected) value := properties.GetFloat64(Foo, expected)
assert.Equal(t, expected, value) assert.Equal(t, expected, value)
} }
func TestGetFloat64InvalidStringProperty(t *testing.T) { func TestGetFloat64InvalidStringProperty(t *testing.T) {
expected := float64(1337) expected := float64(1337)
var properties properties = properties{ThresholdProperty: "invalid"} var properties properties = properties{Foo: "invalid"}
value := properties.getFloat64(ThresholdProperty, expected) value := properties.GetFloat64(Foo, expected)
assert.Equal(t, expected, value) assert.Equal(t, expected, value)
} }
func TestGetFloat64InvalidBoolProperty(t *testing.T) { func TestGetFloat64InvalidBoolProperty(t *testing.T) {
expected := float64(1337) expected := float64(1337)
var properties properties = properties{ThresholdProperty: true} var properties properties = properties{Foo: true}
value := properties.getFloat64(ThresholdProperty, expected) value := properties.GetFloat64(Foo, expected)
assert.Equal(t, expected, value) assert.Equal(t, expected, value)
} }

View file

@ -55,8 +55,8 @@ func (s *scm) init(props Properties, env environment.Environment) {
} }
func (s *scm) truncateBranch(branch string) string { func (s *scm) truncateBranch(branch string) string {
fullBranchPath := s.props.getBool(FullBranchPath, true) fullBranchPath := s.props.GetBool(FullBranchPath, true)
maxLength := s.props.getInt(BranchMaxLength, 0) maxLength := s.props.GetInt(BranchMaxLength, 0)
if !fullBranchPath && strings.Contains(branch, "/") { if !fullBranchPath && strings.Contains(branch, "/") {
index := strings.LastIndex(branch, "/") index := strings.LastIndex(branch, "/")
branch = branch[index+1:] branch = branch[index+1:]
@ -64,12 +64,12 @@ func (s *scm) truncateBranch(branch string) string {
if maxLength == 0 || len(branch) <= maxLength { if maxLength == 0 || len(branch) <= maxLength {
return branch return branch
} }
symbol := s.props.getString(TruncateSymbol, "") symbol := s.props.GetString(TruncateSymbol, "")
return branch[0:maxLength] + symbol return branch[0:maxLength] + symbol
} }
func (s *scm) shouldIgnoreRootRepository(rootDir string) bool { func (s *scm) shouldIgnoreRootRepository(rootDir string) bool {
excludedFolders := s.props.getStringArray(ExcludeFolders, []string{}) excludedFolders := s.props.GetStringArray(ExcludeFolders, []string{})
if len(excludedFolders) == 0 { if len(excludedFolders) == 0 {
return false return false
} }

View file

@ -38,16 +38,6 @@ type SegmentTiming struct {
stringDuration time.Duration stringDuration time.Duration
} }
type Properties interface {
getColor(property Property, defaultColor string) string
getBool(property Property, defaultValue bool) bool
getString(property Property, defaultValue string) string
getFloat64(property Property, defaultValue float64) float64
getInt(property Property, defaultValue int) int
getKeyValueMap(property Property, defaultValue map[string]string) map[string]string
getStringArray(property Property, defaultValue []string) []string
}
// SegmentWriter is the interface used to define what and if to write to the prompt // SegmentWriter is the interface used to define what and if to write to the prompt
type SegmentWriter interface { type SegmentWriter interface {
enabled() bool enabled() bool

View file

@ -37,7 +37,7 @@ func (a *aws) enabled() bool {
} }
return "" return ""
} }
displayDefaultUser := a.props.getBool(DisplayDefault, true) displayDefaultUser := a.props.GetBool(DisplayDefault, true)
a.Profile = getEnvFirstMatch("AWS_VAULT", "AWS_PROFILE") a.Profile = getEnvFirstMatch("AWS_VAULT", "AWS_PROFILE")
if !displayDefaultUser && a.Profile == defaultUser { if !displayDefaultUser && a.Profile == defaultUser {
return false return false

View file

@ -52,11 +52,11 @@ func (b *batt) enabled() bool {
switch b.Battery.State { switch b.Battery.State {
case battery.Discharging, battery.NotCharging: case battery.Discharging, battery.NotCharging:
b.Icon = b.props.getString(DischargingIcon, "") b.Icon = b.props.GetString(DischargingIcon, "")
case battery.Charging: case battery.Charging:
b.Icon = b.props.getString(ChargingIcon, "") b.Icon = b.props.GetString(ChargingIcon, "")
case battery.Full: case battery.Full:
b.Icon = b.props.getString(ChargedIcon, "") b.Icon = b.props.GetString(ChargedIcon, "")
case battery.Empty, battery.Unknown: case battery.Empty, battery.Unknown:
return true return true
} }
@ -70,7 +70,7 @@ func (b *batt) enabledWhileError(err error) bool {
if _, ok := err.(*environment.NoBatteryError); ok { if _, ok := err.(*environment.NoBatteryError); ok {
return false return false
} }
displayError := b.props.getBool(DisplayError, false) displayError := b.props.GetBool(DisplayError, false)
if !displayError { if !displayError {
return false return false
} }

View file

@ -140,12 +140,12 @@ func (bf *brewfather) enabled() bool {
} }
// URL property set to weblink to the full batch page // URL property set to weblink to the full batch page
batchID := bf.props.getString(BFBatchID, "") batchID := bf.props.GetString(BFBatchID, "")
if len(batchID) > 0 { if len(batchID) > 0 {
bf.URL = fmt.Sprintf("https://web.brewfather.app/tabs/batches/batch/%s", batchID) bf.URL = fmt.Sprintf("https://web.brewfather.app/tabs/batches/batch/%s", batchID)
} }
bf.DayIcon = bf.props.getString(BFDayIcon, "d") bf.DayIcon = bf.props.GetString(BFDayIcon, "d")
return true return true
} }
@ -154,49 +154,49 @@ func (bf *brewfather) getTrendIcon(trend float64) string {
// Not a fan of this logic - wondering if Go lets us do something cleaner... // Not a fan of this logic - wondering if Go lets us do something cleaner...
if trend >= 0 { if trend >= 0 {
if trend > 4 { if trend > 4 {
return bf.props.getString(BFDoubleUpIcon, "↑↑") return bf.props.GetString(BFDoubleUpIcon, "↑↑")
} }
if trend > 2 { if trend > 2 {
return bf.props.getString(BFSingleUpIcon, "↑") return bf.props.GetString(BFSingleUpIcon, "↑")
} }
if trend > 0.5 { if trend > 0.5 {
return bf.props.getString(BFFortyFiveUpIcon, "↗") return bf.props.GetString(BFFortyFiveUpIcon, "↗")
} }
return bf.props.getString(BFFlatIcon, "→") return bf.props.GetString(BFFlatIcon, "→")
} }
if trend < -4 { if trend < -4 {
return bf.props.getString(BFDoubleDownIcon, "↓↓") return bf.props.GetString(BFDoubleDownIcon, "↓↓")
} }
if trend < -2 { if trend < -2 {
return bf.props.getString(BFSingleDownIcon, "↓") return bf.props.GetString(BFSingleDownIcon, "↓")
} }
if trend < -0.5 { if trend < -0.5 {
return bf.props.getString(BFFortyFiveDownIcon, "↘") return bf.props.GetString(BFFortyFiveDownIcon, "↘")
} }
return bf.props.getString(BFFlatIcon, "→") return bf.props.GetString(BFFlatIcon, "→")
} }
func (bf *brewfather) getBatchStatusIcon(batchStatus string) string { func (bf *brewfather) getBatchStatusIcon(batchStatus string) string {
switch batchStatus { switch batchStatus {
case BFStatusPlanning: case BFStatusPlanning:
return bf.props.getString(BFPlanningStatusIcon, "\uF8EA") return bf.props.GetString(BFPlanningStatusIcon, "\uF8EA")
case BFStatusBrewing: case BFStatusBrewing:
return bf.props.getString(BFBrewingStatusIcon, "\uF7DE") return bf.props.GetString(BFBrewingStatusIcon, "\uF7DE")
case BFStatusFermenting: case BFStatusFermenting:
return bf.props.getString(BFFermentingStatusIcon, "\uF499") return bf.props.GetString(BFFermentingStatusIcon, "\uF499")
case BFStatusConditioning: case BFStatusConditioning:
return bf.props.getString(BFConditioningStatusIcon, "\uE372") return bf.props.GetString(BFConditioningStatusIcon, "\uE372")
case BFStatusCompleted: case BFStatusCompleted:
return bf.props.getString(BFCompletedStatusIcon, "\uF7A5") return bf.props.GetString(BFCompletedStatusIcon, "\uF7A5")
case BFStatusArchived: case BFStatusArchived:
return bf.props.getString(BFArchivedStatusIcon, "\uF187") return bf.props.GetString(BFArchivedStatusIcon, "\uF187")
default: default:
return "" return ""
} }
@ -227,17 +227,17 @@ func (bf *brewfather) getResult() (*Batch, error) {
return nil return nil
} }
userID := bf.props.getString(BFUserID, "") userID := bf.props.GetString(BFUserID, "")
if len(userID) == 0 { if len(userID) == 0 {
return nil, errors.New("missing Brewfather user id (user_id)") return nil, errors.New("missing Brewfather user id (user_id)")
} }
apiKey := bf.props.getString(BFAPIKey, "") apiKey := bf.props.GetString(BFAPIKey, "")
if len(apiKey) == 0 { if len(apiKey) == 0 {
return nil, errors.New("missing Brewfather api key (api_key)") return nil, errors.New("missing Brewfather api key (api_key)")
} }
batchID := bf.props.getString(BFBatchID, "") batchID := bf.props.GetString(BFBatchID, "")
if len(batchID) == 0 { if len(batchID) == 0 {
return nil, errors.New("missing Brewfather batch id (batch_id)") return nil, errors.New("missing Brewfather batch id (batch_id)")
} }
@ -248,8 +248,8 @@ func (bf *brewfather) getResult() (*Batch, error) {
batchURL := fmt.Sprintf("https://api.brewfather.app/v1/batches/%s", batchID) batchURL := fmt.Sprintf("https://api.brewfather.app/v1/batches/%s", batchID)
batchReadingsURL := fmt.Sprintf("https://api.brewfather.app/v1/batches/%s/readings", batchID) batchReadingsURL := fmt.Sprintf("https://api.brewfather.app/v1/batches/%s/readings", batchID)
httpTimeout := bf.props.getInt(HTTPTimeout, DefaultHTTPTimeout) httpTimeout := bf.props.GetInt(HTTPTimeout, DefaultHTTPTimeout)
cacheTimeout := bf.props.getInt(BFCacheTimeout, 5) cacheTimeout := bf.props.GetInt(BFCacheTimeout, 5)
if cacheTimeout > 0 { if cacheTimeout > 0 {
if data, err := getFromCache(batchURL); err == nil { if data, err := getFromCache(batchURL); err == nil {

View file

@ -24,11 +24,11 @@ func (c *command) template() string {
} }
func (c *command) enabled() bool { func (c *command) enabled() bool {
shell := c.props.getString(ExecutableShell, "bash") shell := c.props.GetString(ExecutableShell, "bash")
if !c.env.HasCommand(shell) { if !c.env.HasCommand(shell) {
return false return false
} }
command := c.props.getString(Command, "echo no command specified") command := c.props.GetString(Command, "echo no command specified")
if strings.Contains(command, "||") { if strings.Contains(command, "||") {
commands := strings.Split(command, "||") commands := strings.Split(command, "||")
for _, cmd := range commands { for _, cmd := range commands {

View file

@ -48,13 +48,13 @@ const (
) )
func (t *executiontime) enabled() bool { func (t *executiontime) enabled() bool {
alwaysEnabled := t.props.getBool(AlwaysEnabled, false) alwaysEnabled := t.props.GetBool(AlwaysEnabled, false)
executionTimeMs := t.env.ExecutionTime() executionTimeMs := t.env.ExecutionTime()
thresholdMs := t.props.getFloat64(ThresholdProperty, float64(500)) thresholdMs := t.props.GetFloat64(ThresholdProperty, float64(500))
if !alwaysEnabled && executionTimeMs < thresholdMs { if !alwaysEnabled && executionTimeMs < thresholdMs {
return false return false
} }
style := DurationStyle(t.props.getString(Style, string(Austin))) style := DurationStyle(t.props.GetString(Style, string(Austin)))
t.Ms = int64(executionTimeMs) t.Ms = int64(executionTimeMs)
t.FormattedMs = t.formatDuration(style) t.FormattedMs = t.formatDuration(style)
return t.FormattedMs != "" return t.FormattedMs != ""

View file

@ -18,7 +18,7 @@ func (e *exit) template() string {
func (e *exit) enabled() bool { func (e *exit) enabled() bool {
e.Text = e.getMeaningFromExitCode(e.env.ErrorCode()) e.Text = e.getMeaningFromExitCode(e.env.ErrorCode())
if e.props.getBool(AlwaysEnabled, false) { if e.props.GetBool(AlwaysEnabled, false) {
return true return true
} }
return e.env.ErrorCode() != 0 return e.env.ErrorCode() != 0

View file

@ -114,7 +114,7 @@ func (g *git) enabled() bool {
if !g.shouldDisplay() { if !g.shouldDisplay() {
return false return false
} }
displayStatus := g.props.getBool(FetchStatus, false) displayStatus := g.props.GetBool(FetchStatus, false)
if displayStatus { if displayStatus {
g.setGitStatus() g.setGitStatus()
g.setGitHEADContext() g.setGitHEADContext()
@ -124,13 +124,13 @@ func (g *git) enabled() bool {
g.Working = &GitStatus{} g.Working = &GitStatus{}
g.Staging = &GitStatus{} g.Staging = &GitStatus{}
} }
if g.Upstream != "" && g.props.getBool(FetchUpstreamIcon, false) { if g.Upstream != "" && g.props.GetBool(FetchUpstreamIcon, false) {
g.UpstreamIcon = g.getUpstreamIcon() g.UpstreamIcon = g.getUpstreamIcon()
} }
if g.props.getBool(FetchStashCount, false) { if g.props.GetBool(FetchStashCount, false) {
g.StashCount = g.getStashContext() g.StashCount = g.getStashContext()
} }
if g.props.getBool(FetchWorktreeCount, false) { if g.props.GetBool(FetchWorktreeCount, false) {
g.WorktreeCount = g.getWorktreeContext() g.WorktreeCount = g.getWorktreeContext()
} }
return true return true
@ -196,19 +196,19 @@ func (g *git) shouldDisplay() bool {
func (g *git) setBranchStatus() { func (g *git) setBranchStatus() {
getBranchStatus := func() string { getBranchStatus := func() string {
if g.Ahead > 0 && g.Behind > 0 { if g.Ahead > 0 && g.Behind > 0 {
return fmt.Sprintf(" %s%d %s%d", g.props.getString(BranchAheadIcon, "\u2191"), g.Ahead, g.props.getString(BranchBehindIcon, "\u2193"), g.Behind) return fmt.Sprintf(" %s%d %s%d", g.props.GetString(BranchAheadIcon, "\u2191"), g.Ahead, g.props.GetString(BranchBehindIcon, "\u2193"), g.Behind)
} }
if g.Ahead > 0 { if g.Ahead > 0 {
return fmt.Sprintf(" %s%d", g.props.getString(BranchAheadIcon, "\u2191"), g.Ahead) return fmt.Sprintf(" %s%d", g.props.GetString(BranchAheadIcon, "\u2191"), g.Ahead)
} }
if g.Behind > 0 { if g.Behind > 0 {
return fmt.Sprintf(" %s%d", g.props.getString(BranchBehindIcon, "\u2193"), g.Behind) return fmt.Sprintf(" %s%d", g.props.GetString(BranchBehindIcon, "\u2193"), g.Behind)
} }
if g.Behind == 0 && g.Ahead == 0 && g.Upstream != "" { if g.Behind == 0 && g.Ahead == 0 && g.Upstream != "" {
return fmt.Sprintf(" %s", g.props.getString(BranchIdenticalIcon, "\u2261")) return fmt.Sprintf(" %s", g.props.GetString(BranchIdenticalIcon, "\u2261"))
} }
if g.Upstream == "" { if g.Upstream == "" {
return fmt.Sprintf(" %s", g.props.getString(BranchGoneIcon, "\u2262")) return fmt.Sprintf(" %s", g.props.GetString(BranchGoneIcon, "\u2262"))
} }
return "" return ""
} }
@ -219,18 +219,18 @@ func (g *git) getUpstreamIcon() string {
upstream := regex.ReplaceAllString("/.*", g.Upstream, "") upstream := regex.ReplaceAllString("/.*", g.Upstream, "")
g.UpstreamURL = g.getOriginURL(upstream) g.UpstreamURL = g.getOriginURL(upstream)
if strings.Contains(g.UpstreamURL, "github") { if strings.Contains(g.UpstreamURL, "github") {
return g.props.getString(GithubIcon, "\uF408 ") return g.props.GetString(GithubIcon, "\uF408 ")
} }
if strings.Contains(g.UpstreamURL, "gitlab") { if strings.Contains(g.UpstreamURL, "gitlab") {
return g.props.getString(GitlabIcon, "\uF296 ") return g.props.GetString(GitlabIcon, "\uF296 ")
} }
if strings.Contains(g.UpstreamURL, "bitbucket") { if strings.Contains(g.UpstreamURL, "bitbucket") {
return g.props.getString(BitbucketIcon, "\uF171 ") return g.props.GetString(BitbucketIcon, "\uF171 ")
} }
if strings.Contains(g.UpstreamURL, "dev.azure.com") || strings.Contains(g.UpstreamURL, "visualstudio.com") { if strings.Contains(g.UpstreamURL, "dev.azure.com") || strings.Contains(g.UpstreamURL, "visualstudio.com") {
return g.props.getString(AzureDevOpsIcon, "\uFD03 ") return g.props.GetString(AzureDevOpsIcon, "\uFD03 ")
} }
return g.props.getString(GitIcon, "\uE5FB ") return g.props.GetString(GitIcon, "\uE5FB ")
} }
func (g *git) setGitStatus() { func (g *git) setGitStatus() {
@ -305,7 +305,7 @@ func (g *git) getGitCommandOutput(args ...string) string {
} }
func (g *git) setGitHEADContext() { func (g *git) setGitHEADContext() {
branchIcon := g.props.getString(BranchIcon, "\uE0A0") branchIcon := g.props.GetString(BranchIcon, "\uE0A0")
if g.Ref == DETACHED { if g.Ref == DETACHED {
g.setPrettyHEADName() g.setPrettyHEADName()
} else { } else {
@ -338,7 +338,7 @@ func (g *git) setGitHEADContext() {
onto = g.formatHEAD(onto) onto = g.formatHEAD(onto)
step := g.FileContents(g.gitWorkingFolder, "rebase-merge/msgnum") step := g.FileContents(g.gitWorkingFolder, "rebase-merge/msgnum")
total := g.FileContents(g.gitWorkingFolder, "rebase-merge/end") total := g.FileContents(g.gitWorkingFolder, "rebase-merge/end")
icon := g.props.getString(RebaseIcon, "\uE728 ") icon := g.props.GetString(RebaseIcon, "\uE728 ")
g.HEAD = fmt.Sprintf("%s%s onto %s%s (%s/%s) at %s", icon, origin, branchIcon, onto, step, total, g.HEAD) g.HEAD = fmt.Sprintf("%s%s onto %s%s (%s/%s) at %s", icon, origin, branchIcon, onto, step, total, g.HEAD)
return return
} }
@ -346,14 +346,14 @@ func (g *git) setGitHEADContext() {
origin := getPrettyNameOrigin("rebase-apply/head-name") origin := getPrettyNameOrigin("rebase-apply/head-name")
step := g.FileContents(g.gitWorkingFolder, "rebase-apply/next") step := g.FileContents(g.gitWorkingFolder, "rebase-apply/next")
total := g.FileContents(g.gitWorkingFolder, "rebase-apply/last") total := g.FileContents(g.gitWorkingFolder, "rebase-apply/last")
icon := g.props.getString(RebaseIcon, "\uE728 ") icon := g.props.GetString(RebaseIcon, "\uE728 ")
g.HEAD = fmt.Sprintf("%s%s (%s/%s) at %s", icon, origin, step, total, g.HEAD) g.HEAD = fmt.Sprintf("%s%s (%s/%s) at %s", icon, origin, step, total, g.HEAD)
return return
} }
// merge // merge
commitIcon := g.props.getString(CommitIcon, "\uF417") commitIcon := g.props.GetString(CommitIcon, "\uF417")
if g.hasGitFile("MERGE_MSG") { if g.hasGitFile("MERGE_MSG") {
icon := g.props.getString(MergeIcon, "\uE727 ") icon := g.props.GetString(MergeIcon, "\uE727 ")
mergeContext := g.FileContents(g.gitWorkingFolder, "MERGE_MSG") mergeContext := g.FileContents(g.gitWorkingFolder, "MERGE_MSG")
matches := regex.FindNamedRegexMatch(`Merge (remote-tracking )?(?P<type>branch|commit|tag) '(?P<theirs>.*)'`, mergeContext) matches := regex.FindNamedRegexMatch(`Merge (remote-tracking )?(?P<type>branch|commit|tag) '(?P<theirs>.*)'`, mergeContext)
// head := g.getGitRefFileSymbolicName("ORIG_HEAD") // head := g.getGitRefFileSymbolicName("ORIG_HEAD")
@ -361,7 +361,7 @@ func (g *git) setGitHEADContext() {
var headIcon, theirs string var headIcon, theirs string
switch matches["type"] { switch matches["type"] {
case "tag": case "tag":
headIcon = g.props.getString(TagIcon, "\uF412") headIcon = g.props.GetString(TagIcon, "\uF412")
theirs = matches["theirs"] theirs = matches["theirs"]
case "commit": case "commit":
headIcon = commitIcon headIcon = commitIcon
@ -381,13 +381,13 @@ func (g *git) setGitHEADContext() {
// the todo file. // the todo file.
if g.hasGitFile("CHERRY_PICK_HEAD") { if g.hasGitFile("CHERRY_PICK_HEAD") {
sha := g.FileContents(g.gitWorkingFolder, "CHERRY_PICK_HEAD") sha := g.FileContents(g.gitWorkingFolder, "CHERRY_PICK_HEAD")
cherry := g.props.getString(CherryPickIcon, "\uE29B ") cherry := g.props.GetString(CherryPickIcon, "\uE29B ")
g.HEAD = fmt.Sprintf("%s%s%s onto %s", cherry, commitIcon, g.formatSHA(sha), formatDetached()) g.HEAD = fmt.Sprintf("%s%s%s onto %s", cherry, commitIcon, g.formatSHA(sha), formatDetached())
return return
} }
if g.hasGitFile("REVERT_HEAD") { if g.hasGitFile("REVERT_HEAD") {
sha := g.FileContents(g.gitWorkingFolder, "REVERT_HEAD") sha := g.FileContents(g.gitWorkingFolder, "REVERT_HEAD")
revert := g.props.getString(RevertIcon, "\uF0E2 ") revert := g.props.GetString(RevertIcon, "\uF0E2 ")
g.HEAD = fmt.Sprintf("%s%s%s onto %s", revert, commitIcon, g.formatSHA(sha), formatDetached()) g.HEAD = fmt.Sprintf("%s%s%s onto %s", revert, commitIcon, g.formatSHA(sha), formatDetached())
return return
} }
@ -399,11 +399,11 @@ func (g *git) setGitHEADContext() {
sha := matches["sha"] sha := matches["sha"]
switch action { switch action {
case "p", "pick": case "p", "pick":
cherry := g.props.getString(CherryPickIcon, "\uE29B ") cherry := g.props.GetString(CherryPickIcon, "\uE29B ")
g.HEAD = fmt.Sprintf("%s%s%s onto %s", cherry, commitIcon, g.formatSHA(sha), formatDetached()) g.HEAD = fmt.Sprintf("%s%s%s onto %s", cherry, commitIcon, g.formatSHA(sha), formatDetached())
return return
case "revert": case "revert":
revert := g.props.getString(RevertIcon, "\uF0E2 ") revert := g.props.GetString(RevertIcon, "\uF0E2 ")
g.HEAD = fmt.Sprintf("%s%s%s onto %s", revert, commitIcon, g.formatSHA(sha), formatDetached()) g.HEAD = fmt.Sprintf("%s%s%s onto %s", revert, commitIcon, g.formatSHA(sha), formatDetached())
return return
} }
@ -413,11 +413,11 @@ func (g *git) setGitHEADContext() {
} }
func (g *git) formatHEAD(head string) string { func (g *git) formatHEAD(head string) string {
maxLength := g.props.getInt(BranchMaxLength, 0) maxLength := g.props.GetInt(BranchMaxLength, 0)
if maxLength == 0 || len(head) < maxLength { if maxLength == 0 || len(head) < maxLength {
return head return head
} }
symbol := g.props.getString(TruncateSymbol, "") symbol := g.props.GetString(TruncateSymbol, "")
return head[0:maxLength] + symbol return head[0:maxLength] + symbol
} }
@ -443,7 +443,7 @@ func (g *git) setPrettyHEADName() {
HEADRef := g.FileContents(g.gitWorkingFolder, "HEAD") HEADRef := g.FileContents(g.gitWorkingFolder, "HEAD")
if strings.HasPrefix(HEADRef, BRANCHPREFIX) { if strings.HasPrefix(HEADRef, BRANCHPREFIX) {
branchName := strings.TrimPrefix(HEADRef, BRANCHPREFIX) branchName := strings.TrimPrefix(HEADRef, BRANCHPREFIX)
g.HEAD = fmt.Sprintf("%s%s", g.props.getString(BranchIcon, "\uE0A0"), g.formatHEAD(branchName)) g.HEAD = fmt.Sprintf("%s%s", g.props.GetString(BranchIcon, "\uE0A0"), g.formatHEAD(branchName))
return return
} }
// no branch, points to commit // no branch, points to commit
@ -454,15 +454,15 @@ func (g *git) setPrettyHEADName() {
// check for tag // check for tag
tagName := g.getGitCommandOutput("describe", "--tags", "--exact-match") tagName := g.getGitCommandOutput("describe", "--tags", "--exact-match")
if len(tagName) > 0 { if len(tagName) > 0 {
g.HEAD = fmt.Sprintf("%s%s", g.props.getString(TagIcon, "\uF412"), tagName) g.HEAD = fmt.Sprintf("%s%s", g.props.GetString(TagIcon, "\uF412"), tagName)
return return
} }
// fallback to commit // fallback to commit
if len(g.Hash) == 0 { if len(g.Hash) == 0 {
g.HEAD = g.props.getString(NoCommitsIcon, "\uF594 ") g.HEAD = g.props.GetString(NoCommitsIcon, "\uF594 ")
return return
} }
g.HEAD = fmt.Sprintf("%s%s", g.props.getString(CommitIcon, "\uF417"), g.Hash) g.HEAD = fmt.Sprintf("%s%s", g.props.GetString(CommitIcon, "\uF417"), g.Hash)
} }
func (g *git) getStashContext() int { func (g *git) getStashContext() int {

View file

@ -39,7 +39,7 @@ func (g *golang) init(props Properties, env environment.Environment) {
} }
func (g *golang) getVersion() (string, error) { func (g *golang) getVersion() (string, error) {
if !g.props.getBool(ParseModFile, false) { if !g.props.GetBool(ParseModFile, false) {
return "", nil return "", nil
} }
gomod, err := g.language.env.HasParentFilePath("go.mod") gomod, err := g.language.env.HasParentFilePath("go.mod")

View file

@ -27,9 +27,9 @@ func (i *ipify) enabled() bool {
} }
func (i *ipify) getResult() (string, error) { func (i *ipify) getResult() (string, error) {
cacheTimeout := i.props.getInt(CacheTimeout, DefaultCacheTimeout) cacheTimeout := i.props.GetInt(CacheTimeout, DefaultCacheTimeout)
url := i.props.getString(IpifyURL, "https://api.ipify.org") url := i.props.GetString(IpifyURL, "https://api.ipify.org")
if cacheTimeout > 0 { if cacheTimeout > 0 {
// check if data stored in cache // check if data stored in cache
@ -40,7 +40,7 @@ func (i *ipify) getResult() (string, error) {
} }
} }
httpTimeout := i.props.getInt(HTTPTimeout, DefaultHTTPTimeout) httpTimeout := i.props.GetInt(HTTPTimeout, DefaultHTTPTimeout)
body, err := i.env.HTTPRequest(url, httpTimeout) body, err := i.env.HTTPRequest(url, httpTimeout)
if err != nil { if err != nil {

View file

@ -43,7 +43,7 @@ func (k *kubectl) init(props Properties, env environment.Environment) {
} }
func (k *kubectl) enabled() bool { func (k *kubectl) enabled() bool {
parseKubeConfig := k.props.getBool(ParseKubeConfig, false) parseKubeConfig := k.props.GetBool(ParseKubeConfig, false)
if parseKubeConfig { if parseKubeConfig {
return k.doParseKubeConfig() return k.doParseKubeConfig()
} }
@ -92,7 +92,7 @@ func (k *kubectl) doParseKubeConfig() bool {
return true return true
} }
displayError := k.props.getBool(DisplayError, false) displayError := k.props.GetBool(DisplayError, false)
if !displayError { if !displayError {
return false return false
} }
@ -106,7 +106,7 @@ func (k *kubectl) doCallKubectl() bool {
return false return false
} }
result, err := k.env.RunCommand(cmd, "config", "view", "--output", "yaml", "--minify") result, err := k.env.RunCommand(cmd, "config", "view", "--output", "yaml", "--minify")
displayError := k.props.getBool(DisplayError, false) displayError := k.props.GetBool(DisplayError, false)
if err != nil && displayError { if err != nil && displayError {
k.setError("KUBECTL ERR") k.setError("KUBECTL ERR")
return true return true

View file

@ -91,18 +91,18 @@ const (
func (l *language) enabled() bool { func (l *language) enabled() bool {
// override default extensions if needed // override default extensions if needed
l.extensions = l.props.getStringArray(LanguageExtensions, l.extensions) l.extensions = l.props.GetStringArray(LanguageExtensions, l.extensions)
inHomeDir := func() bool { inHomeDir := func() bool {
return l.env.Pwd() == l.env.Home() return l.env.Pwd() == l.env.Home()
} }
var enabled bool var enabled bool
homeEnabled := l.props.getBool(HomeEnabled, l.homeEnabled) homeEnabled := l.props.GetBool(HomeEnabled, l.homeEnabled)
if inHomeDir() && !homeEnabled { if inHomeDir() && !homeEnabled {
enabled = false enabled = false
} else { } else {
// set default mode when not set // set default mode when not set
if len(l.displayMode) == 0 { if len(l.displayMode) == 0 {
l.displayMode = l.props.getString(DisplayMode, DisplayModeFiles) l.displayMode = l.props.GetString(DisplayMode, DisplayModeFiles)
} }
l.loadLanguageContext() l.loadLanguageContext()
switch l.displayMode { switch l.displayMode {
@ -118,7 +118,7 @@ func (l *language) enabled() bool {
enabled = l.hasLanguageFiles() || l.inLanguageContext() enabled = l.hasLanguageFiles() || l.inLanguageContext()
} }
} }
if !enabled || !l.props.getBool(FetchVersion, true) { if !enabled || !l.props.GetBool(FetchVersion, true) {
return enabled return enabled
} }
err := l.setVersion() err := l.setVersion()
@ -173,7 +173,7 @@ func (l *language) setVersion() error {
l.buildVersionURL() l.buildVersionURL()
return nil return nil
} }
return errors.New(l.props.getString(MissingCommandText, "")) return errors.New(l.props.GetString(MissingCommandText, ""))
} }
func (l *language) loadLanguageContext() { func (l *language) loadLanguageContext() {
@ -191,7 +191,7 @@ func (l *language) inLanguageContext() bool {
} }
func (l *language) buildVersionURL() { func (l *language) buildVersionURL() {
versionURLTemplate := l.props.getString(VersionURLTemplate, l.versionURLTemplate) versionURLTemplate := l.props.GetString(VersionURLTemplate, l.versionURLTemplate)
if len(versionURLTemplate) == 0 { if len(versionURLTemplate) == 0 {
return return
} }

View file

@ -64,19 +64,19 @@ func (ns *nightscout) enabled() bool {
func (ns *nightscout) getTrendIcon() string { func (ns *nightscout) getTrendIcon() string {
switch ns.Direction { switch ns.Direction {
case "DoubleUp": case "DoubleUp":
return ns.props.getString(DoubleUpIcon, "↑↑") return ns.props.GetString(DoubleUpIcon, "↑↑")
case "SingleUp": case "SingleUp":
return ns.props.getString(SingleUpIcon, "↑") return ns.props.GetString(SingleUpIcon, "↑")
case "FortyFiveUp": case "FortyFiveUp":
return ns.props.getString(FortyFiveUpIcon, "↗") return ns.props.GetString(FortyFiveUpIcon, "↗")
case "Flat": case "Flat":
return ns.props.getString(FlatIcon, "→") return ns.props.GetString(FlatIcon, "→")
case "FortyFiveDown": case "FortyFiveDown":
return ns.props.getString(FortyFiveDownIcon, "↘") return ns.props.GetString(FortyFiveDownIcon, "↘")
case "SingleDown": case "SingleDown":
return ns.props.getString(SingleDownIcon, "↓") return ns.props.GetString(SingleDownIcon, "↓")
case "DoubleDown": case "DoubleDown":
return ns.props.getString(DoubleDownIcon, "↓↓") return ns.props.GetString(DoubleDownIcon, "↓↓")
default: default:
return "" return ""
} }
@ -105,10 +105,10 @@ func (ns *nightscout) getResult() (*NightscoutData, error) {
return nil, errors.New("no data in cache") return nil, errors.New("no data in cache")
} }
url := ns.props.getString(URL, "") url := ns.props.GetString(URL, "")
httpTimeout := ns.props.getInt(HTTPTimeout, DefaultHTTPTimeout) httpTimeout := ns.props.GetInt(HTTPTimeout, DefaultHTTPTimeout)
// natural and understood NS timeout is 5, anything else is unusual // natural and understood NS timeout is 5, anything else is unusual
cacheTimeout := ns.props.getInt(NSCacheTimeout, 5) cacheTimeout := ns.props.GetInt(NSCacheTimeout, 5)
if cacheTimeout > 0 { if cacheTimeout > 0 {
if data, err := getCacheValue(url); err == nil { if data, err := getCacheValue(url); err == nil {

View file

@ -48,15 +48,15 @@ func (n *node) enabled() bool {
} }
func (n *node) loadContext() { func (n *node) loadContext() {
if !n.language.props.getBool(FetchPackageManager, false) { if !n.language.props.GetBool(FetchPackageManager, false) {
return return
} }
if n.language.env.HasFiles("yarn.lock") { if n.language.env.HasFiles("yarn.lock") {
n.PackageManagerIcon = n.language.props.getString(YarnIcon, " \uF61A") n.PackageManagerIcon = n.language.props.GetString(YarnIcon, " \uF61A")
return return
} }
if n.language.env.HasFiles("package-lock.json") || n.language.env.HasFiles("package.json") { if n.language.env.HasFiles("package-lock.json") || n.language.env.HasFiles("package.json") {
n.PackageManagerIcon = n.language.props.getString(NPMIcon, " \uE71E") n.PackageManagerIcon = n.language.props.GetString(NPMIcon, " \uE71E")
} }
} }

View file

@ -66,12 +66,12 @@ func (oi *osInfo) enabled() bool {
goos := oi.env.GOOS() goos := oi.env.GOOS()
switch goos { switch goos {
case environment.WindowsPlatform: case environment.WindowsPlatform:
oi.Icon = oi.props.getString(Windows, "\uE62A") oi.Icon = oi.props.GetString(Windows, "\uE62A")
case environment.DarwinPlatform: case environment.DarwinPlatform:
oi.Icon = oi.props.getString(MacOS, "\uF179") oi.Icon = oi.props.GetString(MacOS, "\uF179")
case environment.LinuxPlatform: case environment.LinuxPlatform:
platform := oi.env.Platform() platform := oi.env.Platform()
displayDistroName := oi.props.getBool(DisplayDistroName, false) displayDistroName := oi.props.GetBool(DisplayDistroName, false)
if displayDistroName { if displayDistroName {
oi.Icon = platform oi.Icon = platform
break break
@ -86,45 +86,45 @@ func (oi *osInfo) enabled() bool {
func (oi *osInfo) getDistroIcon(distro string) string { func (oi *osInfo) getDistroIcon(distro string) string {
switch distro { switch distro {
case "alpine": case "alpine":
return oi.props.getString(Alpine, "\uF300") return oi.props.GetString(Alpine, "\uF300")
case "aosc": case "aosc":
return oi.props.getString(Aosc, "\uF301") return oi.props.GetString(Aosc, "\uF301")
case "arch": case "arch":
return oi.props.getString(Arch, "\uF303") return oi.props.GetString(Arch, "\uF303")
case "centos": case "centos":
return oi.props.getString(Centos, "\uF304") return oi.props.GetString(Centos, "\uF304")
case "coreos": case "coreos":
return oi.props.getString(Coreos, "\uF305") return oi.props.GetString(Coreos, "\uF305")
case "debian": case "debian":
return oi.props.getString(Debian, "\uF306") return oi.props.GetString(Debian, "\uF306")
case "devuan": case "devuan":
return oi.props.getString(Devuan, "\uF307") return oi.props.GetString(Devuan, "\uF307")
case "raspbian": case "raspbian":
return oi.props.getString(Raspbian, "\uF315") return oi.props.GetString(Raspbian, "\uF315")
case "elementary": case "elementary":
return oi.props.getString(Elementary, "\uF309") return oi.props.GetString(Elementary, "\uF309")
case "fedora": case "fedora":
return oi.props.getString(Fedora, "\uF30a") return oi.props.GetString(Fedora, "\uF30a")
case "gentoo": case "gentoo":
return oi.props.getString(Gentoo, "\uF30d") return oi.props.GetString(Gentoo, "\uF30d")
case "mageia": case "mageia":
return oi.props.getString(Mageia, "\uF310") return oi.props.GetString(Mageia, "\uF310")
case "manjaro": case "manjaro":
return oi.props.getString(Manjaro, "\uF312") return oi.props.GetString(Manjaro, "\uF312")
case "mint": case "mint":
return oi.props.getString(Mint, "\uF30e") return oi.props.GetString(Mint, "\uF30e")
case "nixos": case "nixos":
return oi.props.getString(Nixos, "\uF313") return oi.props.GetString(Nixos, "\uF313")
case "opensuse": case "opensuse":
return oi.props.getString(Opensuse, "\uF314") return oi.props.GetString(Opensuse, "\uF314")
case "sabayon": case "sabayon":
return oi.props.getString(Sabayon, "\uF317") return oi.props.GetString(Sabayon, "\uF317")
case "slackware": case "slackware":
return oi.props.getString(Slackware, "\uF319") return oi.props.GetString(Slackware, "\uF319")
case "ubuntu": case "ubuntu":
return oi.props.getString(Ubuntu, "\uF31b") return oi.props.GetString(Ubuntu, "\uF31b")
} }
return oi.props.getString(Linux, "\uF17C") return oi.props.GetString(Linux, "\uF17C")
} }
func (oi *osInfo) init(props Properties, env environment.Environment) { func (oi *osInfo) init(props Properties, env environment.Environment) {

View file

@ -57,7 +57,7 @@ func (d *owm) template() string {
} }
func (d *owm) getResult() (*owmDataResponse, error) { func (d *owm) getResult() (*owmDataResponse, error) {
cacheTimeout := d.props.getInt(CacheTimeout, DefaultCacheTimeout) cacheTimeout := d.props.GetInt(CacheTimeout, DefaultCacheTimeout)
response := new(owmDataResponse) response := new(owmDataResponse)
if cacheTimeout > 0 { if cacheTimeout > 0 {
// check if data stored in cache // check if data stored in cache
@ -73,10 +73,10 @@ func (d *owm) getResult() (*owmDataResponse, error) {
} }
} }
apikey := d.props.getString(APIKey, ".") apikey := d.props.GetString(APIKey, ".")
location := d.props.getString(Location, "De Bilt,NL") location := d.props.GetString(Location, "De Bilt,NL")
units := d.props.getString(Units, "standard") units := d.props.GetString(Units, "standard")
httpTimeout := d.props.getInt(HTTPTimeout, DefaultHTTPTimeout) httpTimeout := d.props.GetInt(HTTPTimeout, DefaultHTTPTimeout)
d.URL = fmt.Sprintf("http://api.openweathermap.org/data/2.5/weather?q=%s&units=%s&appid=%s", location, units, apikey) d.URL = fmt.Sprintf("http://api.openweathermap.org/data/2.5/weather?q=%s&units=%s&appid=%s", location, units, apikey)
body, err := d.env.HTTPRequest(d.URL, httpTimeout) body, err := d.env.HTTPRequest(d.URL, httpTimeout)
@ -97,7 +97,7 @@ func (d *owm) getResult() (*owmDataResponse, error) {
} }
func (d *owm) setStatus() error { func (d *owm) setStatus() error {
units := d.props.getString(Units, "standard") units := d.props.GetString(Units, "standard")
q, err := d.getResult() q, err := d.getResult()
if err != nil { if err != nil {
return err return err

View file

@ -61,7 +61,7 @@ func (pt *path) template() string {
func (pt *path) enabled() bool { func (pt *path) enabled() bool {
pt.pwd = pt.env.Pwd() pt.pwd = pt.env.Pwd()
switch style := pt.props.getString(Style, Agnoster); style { switch style := pt.props.GetString(Style, Agnoster); style {
case Agnoster: case Agnoster:
pt.Path = pt.getAgnosterPath() pt.Path = pt.getAgnosterPath()
case AgnosterFull: case AgnosterFull:
@ -111,7 +111,7 @@ func (pt *path) getMixedPath() string {
var buffer strings.Builder var buffer strings.Builder
pwd := pt.getPwd() pwd := pt.getPwd()
splitted := strings.Split(pwd, pt.env.PathSeperator()) splitted := strings.Split(pwd, pt.env.PathSeperator())
threshold := int(pt.props.getFloat64(MixedThreshold, 4)) threshold := int(pt.props.GetFloat64(MixedThreshold, 4))
for i, part := range splitted { for i, part := range splitted {
if part == "" { if part == "" {
continue continue
@ -119,9 +119,9 @@ func (pt *path) getMixedPath() string {
folder := part folder := part
if len(part) > threshold && i != 0 && i != len(splitted)-1 { if len(part) > threshold && i != 0 && i != len(splitted)-1 {
folder = pt.props.getString(FolderIcon, "..") folder = pt.props.GetString(FolderIcon, "..")
} }
separator := pt.props.getString(FolderSeparatorIcon, pt.env.PathSeperator()) separator := pt.props.GetString(FolderSeparatorIcon, pt.env.PathSeperator())
if i == 0 { if i == 0 {
separator = "" separator = ""
} }
@ -136,8 +136,8 @@ func (pt *path) getAgnosterPath() string {
pwd := pt.getPwd() pwd := pt.getPwd()
buffer.WriteString(pt.rootLocation()) buffer.WriteString(pt.rootLocation())
pathDepth := pt.pathDepth(pwd) pathDepth := pt.pathDepth(pwd)
folderIcon := pt.props.getString(FolderIcon, "..") folderIcon := pt.props.GetString(FolderIcon, "..")
separator := pt.props.getString(FolderSeparatorIcon, pt.env.PathSeperator()) separator := pt.props.GetString(FolderSeparatorIcon, pt.env.PathSeperator())
for i := 1; i < pathDepth; i++ { for i := 1; i < pathDepth; i++ {
buffer.WriteString(fmt.Sprintf("%s%s", separator, folderIcon)) buffer.WriteString(fmt.Sprintf("%s%s", separator, folderIcon))
} }
@ -152,8 +152,8 @@ func (pt *path) getAgnosterLeftPath() string {
separator := pt.env.PathSeperator() separator := pt.env.PathSeperator()
pwd = strings.Trim(pwd, separator) pwd = strings.Trim(pwd, separator)
splitted := strings.Split(pwd, separator) splitted := strings.Split(pwd, separator)
folderIcon := pt.props.getString(FolderIcon, "..") folderIcon := pt.props.GetString(FolderIcon, "..")
separator = pt.props.getString(FolderSeparatorIcon, separator) separator = pt.props.GetString(FolderSeparatorIcon, separator)
switch len(splitted) { switch len(splitted) {
case 0: case 0:
return "" return ""
@ -174,7 +174,7 @@ func (pt *path) getLetterPath() string {
var buffer strings.Builder var buffer strings.Builder
pwd := pt.getPwd() pwd := pt.getPwd()
splitted := strings.Split(pwd, pt.env.PathSeperator()) splitted := strings.Split(pwd, pt.env.PathSeperator())
separator := pt.props.getString(FolderSeparatorIcon, pt.env.PathSeperator()) separator := pt.props.GetString(FolderSeparatorIcon, pt.env.PathSeperator())
for i := 0; i < len(splitted)-1; i++ { for i := 0; i < len(splitted)-1; i++ {
folder := splitted[i] folder := splitted[i]
if len(folder) == 0 { if len(folder) == 0 {
@ -213,7 +213,7 @@ func (pt *path) getAgnosterFullPath() string {
func (pt *path) getAgnosterShortPath() string { func (pt *path) getAgnosterShortPath() string {
pwd := pt.getPwd() pwd := pt.getPwd()
pathDepth := pt.pathDepth(pwd) pathDepth := pt.pathDepth(pwd)
maxDepth := pt.props.getInt(MaxDepth, 1) maxDepth := pt.props.GetInt(MaxDepth, 1)
if maxDepth < 1 { if maxDepth < 1 {
maxDepth = 1 maxDepth = 1
} }
@ -221,8 +221,8 @@ func (pt *path) getAgnosterShortPath() string {
return pt.getAgnosterFullPath() return pt.getAgnosterFullPath()
} }
pathSeparator := pt.env.PathSeperator() pathSeparator := pt.env.PathSeperator()
folderSeparator := pt.props.getString(FolderSeparatorIcon, pathSeparator) folderSeparator := pt.props.GetString(FolderSeparatorIcon, pathSeparator)
folderIcon := pt.props.getString(FolderIcon, "..") folderIcon := pt.props.GetString(FolderIcon, "..")
root := pt.rootLocation() root := pt.rootLocation()
splitted := strings.Split(pwd, pathSeparator) splitted := strings.Split(pwd, pathSeparator)
fullPathDepth := len(splitted) fullPathDepth := len(splitted)
@ -274,15 +274,15 @@ func (pt *path) replaceMappedLocations(pwd string) string {
} }
mappedLocations := map[string]string{} mappedLocations := map[string]string{}
if pt.props.getBool(MappedLocationsEnabled, true) { if pt.props.GetBool(MappedLocationsEnabled, true) {
mappedLocations["HKCU:"] = pt.props.getString(WindowsRegistryIcon, "\uF013") mappedLocations["HKCU:"] = pt.props.GetString(WindowsRegistryIcon, "\uF013")
mappedLocations["HKLM:"] = pt.props.getString(WindowsRegistryIcon, "\uF013") mappedLocations["HKLM:"] = pt.props.GetString(WindowsRegistryIcon, "\uF013")
mappedLocations[pt.normalize(pt.env.Home())] = pt.props.getString(HomeIcon, "~") mappedLocations[pt.normalize(pt.env.Home())] = pt.props.GetString(HomeIcon, "~")
} }
// merge custom locations with mapped locations // merge custom locations with mapped locations
// mapped locations can override predefined locations // mapped locations can override predefined locations
keyValues := pt.props.getKeyValueMap(MappedLocations, make(map[string]string)) keyValues := pt.props.GetKeyValueMap(MappedLocations, make(map[string]string))
for key, val := range keyValues { for key, val := range keyValues {
mappedLocations[pt.normalize(key)] = val mappedLocations[pt.normalize(key)] = val
} }
@ -313,7 +313,7 @@ func (pt *path) replaceFolderSeparators(pwd string) string {
if pwd == defaultSeparator { if pwd == defaultSeparator {
return pwd return pwd
} }
folderSeparator := pt.props.getString(FolderSeparatorIcon, defaultSeparator) folderSeparator := pt.props.GetString(FolderSeparatorIcon, defaultSeparator)
if folderSeparator == defaultSeparator { if folderSeparator == defaultSeparator {
return pwd return pwd
} }

View file

@ -649,7 +649,7 @@ func TestParseMappedLocations(t *testing.T) {
var segment Segment var segment Segment
err = config.BindStruct("", &segment) err = config.BindStruct("", &segment)
assert.NoError(t, err) assert.NoError(t, err)
mappedLocations := segment.Properties.getKeyValueMap(MappedLocations, make(map[string]string)) mappedLocations := segment.Properties.GetKeyValueMap(MappedLocations, make(map[string]string))
assert.Equal(t, "two", mappedLocations["folder2"]) assert.Equal(t, "two", mappedLocations["folder2"])
} }
} }

View file

@ -60,7 +60,7 @@ func (p *plastic) enabled() bool {
return false return false
} }
p.plasticWorkspaceFolder = wkdir.ParentFolder p.plasticWorkspaceFolder = wkdir.ParentFolder
displayStatus := p.props.getBool(FetchStatus, false) displayStatus := p.props.GetBool(FetchStatus, false)
p.setSelector() p.setSelector()
if displayStatus { if displayStatus {
p.setPlasticStatus() p.setPlasticStatus()
@ -135,13 +135,13 @@ func (p *plastic) setSelector() {
// changeset // changeset
ref = p.parseChangesetSelector(selector) ref = p.parseChangesetSelector(selector)
if len(ref) > 0 { if len(ref) > 0 {
p.Selector = fmt.Sprintf("%s%s", p.props.getString(CommitIcon, "\uF417"), ref) p.Selector = fmt.Sprintf("%s%s", p.props.GetString(CommitIcon, "\uF417"), ref)
return return
} }
// fallback to label // fallback to label
ref = p.parseLabelSelector(selector) ref = p.parseLabelSelector(selector)
if len(ref) > 0 { if len(ref) > 0 {
p.Selector = fmt.Sprintf("%s%s", p.props.getString(TagIcon, "\uF412"), ref) p.Selector = fmt.Sprintf("%s%s", p.props.GetString(TagIcon, "\uF412"), ref)
return return
} }
// fallback to branch/smartbranch // fallback to branch/smartbranch
@ -149,7 +149,7 @@ func (p *plastic) setSelector() {
if len(ref) > 0 { if len(ref) > 0 {
ref = p.truncateBranch(ref) ref = p.truncateBranch(ref)
} }
p.Selector = fmt.Sprintf("%s%s", p.props.getString(BranchIcon, "\uE0A0"), ref) p.Selector = fmt.Sprintf("%s%s", p.props.GetString(BranchIcon, "\uE0A0"), ref)
} }
func (p *plastic) parseChangesetSelector(selector string) string { func (p *plastic) parseChangesetSelector(selector string) string {

View file

@ -37,8 +37,8 @@ func (p *python) init(props Properties, env environment.Environment) {
}, },
}, },
versionURLTemplate: "[%s](https://www.python.org/downloads/release/python-%s%s%s/)", versionURLTemplate: "[%s](https://www.python.org/downloads/release/python-%s%s%s/)",
displayMode: props.getString(DisplayMode, DisplayModeEnvironment), displayMode: props.GetString(DisplayMode, DisplayModeEnvironment),
homeEnabled: props.getBool(HomeEnabled, true), homeEnabled: props.GetBool(HomeEnabled, true),
} }
} }
@ -47,7 +47,7 @@ func (p *python) enabled() bool {
} }
func (p *python) loadContext() { func (p *python) loadContext() {
if !p.language.props.getBool(FetchVirtualEnv, true) { if !p.language.props.GetBool(FetchVirtualEnv, true) {
return return
} }
venvVars := []string{ venvVars := []string{
@ -75,7 +75,7 @@ func (p *python) canUseVenvName(name string) bool {
if name == "" || name == "." { if name == "" || name == "." {
return false return false
} }
if p.language.props.getBool(DisplayDefault, true) { if p.language.props.GetBool(DisplayDefault, true) {
return true return true
} }
invalidNames := [2]string{"system", "base"} invalidNames := [2]string{"system", "base"}

View file

@ -22,7 +22,7 @@ func (s *shell) template() string {
} }
func (s *shell) enabled() bool { func (s *shell) enabled() bool {
mappedNames := s.props.getKeyValueMap(MappedShellNames, make(map[string]string)) mappedNames := s.props.GetKeyValueMap(MappedShellNames, make(map[string]string))
s.Name = s.env.Shell() s.Name = s.env.Shell()
for key, val := range mappedNames { for key, val := range mappedNames {
if strings.EqualFold(s.Name, key) { if strings.EqualFold(s.Name, key) {

View file

@ -37,11 +37,11 @@ func (s *spotify) resolveIcon() {
switch s.Status { switch s.Status {
case stopped: case stopped:
// in this case, no artist or track info // in this case, no artist or track info
s.Icon = s.props.getString(StoppedIcon, "\uF04D ") s.Icon = s.props.GetString(StoppedIcon, "\uF04D ")
case paused: case paused:
s.Icon = s.props.getString(PausedIcon, "\uF8E3 ") s.Icon = s.props.GetString(PausedIcon, "\uF8E3 ")
case playing: case playing:
s.Icon = s.props.getString(PlayingIcon, "\uE602 ") s.Icon = s.props.GetString(PlayingIcon, "\uE602 ")
} }
} }

View file

@ -108,19 +108,19 @@ func (s *strava) getActivityIcon() string {
case "VirtualRide": case "VirtualRide":
fallthrough fallthrough
case "Ride": case "Ride":
return s.props.getString(RideIcon, "\uf5a2") return s.props.GetString(RideIcon, "\uf5a2")
case "Run": case "Run":
return s.props.getString(RunIcon, "\ufc0c") return s.props.GetString(RunIcon, "\ufc0c")
case "NordicSki": case "NordicSki":
case "AlpineSki": case "AlpineSki":
case "BackcountrySki": case "BackcountrySki":
return s.props.getString(SkiingIcon, "\ue213") return s.props.GetString(SkiingIcon, "\ue213")
case "WorkOut": case "WorkOut":
return s.props.getString(WorkOutIcon, "\ue213") return s.props.GetString(WorkOutIcon, "\ue213")
default: default:
return s.props.getString(UnknownActivityIcon, "\ue213") return s.props.GetString(UnknownActivityIcon, "\ue213")
} }
return s.props.getString(UnknownActivityIcon, "\ue213") return s.props.GetString(UnknownActivityIcon, "\ue213")
} }
func (s *strava) getAccessToken() (string, error) { func (s *strava) getAccessToken() (string, error) {
@ -135,7 +135,7 @@ func (s *strava) getAccessToken() (string, error) {
} }
} }
// use initial refresh token from property // use initial refresh token from property
refreshToken := s.props.getString(RefreshToken, "") refreshToken := s.props.GetString(RefreshToken, "")
if len(refreshToken) == 0 { if len(refreshToken) == 0 {
return "", &AuthError{ return "", &AuthError{
message: InvalidRefreshToken, message: InvalidRefreshToken,
@ -147,7 +147,7 @@ func (s *strava) getAccessToken() (string, error) {
} }
func (s *strava) refreshToken(refreshToken string) (string, error) { func (s *strava) refreshToken(refreshToken string) (string, error) {
httpTimeout := s.props.getInt(HTTPTimeout, DefaultHTTPTimeout) httpTimeout := s.props.GetInt(HTTPTimeout, DefaultHTTPTimeout)
url := fmt.Sprintf("https://ohmyposh.dev/api/refresh?segment=strava&token=%s", refreshToken) url := fmt.Sprintf("https://ohmyposh.dev/api/refresh?segment=strava&token=%s", refreshToken)
body, err := s.env.HTTPRequest(url, httpTimeout) body, err := s.env.HTTPRequest(url, httpTimeout)
if err != nil { if err != nil {
@ -194,10 +194,10 @@ func (s *strava) getResult() (*StravaData, error) {
// We only want the last activity // We only want the last activity
url := "https://www.strava.com/api/v3/athlete/activities?page=1&per_page=1" url := "https://www.strava.com/api/v3/athlete/activities?page=1&per_page=1"
httpTimeout := s.props.getInt(HTTPTimeout, DefaultHTTPTimeout) httpTimeout := s.props.GetInt(HTTPTimeout, DefaultHTTPTimeout)
// No need to check more the every 30 min // No need to check more the every 30 min
cacheTimeout := s.props.getInt(CacheTimeout, 30) cacheTimeout := s.props.GetInt(CacheTimeout, 30)
if cacheTimeout > 0 { if cacheTimeout > 0 {
if data, err := getCacheValue(url); err == nil { if data, err := getCacheValue(url); err == nil {
return data, nil return data, nil

View file

@ -47,7 +47,7 @@ func (s *sysinfo) enabled() bool {
func (s *sysinfo) init(props Properties, env environment.Environment) { func (s *sysinfo) init(props Properties, env environment.Environment) {
s.props = props s.props = props
s.env = env s.env = env
s.Precision = s.props.getInt(Precision, 2) s.Precision = s.props.GetInt(Precision, 2)
// mem // mem
memStat, err := mem.VirtualMemory() memStat, err := mem.VirtualMemory()
if err == nil { if err == nil {

View file

@ -18,7 +18,7 @@ const (
) )
func (t *tempus) template() string { func (t *tempus) template() string {
return "{{ .CurrentDate | date \"" + t.props.getString(TimeFormat, "15:04:05") + "\" }}" return "{{ .CurrentDate | date \"" + t.props.GetString(TimeFormat, "15:04:05") + "\" }}"
} }
func (t *tempus) enabled() bool { func (t *tempus) enabled() bool {

View file

@ -33,8 +33,8 @@ func (w *wakatime) enabled() bool {
} }
func (w *wakatime) setAPIData() error { func (w *wakatime) setAPIData() error {
url := w.props.getString(URL, "") url := w.props.GetString(URL, "")
cacheTimeout := w.props.getInt(CacheTimeout, DefaultCacheTimeout) cacheTimeout := w.props.GetInt(CacheTimeout, DefaultCacheTimeout)
if cacheTimeout > 0 { if cacheTimeout > 0 {
// check if data stored in cache // check if data stored in cache
if val, found := w.env.Cache().Get(url); found { if val, found := w.env.Cache().Get(url); found {
@ -46,7 +46,7 @@ func (w *wakatime) setAPIData() error {
} }
} }
httpTimeout := w.props.getInt(HTTPTimeout, DefaultHTTPTimeout) httpTimeout := w.props.GetInt(HTTPTimeout, DefaultHTTPTimeout)
body, err := w.env.HTTPRequest(url, httpTimeout) body, err := w.env.HTTPRequest(url, httpTimeout)
if err != nil { if err != nil {

View file

@ -25,7 +25,7 @@ func (w *wifi) enabled() bool {
return false return false
} }
wifiInfo, err := w.env.WifiNetwork() wifiInfo, err := w.env.WifiNetwork()
displayError := w.props.getBool(DisplayError, false) displayError := w.props.GetBool(DisplayError, false)
if err != nil && displayError { if err != nil && displayError {
w.Error = err.Error() w.Error = err.Error()
return true return true

View file

@ -34,8 +34,8 @@ func (wr *winreg) enabled() bool {
return false return false
} }
registryPath := wr.props.getString(RegistryPath, "") registryPath := wr.props.GetString(RegistryPath, "")
fallback := wr.props.getString(Fallback, "") fallback := wr.props.GetString(Fallback, "")
var regValue *environment.WindowsRegistryValue var regValue *environment.WindowsRegistryValue
regValue, _ = wr.env.WindowsRegistryKeyValue(registryPath) regValue, _ = wr.env.WindowsRegistryKeyValue(registryPath)

View file

@ -65,8 +65,8 @@ type track struct {
func (y *ytm) setStatus() error { func (y *ytm) setStatus() error {
// https://github.com/ytmdesktop/ytmdesktop/wiki/Remote-Control-API // https://github.com/ytmdesktop/ytmdesktop/wiki/Remote-Control-API
url := y.props.getString(APIURL, "http://127.0.0.1:9863") url := y.props.GetString(APIURL, "http://127.0.0.1:9863")
httpTimeout := y.props.getInt(APIURL, DefaultHTTPTimeout) httpTimeout := y.props.GetInt(APIURL, DefaultHTTPTimeout)
body, err := y.env.HTTPRequest(url+"/query", httpTimeout) body, err := y.env.HTTPRequest(url+"/query", httpTimeout)
if err != nil { if err != nil {
return err return err
@ -77,13 +77,13 @@ func (y *ytm) setStatus() error {
return err return err
} }
y.Status = playing y.Status = playing
y.Icon = y.props.getString(PlayingIcon, "\uE602 ") y.Icon = y.props.GetString(PlayingIcon, "\uE602 ")
if !q.player.HasSong { if !q.player.HasSong {
y.Status = stopped y.Status = stopped
y.Icon = y.props.getString(StoppedIcon, "\uF04D ") y.Icon = y.props.GetString(StoppedIcon, "\uF04D ")
} else if q.player.IsPaused { } else if q.player.IsPaused {
y.Status = paused y.Status = paused
y.Icon = y.props.getString(PausedIcon, "\uF8E3 ") y.Icon = y.props.GetString(PausedIcon, "\uF8E3 ")
} }
y.Artist = q.track.Author y.Artist = q.track.Author
y.Track = q.track.Title y.Track = q.track.Title