mirror of
https://github.com/JanDeDobbeleer/oh-my-posh.git
synced 2024-11-10 04:54:03 -08:00
refactor: ansi module cleanup
This commit is contained in:
parent
c24ca82f17
commit
b11b69f0e8
|
@ -9,7 +9,7 @@ const (
|
|||
ANSIRegex = "[\u001B\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))"
|
||||
)
|
||||
|
||||
type ansiFormats struct {
|
||||
type ansiUtils struct {
|
||||
shell string
|
||||
linechange string
|
||||
left string
|
||||
|
@ -32,7 +32,7 @@ type ansiFormats struct {
|
|||
strikethrough string
|
||||
}
|
||||
|
||||
func (a *ansiFormats) init(shell string) {
|
||||
func (a *ansiUtils) init(shell string) {
|
||||
a.shell = shell
|
||||
switch shell {
|
||||
case zsh:
|
||||
|
@ -98,7 +98,7 @@ func (a *ansiFormats) init(shell string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (a *ansiFormats) lenWithoutANSI(text string) int {
|
||||
func (a *ansiUtils) lenWithoutANSI(text string) int {
|
||||
if len(text) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ func (a *ansiFormats) lenWithoutANSI(text string) int {
|
|||
return len(runeText)
|
||||
}
|
||||
|
||||
func (a *ansiFormats) generateHyperlink(text string) string {
|
||||
func (a *ansiUtils) generateHyperlink(text string) string {
|
||||
// hyperlink matching
|
||||
results := findNamedRegexMatch("(?P<all>(?:\\[(?P<name>.+)\\])(?:\\((?P<url>.*)\\)))", text)
|
||||
if len(results) != 3 {
|
||||
|
@ -131,7 +131,7 @@ func (a *ansiFormats) generateHyperlink(text string) string {
|
|||
return strings.Replace(text, results["all"], hyperlink, 1)
|
||||
}
|
||||
|
||||
func (a *ansiFormats) formatText(text string) string {
|
||||
func (a *ansiUtils) formatText(text string) string {
|
||||
results := findAllNamedRegexMatch("(?P<context><(?P<format>[buis])>(?P<text>[^<]+)</[buis]>)", text)
|
||||
for _, result := range results {
|
||||
var formatted string
|
||||
|
@ -149,3 +149,25 @@ func (a *ansiFormats) formatText(text string) string {
|
|||
}
|
||||
return text
|
||||
}
|
||||
|
||||
func (a *ansiUtils) carriageForward() string {
|
||||
return fmt.Sprintf(a.left, 1000)
|
||||
}
|
||||
|
||||
func (a *ansiUtils) getCursorForRightWrite(text string, offset int) string {
|
||||
strippedLen := a.lenWithoutANSI(text) + -offset
|
||||
return fmt.Sprintf(a.right, strippedLen)
|
||||
}
|
||||
|
||||
func (a *ansiUtils) changeLine(numberOfLines int) string {
|
||||
position := "B"
|
||||
if numberOfLines < 0 {
|
||||
position = "F"
|
||||
numberOfLines = -numberOfLines
|
||||
}
|
||||
return fmt.Sprintf(a.linechange, numberOfLines, position)
|
||||
}
|
||||
|
||||
func (a *ansiUtils) consolePwd(pwd string) string {
|
||||
return fmt.Sprintf(a.osc99, pwd)
|
||||
}
|
|
@ -43,10 +43,16 @@ func getColorFromName(colorName string, isBackground bool) (string, error) {
|
|||
return "", errors.New("color name does not exist")
|
||||
}
|
||||
|
||||
type colorWriter interface {
|
||||
write(background, foreground, text string)
|
||||
string() string
|
||||
reset()
|
||||
}
|
||||
|
||||
// AnsiColor writes colorized strings
|
||||
type AnsiColor struct {
|
||||
builder strings.Builder
|
||||
formats *ansiFormats
|
||||
ansi *ansiUtils
|
||||
terminalBackground string
|
||||
}
|
||||
|
||||
|
@ -75,24 +81,24 @@ func (a *AnsiColor) writeColoredText(background, foreground, text string) {
|
|||
if foreground == Transparent && background != "" && a.terminalBackground != "" {
|
||||
bgAnsiColor := a.getAnsiFromColorString(background, true)
|
||||
fgAnsiColor := a.getAnsiFromColorString(a.terminalBackground, false)
|
||||
coloredText := fmt.Sprintf(a.formats.colorFull, bgAnsiColor, fgAnsiColor, text)
|
||||
coloredText := fmt.Sprintf(a.ansi.colorFull, bgAnsiColor, fgAnsiColor, text)
|
||||
a.builder.WriteString(coloredText)
|
||||
return
|
||||
}
|
||||
if foreground == Transparent && background != "" {
|
||||
ansiColor := a.getAnsiFromColorString(background, false)
|
||||
coloredText := fmt.Sprintf(a.formats.colorTransparent, ansiColor, text)
|
||||
coloredText := fmt.Sprintf(a.ansi.colorTransparent, ansiColor, text)
|
||||
a.builder.WriteString(coloredText)
|
||||
return
|
||||
} else if background == "" || background == Transparent {
|
||||
ansiColor := a.getAnsiFromColorString(foreground, false)
|
||||
coloredText := fmt.Sprintf(a.formats.colorSingle, ansiColor, text)
|
||||
coloredText := fmt.Sprintf(a.ansi.colorSingle, ansiColor, text)
|
||||
a.builder.WriteString(coloredText)
|
||||
return
|
||||
}
|
||||
bgAnsiColor := a.getAnsiFromColorString(background, true)
|
||||
fgAnsiColor := a.getAnsiFromColorString(foreground, false)
|
||||
coloredText := fmt.Sprintf(a.formats.colorFull, bgAnsiColor, fgAnsiColor, text)
|
||||
coloredText := fmt.Sprintf(a.ansi.colorFull, bgAnsiColor, fgAnsiColor, text)
|
||||
a.builder.WriteString(coloredText)
|
||||
}
|
||||
|
||||
|
@ -102,7 +108,7 @@ func (a *AnsiColor) writeAndRemoveText(background, foreground, text, textToRemov
|
|||
}
|
||||
|
||||
func (a *AnsiColor) write(background, foreground, text string) {
|
||||
text = a.formats.formatText(text)
|
||||
text = a.ansi.formatText(text)
|
||||
// first we match for any potentially valid colors enclosed in <>
|
||||
match := findAllNamedRegexMatch(`<(?P<foreground>[^,>]+)?,?(?P<background>[^>]+)?>(?P<content>[^<]*)<\/>`, text)
|
||||
for i := range match {
|
||||
|
|
|
@ -12,10 +12,10 @@ const (
|
|||
)
|
||||
|
||||
func TestWriteAndRemoveText(t *testing.T) {
|
||||
formats := &ansiFormats{}
|
||||
formats.init("pwsh")
|
||||
ansi := &ansiUtils{}
|
||||
ansi.init("pwsh")
|
||||
renderer := &AnsiColor{
|
||||
formats: formats,
|
||||
ansi: ansi,
|
||||
}
|
||||
text := renderer.writeAndRemoveText("#193549", "#fff", "This is white, ", "This is white, ", inputText)
|
||||
assert.Equal(t, "<#ff5733>this is orange</>, white again", text)
|
||||
|
@ -23,10 +23,10 @@ func TestWriteAndRemoveText(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestWriteAndRemoveTextColored(t *testing.T) {
|
||||
formats := &ansiFormats{}
|
||||
formats.init("pwsh")
|
||||
ansi := &ansiUtils{}
|
||||
ansi.init("pwsh")
|
||||
renderer := &AnsiColor{
|
||||
formats: formats,
|
||||
ansi: ansi,
|
||||
}
|
||||
text := renderer.writeAndRemoveText("#193549", "#ff5733", "this is orange", "<#ff5733>this is orange</>", inputText)
|
||||
assert.Equal(t, "This is white, , white again", text)
|
||||
|
@ -34,20 +34,20 @@ func TestWriteAndRemoveTextColored(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestWriteColorOverride(t *testing.T) {
|
||||
formats := &ansiFormats{}
|
||||
formats.init("pwsh")
|
||||
ansi := &ansiUtils{}
|
||||
ansi.init("pwsh")
|
||||
renderer := &AnsiColor{
|
||||
formats: formats,
|
||||
ansi: ansi,
|
||||
}
|
||||
renderer.write("#193549", "#ff5733", inputText)
|
||||
assert.NotContains(t, renderer.string(), "<#ff5733>")
|
||||
}
|
||||
|
||||
func TestWriteColorOverrideBackground(t *testing.T) {
|
||||
formats := &ansiFormats{}
|
||||
formats.init("pwsh")
|
||||
ansi := &ansiUtils{}
|
||||
ansi.init("pwsh")
|
||||
renderer := &AnsiColor{
|
||||
formats: formats,
|
||||
ansi: ansi,
|
||||
}
|
||||
text := "This is white, <,#000000>this is black</>, white again"
|
||||
renderer.write("#193549", "#ff5733", text)
|
||||
|
@ -55,10 +55,10 @@ func TestWriteColorOverrideBackground(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestWriteColorOverrideBackground16(t *testing.T) {
|
||||
formats := &ansiFormats{}
|
||||
formats.init("pwsh")
|
||||
ansi := &ansiUtils{}
|
||||
ansi.init("pwsh")
|
||||
renderer := &AnsiColor{
|
||||
formats: formats,
|
||||
ansi: ansi,
|
||||
}
|
||||
text := "This is default <,white> this background is changed</> default again"
|
||||
renderer.write("#193549", "#ff5733", text)
|
||||
|
@ -68,10 +68,10 @@ func TestWriteColorOverrideBackground16(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestWriteColorOverrideBoth(t *testing.T) {
|
||||
formats := &ansiFormats{}
|
||||
formats.init("pwsh")
|
||||
ansi := &ansiUtils{}
|
||||
ansi.init("pwsh")
|
||||
renderer := &AnsiColor{
|
||||
formats: formats,
|
||||
ansi: ansi,
|
||||
}
|
||||
text := "This is white, <#000000,#ffffff>this is black</>, white again"
|
||||
renderer.write("#193549", "#ff5733", text)
|
||||
|
@ -80,10 +80,10 @@ func TestWriteColorOverrideBoth(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestWriteColorOverrideBoth16(t *testing.T) {
|
||||
formats := &ansiFormats{}
|
||||
formats.init("pwsh")
|
||||
ansi := &ansiUtils{}
|
||||
ansi.init("pwsh")
|
||||
renderer := &AnsiColor{
|
||||
formats: formats,
|
||||
ansi: ansi,
|
||||
}
|
||||
text := "This is white, <black,white>this is black</>, white again"
|
||||
renderer.write("#193549", "#ff5733", text)
|
||||
|
@ -92,10 +92,10 @@ func TestWriteColorOverrideBoth16(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestWriteColorOverrideDouble(t *testing.T) {
|
||||
formats := &ansiFormats{}
|
||||
formats.init("pwsh")
|
||||
ansi := &ansiUtils{}
|
||||
ansi.init("pwsh")
|
||||
renderer := &AnsiColor{
|
||||
formats: formats,
|
||||
ansi: ansi,
|
||||
}
|
||||
text := "<#ffffff>jan</>@<#ffffff>Jans-MBP</>"
|
||||
renderer.write("#193549", "#ff5733", text)
|
||||
|
@ -104,10 +104,10 @@ func TestWriteColorOverrideDouble(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestWriteColorTransparent(t *testing.T) {
|
||||
formats := &ansiFormats{}
|
||||
formats.init("pwsh")
|
||||
ansi := &ansiUtils{}
|
||||
ansi.init("pwsh")
|
||||
renderer := &AnsiColor{
|
||||
formats: formats,
|
||||
ansi: ansi,
|
||||
}
|
||||
text := "This is white"
|
||||
renderer.writeColoredText("#193549", Transparent, text)
|
||||
|
@ -115,10 +115,10 @@ func TestWriteColorTransparent(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestWriteColorName(t *testing.T) {
|
||||
formats := &ansiFormats{}
|
||||
formats.init("pwsh")
|
||||
ansi := &ansiUtils{}
|
||||
ansi.init("pwsh")
|
||||
renderer := &AnsiColor{
|
||||
formats: formats,
|
||||
ansi: ansi,
|
||||
}
|
||||
text := "This is white, <red>this is red</>, white again"
|
||||
renderer.write("#193549", "red", text)
|
||||
|
@ -126,10 +126,10 @@ func TestWriteColorName(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestWriteColorInvalid(t *testing.T) {
|
||||
formats := &ansiFormats{}
|
||||
formats.init("pwsh")
|
||||
ansi := &ansiUtils{}
|
||||
ansi.init("pwsh")
|
||||
renderer := &AnsiColor{
|
||||
formats: formats,
|
||||
ansi: ansi,
|
||||
}
|
||||
text := "This is white, <invalid>this is orange</>, white again"
|
||||
renderer.write("#193549", "invalid", text)
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// AnsiRenderer exposes functionality using ANSI
|
||||
type AnsiRenderer struct {
|
||||
builder strings.Builder
|
||||
formats *ansiFormats
|
||||
}
|
||||
|
||||
func (r *AnsiRenderer) carriageForward() {
|
||||
r.builder.WriteString(fmt.Sprintf(r.formats.left, 1000))
|
||||
}
|
||||
|
||||
func (r *AnsiRenderer) setCursorForRightWrite(text string, offset int) {
|
||||
strippedLen := r.formats.lenWithoutANSI(text) + -offset
|
||||
r.builder.WriteString(fmt.Sprintf(r.formats.right, strippedLen))
|
||||
}
|
||||
|
||||
func (r *AnsiRenderer) changeLine(numberOfLines int) {
|
||||
position := "B"
|
||||
if numberOfLines < 0 {
|
||||
position = "F"
|
||||
numberOfLines = -numberOfLines
|
||||
}
|
||||
r.builder.WriteString(fmt.Sprintf(r.formats.linechange, numberOfLines, position))
|
||||
}
|
||||
|
||||
func (r *AnsiRenderer) creset() {
|
||||
r.builder.WriteString(r.formats.creset)
|
||||
}
|
||||
|
||||
func (r *AnsiRenderer) write(text string) {
|
||||
r.builder.WriteString(text)
|
||||
// Due to a bug in Powershell, the end of the line needs to be cleared.
|
||||
// If this doesn't happen, the portion after the prompt gets colored in the background
|
||||
// color of the line above the new input line. Clearing the line fixes this,
|
||||
// but can hopefully one day be removed when this is resolved natively.
|
||||
if r.formats.shell == pwsh || r.formats.shell == powershell5 {
|
||||
r.builder.WriteString(r.formats.clearEOL)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *AnsiRenderer) string() string {
|
||||
return r.builder.String()
|
||||
}
|
||||
|
||||
func (r *AnsiRenderer) saveCursorPosition() {
|
||||
r.builder.WriteString(r.formats.saveCursorPosition)
|
||||
}
|
||||
|
||||
func (r *AnsiRenderer) restoreCursorPosition() {
|
||||
r.builder.WriteString(r.formats.restoreCursorPosition)
|
||||
}
|
||||
|
||||
func (r *AnsiRenderer) osc99(pwd string) {
|
||||
r.builder.WriteString(fmt.Sprintf(r.formats.osc99, pwd))
|
||||
}
|
|
@ -17,7 +17,7 @@ func TestLenWithoutAnsi(t *testing.T) {
|
|||
{Text: "\\[\x1b[44m\\]hello\\[\x1b[0m\\]", ShellName: bash, Expected: 5},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
a := ansiFormats{}
|
||||
a := ansiUtils{}
|
||||
a.init(tc.ShellName)
|
||||
strippedLength := a.lenWithoutANSI(tc.Text)
|
||||
assert.Equal(t, 5, strippedLength)
|
||||
|
@ -35,7 +35,7 @@ func TestGenerateHyperlinkNoUrl(t *testing.T) {
|
|||
{Text: "sample text with no url", ShellName: bash, Expected: "sample text with no url"},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
a := ansiFormats{}
|
||||
a := ansiUtils{}
|
||||
a.init(tc.ShellName)
|
||||
hyperlinkText := a.generateHyperlink(tc.Text)
|
||||
assert.Equal(t, tc.Expected, hyperlinkText)
|
||||
|
@ -53,7 +53,7 @@ func TestGenerateHyperlinkWithUrl(t *testing.T) {
|
|||
{Text: "[google](http://www.google.be)", ShellName: bash, Expected: "\\[\x1b]8;;http://www.google.be\x1b\\\\\\]google\\[\x1b]8;;\x1b\\\\\\]"},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
a := ansiFormats{}
|
||||
a := ansiUtils{}
|
||||
a.init(tc.ShellName)
|
||||
hyperlinkText := a.generateHyperlink(tc.Text)
|
||||
assert.Equal(t, tc.Expected, hyperlinkText)
|
||||
|
@ -71,7 +71,7 @@ func TestGenerateHyperlinkWithUrlNoName(t *testing.T) {
|
|||
{Text: "[](http://www.google.be)", ShellName: bash, Expected: "[](http://www.google.be)"},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
a := ansiFormats{}
|
||||
a := ansiUtils{}
|
||||
a.init(tc.ShellName)
|
||||
hyperlinkText := a.generateHyperlink(tc.Text)
|
||||
assert.Equal(t, tc.Expected, hyperlinkText)
|
||||
|
@ -91,7 +91,7 @@ func TestFormatText(t *testing.T) {
|
|||
{Case: "strikethrough", Text: "This <s>is</s> white", Expected: "This \x1b[9mis\x1b[29m white"},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
a := ansiFormats{}
|
||||
a := ansiUtils{}
|
||||
a.init("")
|
||||
formattedText := a.formatText(tc.Text)
|
||||
assert.Equal(t, tc.Expected, formattedText, tc.Case)
|
27
src/block.go
27
src/block.go
|
@ -35,14 +35,16 @@ type Block struct {
|
|||
Newline bool `config:"newline"`
|
||||
|
||||
env environmentInfo
|
||||
color *AnsiColor
|
||||
writer colorWriter
|
||||
ansi *ansiUtils
|
||||
activeSegment *Segment
|
||||
previousActiveSegment *Segment
|
||||
}
|
||||
|
||||
func (b *Block) init(env environmentInfo, color *AnsiColor) {
|
||||
func (b *Block) init(env environmentInfo, writer colorWriter, ansi *ansiUtils) {
|
||||
b.env = env
|
||||
b.color = color
|
||||
b.writer = writer
|
||||
b.ansi = ansi
|
||||
}
|
||||
|
||||
func (b *Block) enabled() bool {
|
||||
|
@ -71,6 +73,7 @@ func (b *Block) setStringValues() {
|
|||
}
|
||||
|
||||
func (b *Block) renderSegments() string {
|
||||
defer b.writer.reset()
|
||||
for _, segment := range b.Segments {
|
||||
if !segment.active {
|
||||
continue
|
||||
|
@ -82,7 +85,7 @@ func (b *Block) renderSegments() string {
|
|||
if b.previousActiveSegment != nil && b.previousActiveSegment.Style == Powerline {
|
||||
b.writePowerLineSeparator(Transparent, b.previousActiveSegment.background(), true)
|
||||
}
|
||||
return b.color.string()
|
||||
return b.writer.string()
|
||||
}
|
||||
|
||||
func (b *Block) endPowerline() {
|
||||
|
@ -100,10 +103,10 @@ func (b *Block) writePowerLineSeparator(background, foreground string, end bool)
|
|||
symbol = b.previousActiveSegment.PowerlineSymbol
|
||||
}
|
||||
if b.activeSegment.InvertPowerline {
|
||||
b.color.write(foreground, background, symbol)
|
||||
b.writer.write(foreground, background, symbol)
|
||||
return
|
||||
}
|
||||
b.color.write(background, foreground, symbol)
|
||||
b.writer.write(background, foreground, symbol)
|
||||
}
|
||||
|
||||
func (b *Block) getPowerlineColor(foreground bool) string {
|
||||
|
@ -141,17 +144,17 @@ func (b *Block) renderPlainSegment(text string) {
|
|||
}
|
||||
|
||||
func (b *Block) renderDiamondSegment(text string) {
|
||||
b.color.write(Transparent, b.activeSegment.background(), b.activeSegment.LeadingDiamond)
|
||||
b.writer.write(Transparent, b.activeSegment.background(), b.activeSegment.LeadingDiamond)
|
||||
b.renderText(text)
|
||||
b.color.write(Transparent, b.activeSegment.background(), b.activeSegment.TrailingDiamond)
|
||||
b.writer.write(Transparent, b.activeSegment.background(), b.activeSegment.TrailingDiamond)
|
||||
}
|
||||
|
||||
func (b *Block) renderText(text string) {
|
||||
text = b.color.formats.generateHyperlink(text)
|
||||
text = b.ansi.generateHyperlink(text)
|
||||
defaultValue := " "
|
||||
prefix := b.activeSegment.getValue(Prefix, defaultValue)
|
||||
postfix := b.activeSegment.getValue(Postfix, defaultValue)
|
||||
b.color.write(b.activeSegment.background(), b.activeSegment.foreground(), fmt.Sprintf("%s%s%s", prefix, text, postfix))
|
||||
b.writer.write(b.activeSegment.background(), b.activeSegment.foreground(), fmt.Sprintf("%s%s%s", prefix, text, postfix))
|
||||
}
|
||||
|
||||
func (b *Block) debug() (int, []*SegmentTiming) {
|
||||
|
@ -183,8 +186,8 @@ func (b *Block) debug() (int, []*SegmentTiming) {
|
|||
if b.activeSegment.Style == Powerline {
|
||||
b.writePowerLineSeparator(Transparent, b.activeSegment.background(), true)
|
||||
}
|
||||
segmentTiming.stringValue = b.color.string()
|
||||
b.color.builder.Reset()
|
||||
segmentTiming.stringValue = b.writer.string()
|
||||
b.writer.reset()
|
||||
}
|
||||
segmentTimings = append(segmentTimings, &segmentTiming)
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@ import (
|
|||
)
|
||||
|
||||
type consoleTitle struct {
|
||||
env environmentInfo
|
||||
config *Config
|
||||
formats *ansiFormats
|
||||
env environmentInfo
|
||||
config *Config
|
||||
ansi *ansiUtils
|
||||
}
|
||||
|
||||
// ConsoleTitleStyle defines how to show the title in the console window
|
||||
|
@ -37,7 +37,7 @@ func (t *consoleTitle) getConsoleTitle() string {
|
|||
default:
|
||||
title = base(t.getPwd(), t.env)
|
||||
}
|
||||
return fmt.Sprintf(t.formats.title, title)
|
||||
return fmt.Sprintf(t.ansi.title, title)
|
||||
}
|
||||
|
||||
func (t *consoleTitle) getTemplateText() string {
|
||||
|
|
|
@ -62,12 +62,12 @@ func TestGetConsoleTitle(t *testing.T) {
|
|||
env.On("getenv", "USERDOMAIN").Return("MyCompany")
|
||||
env.On("getCurrentUser", nil).Return("MyUser")
|
||||
env.On("getHostName", nil).Return("MyHost", nil)
|
||||
formats := &ansiFormats{}
|
||||
formats.init(tc.ShellName)
|
||||
ansi := &ansiUtils{}
|
||||
ansi.init(tc.ShellName)
|
||||
ct := &consoleTitle{
|
||||
env: env,
|
||||
config: config,
|
||||
formats: formats,
|
||||
env: env,
|
||||
config: config,
|
||||
ansi: ansi,
|
||||
}
|
||||
got := ct.getConsoleTitle()
|
||||
assert.Equal(t, tc.Expected, got)
|
||||
|
@ -117,12 +117,12 @@ func TestGetConsoleTitleIfGethostnameReturnsError(t *testing.T) {
|
|||
env.On("getenv", "USERDOMAIN").Return("MyCompany")
|
||||
env.On("getCurrentUser", nil).Return("MyUser")
|
||||
env.On("getHostName", nil).Return("", fmt.Errorf("I have a bad feeling about this"))
|
||||
formats := &ansiFormats{}
|
||||
formats.init(tc.ShellName)
|
||||
ansi := &ansiUtils{}
|
||||
ansi.init(tc.ShellName)
|
||||
ct := &consoleTitle{
|
||||
env: env,
|
||||
config: config,
|
||||
formats: formats,
|
||||
env: env,
|
||||
config: config,
|
||||
ansi: ansi,
|
||||
}
|
||||
got := ct.getConsoleTitle()
|
||||
assert.Equal(t, tc.Expected, got)
|
||||
|
|
|
@ -9,25 +9,39 @@ import (
|
|||
type engine struct {
|
||||
config *Config
|
||||
env environmentInfo
|
||||
color *AnsiColor
|
||||
renderer *AnsiRenderer
|
||||
colorWriter colorWriter
|
||||
ansi *ansiUtils
|
||||
consoleTitle *consoleTitle
|
||||
// activeBlock *Block
|
||||
// activeSegment *Segment
|
||||
// previousActiveSegment *Segment
|
||||
|
||||
console strings.Builder
|
||||
rprompt string
|
||||
}
|
||||
|
||||
func (e *engine) write(text string) {
|
||||
e.console.WriteString(text)
|
||||
// Due to a bug in Powershell, the end of the line needs to be cleared.
|
||||
// If this doesn't happen, the portion after the prompt gets colored in the background
|
||||
// color of the line above the new input line. Clearing the line fixes this,
|
||||
// but can hopefully one day be removed when this is resolved natively.
|
||||
if e.ansi.shell == pwsh || e.ansi.shell == powershell5 {
|
||||
e.console.WriteString(e.ansi.clearEOL)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *engine) string() string {
|
||||
return e.console.String()
|
||||
}
|
||||
|
||||
func (e *engine) render() string {
|
||||
for _, block := range e.config.Blocks {
|
||||
e.renderBlock(block)
|
||||
}
|
||||
if e.config.ConsoleTitle {
|
||||
e.renderer.write(e.consoleTitle.getConsoleTitle())
|
||||
e.write(e.consoleTitle.getConsoleTitle())
|
||||
}
|
||||
e.renderer.creset()
|
||||
e.write(e.ansi.creset)
|
||||
if e.config.FinalSpace {
|
||||
e.renderer.write(" ")
|
||||
e.write(" ")
|
||||
}
|
||||
|
||||
if !e.config.OSC99 {
|
||||
|
@ -37,38 +51,37 @@ func (e *engine) render() string {
|
|||
if e.env.isWsl() {
|
||||
cwd, _ = e.env.runCommand("wslpath", "-m", cwd)
|
||||
}
|
||||
e.renderer.osc99(cwd)
|
||||
e.write(e.ansi.consolePwd(cwd))
|
||||
return e.print()
|
||||
}
|
||||
|
||||
func (e *engine) renderBlock(block *Block) {
|
||||
block.init(e.env, e.color)
|
||||
block.init(e.env, e.colorWriter, e.ansi)
|
||||
block.setStringValues()
|
||||
defer e.color.reset()
|
||||
if !block.enabled() {
|
||||
return
|
||||
}
|
||||
if block.Newline {
|
||||
e.renderer.write("\n")
|
||||
e.write("\n")
|
||||
}
|
||||
switch block.Type {
|
||||
// This is deprecated but leave if to not break current configs
|
||||
// It is encouraged to used "newline": true on block level
|
||||
// rather than the standalone the linebreak block
|
||||
case LineBreak:
|
||||
e.renderer.write("\n")
|
||||
e.write("\n")
|
||||
case Prompt:
|
||||
if block.VerticalOffset != 0 {
|
||||
e.renderer.changeLine(block.VerticalOffset)
|
||||
e.write(e.ansi.changeLine(block.VerticalOffset))
|
||||
}
|
||||
switch block.Alignment {
|
||||
case Right:
|
||||
e.renderer.carriageForward()
|
||||
e.write(e.ansi.carriageForward())
|
||||
blockText := block.renderSegments()
|
||||
e.renderer.setCursorForRightWrite(blockText, block.HorizontalOffset)
|
||||
e.renderer.write(blockText)
|
||||
e.write(e.ansi.getCursorForRightWrite(blockText, block.HorizontalOffset))
|
||||
e.write(blockText)
|
||||
case Left:
|
||||
e.renderer.write(block.renderSegments())
|
||||
e.write(block.renderSegments())
|
||||
}
|
||||
case RPrompt:
|
||||
e.rprompt = block.renderSegments()
|
||||
|
@ -79,7 +92,7 @@ func (e *engine) renderBlock(block *Block) {
|
|||
func (e *engine) debug() string {
|
||||
var segmentTimings []*SegmentTiming
|
||||
largestSegmentNameLength := 0
|
||||
e.renderer.write("\n\x1b[1mHere are the timings of segments in your prompt:\x1b[0m\n\n")
|
||||
e.write("\n\x1b[1mHere are the timings of segments in your prompt:\x1b[0m\n\n")
|
||||
|
||||
// console title timing
|
||||
start := time.Now()
|
||||
|
@ -96,7 +109,7 @@ func (e *engine) debug() string {
|
|||
segmentTimings = append(segmentTimings, segmentTiming)
|
||||
// loop each segments of each blocks
|
||||
for _, block := range e.config.Blocks {
|
||||
block.init(e.env, e.color)
|
||||
block.init(e.env, e.colorWriter, e.ansi)
|
||||
longestSegmentName, timings := block.debug()
|
||||
segmentTimings = append(segmentTimings, timings...)
|
||||
if longestSegmentName > largestSegmentNameLength {
|
||||
|
@ -112,9 +125,9 @@ func (e *engine) debug() string {
|
|||
duration += segment.stringDuration.Milliseconds()
|
||||
}
|
||||
segmentName := fmt.Sprintf("%s(%t)", segment.name, segment.enabled)
|
||||
e.renderer.write(fmt.Sprintf("%-*s - %3d ms - %s\n", largestSegmentNameLength, segmentName, duration, segment.stringValue))
|
||||
e.write(fmt.Sprintf("%-*s - %3d ms - %s\n", largestSegmentNameLength, segmentName, duration, segment.stringValue))
|
||||
}
|
||||
return e.renderer.string()
|
||||
return e.string()
|
||||
}
|
||||
|
||||
func (e *engine) print() string {
|
||||
|
@ -122,18 +135,18 @@ func (e *engine) print() string {
|
|||
case zsh:
|
||||
if *e.env.getArgs().Eval {
|
||||
// escape double quotes contained in the prompt
|
||||
prompt := fmt.Sprintf("PS1=\"%s\"", strings.ReplaceAll(e.renderer.string(), "\"", "\"\""))
|
||||
prompt := fmt.Sprintf("PS1=\"%s\"", strings.ReplaceAll(e.string(), "\"", "\"\""))
|
||||
prompt += fmt.Sprintf("\nRPROMPT=\"%s\"", e.rprompt)
|
||||
return prompt
|
||||
}
|
||||
case pwsh, powershell5, bash, shelly:
|
||||
if e.rprompt != "" {
|
||||
e.renderer.saveCursorPosition()
|
||||
e.renderer.carriageForward()
|
||||
e.renderer.setCursorForRightWrite(e.rprompt, 0)
|
||||
e.renderer.write(e.rprompt)
|
||||
e.renderer.restoreCursorPosition()
|
||||
e.write(e.ansi.saveCursorPosition)
|
||||
e.write(e.ansi.carriageForward())
|
||||
e.write(e.ansi.getCursorForRightWrite(e.rprompt, 0))
|
||||
e.write(e.rprompt)
|
||||
e.write(e.ansi.restoreCursorPosition)
|
||||
}
|
||||
}
|
||||
return e.renderer.string()
|
||||
return e.string()
|
||||
}
|
||||
|
|
|
@ -96,7 +96,7 @@ func NewRGBColor(ansiColor string) *RGB {
|
|||
type ImageRenderer struct {
|
||||
ansiString string
|
||||
author string
|
||||
formats *ansiFormats
|
||||
ansi *ansiUtils
|
||||
|
||||
factor float64
|
||||
|
||||
|
@ -189,7 +189,7 @@ func (ir *ImageRenderer) fontHeight() float64 {
|
|||
func (ir *ImageRenderer) calculateWidth() int {
|
||||
longest := 0
|
||||
for _, line := range strings.Split(ir.ansiString, "\n") {
|
||||
length := ir.formats.lenWithoutANSI(line)
|
||||
length := ir.ansi.lenWithoutANSI(line)
|
||||
if length > longest {
|
||||
longest = length
|
||||
}
|
||||
|
|
|
@ -15,11 +15,11 @@ func runImageTest(content string) error {
|
|||
return err
|
||||
}
|
||||
defer os.Remove(file.Name())
|
||||
formats := &ansiFormats{}
|
||||
formats.init(shelly)
|
||||
ansi := &ansiUtils{}
|
||||
ansi.init(shelly)
|
||||
image := &ImageRenderer{
|
||||
ansiString: content,
|
||||
formats: formats,
|
||||
ansi: ansi,
|
||||
}
|
||||
image.init()
|
||||
err = image.SavePNG(poshImagePath)
|
||||
|
|
21
src/main.go
21
src/main.go
|
@ -173,26 +173,23 @@ func main() {
|
|||
return
|
||||
}
|
||||
|
||||
formats := &ansiFormats{}
|
||||
formats.init(env.getShellName())
|
||||
renderer := &AnsiRenderer{
|
||||
formats: formats,
|
||||
}
|
||||
ansi := &ansiUtils{}
|
||||
ansi.init(env.getShellName())
|
||||
colorer := &AnsiColor{
|
||||
formats: formats,
|
||||
ansi: ansi,
|
||||
terminalBackground: getConsoleBackgroundColor(env, cfg.TerminalBackground),
|
||||
}
|
||||
title := &consoleTitle{
|
||||
env: env,
|
||||
config: cfg,
|
||||
formats: formats,
|
||||
env: env,
|
||||
config: cfg,
|
||||
ansi: ansi,
|
||||
}
|
||||
engine := &engine{
|
||||
config: cfg,
|
||||
env: env,
|
||||
color: colorer,
|
||||
renderer: renderer,
|
||||
colorWriter: colorer,
|
||||
consoleTitle: title,
|
||||
ansi: ansi,
|
||||
}
|
||||
|
||||
if *args.Debug {
|
||||
|
@ -209,7 +206,7 @@ func main() {
|
|||
author: *args.Author,
|
||||
cursorPadding: *args.CursorPadding,
|
||||
rPromptOffset: *args.RPromptOffset,
|
||||
formats: formats,
|
||||
ansi: ansi,
|
||||
}
|
||||
imageCreator.init()
|
||||
match := findNamedRegexMatch(`.*(\/|\\)(?P<STR>.+).omp.(json|yaml|toml)`, *args.Config)
|
||||
|
|
Loading…
Reference in a new issue