mirror of
https://github.com/JanDeDobbeleer/oh-my-posh.git
synced 2025-02-21 02:55:37 -08:00
refactor: rename color module to ansi
This commit is contained in:
parent
005445b9fe
commit
48d8a522bf
501
src/ansi/ansi_writer.go
Normal file
501
src/ansi/ansi_writer.go
Normal file
|
@ -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: `<b>`, AnchorEnd: `</b>`, Start: "\x1b[1m", End: "\x1b[22m"},
|
||||
{AnchorStart: `<u>`, AnchorEnd: `</u>`, Start: "\x1b[4m", End: "\x1b[24m"},
|
||||
{AnchorStart: `<o>`, AnchorEnd: `</o>`, Start: "\x1b[53m", End: "\x1b[55m"},
|
||||
{AnchorStart: `<i>`, AnchorEnd: `</i>`, Start: "\x1b[3m", End: "\x1b[23m"},
|
||||
{AnchorStart: `<s>`, AnchorEnd: `</s>`, Start: "\x1b[9m", End: "\x1b[29m"},
|
||||
{AnchorStart: `<d>`, AnchorEnd: `</d>`, Start: "\x1b[2m", End: "\x1b[22m"},
|
||||
{AnchorStart: `<f>`, AnchorEnd: `</f>`, Start: "\x1b[5m", End: "\x1b[25m"},
|
||||
{AnchorStart: `<r>`, AnchorEnd: `</r>`, 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<ANCHOR><(?P<FG>[^,>]+)?,?(?P<BG>[^>]+)?>)`
|
||||
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<STR>\\\[\x1b\]8;;(.+)\x1b\\\\\\\](?P<TEXT>.+)\\\[\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<STR>%{\x1b]8;;(.+)\x1b\\%}(?P<TEXT>.+)%{\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<STR>\x1b]8;;(.+)\x1b\\\\\\\\?(?P<TEXT>.+)\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
|
||||
}
|
|
@ -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<ALL>(?:\\[(?P<TEXT>.+)\\])(?:\\((?P<URL>.*)\\)))", 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{
|
|
@ -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)
|
|
@ -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: "<b>test</b>",
|
||||
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: "<b><#ffffff>test</></b>",
|
||||
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><b>test</b></>",
|
||||
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 <parentForeground>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 <black,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 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 <parentForeground>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 <parentForeground,parentBackground>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 <parentBackground,parentForeground>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, <red>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: "<foreground>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: "<blue,white>G</><red,white>o</><yellow,white>o</><blue,white>g</><green,white>l</><red,white>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: "<background>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: "<background,foreground>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{},
|
|
@ -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 {
|
|
@ -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{}
|
|
@ -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)),
|
||||
}
|
|
@ -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(),
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package color
|
||||
package ansi
|
||||
|
||||
import (
|
||||
"fmt"
|
|
@ -1,4 +1,4 @@
|
|||
package color
|
||||
package ansi
|
||||
|
||||
import (
|
||||
"testing"
|
|
@ -1,4 +1,4 @@
|
|||
package color
|
||||
package ansi
|
||||
|
||||
type Palettes struct {
|
||||
Template string `json:"template,omitempty"`
|
|
@ -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
|
||||
}
|
|
@ -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,
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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: `<b>`, AnchorEnd: `</b>`, Start: "\x1b[1m", End: "\x1b[22m"},
|
||||
{AnchorStart: `<u>`, AnchorEnd: `</u>`, Start: "\x1b[4m", End: "\x1b[24m"},
|
||||
{AnchorStart: `<o>`, AnchorEnd: `</o>`, Start: "\x1b[53m", End: "\x1b[55m"},
|
||||
{AnchorStart: `<i>`, AnchorEnd: `</i>`, Start: "\x1b[3m", End: "\x1b[23m"},
|
||||
{AnchorStart: `<s>`, AnchorEnd: `</s>`, Start: "\x1b[9m", End: "\x1b[29m"},
|
||||
{AnchorStart: `<d>`, AnchorEnd: `</d>`, Start: "\x1b[2m", End: "\x1b[22m"},
|
||||
{AnchorStart: `<f>`, AnchorEnd: `</f>`, Start: "\x1b[5m", End: "\x1b[25m"},
|
||||
{AnchorStart: `<r>`, AnchorEnd: `</r>`, 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<ANCHOR><(?P<FG>[^,>]+)?,?(?P<BG>[^>]+)?>)`
|
||||
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<STR>\\\[\x1b\]8;;(.+)\x1b\\\\\\\](?P<TEXT>.+)\\\[\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<STR>%{\x1b]8;;(.+)\x1b\\%}(?P<TEXT>.+)%{\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<STR>\x1b]8;;(.+)\x1b\\\\\\\\?(?P<TEXT>.+)\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
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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<color>#[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}|p:.*)`, colorString)
|
||||
|
|
Loading…
Reference in a new issue