diff --git a/src/ansi/ansi_writer.go b/src/ansi/ansi_writer.go
new file mode 100644
index 00000000..04e5d7d4
--- /dev/null
+++ b/src/ansi/ansi_writer.go
@@ -0,0 +1,501 @@
+package ansi
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/jandedobbeleer/oh-my-posh/regex"
+ "github.com/jandedobbeleer/oh-my-posh/shell"
+ "github.com/mattn/go-runewidth"
+)
+
+var (
+ knownStyles = []*style{
+ {AnchorStart: ``, AnchorEnd: ``, Start: "\x1b[1m", End: "\x1b[22m"},
+ {AnchorStart: ``, AnchorEnd: ``, Start: "\x1b[4m", End: "\x1b[24m"},
+ {AnchorStart: ``, AnchorEnd: ``, Start: "\x1b[53m", End: "\x1b[55m"},
+ {AnchorStart: ``, AnchorEnd: ``, Start: "\x1b[3m", End: "\x1b[23m"},
+ {AnchorStart: ``, AnchorEnd: ``, Start: "\x1b[9m", End: "\x1b[29m"},
+ {AnchorStart: ``, AnchorEnd: ``, Start: "\x1b[2m", End: "\x1b[22m"},
+ {AnchorStart: ``, AnchorEnd: ``, Start: "\x1b[5m", End: "\x1b[25m"},
+ {AnchorStart: ``, AnchorEnd: ``, Start: "\x1b[7m", End: "\x1b[27m"},
+ }
+ colorStyle = &style{AnchorStart: "COLOR", AnchorEnd: `>`, End: "\x1b[0m"}
+)
+
+type style struct {
+ AnchorStart string
+ AnchorEnd string
+ Start string
+ End string
+}
+
+type cachedColor struct {
+ Background string
+ Foreground string
+}
+
+const (
+ // Transparent implies a transparent color
+ Transparent = "transparent"
+ // Accent is the OS accent color
+ Accent = "accent"
+ // ParentBackground takes the previous segment's background color
+ ParentBackground = "parentBackground"
+ // ParentForeground takes the previous segment's color
+ ParentForeground = "parentForeground"
+ // Background takes the current segment's background color
+ Background = "background"
+ // Foreground takes the current segment's foreground color
+ Foreground = "foreground"
+
+ anchorRegex = `^(?P<(?P[^,>]+)?,?(?P[^>]+)?>)`
+ colorise = "\x1b[%sm"
+ transparent = "\x1b[%s;49m\x1b[7m"
+
+ AnsiRegex = "[\u001B\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))"
+
+ OSC99 string = "osc99"
+ OSC7 string = "osc7"
+ OSC51 string = "osc51"
+)
+
+// Writer writes colorized ANSI strings
+type Writer struct {
+ TerminalBackground string
+ Colors *cachedColor
+ ParentColors []*cachedColor
+ AnsiColors Colors
+ Plain bool
+
+ builder strings.Builder
+ length int
+
+ foreground Color
+ background Color
+ currentForeground Color
+ currentBackground Color
+ runes []rune
+
+ shell string
+ format string
+ left string
+ right string
+ title string
+ linechange string
+ clearBelow string
+ clearLine string
+ saveCursorPosition string
+ restoreCursorPosition string
+ escapeLeft string
+ escapeRight string
+ hyperlink string
+ hyperlinkRegex string
+ osc99 string
+ osc7 string
+ osc51 string
+}
+
+func (w *Writer) Init(shellName string) {
+ w.shell = shellName
+ switch w.shell {
+ case shell.BASH:
+ w.format = "\\[%s\\]"
+ w.linechange = "\\[\x1b[%d%s\\]"
+ w.right = "\\[\x1b[%dC\\]"
+ w.left = "\\[\x1b[%dD\\]"
+ w.clearBelow = "\\[\x1b[0J\\]"
+ w.clearLine = "\\[\x1b[K\\]"
+ w.saveCursorPosition = "\\[\x1b7\\]"
+ w.restoreCursorPosition = "\\[\x1b8\\]"
+ w.title = "\\[\x1b]0;%s\007\\]"
+ w.escapeLeft = "\\["
+ w.escapeRight = "\\]"
+ w.hyperlink = "\\[\x1b]8;;%s\x1b\\\\\\]%s\\[\x1b]8;;\x1b\\\\\\]"
+ w.hyperlinkRegex = `(?P\\\[\x1b\]8;;(.+)\x1b\\\\\\\](?P.+)\\\[\x1b\]8;;\x1b\\\\\\\])`
+ w.osc99 = "\\[\x1b]9;9;\"%s\"\x1b\\\\\\]"
+ w.osc7 = "\\[\x1b]7;\"file://%s/%s\"\x1b\\\\\\]"
+ w.osc51 = "\\[\x1b]51;A;%s@%s:%s\x1b\\\\\\]"
+ case "zsh":
+ w.format = "%%{%s%%}"
+ w.linechange = "%%{\x1b[%d%s%%}"
+ w.right = "%%{\x1b[%dC%%}"
+ w.left = "%%{\x1b[%dD%%}"
+ w.clearBelow = "%{\x1b[0J%}"
+ w.clearLine = "%{\x1b[K%}"
+ w.saveCursorPosition = "%{\x1b7%}"
+ w.restoreCursorPosition = "%{\x1b8%}"
+ w.title = "%%{\x1b]0;%s\007%%}"
+ w.escapeLeft = "%{"
+ w.escapeRight = "%}"
+ w.hyperlink = "%%{\x1b]8;;%s\x1b\\%%}%s%%{\x1b]8;;\x1b\\%%}"
+ w.hyperlinkRegex = `(?P%{\x1b]8;;(.+)\x1b\\%}(?P.+)%{\x1b]8;;\x1b\\%})`
+ w.osc99 = "%%{\x1b]9;9;\"%s\"\x1b\\%%}"
+ w.osc7 = "%%{\x1b]7;file:\"//%s/%s\"\x1b\\%%}"
+ w.osc51 = "%%{\x1b]51;A%s@%s:%s\x1b\\%%}"
+ default:
+ w.linechange = "\x1b[%d%s"
+ w.right = "\x1b[%dC"
+ w.left = "\x1b[%dD"
+ w.clearBelow = "\x1b[0J"
+ w.clearLine = "\x1b[K"
+ w.saveCursorPosition = "\x1b7"
+ w.restoreCursorPosition = "\x1b8"
+ w.title = "\x1b]0;%s\007"
+ // when in fish on Linux, it seems hyperlinks ending with \\ print a \
+ // unlike on macOS. However, this is a fish bug, so do not try to fix it here:
+ // https://github.com/JanDeDobbeleer/oh-my-posh/pull/3288#issuecomment-1369137068
+ w.hyperlink = "\x1b]8;;%s\x1b\\%s\x1b]8;;\x1b\\"
+ w.hyperlinkRegex = "(?P\x1b]8;;(.+)\x1b\\\\\\\\?(?P.+)\x1b]8;;\x1b\\\\)"
+ w.osc99 = "\x1b]9;9;\"%s\"\x1b\\"
+ w.osc7 = "\x1b]7;\"file://%s/%s\"\x1b\\"
+ w.osc51 = "\x1b]51;A%s@%s:%s\x1b\\"
+ }
+}
+
+func (w *Writer) SetColors(background, foreground string) {
+ w.Colors = &cachedColor{
+ Background: background,
+ Foreground: foreground,
+ }
+}
+
+func (w *Writer) SetParentColors(background, foreground string) {
+ if w.ParentColors == nil {
+ w.ParentColors = make([]*cachedColor, 0)
+ }
+ w.ParentColors = append([]*cachedColor{{
+ Background: background,
+ Foreground: foreground,
+ }}, w.ParentColors...)
+}
+
+func (w *Writer) CarriageForward() string {
+ return fmt.Sprintf(w.right, 1000)
+}
+
+func (w *Writer) GetCursorForRightWrite(length, offset int) string {
+ strippedLen := length + (-offset)
+ return fmt.Sprintf(w.left, strippedLen)
+}
+
+func (w *Writer) ChangeLine(numberOfLines int) string {
+ if w.Plain {
+ return ""
+ }
+ position := "B"
+ if numberOfLines < 0 {
+ position = "F"
+ numberOfLines = -numberOfLines
+ }
+ return fmt.Sprintf(w.linechange, numberOfLines, position)
+}
+
+func (w *Writer) ConsolePwd(pwdType, userName, hostName, pwd string) string {
+ if w.Plain {
+ return ""
+ }
+ if strings.HasSuffix(pwd, ":") {
+ pwd += "\\"
+ }
+ switch pwdType {
+ case OSC7:
+ return fmt.Sprintf(w.osc7, hostName, pwd)
+ case OSC51:
+ return fmt.Sprintf(w.osc51, userName, hostName, pwd)
+ case OSC99:
+ fallthrough
+ default:
+ return fmt.Sprintf(w.osc99, pwd)
+ }
+}
+
+func (w *Writer) ClearAfter() string {
+ if w.Plain {
+ return ""
+ }
+ return w.clearLine + w.clearBelow
+}
+
+func (w *Writer) FormatTitle(title string) string {
+ title = w.trimAnsi(title)
+ // we have to do this to prevent bash/zsh from misidentifying escape sequences
+ switch w.shell {
+ case shell.BASH:
+ title = strings.NewReplacer("`", "\\`", `\`, `\\`).Replace(title)
+ case shell.ZSH:
+ title = strings.NewReplacer("`", "\\`", `%`, `%%`).Replace(title)
+ }
+ return fmt.Sprintf(w.title, title)
+}
+
+func (w *Writer) FormatText(text string) string {
+ return fmt.Sprintf(w.format, text)
+}
+
+func (w *Writer) SaveCursorPosition() string {
+ return w.saveCursorPosition
+}
+
+func (w *Writer) RestoreCursorPosition() string {
+ return w.restoreCursorPosition
+}
+
+func (w *Writer) LineBreak() string {
+ cr := fmt.Sprintf(w.left, 1000)
+ lf := fmt.Sprintf(w.linechange, 1, "B")
+ return cr + lf
+}
+
+func (w *Writer) Write(background, foreground, text string) {
+ if len(text) == 0 {
+ return
+ }
+
+ if !w.Plain {
+ text = w.GenerateHyperlink(text)
+ }
+
+ w.background, w.foreground = w.asAnsiColors(background, foreground)
+ // default to white foreground
+ if w.foreground.IsEmpty() {
+ w.foreground = w.AnsiColors.AnsiColorFromString("white", false)
+ }
+ // validate if we start with a color override
+ match := regex.FindNamedRegexMatch(anchorRegex, text)
+ if len(match) != 0 {
+ colorOverride := true
+ for _, style := range knownStyles {
+ if match["ANCHOR"] != style.AnchorStart {
+ continue
+ }
+ w.printEscapedAnsiString(style.Start)
+ colorOverride = false
+ }
+ if colorOverride {
+ w.currentBackground, w.currentForeground = w.asAnsiColors(match["BG"], match["FG"])
+ }
+ }
+ w.writeSegmentColors()
+
+ text = text[len(match["ANCHOR"]):]
+ w.runes = []rune(text)
+
+ for i := 0; i < len(w.runes); i++ {
+ s := w.runes[i]
+ // ignore everything which isn't overriding
+ if s != '<' {
+ w.length += runewidth.RuneWidth(s)
+ w.builder.WriteRune(s)
+ continue
+ }
+
+ // color/end overrides first
+ text = string(w.runes[i:])
+ match = regex.FindNamedRegexMatch(anchorRegex, text)
+ if len(match) > 0 {
+ i = w.writeColorOverrides(match, background, i)
+ continue
+ }
+
+ w.length += runewidth.RuneWidth(s)
+ w.builder.WriteRune(s)
+ }
+
+ w.printEscapedAnsiString(colorStyle.End)
+
+ // reset current
+ w.currentBackground = ""
+ w.currentForeground = ""
+}
+
+func (w *Writer) printEscapedAnsiString(text string) {
+ if w.Plain {
+ return
+ }
+ if len(w.format) == 0 {
+ w.builder.WriteString(text)
+ return
+ }
+ w.builder.WriteString(fmt.Sprintf(w.format, text))
+}
+
+func (w *Writer) getAnsiFromColorString(colorString string, isBackground bool) Color {
+ return w.AnsiColors.AnsiColorFromString(colorString, isBackground)
+}
+
+func (w *Writer) writeSegmentColors() {
+ // use correct starting colors
+ bg := w.background
+ fg := w.foreground
+ if !w.currentBackground.IsEmpty() {
+ bg = w.currentBackground
+ }
+ if !w.currentForeground.IsEmpty() {
+ fg = w.currentForeground
+ }
+
+ if fg.IsTransparent() && len(w.TerminalBackground) != 0 {
+ background := w.getAnsiFromColorString(w.TerminalBackground, false)
+ w.printEscapedAnsiString(fmt.Sprintf(colorise, background))
+ w.printEscapedAnsiString(fmt.Sprintf(colorise, bg.ToForeground()))
+ } else if fg.IsTransparent() && !bg.IsEmpty() {
+ w.printEscapedAnsiString(fmt.Sprintf(transparent, bg))
+ } else {
+ if !bg.IsEmpty() && !bg.IsTransparent() {
+ w.printEscapedAnsiString(fmt.Sprintf(colorise, bg))
+ }
+ if !fg.IsEmpty() {
+ w.printEscapedAnsiString(fmt.Sprintf(colorise, fg))
+ }
+ }
+
+ // set current colors
+ w.currentBackground = bg
+ w.currentForeground = fg
+}
+
+func (w *Writer) writeColorOverrides(match map[string]string, background string, i int) (position int) {
+ position = i
+ // check color reset first
+ if match["ANCHOR"] == colorStyle.AnchorEnd {
+ // make sure to reset the colors if needed
+ position += len([]rune(colorStyle.AnchorEnd)) - 1
+ // do not restore colors at the end of the string, we print it anyways
+ if position == len(w.runes)-1 {
+ return
+ }
+ if w.currentBackground != w.background {
+ w.printEscapedAnsiString(fmt.Sprintf(colorise, w.background))
+ }
+ if w.currentForeground != w.foreground {
+ w.printEscapedAnsiString(fmt.Sprintf(colorise, w.foreground))
+ }
+ return
+ }
+
+ position += len([]rune(match["ANCHOR"])) - 1
+
+ for _, style := range knownStyles {
+ if style.AnchorEnd == match["ANCHOR"] {
+ w.printEscapedAnsiString(style.End)
+ return
+ }
+ if style.AnchorStart == match["ANCHOR"] {
+ w.printEscapedAnsiString(style.Start)
+ return
+ }
+ }
+
+ if match["FG"] == Transparent && len(match["BG"]) == 0 {
+ match["BG"] = background
+ }
+ w.currentBackground, w.currentForeground = w.asAnsiColors(match["BG"], match["FG"])
+
+ // make sure we have colors
+ if w.currentForeground.IsEmpty() {
+ w.currentForeground = w.foreground
+ }
+ if w.currentBackground.IsEmpty() {
+ w.currentBackground = w.background
+ }
+
+ if w.currentForeground.IsTransparent() && len(w.TerminalBackground) != 0 {
+ background := w.getAnsiFromColorString(w.TerminalBackground, false)
+ w.printEscapedAnsiString(fmt.Sprintf(colorise, background))
+ w.printEscapedAnsiString(fmt.Sprintf(colorise, w.currentBackground.ToForeground()))
+ return
+ }
+
+ if w.currentForeground.IsTransparent() && !w.currentBackground.IsTransparent() {
+ w.printEscapedAnsiString(fmt.Sprintf(transparent, w.currentBackground))
+ return
+ }
+
+ if w.currentBackground != w.background {
+ // end the colors in case we have a transparent background
+ if w.currentBackground.IsTransparent() {
+ w.printEscapedAnsiString(colorStyle.End)
+ } else {
+ w.printEscapedAnsiString(fmt.Sprintf(colorise, w.currentBackground))
+ }
+ }
+
+ if w.currentForeground != w.foreground || w.currentBackground.IsTransparent() {
+ w.printEscapedAnsiString(fmt.Sprintf(colorise, w.currentForeground))
+ }
+
+ return position
+}
+
+func (w *Writer) asAnsiColors(background, foreground string) (Color, Color) {
+ background = w.expandKeyword(background)
+ foreground = w.expandKeyword(foreground)
+ inverted := foreground == Transparent && len(background) != 0
+ backgroundAnsi := w.getAnsiFromColorString(background, !inverted)
+ foregroundAnsi := w.getAnsiFromColorString(foreground, false)
+ return backgroundAnsi, foregroundAnsi
+}
+
+func (w *Writer) isKeyword(color string) bool {
+ switch color {
+ case Transparent, ParentBackground, ParentForeground, Background, Foreground:
+ return true
+ default:
+ return false
+ }
+}
+
+func (w *Writer) expandKeyword(keyword string) string {
+ resolveParentColor := func(keyword string) string {
+ for _, color := range w.ParentColors {
+ if color == nil {
+ return Transparent
+ }
+ switch keyword {
+ case ParentBackground:
+ keyword = color.Background
+ case ParentForeground:
+ keyword = color.Foreground
+ default:
+ if len(keyword) == 0 {
+ return Transparent
+ }
+ return keyword
+ }
+ }
+ if len(keyword) == 0 {
+ return Transparent
+ }
+ return keyword
+ }
+ resolveKeyword := func(keyword string) string {
+ switch {
+ case keyword == Background && w.Colors != nil:
+ return w.Colors.Background
+ case keyword == Foreground && w.Colors != nil:
+ return w.Colors.Foreground
+ case (keyword == ParentBackground || keyword == ParentForeground) && w.ParentColors != nil:
+ return resolveParentColor(keyword)
+ default:
+ return Transparent
+ }
+ }
+ for ok := w.isKeyword(keyword); ok; ok = w.isKeyword(keyword) {
+ resolved := resolveKeyword(keyword)
+ if resolved == keyword {
+ break
+ }
+ keyword = resolved
+ }
+ return keyword
+}
+
+func (w *Writer) String() (string, int) {
+ defer func() {
+ w.length = 0
+ w.builder.Reset()
+ }()
+
+ return w.builder.String(), w.length
+}
diff --git a/src/color/ansi_writer_hyperlink.go b/src/ansi/ansi_writer_hyperlink.go
similarity index 82%
rename from src/color/ansi_writer_hyperlink.go
rename to src/ansi/ansi_writer_hyperlink.go
index bc47de15..e5b2d997 100644
--- a/src/color/ansi_writer_hyperlink.go
+++ b/src/ansi/ansi_writer_hyperlink.go
@@ -1,4 +1,4 @@
-package color
+package ansi
import (
"fmt"
@@ -8,7 +8,7 @@ import (
"github.com/jandedobbeleer/oh-my-posh/shell"
)
-func (a *AnsiWriter) GenerateHyperlink(text string) string {
+func (w *Writer) GenerateHyperlink(text string) string {
const (
LINK = "link"
TEXT = "text"
@@ -60,7 +60,7 @@ func (a *AnsiWriter) GenerateHyperlink(text string) string {
continue
}
// end of link part
- result.WriteString(a.replaceHyperlink(hyperlink.String()))
+ result.WriteString(w.replaceHyperlink(hyperlink.String()))
hyperlink.Reset()
state = OTHER
}
@@ -70,21 +70,21 @@ func (a *AnsiWriter) GenerateHyperlink(text string) string {
return result.String()
}
-func (a *AnsiWriter) replaceHyperlink(text string) string {
+func (w *Writer) replaceHyperlink(text string) string {
// hyperlink matching
results := regex.FindNamedRegexMatch("(?P(?:\\[(?P.+)\\])(?:\\((?P.*)\\)))", text)
if len(results) != 3 {
return text
}
- linkText := a.escapeLinkTextForFishShell(results["TEXT"])
+ linkText := w.escapeLinkTextForFishShell(results["TEXT"])
// build hyperlink ansi
- hyperlink := fmt.Sprintf(a.hyperlink, results["URL"], linkText)
+ hyperlink := fmt.Sprintf(w.hyperlink, results["URL"], linkText)
// replace original text by the new onex
return strings.Replace(text, results["ALL"], hyperlink, 1)
}
-func (a *AnsiWriter) escapeLinkTextForFishShell(text string) string {
- if a.shell != shell.FISH {
+func (w *Writer) escapeLinkTextForFishShell(text string) string {
+ if w.shell != shell.FISH {
return text
}
escapeChars := map[string]string{
diff --git a/src/color/ansi_writer_hyperlink_test.go b/src/ansi/ansi_writer_hyperlink_test.go
similarity index 97%
rename from src/color/ansi_writer_hyperlink_test.go
rename to src/ansi/ansi_writer_hyperlink_test.go
index e7f824a2..e81837f4 100644
--- a/src/color/ansi_writer_hyperlink_test.go
+++ b/src/ansi/ansi_writer_hyperlink_test.go
@@ -1,4 +1,4 @@
-package color
+package ansi
import (
"testing"
@@ -19,7 +19,7 @@ func TestGenerateHyperlinkNoUrl(t *testing.T) {
{Text: "sample text with no url", ShellName: shell.BASH, Expected: "sample text with no url"},
}
for _, tc := range cases {
- a := AnsiWriter{}
+ a := Writer{}
a.Init(tc.ShellName)
hyperlinkText := a.GenerateHyperlink(tc.Text)
assert.Equal(t, tc.Expected, hyperlinkText)
@@ -52,7 +52,7 @@ func TestGenerateHyperlinkWithUrl(t *testing.T) {
},
}
for _, tc := range cases {
- a := AnsiWriter{}
+ a := Writer{}
a.Init(tc.ShellName)
hyperlinkText := a.GenerateHyperlink(tc.Text)
assert.Equal(t, tc.Expected, hyperlinkText)
@@ -70,7 +70,7 @@ func TestGenerateHyperlinkWithUrlNoName(t *testing.T) {
{Text: "[](http://www.google.be)", ShellName: shell.BASH, Expected: "[](http://www.google.be)"},
}
for _, tc := range cases {
- a := AnsiWriter{}
+ a := Writer{}
a.Init(tc.ShellName)
hyperlinkText := a.GenerateHyperlink(tc.Text)
assert.Equal(t, tc.Expected, hyperlinkText)
@@ -89,7 +89,7 @@ func TestGenerateFileLink(t *testing.T) {
{Text: `[Windows](file:C:/Windows)`, Expected: "\x1b]8;;file:C:/Windows\x1b\\Windows\x1b]8;;\x1b\\"},
}
for _, tc := range cases {
- a := AnsiWriter{}
+ a := Writer{}
a.Init(shell.PWSH)
hyperlinkText := a.GenerateHyperlink(tc.Text)
assert.Equal(t, tc.Expected, hyperlinkText)
diff --git a/src/color/ansi_writer_test.go b/src/ansi/ansi_writer_test.go
similarity index 65%
rename from src/color/ansi_writer_test.go
rename to src/ansi/ansi_writer_test.go
index a1599c68..c6eccbd7 100644
--- a/src/color/ansi_writer_test.go
+++ b/src/ansi/ansi_writer_test.go
@@ -1,4 +1,4 @@
-package color
+package ansi
import (
"testing"
@@ -13,187 +13,187 @@ func TestWriteANSIColors(t *testing.T) {
Case string
Expected string
Input string
- Colors *Color
- Parent *Color
+ Colors *cachedColor
+ Parent *cachedColor
TerminalBackground string
}{
{
Case: "Bold",
Input: "test",
Expected: "\x1b[1m\x1b[30mtest\x1b[22m\x1b[0m",
- Colors: &Color{Foreground: "black", Background: ParentBackground},
+ Colors: &cachedColor{Foreground: "black", Background: ParentBackground},
},
{
Case: "Bold with color override",
Input: "<#ffffff>test>",
Expected: "\x1b[1m\x1b[30m\x1b[38;2;255;255;255mtest\x1b[30m\x1b[22m\x1b[0m",
- Colors: &Color{Foreground: "black", Background: ParentBackground},
+ Colors: &cachedColor{Foreground: "black", Background: ParentBackground},
},
{
Case: "Bold with color override, flavor 2",
Input: "<#ffffff>test>",
Expected: "\x1b[38;2;255;255;255m\x1b[1mtest\x1b[22m\x1b[0m",
- Colors: &Color{Foreground: "black", Background: ParentBackground},
+ Colors: &cachedColor{Foreground: "black", Background: ParentBackground},
},
{
Case: "Double override",
Input: "<#ffffff>jan>@<#ffffff>Jans-MBP>",
Expected: "\x1b[48;2;255;87;51m\x1b[38;2;255;255;255mjan\x1b[32m@\x1b[38;2;255;255;255mJans-MBP\x1b[0m",
- Colors: &Color{Foreground: "green", Background: "#FF5733"},
+ Colors: &cachedColor{Foreground: "green", Background: "#FF5733"},
},
{
Case: "No color override",
Input: "test",
Expected: "\x1b[47m\x1b[30mtest\x1b[0m",
- Colors: &Color{Foreground: "black", Background: "white"},
- Parent: &Color{Foreground: "black", Background: "white"},
+ Colors: &cachedColor{Foreground: "black", Background: "white"},
+ Parent: &cachedColor{Foreground: "black", Background: "white"},
},
{
Case: "Inherit foreground",
Input: "test",
Expected: "\x1b[47m\x1b[33mtest\x1b[0m",
- Colors: &Color{Foreground: ParentForeground, Background: "white"},
- Parent: &Color{Foreground: "yellow", Background: "white"},
+ Colors: &cachedColor{Foreground: ParentForeground, Background: "white"},
+ Parent: &cachedColor{Foreground: "yellow", Background: "white"},
},
{
Case: "Inherit background",
Input: "test",
Expected: "\x1b[41m\x1b[30mtest\x1b[0m",
- Colors: &Color{Foreground: "black", Background: ParentBackground},
- Parent: &Color{Foreground: "yellow", Background: "red"},
+ Colors: &cachedColor{Foreground: "black", Background: ParentBackground},
+ Parent: &cachedColor{Foreground: "yellow", Background: "red"},
},
{
Case: "No parent",
Input: "test",
Expected: "\x1b[30mtest\x1b[0m",
- Colors: &Color{Foreground: "black", Background: ParentBackground},
+ Colors: &cachedColor{Foreground: "black", Background: ParentBackground},
},
{
Case: "Inherit override foreground",
Input: "hello world>",
Expected: "\x1b[47m\x1b[30mhello \x1b[33mworld\x1b[0m",
- Colors: &Color{Foreground: "black", Background: "white"},
- Parent: &Color{Foreground: "yellow", Background: "red"},
+ Colors: &cachedColor{Foreground: "black", Background: "white"},
+ Parent: &cachedColor{Foreground: "yellow", Background: "red"},
},
{
Case: "Inherit override background",
Input: "hello world>",
Expected: "\x1b[47m\x1b[30mhello \x1b[41mworld\x1b[0m",
- Colors: &Color{Foreground: "black", Background: "white"},
- Parent: &Color{Foreground: "yellow", Background: "red"},
+ Colors: &cachedColor{Foreground: "black", Background: "white"},
+ Parent: &cachedColor{Foreground: "yellow", Background: "red"},
},
{
Case: "Inherit override background, no foreground specified",
Input: "hello <,parentBackground>world>",
Expected: "\x1b[47m\x1b[30mhello \x1b[41mworld\x1b[0m",
- Colors: &Color{Foreground: "black", Background: "white"},
- Parent: &Color{Foreground: "yellow", Background: "red"},
+ Colors: &cachedColor{Foreground: "black", Background: "white"},
+ Parent: &cachedColor{Foreground: "yellow", Background: "red"},
},
{
Case: "Inherit no parent foreground",
Input: "hello world>",
Expected: "\x1b[47m\x1b[30mhello \x1b[47;49m\x1b[7mworld\x1b[0m",
- Colors: &Color{Foreground: "black", Background: "white"},
+ Colors: &cachedColor{Foreground: "black", Background: "white"},
},
{
Case: "Inherit no parent background",
Input: "hello <,parentBackground>world>",
Expected: "\x1b[47m\x1b[30mhello \x1b[0m\x1b[30mworld\x1b[0m",
- Colors: &Color{Foreground: "black", Background: "white"},
+ Colors: &cachedColor{Foreground: "black", Background: "white"},
},
{
Case: "Inherit override both",
Input: "hello world>",
Expected: "\x1b[47m\x1b[30mhello \x1b[41m\x1b[33mworld\x1b[0m",
- Colors: &Color{Foreground: "black", Background: "white"},
- Parent: &Color{Foreground: "yellow", Background: "red"},
+ Colors: &cachedColor{Foreground: "black", Background: "white"},
+ Parent: &cachedColor{Foreground: "yellow", Background: "red"},
},
{
Case: "Inherit override both inverted",
Input: "hello world>",
Expected: "\x1b[47m\x1b[30mhello \x1b[43m\x1b[31mworld\x1b[0m",
- Colors: &Color{Foreground: "black", Background: "white"},
- Parent: &Color{Foreground: "yellow", Background: "red"},
+ Colors: &cachedColor{Foreground: "black", Background: "white"},
+ Parent: &cachedColor{Foreground: "yellow", Background: "red"},
},
{
Case: "Inline override",
Input: "hello, world>, rabbit",
Expected: "\x1b[47m\x1b[30mhello, \x1b[31mworld\x1b[30m, rabbit\x1b[0m",
- Colors: &Color{Foreground: "black", Background: "white"},
+ Colors: &cachedColor{Foreground: "black", Background: "white"},
},
{
Case: "Transparent background",
Input: "hello world",
Expected: "\x1b[37mhello world\x1b[0m",
- Colors: &Color{Foreground: "white", Background: Transparent},
+ Colors: &cachedColor{Foreground: "white", Background: Transparent},
},
{
Case: "Transparent foreground override",
Input: "hello <#ffffff>world>",
Expected: "\x1b[32mhello \x1b[38;2;255;255;255mworld\x1b[0m",
- Colors: &Color{Foreground: "green", Background: Transparent},
+ Colors: &cachedColor{Foreground: "green", Background: Transparent},
},
{
Case: "No foreground",
Input: "test",
Expected: "\x1b[48;2;255;87;51m\x1b[37mtest\x1b[0m",
- Colors: &Color{Foreground: "", Background: "#FF5733"},
+ Colors: &cachedColor{Foreground: "", Background: "#FF5733"},
},
{
Case: "Transparent foreground",
Input: "test",
Expected: "\x1b[38;2;255;87;51;49m\x1b[7mtest\x1b[0m",
- Colors: &Color{Foreground: Transparent, Background: "#FF5733"},
+ Colors: &cachedColor{Foreground: Transparent, Background: "#FF5733"},
},
{
Case: "Transparent foreground, terminal background set",
Input: "test",
Expected: "\x1b[38;2;33;47;60m\x1b[48;2;255;87;51mtest\x1b[0m",
- Colors: &Color{Foreground: Transparent, Background: "#FF5733"},
+ Colors: &cachedColor{Foreground: Transparent, Background: "#FF5733"},
TerminalBackground: "#212F3C",
},
{
Case: "Foreground for foreground override",
Input: "test>",
Expected: "\x1b[47m\x1b[30mtest\x1b[0m",
- Colors: &Color{Foreground: "black", Background: "white"},
+ Colors: &cachedColor{Foreground: "black", Background: "white"},
},
{
Case: "Background for background override",
Input: "<,background>test>",
Expected: "\x1b[47m\x1b[30mtest\x1b[0m",
- Colors: &Color{Foreground: "black", Background: "white"},
+ Colors: &cachedColor{Foreground: "black", Background: "white"},
},
{
Case: "Google",
Input: "G>o>o>g>l>e>",
Expected: "\x1b[47m\x1b[34mG\x1b[40m\x1b[30m\x1b[47m\x1b[31mo\x1b[40m\x1b[30m\x1b[47m\x1b[33mo\x1b[40m\x1b[30m\x1b[47m\x1b[34mg\x1b[40m\x1b[30m\x1b[47m\x1b[32ml\x1b[40m\x1b[30m\x1b[47m\x1b[31me\x1b[0m", //nolint: lll
- Colors: &Color{Foreground: "black", Background: "black"},
+ Colors: &cachedColor{Foreground: "black", Background: "black"},
},
{
Case: "Foreground for background override",
Input: "test>",
Expected: "\x1b[47m\x1b[37mtest\x1b[0m",
- Colors: &Color{Foreground: "black", Background: "white"},
+ Colors: &cachedColor{Foreground: "black", Background: "white"},
},
{
Case: "Foreground for background vice versa override",
Input: "test>",
Expected: "\x1b[40m\x1b[37mtest\x1b[0m",
- Colors: &Color{Foreground: "black", Background: "white"},
+ Colors: &cachedColor{Foreground: "black", Background: "white"},
},
{
Case: "Background for foreground override",
Input: "<,foreground>test>",
Expected: "\x1b[40m\x1b[30mtest\x1b[0m",
- Colors: &Color{Foreground: "black", Background: "white"},
+ Colors: &cachedColor{Foreground: "black", Background: "white"},
},
}
for _, tc := range cases {
- renderer := &AnsiWriter{
- ParentColors: []*Color{tc.Parent},
+ renderer := &Writer{
+ ParentColors: []*cachedColor{tc.Parent},
Colors: tc.Colors,
TerminalBackground: tc.TerminalBackground,
AnsiColors: &DefaultColors{},
diff --git a/src/color/colors.go b/src/ansi/colors.go
similarity index 75%
rename from src/color/colors.go
rename to src/ansi/colors.go
index 95f7a2c6..e31f0d58 100644
--- a/src/color/colors.go
+++ b/src/ansi/colors.go
@@ -1,4 +1,4 @@
-package color
+package ansi
import (
"fmt"
@@ -10,41 +10,41 @@ import (
"github.com/gookit/color"
)
-// AnsiColors is the interface that wraps AnsiColorFromString method.
+// Colors is the interface that wraps AnsiColorFromString method.
//
// AnsiColorFromString gets the ANSI color code for a given color string.
// This can include a valid hex color in the format `#FFFFFF`,
// but also a name of one of the first 16 ANSI colors like `lightBlue`.
-type AnsiColors interface {
- AnsiColorFromString(colorString string, isBackground bool) AnsiColor
+type Colors interface {
+ AnsiColorFromString(colorString string, isBackground bool) Color
}
-// AnsiColor is an ANSI color code ready to be printed to the console.
+// Color is an ANSI color code ready to be printed to the console.
// Example: "38;2;255;255;255", "48;2;255;255;255", "31", "95".
-type AnsiColor string
+type Color string
const (
- emptyAnsiColor = AnsiColor("")
- transparentAnsiColor = AnsiColor(Transparent)
+ emptyColor = Color("")
+ transparentColor = Color(Transparent)
)
-func (c AnsiColor) IsEmpty() bool {
- return c == emptyAnsiColor
+func (c Color) IsEmpty() bool {
+ return c == emptyColor
}
-func (c AnsiColor) IsTransparent() bool {
- return c == transparentAnsiColor
+func (c Color) IsTransparent() bool {
+ return c == transparentColor
}
-func (c AnsiColor) ToForeground() AnsiColor {
+func (c Color) ToForeground() Color {
colorString := string(c)
if strings.HasPrefix(colorString, "38;") {
- return AnsiColor(strings.Replace(colorString, "38;", "48;", 1))
+ return Color(strings.Replace(colorString, "38;", "48;", 1))
}
return c
}
-func MakeColors(palette Palette, cacheEnabled bool, accentColor string, env platform.Environment) (colors AnsiColors) {
+func MakeColors(palette Palette, cacheEnabled bool, accentColor string, env platform.Environment) (colors Colors) {
defaultColors := &DefaultColors{}
defaultColors.SetAccentColor(env, accentColor)
colors = defaultColors
@@ -63,12 +63,12 @@ type RGB struct {
// DefaultColors is the default AnsiColors implementation.
type DefaultColors struct {
- accent *Color
+ accent *cachedColor
}
var (
// Map for color names and their respective foreground [0] or background [1] color codes
- ansiColorCodes = map[string][2]AnsiColor{
+ ansiColorCodes = map[string][2]Color{
"black": {"30", "40"},
"red": {"31", "41"},
"green": {"32", "42"},
@@ -94,21 +94,21 @@ const (
backgroundIndex = 1
)
-func (d *DefaultColors) AnsiColorFromString(colorString string, isBackground bool) AnsiColor {
+func (d *DefaultColors) AnsiColorFromString(colorString string, isBackground bool) Color {
if len(colorString) == 0 {
- return emptyAnsiColor
+ return emptyColor
}
if colorString == Transparent {
- return transparentAnsiColor
+ return transparentColor
}
if colorString == Accent {
if d.accent == nil {
- return emptyAnsiColor
+ return emptyColor
}
if isBackground {
- return AnsiColor(d.accent.Background)
+ return Color(d.accent.Background)
}
- return AnsiColor(d.accent.Foreground)
+ return Color(d.accent.Foreground)
}
colorFromName, err := getAnsiColorFromName(colorString, isBackground)
if err == nil {
@@ -117,25 +117,25 @@ func (d *DefaultColors) AnsiColorFromString(colorString string, isBackground boo
if !strings.HasPrefix(colorString, "#") {
val, err := strconv.ParseUint(colorString, 10, 64)
if err != nil || val > 255 {
- return emptyAnsiColor
+ return emptyColor
}
c256 := color.C256(uint8(val), isBackground)
- return AnsiColor(c256.RGBColor().String())
+ return Color(c256.RGBColor().String())
}
style := color.HEX(colorString, isBackground)
if !style.IsEmpty() {
- return AnsiColor(style.String())
+ return Color(style.String())
}
if colorInt, err := strconv.ParseInt(colorString, 10, 8); err == nil {
c := color.C256(uint8(colorInt), isBackground)
- return AnsiColor(c.String())
+ return Color(c.String())
}
- return emptyAnsiColor
+ return emptyColor
}
// getAnsiColorFromName returns the color code for a given color name if the name is
// known ANSI color name.
-func getAnsiColorFromName(colorName string, isBackground bool) (AnsiColor, error) {
+func getAnsiColorFromName(colorName string, isBackground bool) (Color, error) {
if colorCodes, found := ansiColorCodes[colorName]; found {
if isBackground {
return colorCodes[backgroundIndex], nil
@@ -153,14 +153,14 @@ func IsAnsiColorName(colorString string) bool {
// PaletteColors is the AnsiColors Decorator that uses the Palette to do named color
// lookups before ANSI color code generation.
type PaletteColors struct {
- ansiColors AnsiColors
+ ansiColors Colors
palette Palette
}
-func (p *PaletteColors) AnsiColorFromString(colorString string, isBackground bool) AnsiColor {
+func (p *PaletteColors) AnsiColorFromString(colorString string, isBackground bool) Color {
paletteColor, err := p.palette.ResolveColor(colorString)
if err != nil {
- return emptyAnsiColor
+ return emptyColor
}
ansiColor := p.ansiColors.AnsiColorFromString(paletteColor, isBackground)
return ansiColor
@@ -170,8 +170,8 @@ func (p *PaletteColors) AnsiColorFromString(colorString string, isBackground boo
// AnsiColorFromString calls are cheap, but not free, and having a simple cache in
// has measurable positive effect on performance.
type CachedColors struct {
- ansiColors AnsiColors
- colorCache map[cachedColorKey]AnsiColor
+ ansiColors Colors
+ colorCache map[cachedColorKey]Color
}
type cachedColorKey struct {
@@ -179,9 +179,9 @@ type cachedColorKey struct {
isBackground bool
}
-func (c *CachedColors) AnsiColorFromString(colorString string, isBackground bool) AnsiColor {
+func (c *CachedColors) AnsiColorFromString(colorString string, isBackground bool) Color {
if c.colorCache == nil {
- c.colorCache = make(map[cachedColorKey]AnsiColor)
+ c.colorCache = make(map[cachedColorKey]Color)
}
key := cachedColorKey{colorString, isBackground}
if ansiColor, hit := c.colorCache[key]; hit {
diff --git a/src/color/colors_test.go b/src/ansi/colors_test.go
similarity index 52%
rename from src/color/colors_test.go
rename to src/ansi/colors_test.go
index b951c631..dae79950 100644
--- a/src/color/colors_test.go
+++ b/src/ansi/colors_test.go
@@ -1,4 +1,4 @@
-package color
+package ansi
import (
"testing"
@@ -9,20 +9,20 @@ import (
func TestGetAnsiFromColorString(t *testing.T) {
cases := []struct {
Case string
- Expected AnsiColor
+ Expected Color
Color string
Background bool
}{
- {Case: "256 color", Expected: AnsiColor("38;2;135;95;255"), Color: "99", Background: false},
- {Case: "256 color", Expected: AnsiColor("38;2;135;255;215"), Color: "122", Background: false},
- {Case: "Invalid background", Expected: emptyAnsiColor, Color: "invalid", Background: true},
- {Case: "Invalid background", Expected: emptyAnsiColor, Color: "invalid", Background: false},
- {Case: "Hex foreground", Expected: AnsiColor("38;2;170;187;204"), Color: "#AABBCC", Background: false},
- {Case: "Hex backgrond", Expected: AnsiColor("48;2;170;187;204"), Color: "#AABBCC", Background: true},
- {Case: "Base 8 foreground", Expected: AnsiColor("31"), Color: "red", Background: false},
- {Case: "Base 8 background", Expected: AnsiColor("41"), Color: "red", Background: true},
- {Case: "Base 16 foreground", Expected: AnsiColor("91"), Color: "lightRed", Background: false},
- {Case: "Base 16 backround", Expected: AnsiColor("101"), Color: "lightRed", Background: true},
+ {Case: "256 color", Expected: Color("38;2;135;95;255"), Color: "99", Background: false},
+ {Case: "256 color", Expected: Color("38;2;135;255;215"), Color: "122", Background: false},
+ {Case: "Invalid background", Expected: emptyColor, Color: "invalid", Background: true},
+ {Case: "Invalid background", Expected: emptyColor, Color: "invalid", Background: false},
+ {Case: "Hex foreground", Expected: Color("38;2;170;187;204"), Color: "#AABBCC", Background: false},
+ {Case: "Hex backgrond", Expected: Color("48;2;170;187;204"), Color: "#AABBCC", Background: true},
+ {Case: "Base 8 foreground", Expected: Color("31"), Color: "red", Background: false},
+ {Case: "Base 8 background", Expected: Color("41"), Color: "red", Background: true},
+ {Case: "Base 16 foreground", Expected: Color("91"), Color: "lightRed", Background: false},
+ {Case: "Base 16 backround", Expected: Color("101"), Color: "lightRed", Background: true},
}
for _, tc := range cases {
ansiColors := &DefaultColors{}
diff --git a/src/color/colors_unix.go b/src/ansi/colors_unix.go
similarity index 91%
rename from src/color/colors_unix.go
rename to src/ansi/colors_unix.go
index 188a48e7..57407937 100644
--- a/src/color/colors_unix.go
+++ b/src/ansi/colors_unix.go
@@ -1,6 +1,6 @@
//go:build !windows
-package color
+package ansi
import "github.com/jandedobbeleer/oh-my-posh/platform"
@@ -12,7 +12,7 @@ func (d *DefaultColors) SetAccentColor(env platform.Environment, defaultColor st
if len(defaultColor) == 0 {
return
}
- d.accent = &Color{
+ d.accent = &cachedColor{
Foreground: string(d.AnsiColorFromString(defaultColor, false)),
Background: string(d.AnsiColorFromString(defaultColor, true)),
}
diff --git a/src/color/colors_windows.go b/src/ansi/colors_windows.go
similarity index 94%
rename from src/color/colors_windows.go
rename to src/ansi/colors_windows.go
index b44e801b..744026d6 100644
--- a/src/color/colors_windows.go
+++ b/src/ansi/colors_windows.go
@@ -1,4 +1,4 @@
-package color
+package ansi
import (
"errors"
@@ -27,7 +27,7 @@ func GetAccentColor(env platform.Environment) (*RGB, error) {
func (d *DefaultColors) SetAccentColor(env platform.Environment, defaultColor string) {
rgb, err := GetAccentColor(env)
if err != nil {
- d.accent = &Color{
+ d.accent = &cachedColor{
Foreground: string(d.AnsiColorFromString(defaultColor, false)),
Background: string(d.AnsiColorFromString(defaultColor, true)),
}
@@ -35,7 +35,7 @@ func (d *DefaultColors) SetAccentColor(env platform.Environment, defaultColor st
}
foreground := color.RGB(rgb.R, rgb.G, rgb.B, false)
background := color.RGB(rgb.R, rgb.G, rgb.B, true)
- d.accent = &Color{
+ d.accent = &cachedColor{
Foreground: foreground.String(),
Background: background.String(),
}
diff --git a/src/color/palette.go b/src/ansi/palette.go
similarity index 99%
rename from src/color/palette.go
rename to src/ansi/palette.go
index 103864d5..1aa033f6 100644
--- a/src/color/palette.go
+++ b/src/ansi/palette.go
@@ -1,4 +1,4 @@
-package color
+package ansi
import (
"fmt"
diff --git a/src/color/palette_test.go b/src/ansi/palette_test.go
similarity index 99%
rename from src/color/palette_test.go
rename to src/ansi/palette_test.go
index 5a0b31e6..37e6ad83 100644
--- a/src/color/palette_test.go
+++ b/src/ansi/palette_test.go
@@ -1,4 +1,4 @@
-package color
+package ansi
import (
"testing"
diff --git a/src/color/palettes.go b/src/ansi/palettes.go
similarity index 90%
rename from src/color/palettes.go
rename to src/ansi/palettes.go
index a6019dc3..9cbd7fbb 100644
--- a/src/color/palettes.go
+++ b/src/ansi/palettes.go
@@ -1,4 +1,4 @@
-package color
+package ansi
type Palettes struct {
Template string `json:"template,omitempty"`
diff --git a/src/color/text.go b/src/ansi/text.go
similarity index 82%
rename from src/color/text.go
rename to src/ansi/text.go
index b47f68be..9b8fff85 100644
--- a/src/color/text.go
+++ b/src/ansi/text.go
@@ -1,4 +1,4 @@
-package color
+package ansi
import (
"strings"
@@ -12,7 +12,7 @@ func init() { //nolint:gochecknoinits
runewidth.DefaultCondition.EastAsianWidth = false
}
-func (a *AnsiWriter) MeasureText(text string) int {
+func (a *Writer) MeasureText(text string) int {
// skip strings with ANSI
if !strings.Contains(text, "\x1b") {
text = a.TrimEscapeSequences(text)
@@ -25,20 +25,20 @@ func (a *AnsiWriter) MeasureText(text string) int {
text = strings.ReplaceAll(text, match["STR"], match["TEXT"])
}
}
- text = a.TrimAnsi(text)
+ text = a.trimAnsi(text)
text = a.TrimEscapeSequences(text)
length := runewidth.StringWidth(text)
return length
}
-func (a *AnsiWriter) TrimAnsi(text string) string {
+func (a *Writer) trimAnsi(text string) string {
if len(text) == 0 || !strings.Contains(text, "\x1b") {
return text
}
return regex.ReplaceAllString(AnsiRegex, text, "")
}
-func (a *AnsiWriter) TrimEscapeSequences(text string) string {
+func (a *Writer) TrimEscapeSequences(text string) string {
if len(text) == 0 {
return text
}
diff --git a/src/color/text_test.go b/src/ansi/text_test.go
similarity index 96%
rename from src/color/text_test.go
rename to src/ansi/text_test.go
index 63935277..01e1e9c3 100644
--- a/src/color/text_test.go
+++ b/src/ansi/text_test.go
@@ -1,4 +1,4 @@
-package color
+package ansi
import (
"fmt"
@@ -36,7 +36,7 @@ func TestMeasureText(t *testing.T) {
shells := []string{shell.BASH, shell.ZSH, shell.GENERIC}
for _, shell := range shells {
for _, tc := range cases {
- ansiWriter := &AnsiWriter{}
+ ansiWriter := &Writer{}
ansiWriter.Init(shell)
tmpl := &template.Text{
Template: tc.Template,
diff --git a/src/cli/config_export_image.go b/src/cli/config_export_image.go
index 6714deb5..0589e889 100644
--- a/src/cli/config_export_image.go
+++ b/src/cli/config_export_image.go
@@ -3,7 +3,7 @@ package cli
import (
"fmt"
- "github.com/jandedobbeleer/oh-my-posh/color"
+ "github.com/jandedobbeleer/oh-my-posh/ansi"
"github.com/jandedobbeleer/oh-my-posh/engine"
"github.com/jandedobbeleer/oh-my-posh/platform"
"github.com/jandedobbeleer/oh-my-posh/shell"
@@ -58,7 +58,7 @@ Exports the config to an image file using customized output options.`,
defer env.Close()
cfg := engine.LoadConfig(env)
writerColors := cfg.MakeColors()
- writer := &color.AnsiWriter{
+ writer := &ansi.Writer{
TerminalBackground: shell.ConsoleBackgroundColor(env, cfg.TerminalBackground),
AnsiColors: writerColors,
}
diff --git a/src/cli/debug.go b/src/cli/debug.go
index 43b8e0f8..5ba40088 100644
--- a/src/cli/debug.go
+++ b/src/cli/debug.go
@@ -4,7 +4,7 @@ import (
"fmt"
"time"
- "github.com/jandedobbeleer/oh-my-posh/color"
+ "github.com/jandedobbeleer/oh-my-posh/ansi"
"github.com/jandedobbeleer/oh-my-posh/engine"
"github.com/jandedobbeleer/oh-my-posh/platform"
"github.com/jandedobbeleer/oh-my-posh/shell"
@@ -33,7 +33,7 @@ var debugCmd = &cobra.Command{
defer env.Close()
cfg := engine.LoadConfig(env)
writerColors := cfg.MakeColors()
- writer := &color.AnsiWriter{
+ writer := &ansi.Writer{
TerminalBackground: shell.ConsoleBackgroundColor(env, cfg.TerminalBackground),
AnsiColors: writerColors,
}
diff --git a/src/cli/get.go b/src/cli/get.go
index 913f624a..678be4e1 100644
--- a/src/cli/get.go
+++ b/src/cli/get.go
@@ -5,7 +5,7 @@ import (
"strings"
"time"
- "github.com/jandedobbeleer/oh-my-posh/color"
+ "github.com/jandedobbeleer/oh-my-posh/ansi"
"github.com/jandedobbeleer/oh-my-posh/platform"
color2 "github.com/gookit/color"
@@ -52,7 +52,7 @@ This command is used to get the value of the following variables:
case "shell":
fmt.Println(env.Shell())
case "accent":
- rgb, err := color.GetAccentColor(env)
+ rgb, err := ansi.GetAccentColor(env)
if err != nil {
fmt.Println("error getting accent color:", err.Error())
return
diff --git a/src/color/ansi_writer.go b/src/color/ansi_writer.go
deleted file mode 100644
index 3c57b1cf..00000000
--- a/src/color/ansi_writer.go
+++ /dev/null
@@ -1,520 +0,0 @@
-package color
-
-import (
- "fmt"
- "strings"
-
- "github.com/jandedobbeleer/oh-my-posh/regex"
- "github.com/jandedobbeleer/oh-my-posh/shell"
- "github.com/mattn/go-runewidth"
-)
-
-type Writer interface {
- Init(shellName string)
- Write(background, foreground, text string)
- String() (string, int)
- SetColors(background, foreground string)
- SetParentColors(background, foreground string)
- CarriageForward() string
- GetCursorForRightWrite(length, offset int) string
- ChangeLine(numberOfLines int) string
- ConsolePwd(pwdType, userName, hostName, pwd string) string
- ClearAfter() string
- FormatTitle(title string) string
- FormatText(text string) string
- SaveCursorPosition() string
- RestoreCursorPosition() string
- LineBreak() string
- TrimAnsi(text string) string
-}
-
-var (
- knownStyles = []*style{
- {AnchorStart: ``, AnchorEnd: ``, Start: "\x1b[1m", End: "\x1b[22m"},
- {AnchorStart: ``, AnchorEnd: ``, Start: "\x1b[4m", End: "\x1b[24m"},
- {AnchorStart: ``, AnchorEnd: ``, Start: "\x1b[53m", End: "\x1b[55m"},
- {AnchorStart: ``, AnchorEnd: ``, Start: "\x1b[3m", End: "\x1b[23m"},
- {AnchorStart: ``, AnchorEnd: ``, Start: "\x1b[9m", End: "\x1b[29m"},
- {AnchorStart: ``, AnchorEnd: ``, Start: "\x1b[2m", End: "\x1b[22m"},
- {AnchorStart: ``, AnchorEnd: ``, Start: "\x1b[5m", End: "\x1b[25m"},
- {AnchorStart: ``, AnchorEnd: ``, Start: "\x1b[7m", End: "\x1b[27m"},
- }
- colorStyle = &style{AnchorStart: "COLOR", AnchorEnd: `>`, End: "\x1b[0m"}
-)
-
-type style struct {
- AnchorStart string
- AnchorEnd string
- Start string
- End string
-}
-
-type Color struct {
- Background string
- Foreground string
-}
-
-const (
- // Transparent implies a transparent color
- Transparent = "transparent"
- // Accent is the OS accent color
- Accent = "accent"
- // ParentBackground takes the previous segment's background color
- ParentBackground = "parentBackground"
- // ParentForeground takes the previous segment's color
- ParentForeground = "parentForeground"
- // Background takes the current segment's background color
- Background = "background"
- // Foreground takes the current segment's foreground color
- Foreground = "foreground"
-
- anchorRegex = `^(?P<(?P[^,>]+)?,?(?P[^>]+)?>)`
- colorise = "\x1b[%sm"
- transparent = "\x1b[%s;49m\x1b[7m"
-
- AnsiRegex = "[\u001B\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))"
-
- OSC99 string = "osc99"
- OSC7 string = "osc7"
- OSC51 string = "osc51"
-)
-
-// AnsiWriter writes colorized ANSI strings
-type AnsiWriter struct {
- TerminalBackground string
- Colors *Color
- ParentColors []*Color
- AnsiColors AnsiColors
- Plain bool
-
- builder strings.Builder
- length int
-
- foreground AnsiColor
- background AnsiColor
- currentForeground AnsiColor
- currentBackground AnsiColor
- runes []rune
-
- shell string
- format string
- left string
- right string
- title string
- linechange string
- clearBelow string
- clearLine string
- saveCursorPosition string
- restoreCursorPosition string
- escapeLeft string
- escapeRight string
- hyperlink string
- hyperlinkRegex string
- osc99 string
- osc7 string
- osc51 string
-}
-
-func (a *AnsiWriter) Init(shellName string) {
- a.shell = shellName
- switch a.shell {
- case shell.BASH:
- a.format = "\\[%s\\]"
- a.linechange = "\\[\x1b[%d%s\\]"
- a.right = "\\[\x1b[%dC\\]"
- a.left = "\\[\x1b[%dD\\]"
- a.clearBelow = "\\[\x1b[0J\\]"
- a.clearLine = "\\[\x1b[K\\]"
- a.saveCursorPosition = "\\[\x1b7\\]"
- a.restoreCursorPosition = "\\[\x1b8\\]"
- a.title = "\\[\x1b]0;%s\007\\]"
- a.escapeLeft = "\\["
- a.escapeRight = "\\]"
- a.hyperlink = "\\[\x1b]8;;%s\x1b\\\\\\]%s\\[\x1b]8;;\x1b\\\\\\]"
- a.hyperlinkRegex = `(?P\\\[\x1b\]8;;(.+)\x1b\\\\\\\](?P.+)\\\[\x1b\]8;;\x1b\\\\\\\])`
- a.osc99 = "\\[\x1b]9;9;\"%s\"\x1b\\\\\\]"
- a.osc7 = "\\[\x1b]7;\"file://%s/%s\"\x1b\\\\\\]"
- a.osc51 = "\\[\x1b]51;A;%s@%s:%s\x1b\\\\\\]"
- case "zsh":
- a.format = "%%{%s%%}"
- a.linechange = "%%{\x1b[%d%s%%}"
- a.right = "%%{\x1b[%dC%%}"
- a.left = "%%{\x1b[%dD%%}"
- a.clearBelow = "%{\x1b[0J%}"
- a.clearLine = "%{\x1b[K%}"
- a.saveCursorPosition = "%{\x1b7%}"
- a.restoreCursorPosition = "%{\x1b8%}"
- a.title = "%%{\x1b]0;%s\007%%}"
- a.escapeLeft = "%{"
- a.escapeRight = "%}"
- a.hyperlink = "%%{\x1b]8;;%s\x1b\\%%}%s%%{\x1b]8;;\x1b\\%%}"
- a.hyperlinkRegex = `(?P%{\x1b]8;;(.+)\x1b\\%}(?P.+)%{\x1b]8;;\x1b\\%})`
- a.osc99 = "%%{\x1b]9;9;\"%s\"\x1b\\%%}"
- a.osc7 = "%%{\x1b]7;file:\"//%s/%s\"\x1b\\%%}"
- a.osc51 = "%%{\x1b]51;A%s@%s:%s\x1b\\%%}"
- default:
- a.linechange = "\x1b[%d%s"
- a.right = "\x1b[%dC"
- a.left = "\x1b[%dD"
- a.clearBelow = "\x1b[0J"
- a.clearLine = "\x1b[K"
- a.saveCursorPosition = "\x1b7"
- a.restoreCursorPosition = "\x1b8"
- a.title = "\x1b]0;%s\007"
- // when in fish on Linux, it seems hyperlinks ending with \\ print a \
- // unlike on macOS. However, this is a fish bug, so do not try to fix it here:
- // https://github.com/JanDeDobbeleer/oh-my-posh/pull/3288#issuecomment-1369137068
- a.hyperlink = "\x1b]8;;%s\x1b\\%s\x1b]8;;\x1b\\"
- a.hyperlinkRegex = "(?P\x1b]8;;(.+)\x1b\\\\\\\\?(?P.+)\x1b]8;;\x1b\\\\)"
- a.osc99 = "\x1b]9;9;\"%s\"\x1b\\"
- a.osc7 = "\x1b]7;\"file://%s/%s\"\x1b\\"
- a.osc51 = "\x1b]51;A%s@%s:%s\x1b\\"
- }
-}
-
-func (a *AnsiWriter) SetColors(background, foreground string) {
- a.Colors = &Color{
- Background: background,
- Foreground: foreground,
- }
-}
-
-func (a *AnsiWriter) SetParentColors(background, foreground string) {
- if a.ParentColors == nil {
- a.ParentColors = make([]*Color, 0)
- }
- a.ParentColors = append([]*Color{{
- Background: background,
- Foreground: foreground,
- }}, a.ParentColors...)
-}
-
-func (a *AnsiWriter) CarriageForward() string {
- return fmt.Sprintf(a.right, 1000)
-}
-
-func (a *AnsiWriter) GetCursorForRightWrite(length, offset int) string {
- strippedLen := length + (-offset)
- return fmt.Sprintf(a.left, strippedLen)
-}
-
-func (a *AnsiWriter) ChangeLine(numberOfLines int) string {
- if a.Plain {
- return ""
- }
- position := "B"
- if numberOfLines < 0 {
- position = "F"
- numberOfLines = -numberOfLines
- }
- return fmt.Sprintf(a.linechange, numberOfLines, position)
-}
-
-func (a *AnsiWriter) ConsolePwd(pwdType, userName, hostName, pwd string) string {
- if a.Plain {
- return ""
- }
- if strings.HasSuffix(pwd, ":") {
- pwd += "\\"
- }
- switch pwdType {
- case OSC7:
- return fmt.Sprintf(a.osc7, hostName, pwd)
- case OSC51:
- return fmt.Sprintf(a.osc51, userName, hostName, pwd)
- case OSC99:
- fallthrough
- default:
- return fmt.Sprintf(a.osc99, pwd)
- }
-}
-
-func (a *AnsiWriter) ClearAfter() string {
- if a.Plain {
- return ""
- }
- return a.clearLine + a.clearBelow
-}
-
-func (a *AnsiWriter) FormatTitle(title string) string {
- title = a.TrimAnsi(title)
- // we have to do this to prevent bash/zsh from misidentifying escape sequences
- switch a.shell {
- case shell.BASH:
- title = strings.NewReplacer("`", "\\`", `\`, `\\`).Replace(title)
- case shell.ZSH:
- title = strings.NewReplacer("`", "\\`", `%`, `%%`).Replace(title)
- }
- return fmt.Sprintf(a.title, title)
-}
-
-func (a *AnsiWriter) FormatText(text string) string {
- return fmt.Sprintf(a.format, text)
-}
-
-func (a *AnsiWriter) SaveCursorPosition() string {
- return a.saveCursorPosition
-}
-
-func (a *AnsiWriter) RestoreCursorPosition() string {
- return a.restoreCursorPosition
-}
-
-func (a *AnsiWriter) LineBreak() string {
- cr := fmt.Sprintf(a.left, 1000)
- lf := fmt.Sprintf(a.linechange, 1, "B")
- return cr + lf
-}
-
-func (a *AnsiWriter) Write(background, foreground, text string) {
- if len(text) == 0 {
- return
- }
-
- if !a.Plain {
- text = a.GenerateHyperlink(text)
- }
-
- a.background, a.foreground = a.asAnsiColors(background, foreground)
- // default to white foreground
- if a.foreground.IsEmpty() {
- a.foreground = a.AnsiColors.AnsiColorFromString("white", false)
- }
- // validate if we start with a color override
- match := regex.FindNamedRegexMatch(anchorRegex, text)
- if len(match) != 0 {
- colorOverride := true
- for _, style := range knownStyles {
- if match["ANCHOR"] != style.AnchorStart {
- continue
- }
- a.printEscapedAnsiString(style.Start)
- colorOverride = false
- }
- if colorOverride {
- a.currentBackground, a.currentForeground = a.asAnsiColors(match["BG"], match["FG"])
- }
- }
- a.writeSegmentColors()
-
- text = text[len(match["ANCHOR"]):]
- a.runes = []rune(text)
-
- for i := 0; i < len(a.runes); i++ {
- s := a.runes[i]
- // ignore everything which isn't overriding
- if s != '<' {
- a.length += runewidth.RuneWidth(s)
- a.builder.WriteRune(s)
- continue
- }
-
- // color/end overrides first
- text = string(a.runes[i:])
- match = regex.FindNamedRegexMatch(anchorRegex, text)
- if len(match) > 0 {
- i = a.writeColorOverrides(match, background, i)
- continue
- }
-
- a.length += runewidth.RuneWidth(s)
- a.builder.WriteRune(s)
- }
-
- a.printEscapedAnsiString(colorStyle.End)
-
- // reset current
- a.currentBackground = ""
- a.currentForeground = ""
-}
-
-func (a *AnsiWriter) printEscapedAnsiString(text string) {
- if a.Plain {
- return
- }
- if len(a.format) == 0 {
- a.builder.WriteString(text)
- return
- }
- a.builder.WriteString(fmt.Sprintf(a.format, text))
-}
-
-func (a *AnsiWriter) getAnsiFromColorString(colorString string, isBackground bool) AnsiColor {
- return a.AnsiColors.AnsiColorFromString(colorString, isBackground)
-}
-
-func (a *AnsiWriter) writeSegmentColors() {
- // use correct starting colors
- bg := a.background
- fg := a.foreground
- if !a.currentBackground.IsEmpty() {
- bg = a.currentBackground
- }
- if !a.currentForeground.IsEmpty() {
- fg = a.currentForeground
- }
-
- if fg.IsTransparent() && len(a.TerminalBackground) != 0 {
- background := a.getAnsiFromColorString(a.TerminalBackground, false)
- a.printEscapedAnsiString(fmt.Sprintf(colorise, background))
- a.printEscapedAnsiString(fmt.Sprintf(colorise, bg.ToForeground()))
- } else if fg.IsTransparent() && !bg.IsEmpty() {
- a.printEscapedAnsiString(fmt.Sprintf(transparent, bg))
- } else {
- if !bg.IsEmpty() && !bg.IsTransparent() {
- a.printEscapedAnsiString(fmt.Sprintf(colorise, bg))
- }
- if !fg.IsEmpty() {
- a.printEscapedAnsiString(fmt.Sprintf(colorise, fg))
- }
- }
-
- // set current colors
- a.currentBackground = bg
- a.currentForeground = fg
-}
-
-func (a *AnsiWriter) writeColorOverrides(match map[string]string, background string, i int) (position int) {
- position = i
- // check color reset first
- if match["ANCHOR"] == colorStyle.AnchorEnd {
- // make sure to reset the colors if needed
- position += len([]rune(colorStyle.AnchorEnd)) - 1
- // do not restore colors at the end of the string, we print it anyways
- if position == len(a.runes)-1 {
- return
- }
- if a.currentBackground != a.background {
- a.printEscapedAnsiString(fmt.Sprintf(colorise, a.background))
- }
- if a.currentForeground != a.foreground {
- a.printEscapedAnsiString(fmt.Sprintf(colorise, a.foreground))
- }
- return
- }
-
- position += len([]rune(match["ANCHOR"])) - 1
-
- for _, style := range knownStyles {
- if style.AnchorEnd == match["ANCHOR"] {
- a.printEscapedAnsiString(style.End)
- return
- }
- if style.AnchorStart == match["ANCHOR"] {
- a.printEscapedAnsiString(style.Start)
- return
- }
- }
-
- if match["FG"] == Transparent && len(match["BG"]) == 0 {
- match["BG"] = background
- }
- a.currentBackground, a.currentForeground = a.asAnsiColors(match["BG"], match["FG"])
-
- // make sure we have colors
- if a.currentForeground.IsEmpty() {
- a.currentForeground = a.foreground
- }
- if a.currentBackground.IsEmpty() {
- a.currentBackground = a.background
- }
-
- if a.currentForeground.IsTransparent() && len(a.TerminalBackground) != 0 {
- background := a.getAnsiFromColorString(a.TerminalBackground, false)
- a.printEscapedAnsiString(fmt.Sprintf(colorise, background))
- a.printEscapedAnsiString(fmt.Sprintf(colorise, a.currentBackground.ToForeground()))
- return
- }
-
- if a.currentForeground.IsTransparent() && !a.currentBackground.IsTransparent() {
- a.printEscapedAnsiString(fmt.Sprintf(transparent, a.currentBackground))
- return
- }
-
- if a.currentBackground != a.background {
- // end the colors in case we have a transparent background
- if a.currentBackground.IsTransparent() {
- a.printEscapedAnsiString(colorStyle.End)
- } else {
- a.printEscapedAnsiString(fmt.Sprintf(colorise, a.currentBackground))
- }
- }
-
- if a.currentForeground != a.foreground || a.currentBackground.IsTransparent() {
- a.printEscapedAnsiString(fmt.Sprintf(colorise, a.currentForeground))
- }
-
- return position
-}
-
-func (a *AnsiWriter) asAnsiColors(background, foreground string) (AnsiColor, AnsiColor) {
- background = a.expandKeyword(background)
- foreground = a.expandKeyword(foreground)
- inverted := foreground == Transparent && len(background) != 0
- backgroundAnsi := a.getAnsiFromColorString(background, !inverted)
- foregroundAnsi := a.getAnsiFromColorString(foreground, false)
- return backgroundAnsi, foregroundAnsi
-}
-
-func (a *AnsiWriter) isKeyword(color string) bool {
- switch color {
- case Transparent, ParentBackground, ParentForeground, Background, Foreground:
- return true
- default:
- return false
- }
-}
-
-func (a *AnsiWriter) expandKeyword(keyword string) string {
- resolveParentColor := func(keyword string) string {
- for _, color := range a.ParentColors {
- if color == nil {
- return Transparent
- }
- switch keyword {
- case ParentBackground:
- keyword = color.Background
- case ParentForeground:
- keyword = color.Foreground
- default:
- if len(keyword) == 0 {
- return Transparent
- }
- return keyword
- }
- }
- if len(keyword) == 0 {
- return Transparent
- }
- return keyword
- }
- resolveKeyword := func(keyword string) string {
- switch {
- case keyword == Background && a.Colors != nil:
- return a.Colors.Background
- case keyword == Foreground && a.Colors != nil:
- return a.Colors.Foreground
- case (keyword == ParentBackground || keyword == ParentForeground) && a.ParentColors != nil:
- return resolveParentColor(keyword)
- default:
- return Transparent
- }
- }
- for ok := a.isKeyword(keyword); ok; ok = a.isKeyword(keyword) {
- resolved := resolveKeyword(keyword)
- if resolved == keyword {
- break
- }
- keyword = resolved
- }
- return keyword
-}
-
-func (a *AnsiWriter) String() (string, int) {
- defer func() {
- a.length = 0
- a.builder.Reset()
- }()
-
- return a.builder.String(), a.length
-}
diff --git a/src/engine/block.go b/src/engine/block.go
index 96d345fb..10815177 100644
--- a/src/engine/block.go
+++ b/src/engine/block.go
@@ -4,7 +4,7 @@ import (
"sync"
"time"
- "github.com/jandedobbeleer/oh-my-posh/color"
+ "github.com/jandedobbeleer/oh-my-posh/ansi"
"github.com/jandedobbeleer/oh-my-posh/platform"
"github.com/jandedobbeleer/oh-my-posh/shell"
)
@@ -52,19 +52,19 @@ type Block struct {
MinWidth int `json:"min_width,omitempty"`
env platform.Environment
- writer color.Writer
+ writer *ansi.Writer
activeSegment *Segment
previousActiveSegment *Segment
}
-func (b *Block) Init(env platform.Environment, writer color.Writer) {
+func (b *Block) Init(env platform.Environment, writer *ansi.Writer) {
b.env = env
b.writer = writer
b.executeSegmentLogic()
}
func (b *Block) InitPlain(env platform.Environment, config *Config) {
- b.writer = &color.AnsiWriter{
+ b.writer = &ansi.Writer{
TerminalBackground: shell.ConsoleBackgroundColor(env, config.TerminalBackground),
AnsiColors: config.MakeColors(),
}
@@ -141,14 +141,14 @@ func (b *Block) renderActiveSegment() {
b.writePowerline(false)
switch b.activeSegment.style() {
case Plain, Powerline:
- b.writer.Write(color.Background, color.Foreground, b.activeSegment.text)
+ b.writer.Write(ansi.Background, ansi.Foreground, b.activeSegment.text)
case Diamond:
- b.writer.Write(color.Transparent, color.Background, b.activeSegment.LeadingDiamond)
- b.writer.Write(color.Background, color.Foreground, b.activeSegment.text)
- b.writer.Write(color.Transparent, color.Background, b.activeSegment.TrailingDiamond)
+ b.writer.Write(ansi.Transparent, ansi.Background, b.activeSegment.LeadingDiamond)
+ b.writer.Write(ansi.Background, ansi.Foreground, b.activeSegment.text)
+ b.writer.Write(ansi.Transparent, ansi.Background, b.activeSegment.TrailingDiamond)
case Accordion:
if b.activeSegment.Enabled {
- b.writer.Write(color.Background, color.Foreground, b.activeSegment.text)
+ b.writer.Write(ansi.Background, ansi.Foreground, b.activeSegment.text)
}
}
b.previousActiveSegment = b.activeSegment
@@ -169,12 +169,12 @@ func (b *Block) writePowerline(final bool) {
if len(symbol) == 0 {
return
}
- bgColor := color.Background
+ bgColor := ansi.Background
if final || !b.activeSegment.isPowerline() {
- bgColor = color.Transparent
+ bgColor = ansi.Transparent
}
if b.activeSegment.style() == Diamond && len(b.activeSegment.LeadingDiamond) == 0 {
- bgColor = color.Background
+ bgColor = ansi.Background
}
if b.activeSegment.InvertPowerline {
b.writer.Write(b.getPowerlineColor(), bgColor, symbol)
@@ -185,7 +185,7 @@ func (b *Block) writePowerline(final bool) {
func (b *Block) getPowerlineColor() string {
if b.previousActiveSegment == nil {
- return color.Transparent
+ return ansi.Transparent
}
if b.previousActiveSegment.style() == Diamond && len(b.previousActiveSegment.TrailingDiamond) == 0 {
return b.previousActiveSegment.background()
@@ -194,7 +194,7 @@ func (b *Block) getPowerlineColor() string {
return b.previousActiveSegment.background()
}
if !b.previousActiveSegment.isPowerline() {
- return color.Transparent
+ return ansi.Transparent
}
return b.previousActiveSegment.background()
}
diff --git a/src/engine/config.go b/src/engine/config.go
index 93c7d118..a7ab48a7 100644
--- a/src/engine/config.go
+++ b/src/engine/config.go
@@ -10,7 +10,7 @@ import (
"strings"
"time"
- "github.com/jandedobbeleer/oh-my-posh/color"
+ "github.com/jandedobbeleer/oh-my-posh/ansi"
"github.com/jandedobbeleer/oh-my-posh/platform"
"github.com/jandedobbeleer/oh-my-posh/properties"
"github.com/jandedobbeleer/oh-my-posh/segments"
@@ -33,21 +33,21 @@ const (
// Config holds all the theme for rendering the prompt
type Config struct {
- Version int `json:"version"`
- FinalSpace bool `json:"final_space,omitempty"`
- ConsoleTitleTemplate string `json:"console_title_template,omitempty"`
- TerminalBackground string `json:"terminal_background,omitempty"`
- AccentColor string `json:"accent_color,omitempty"`
- Blocks []*Block `json:"blocks,omitempty"`
- Tooltips []*Segment `json:"tooltips,omitempty"`
- TransientPrompt *Segment `json:"transient_prompt,omitempty"`
- ValidLine *Segment `json:"valid_line,omitempty"`
- ErrorLine *Segment `json:"error_line,omitempty"`
- SecondaryPrompt *Segment `json:"secondary_prompt,omitempty"`
- DebugPrompt *Segment `json:"debug_prompt,omitempty"`
- Palette color.Palette `json:"palette,omitempty"`
- Palettes *color.Palettes `json:"palettes,omitempty"`
- PWD string `json:"pwd,omitempty"`
+ Version int `json:"version"`
+ FinalSpace bool `json:"final_space,omitempty"`
+ ConsoleTitleTemplate string `json:"console_title_template,omitempty"`
+ TerminalBackground string `json:"terminal_background,omitempty"`
+ AccentColor string `json:"accent_color,omitempty"`
+ Blocks []*Block `json:"blocks,omitempty"`
+ Tooltips []*Segment `json:"tooltips,omitempty"`
+ TransientPrompt *Segment `json:"transient_prompt,omitempty"`
+ ValidLine *Segment `json:"valid_line,omitempty"`
+ ErrorLine *Segment `json:"error_line,omitempty"`
+ SecondaryPrompt *Segment `json:"secondary_prompt,omitempty"`
+ DebugPrompt *Segment `json:"debug_prompt,omitempty"`
+ Palette ansi.Palette `json:"palette,omitempty"`
+ Palettes *ansi.Palettes `json:"palettes,omitempty"`
+ PWD string `json:"pwd,omitempty"`
// Deprecated
OSC99 bool `json:"osc99,omitempty"`
@@ -63,12 +63,12 @@ type Config struct {
// MakeColors creates instance of AnsiColors to use in AnsiWriter according to
// environment and configuration.
-func (cfg *Config) MakeColors() color.AnsiColors {
+func (cfg *Config) MakeColors() ansi.Colors {
cacheDisabled := cfg.env.Getenv("OMP_CACHE_DISABLED") == "1"
- return color.MakeColors(cfg.getPalette(), !cacheDisabled, cfg.AccentColor, cfg.env)
+ return ansi.MakeColors(cfg.getPalette(), !cacheDisabled, cfg.AccentColor, cfg.env)
}
-func (cfg *Config) getPalette() color.Palette {
+func (cfg *Config) getPalette() ansi.Palette {
if cfg.Palettes == nil {
return cfg.Palette
}
@@ -387,7 +387,7 @@ func defaultConfig(warning bool) *Config {
},
},
ConsoleTitleTemplate: "{{ .Shell }} in {{ .Folder }}",
- Palette: color.Palette{
+ Palette: ansi.Palette{
"black": "#262B44",
"blue": "#4B95E9",
"green": "#59C9A5",
diff --git a/src/engine/config_test.go b/src/engine/config_test.go
index c21836a9..fcdf1c03 100644
--- a/src/engine/config_test.go
+++ b/src/engine/config_test.go
@@ -3,7 +3,7 @@ package engine
import (
"testing"
- "github.com/jandedobbeleer/oh-my-posh/color"
+ "github.com/jandedobbeleer/oh-my-posh/ansi"
"github.com/jandedobbeleer/oh-my-posh/mock"
"github.com/jandedobbeleer/oh-my-posh/platform"
"github.com/jandedobbeleer/oh-my-posh/segments"
@@ -61,21 +61,21 @@ func TestEscapeGlyphs(t *testing.T) {
}
func TestGetPalette(t *testing.T) {
- palette := color.Palette{
+ palette := ansi.Palette{
"red": "#ff0000",
"blue": "#0000ff",
}
cases := []struct {
Case string
- Palettes *color.Palettes
- Palette color.Palette
- ExpectedPalette color.Palette
+ Palettes *ansi.Palettes
+ Palette ansi.Palette
+ ExpectedPalette ansi.Palette
}{
{
Case: "match",
- Palettes: &color.Palettes{
+ Palettes: &ansi.Palettes{
Template: "{{ .Shell }}",
- List: map[string]color.Palette{
+ List: map[string]ansi.Palette{
"bash": palette,
"zsh": {
"red": "#ff0001",
@@ -87,9 +87,9 @@ func TestGetPalette(t *testing.T) {
},
{
Case: "no match, no fallback",
- Palettes: &color.Palettes{
+ Palettes: &ansi.Palettes{
Template: "{{ .Shell }}",
- List: map[string]color.Palette{
+ List: map[string]ansi.Palette{
"fish": palette,
"zsh": {
"red": "#ff0001",
@@ -101,9 +101,9 @@ func TestGetPalette(t *testing.T) {
},
{
Case: "no match, default",
- Palettes: &color.Palettes{
+ Palettes: &ansi.Palettes{
Template: "{{ .Shell }}",
- List: map[string]color.Palette{
+ List: map[string]ansi.Palette{
"zsh": {
"red": "#ff0001",
"blue": "#0000fb",
diff --git a/src/engine/engine.go b/src/engine/engine.go
index f4bf97b8..13559453 100644
--- a/src/engine/engine.go
+++ b/src/engine/engine.go
@@ -5,7 +5,7 @@ import (
"strings"
"time"
- "github.com/jandedobbeleer/oh-my-posh/color"
+ "github.com/jandedobbeleer/oh-my-posh/ansi"
"github.com/jandedobbeleer/oh-my-posh/platform"
"github.com/jandedobbeleer/oh-my-posh/shell"
"github.com/jandedobbeleer/oh-my-posh/template"
@@ -14,7 +14,7 @@ import (
type Engine struct {
Config *Config
Env platform.Environment
- Writer color.Writer
+ Writer *ansi.Writer
Plain bool
console strings.Builder
@@ -78,7 +78,7 @@ func (e *Engine) printPWD() {
cwd := e.Env.Pwd()
// Backwards compatibility for deprecated OSC99
if e.Config.OSC99 {
- e.write(e.Writer.ConsolePwd(color.OSC99, "", "", cwd))
+ e.write(e.Writer.ConsolePwd(ansi.OSC99, "", "", cwd))
return
}
// Allow template logic to define when to enable the PWD (when supported)
@@ -304,7 +304,7 @@ func (e *Engine) print() string {
}
// in bash, the entire rprompt needs to be escaped for the prompt to be interpreted correctly
// see https://github.com/jandedobbeleer/oh-my-posh/pull/2398
- writer := &color.AnsiWriter{}
+ writer := &ansi.Writer{}
writer.Init(shell.GENERIC)
prompt := writer.SaveCursorPosition()
prompt += writer.CarriageForward()
diff --git a/src/engine/engine_test.go b/src/engine/engine_test.go
index 88189223..dc5e8c0e 100644
--- a/src/engine/engine_test.go
+++ b/src/engine/engine_test.go
@@ -4,7 +4,7 @@ import (
"errors"
"testing"
- "github.com/jandedobbeleer/oh-my-posh/color"
+ "github.com/jandedobbeleer/oh-my-posh/ansi"
"github.com/jandedobbeleer/oh-my-posh/mock"
"github.com/jandedobbeleer/oh-my-posh/platform"
"github.com/jandedobbeleer/oh-my-posh/shell"
@@ -52,9 +52,9 @@ func TestPrintPWD(t *testing.T) {
OSC99 bool
}{
{Case: "Empty PWD"},
- {Case: "OSC99", PWD: color.OSC99, Expected: "\x1b]9;9;\"pwd\"\x1b\\"},
- {Case: "OSC7", PWD: color.OSC7, Expected: "\x1b]7;\"file://host/pwd\"\x1b\\"},
- {Case: "OSC51", PWD: color.OSC51, Expected: "\x1b]51;Auser@host:pwd\x1b\\"},
+ {Case: "OSC99", PWD: ansi.OSC99, Expected: "\x1b]9;9;\"pwd\"\x1b\\"},
+ {Case: "OSC7", PWD: ansi.OSC7, Expected: "\x1b]7;\"file://host/pwd\"\x1b\\"},
+ {Case: "OSC51", PWD: ansi.OSC51, Expected: "\x1b]51;Auser@host:pwd\x1b\\"},
{Case: "Deprecated OSC99", OSC99: true, Expected: "\x1b]9;9;\"pwd\"\x1b\\"},
{Case: "Template (empty)", PWD: "{{ if eq .Shell \"pwsh\" }}osc7{{ end }}"},
{Case: "Template (non empty)", PWD: "{{ if eq .Shell \"shell\" }}osc7{{ end }}", Expected: "\x1b]7;\"file://host/pwd\"\x1b\\"},
@@ -71,7 +71,7 @@ func TestPrintPWD(t *testing.T) {
Shell: "shell",
})
- writer := &color.AnsiWriter{}
+ writer := &ansi.Writer{}
writer.Init(shell.GENERIC)
engine := &Engine{
Env: env,
@@ -102,7 +102,7 @@ func engineRender() {
defer testClearDefaultConfig()
writerColors := cfg.MakeColors()
- writer := &color.AnsiWriter{
+ writer := &ansi.Writer{
TerminalBackground: shell.ConsoleBackgroundColor(env, cfg.TerminalBackground),
AnsiColors: writerColors,
}
@@ -173,17 +173,17 @@ func TestGetTitle(t *testing.T) {
PWD: tc.Cwd,
Folder: "vagrant",
})
- ansi := &color.AnsiWriter{}
- ansi.Init(shell.GENERIC)
+ writer := &ansi.Writer{}
+ writer.Init(shell.GENERIC)
engine := &Engine{
Config: &Config{
ConsoleTitleTemplate: tc.Template,
},
- Writer: ansi,
+ Writer: writer,
Env: env,
}
title := engine.getTitleTemplateText()
- got := ansi.FormatTitle(title)
+ got := writer.FormatTitle(title)
assert.Equal(t, tc.Expected, got)
}
}
@@ -231,17 +231,17 @@ func TestGetConsoleTitleIfGethostnameReturnsError(t *testing.T) {
Root: tc.Root,
HostName: "",
})
- ansi := &color.AnsiWriter{}
- ansi.Init(shell.GENERIC)
+ writer := &ansi.Writer{}
+ writer.Init(shell.GENERIC)
engine := &Engine{
Config: &Config{
ConsoleTitleTemplate: tc.Template,
},
- Writer: ansi,
+ Writer: writer,
Env: env,
}
title := engine.getTitleTemplateText()
- got := ansi.FormatTitle(title)
+ got := writer.FormatTitle(title)
assert.Equal(t, tc.Expected, got)
}
}
diff --git a/src/engine/image.go b/src/engine/image.go
index 16b5d983..cccaaad3 100644
--- a/src/engine/image.go
+++ b/src/engine/image.go
@@ -30,7 +30,7 @@ import (
"strings"
"unicode/utf8"
- "github.com/jandedobbeleer/oh-my-posh/color"
+ "github.com/jandedobbeleer/oh-my-posh/ansi"
"github.com/jandedobbeleer/oh-my-posh/regex"
"github.com/esimov/stackblur-go"
@@ -110,7 +110,7 @@ type ImageRenderer struct {
CursorPadding int
RPromptOffset int
BgColor string
- Ansi *color.AnsiWriter
+ Ansi *ansi.Writer
Path string
@@ -278,7 +278,7 @@ func (ir *ImageRenderer) lenWithoutANSI(text string) int {
for _, match := range matches {
text = strings.ReplaceAll(text, match[str], "")
}
- stripped := regex.ReplaceAllString(color.AnsiRegex, text, "")
+ stripped := regex.ReplaceAllString(ansi.AnsiRegex, text, "")
length := utf8.RuneCountInString(stripped)
for _, rune := range stripped {
length += ir.runeAdditionalWidth(rune)
diff --git a/src/engine/image_test.go b/src/engine/image_test.go
index f2831d19..b989b192 100644
--- a/src/engine/image_test.go
+++ b/src/engine/image_test.go
@@ -6,7 +6,7 @@ import (
"path/filepath"
"testing"
- "github.com/jandedobbeleer/oh-my-posh/color"
+ "github.com/jandedobbeleer/oh-my-posh/ansi"
"github.com/jandedobbeleer/oh-my-posh/shell"
"github.com/stretchr/testify/assert"
@@ -33,11 +33,11 @@ func runImageTest(config, content string) (string, error) {
return "", err
}
defer os.Remove(file.Name())
- ansi := &color.AnsiWriter{}
- ansi.Init(shell.GENERIC)
+ writer := &ansi.Writer{}
+ writer.Init(shell.GENERIC)
image := &ImageRenderer{
AnsiString: content,
- Ansi: ansi,
+ Ansi: writer,
}
image.Init(config)
err = image.SavePNG()
diff --git a/src/engine/new.go b/src/engine/new.go
index 5dcc10c1..4ba2fd92 100644
--- a/src/engine/new.go
+++ b/src/engine/new.go
@@ -1,7 +1,7 @@
package engine
import (
- "github.com/jandedobbeleer/oh-my-posh/color"
+ "github.com/jandedobbeleer/oh-my-posh/ansi"
"github.com/jandedobbeleer/oh-my-posh/platform"
"github.com/jandedobbeleer/oh-my-posh/shell"
)
@@ -17,7 +17,7 @@ func New(flags *platform.Flags) *Engine {
env.Init()
cfg := LoadConfig(env)
- ansiWriter := &color.AnsiWriter{
+ ansiWriter := &ansi.Writer{
TerminalBackground: shell.ConsoleBackgroundColor(env, cfg.TerminalBackground),
AnsiColors: cfg.MakeColors(),
Plain: flags.Plain,
diff --git a/src/properties/properties.go b/src/properties/properties.go
index 1793a83e..579c313b 100644
--- a/src/properties/properties.go
+++ b/src/properties/properties.go
@@ -3,7 +3,7 @@ package properties
import (
"fmt"
- "github.com/jandedobbeleer/oh-my-posh/color"
+ "github.com/jandedobbeleer/oh-my-posh/ansi"
"github.com/jandedobbeleer/oh-my-posh/regex"
)
@@ -70,7 +70,7 @@ func (m Map) GetColor(property Property, defaultValue string) string {
return defaultValue
}
colorString := fmt.Sprint(val)
- if color.IsAnsiColorName(colorString) {
+ if ansi.IsAnsiColorName(colorString) {
return colorString
}
values := regex.FindNamedRegexMatch(`(?P#[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}|p:.*)`, colorString)