mirror of
https://github.com/JanDeDobbeleer/oh-my-posh.git
synced 2025-03-05 20:49:04 -08:00
refactor: migrate terminal to module
This commit is contained in:
parent
8e2c8eb6b1
commit
0c8b8021b8
|
@ -67,17 +67,14 @@ Exports the config to an image file using customized output options.`,
|
||||||
// add variables to the environment
|
// add variables to the environment
|
||||||
env.Var = cfg.Var
|
env.Var = cfg.Var
|
||||||
|
|
||||||
writerColors := cfg.MakeColors()
|
terminal.Init(shell.GENERIC)
|
||||||
writer := &terminal.Writer{
|
terminal.BackgroundColor = shell.ConsoleBackgroundColor(env, cfg.TerminalBackground)
|
||||||
BackgroundColor: shell.ConsoleBackgroundColor(env, cfg.TerminalBackground),
|
terminal.AnsiColors = cfg.MakeColors()
|
||||||
AnsiColors: writerColors,
|
terminal.TrueColor = env.CmdFlags.TrueColor
|
||||||
TrueColor: env.CmdFlags.TrueColor,
|
|
||||||
}
|
|
||||||
writer.Init(shell.GENERIC)
|
|
||||||
eng := &engine.Engine{
|
eng := &engine.Engine{
|
||||||
Config: cfg,
|
Config: cfg,
|
||||||
Env: env,
|
Env: env,
|
||||||
Writer: writer,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
prompt := eng.Primary()
|
prompt := eng.Primary()
|
||||||
|
@ -86,7 +83,6 @@ Exports the config to an image file using customized output options.`,
|
||||||
AnsiString: prompt,
|
AnsiString: prompt,
|
||||||
Author: author,
|
Author: author,
|
||||||
BgColor: bgColor,
|
BgColor: bgColor,
|
||||||
Ansi: writer,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if outputImage != "" {
|
if outputImage != "" {
|
||||||
|
|
|
@ -40,19 +40,15 @@ var debugCmd = &cobra.Command{
|
||||||
// add variables to the environment
|
// add variables to the environment
|
||||||
env.Var = cfg.Var
|
env.Var = cfg.Var
|
||||||
|
|
||||||
writerColors := cfg.MakeColors()
|
terminal.Init(shell.GENERIC)
|
||||||
writer := &terminal.Writer{
|
terminal.BackgroundColor = shell.ConsoleBackgroundColor(env, cfg.TerminalBackground)
|
||||||
BackgroundColor: shell.ConsoleBackgroundColor(env, cfg.TerminalBackground),
|
terminal.AnsiColors = cfg.MakeColors()
|
||||||
AnsiColors: writerColors,
|
terminal.Plain = plain
|
||||||
Plain: plain,
|
terminal.TrueColor = env.CmdFlags.TrueColor
|
||||||
TrueColor: env.CmdFlags.TrueColor,
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.Init(shell.GENERIC)
|
|
||||||
eng := &engine.Engine{
|
eng := &engine.Engine{
|
||||||
Config: cfg,
|
Config: cfg,
|
||||||
Env: env,
|
Env: env,
|
||||||
Writer: writer,
|
|
||||||
Plain: plain,
|
Plain: plain,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/terminal"
|
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/platform"
|
"github.com/jandedobbeleer/oh-my-posh/src/platform"
|
||||||
|
"github.com/jandedobbeleer/oh-my-posh/src/terminal"
|
||||||
|
|
||||||
color2 "github.com/gookit/color"
|
color2 "github.com/gookit/color"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
|
@ -56,25 +56,21 @@ type Block struct {
|
||||||
MinWidth int `json:"min_width,omitempty" toml:"min_width,omitempty"`
|
MinWidth int `json:"min_width,omitempty" toml:"min_width,omitempty"`
|
||||||
|
|
||||||
env platform.Environment
|
env platform.Environment
|
||||||
writer *terminal.Writer
|
|
||||||
activeSegment *Segment
|
activeSegment *Segment
|
||||||
previousActiveSegment *Segment
|
previousActiveSegment *Segment
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Block) Init(env platform.Environment, writer *terminal.Writer) {
|
func (b *Block) Init(env platform.Environment) {
|
||||||
b.env = env
|
b.env = env
|
||||||
b.writer = writer
|
|
||||||
b.executeSegmentLogic()
|
b.executeSegmentLogic()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Block) InitPlain(env platform.Environment, config *Config) {
|
func (b *Block) InitPlain(env platform.Environment, config *Config) {
|
||||||
b.writer = &terminal.Writer{
|
terminal.Init(shell.GENERIC)
|
||||||
BackgroundColor: shell.ConsoleBackgroundColor(env, config.TerminalBackground),
|
terminal.BackgroundColor = shell.ConsoleBackgroundColor(env, config.TerminalBackground)
|
||||||
AnsiColors: config.MakeColors(),
|
terminal.AnsiColors = config.MakeColors()
|
||||||
TrueColor: env.Flags().TrueColor,
|
terminal.TrueColor = env.Flags().TrueColor
|
||||||
}
|
|
||||||
|
|
||||||
b.writer.Init(shell.GENERIC)
|
|
||||||
b.env = env
|
b.env = env
|
||||||
b.executeSegmentLogic()
|
b.executeSegmentLogic()
|
||||||
}
|
}
|
||||||
|
@ -90,8 +86,8 @@ func (b *Block) executeSegmentLogic() {
|
||||||
|
|
||||||
func (b *Block) setActiveSegment(segment *Segment) {
|
func (b *Block) setActiveSegment(segment *Segment) {
|
||||||
b.activeSegment = segment
|
b.activeSegment = segment
|
||||||
b.writer.Interactive = segment.Interactive
|
terminal.Interactive = segment.Interactive
|
||||||
b.writer.SetColors(segment.background(), segment.foreground())
|
terminal.SetColors(segment.background(), segment.foreground())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Block) Enabled() bool {
|
func (b *Block) Enabled() bool {
|
||||||
|
@ -156,7 +152,7 @@ func (b *Block) RenderSegments() (string, int) {
|
||||||
|
|
||||||
b.writeSeparator(true)
|
b.writeSeparator(true)
|
||||||
|
|
||||||
return b.writer.String()
|
return terminal.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Block) filterSegments() {
|
func (b *Block) filterSegments() {
|
||||||
|
@ -177,27 +173,27 @@ func (b *Block) renderActiveSegment() {
|
||||||
b.writeSeparator(false)
|
b.writeSeparator(false)
|
||||||
switch b.activeSegment.style() {
|
switch b.activeSegment.style() {
|
||||||
case Plain, Powerline:
|
case Plain, Powerline:
|
||||||
b.writer.Write(terminal.Background, terminal.Foreground, b.activeSegment.text)
|
terminal.Write(terminal.Background, terminal.Foreground, b.activeSegment.text)
|
||||||
case Diamond:
|
case Diamond:
|
||||||
background := terminal.Transparent
|
background := terminal.Transparent
|
||||||
if b.previousActiveSegment != nil && b.previousActiveSegment.hasEmptyDiamondAtEnd() {
|
if b.previousActiveSegment != nil && b.previousActiveSegment.hasEmptyDiamondAtEnd() {
|
||||||
background = b.previousActiveSegment.background()
|
background = b.previousActiveSegment.background()
|
||||||
}
|
}
|
||||||
b.writer.Write(background, terminal.Background, b.activeSegment.LeadingDiamond)
|
terminal.Write(background, terminal.Background, b.activeSegment.LeadingDiamond)
|
||||||
b.writer.Write(terminal.Background, terminal.Foreground, b.activeSegment.text)
|
terminal.Write(terminal.Background, terminal.Foreground, b.activeSegment.text)
|
||||||
case Accordion:
|
case Accordion:
|
||||||
if b.activeSegment.Enabled {
|
if b.activeSegment.Enabled {
|
||||||
b.writer.Write(terminal.Background, terminal.Foreground, b.activeSegment.text)
|
terminal.Write(terminal.Background, terminal.Foreground, b.activeSegment.text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
b.previousActiveSegment = b.activeSegment
|
b.previousActiveSegment = b.activeSegment
|
||||||
b.writer.SetParentColors(b.previousActiveSegment.background(), b.previousActiveSegment.foreground())
|
terminal.SetParentColors(b.previousActiveSegment.background(), b.previousActiveSegment.foreground())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Block) writeSeparator(final bool) {
|
func (b *Block) writeSeparator(final bool) {
|
||||||
isCurrentDiamond := b.activeSegment.style() == Diamond
|
isCurrentDiamond := b.activeSegment.style() == Diamond
|
||||||
if final && isCurrentDiamond {
|
if final && isCurrentDiamond {
|
||||||
b.writer.Write(terminal.Transparent, terminal.Background, b.activeSegment.TrailingDiamond)
|
terminal.Write(terminal.Transparent, terminal.Background, b.activeSegment.TrailingDiamond)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,12 +203,12 @@ func (b *Block) writeSeparator(final bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if isPreviousDiamond && isCurrentDiamond && len(b.activeSegment.LeadingDiamond) == 0 {
|
if isPreviousDiamond && isCurrentDiamond && len(b.activeSegment.LeadingDiamond) == 0 {
|
||||||
b.writer.Write(terminal.Background, terminal.ParentBackground, b.previousActiveSegment.TrailingDiamond)
|
terminal.Write(terminal.Background, terminal.ParentBackground, b.previousActiveSegment.TrailingDiamond)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if isPreviousDiamond && len(b.previousActiveSegment.TrailingDiamond) > 0 {
|
if isPreviousDiamond && len(b.previousActiveSegment.TrailingDiamond) > 0 {
|
||||||
b.writer.Write(terminal.Transparent, terminal.ParentBackground, b.previousActiveSegment.TrailingDiamond)
|
terminal.Write(terminal.Transparent, terminal.ParentBackground, b.previousActiveSegment.TrailingDiamond)
|
||||||
}
|
}
|
||||||
|
|
||||||
isPowerline := b.activeSegment.isPowerline()
|
isPowerline := b.activeSegment.isPowerline()
|
||||||
|
@ -234,7 +230,7 @@ func (b *Block) writeSeparator(final bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if shouldOverridePowerlineLeadingSymbol() {
|
if shouldOverridePowerlineLeadingSymbol() {
|
||||||
b.writer.Write(terminal.Transparent, terminal.Background, b.activeSegment.LeadingPowerlineSymbol)
|
terminal.Write(terminal.Transparent, terminal.Background, b.activeSegment.LeadingPowerlineSymbol)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,11 +261,11 @@ func (b *Block) writeSeparator(final bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.activeSegment.InvertPowerline {
|
if b.activeSegment.InvertPowerline {
|
||||||
b.writer.Write(b.getPowerlineColor(), bgColor, symbol)
|
terminal.Write(b.getPowerlineColor(), bgColor, symbol)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
b.writer.Write(bgColor, b.getPowerlineColor(), symbol)
|
terminal.Write(bgColor, b.getPowerlineColor(), symbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Block) adjustTrailingDiamondColorOverrides() {
|
func (b *Block) adjustTrailingDiamondColorOverrides() {
|
||||||
|
|
|
@ -16,7 +16,6 @@ var (
|
||||||
type Engine struct {
|
type Engine struct {
|
||||||
Config *Config
|
Config *Config
|
||||||
Env platform.Environment
|
Env platform.Environment
|
||||||
Writer *terminal.Writer
|
|
||||||
Plain bool
|
Plain bool
|
||||||
|
|
||||||
console strings.Builder
|
console strings.Builder
|
||||||
|
@ -73,10 +72,10 @@ func (e *Engine) writeRPrompt() {
|
||||||
if !OK {
|
if !OK {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
e.write(e.Writer.SaveCursorPosition())
|
e.write(terminal.SaveCursorPosition())
|
||||||
e.write(strings.Repeat(" ", space))
|
e.write(strings.Repeat(" ", space))
|
||||||
e.write(e.rprompt)
|
e.write(e.rprompt)
|
||||||
e.write(e.Writer.RestoreCursorPosition())
|
e.write(terminal.RestoreCursorPosition())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Engine) pwd() {
|
func (e *Engine) pwd() {
|
||||||
|
@ -94,7 +93,7 @@ func (e *Engine) pwd() {
|
||||||
|
|
||||||
// Backwards compatibility for deprecated OSC99
|
// Backwards compatibility for deprecated OSC99
|
||||||
if e.Config.OSC99 {
|
if e.Config.OSC99 {
|
||||||
e.write(e.Writer.ConsolePwd(terminal.OSC99, "", "", cwd))
|
e.write(terminal.ConsolePwd(terminal.OSC99, "", "", cwd))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +110,7 @@ func (e *Engine) pwd() {
|
||||||
|
|
||||||
user := e.Env.User()
|
user := e.Env.User()
|
||||||
host, _ := e.Env.Host()
|
host, _ := e.Env.Host()
|
||||||
e.write(e.Writer.ConsolePwd(pwdType, user, host, cwd))
|
e.write(terminal.ConsolePwd(pwdType, user, host, cwd))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Engine) newline() {
|
func (e *Engine) newline() {
|
||||||
|
@ -121,7 +120,7 @@ func (e *Engine) newline() {
|
||||||
|
|
||||||
// WARP terminal will remove \n from the prompt, so we hack a newline in
|
// WARP terminal will remove \n from the prompt, so we hack a newline in
|
||||||
if e.isWarp() {
|
if e.isWarp() {
|
||||||
e.write(e.Writer.LineBreak())
|
e.write(terminal.LineBreak())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,8 +154,8 @@ func (e *Engine) shouldFill(filler string, remaining, blockLength int) (string,
|
||||||
}
|
}
|
||||||
|
|
||||||
// allow for easy color overrides and templates
|
// allow for easy color overrides and templates
|
||||||
e.Writer.Write("", "", filler)
|
terminal.Write("", "", filler)
|
||||||
filler, lenFiller := e.Writer.String()
|
filler, lenFiller := terminal.String()
|
||||||
if lenFiller == 0 {
|
if lenFiller == 0 {
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
@ -197,7 +196,7 @@ func (e *Engine) renderBlock(block *Block, cancelNewline bool) bool {
|
||||||
if e.Env.Shell() == shell.BASH && block.Type == RPrompt {
|
if e.Env.Shell() == shell.BASH && block.Type == RPrompt {
|
||||||
block.InitPlain(e.Env, e.Config)
|
block.InitPlain(e.Env, e.Config)
|
||||||
} else {
|
} else {
|
||||||
block.Init(e.Env, e.Writer)
|
block.Init(e.Env)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !block.Enabled() {
|
if !block.Enabled() {
|
||||||
|
@ -221,7 +220,7 @@ func (e *Engine) renderBlock(block *Block, cancelNewline bool) bool {
|
||||||
switch block.Type { //nolint:exhaustive
|
switch block.Type { //nolint:exhaustive
|
||||||
case Prompt:
|
case Prompt:
|
||||||
if block.VerticalOffset != 0 {
|
if block.VerticalOffset != 0 {
|
||||||
e.write(e.Writer.ChangeLine(block.VerticalOffset))
|
e.write(terminal.ChangeLine(block.VerticalOffset))
|
||||||
}
|
}
|
||||||
|
|
||||||
if block.Alignment == Left {
|
if block.Alignment == Left {
|
||||||
|
@ -292,5 +291,5 @@ func (e *Engine) patchPowerShellBleed() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
e.write(e.Writer.ClearAfter())
|
e.write(terminal.ClearAfter())
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,18 +85,19 @@ func TestPrintPWD(t *testing.T) {
|
||||||
Shell: "shell",
|
Shell: "shell",
|
||||||
})
|
})
|
||||||
|
|
||||||
writer := &terminal.Writer{}
|
terminal.Init(shell.GENERIC)
|
||||||
writer.Init(shell.GENERIC)
|
|
||||||
engine := &Engine{
|
engine := &Engine{
|
||||||
Env: env,
|
Env: env,
|
||||||
Config: &Config{
|
Config: &Config{
|
||||||
PWD: tc.Config,
|
PWD: tc.Config,
|
||||||
OSC99: tc.OSC99,
|
OSC99: tc.OSC99,
|
||||||
},
|
},
|
||||||
Writer: writer,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
engine.pwd()
|
engine.pwd()
|
||||||
got := engine.string()
|
got := engine.string()
|
||||||
|
|
||||||
assert.Equal(t, tc.Expected, got, tc.Case)
|
assert.Equal(t, tc.Expected, got, tc.Case)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,17 +115,14 @@ func engineRender() {
|
||||||
|
|
||||||
cfg := LoadConfig(env)
|
cfg := LoadConfig(env)
|
||||||
|
|
||||||
writerColors := cfg.MakeColors()
|
terminal.Init(shell.GENERIC)
|
||||||
writer := &terminal.Writer{
|
terminal.BackgroundColor = shell.ConsoleBackgroundColor(env, cfg.TerminalBackground)
|
||||||
BackgroundColor: shell.ConsoleBackgroundColor(env, cfg.TerminalBackground),
|
terminal.AnsiColors = cfg.MakeColors()
|
||||||
AnsiColors: writerColors,
|
terminal.TrueColor = env.CmdFlags.TrueColor
|
||||||
TrueColor: env.CmdFlags.TrueColor,
|
|
||||||
}
|
|
||||||
writer.Init(shell.GENERIC)
|
|
||||||
engine := &Engine{
|
engine := &Engine{
|
||||||
Config: cfg,
|
Config: cfg,
|
||||||
Env: env,
|
Env: env,
|
||||||
Writer: writer,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
engine.Primary()
|
engine.Primary()
|
||||||
|
@ -188,17 +186,19 @@ func TestGetTitle(t *testing.T) {
|
||||||
PWD: tc.Cwd,
|
PWD: tc.Cwd,
|
||||||
Folder: "vagrant",
|
Folder: "vagrant",
|
||||||
})
|
})
|
||||||
writer := &terminal.Writer{}
|
|
||||||
writer.Init(shell.GENERIC)
|
terminal.Init(shell.GENERIC)
|
||||||
|
|
||||||
engine := &Engine{
|
engine := &Engine{
|
||||||
Config: &Config{
|
Config: &Config{
|
||||||
ConsoleTitleTemplate: tc.Template,
|
ConsoleTitleTemplate: tc.Template,
|
||||||
},
|
},
|
||||||
Writer: writer,
|
Env: env,
|
||||||
Env: env,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
title := engine.getTitleTemplateText()
|
title := engine.getTitleTemplateText()
|
||||||
got := writer.FormatTitle(title)
|
got := terminal.FormatTitle(title)
|
||||||
|
|
||||||
assert.Equal(t, tc.Expected, got)
|
assert.Equal(t, tc.Expected, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -247,17 +247,19 @@ func TestGetConsoleTitleIfGethostnameReturnsError(t *testing.T) {
|
||||||
Root: tc.Root,
|
Root: tc.Root,
|
||||||
HostName: "",
|
HostName: "",
|
||||||
})
|
})
|
||||||
writer := &terminal.Writer{}
|
|
||||||
writer.Init(shell.GENERIC)
|
terminal.Init(shell.GENERIC)
|
||||||
|
|
||||||
engine := &Engine{
|
engine := &Engine{
|
||||||
Config: &Config{
|
Config: &Config{
|
||||||
ConsoleTitleTemplate: tc.Template,
|
ConsoleTitleTemplate: tc.Template,
|
||||||
},
|
},
|
||||||
Writer: writer,
|
Env: env,
|
||||||
Env: env,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
title := engine.getTitleTemplateText()
|
title := engine.getTitleTemplateText()
|
||||||
got := writer.FormatTitle(title)
|
got := terminal.FormatTitle(title)
|
||||||
|
|
||||||
assert.Equal(t, tc.Expected, got)
|
assert.Equal(t, tc.Expected, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,7 +114,6 @@ type ImageRenderer struct {
|
||||||
CursorPadding int
|
CursorPadding int
|
||||||
RPromptOffset int
|
RPromptOffset int
|
||||||
BgColor string
|
BgColor string
|
||||||
Ansi *terminal.Writer
|
|
||||||
|
|
||||||
env platform.Environment
|
env platform.Environment
|
||||||
|
|
||||||
|
|
|
@ -34,11 +34,10 @@ func runImageTest(config, content string) (string, error) {
|
||||||
}
|
}
|
||||||
defer os.Remove(file.Name())
|
defer os.Remove(file.Name())
|
||||||
|
|
||||||
writer := &terminal.Writer{}
|
terminal.Init(shell.GENERIC)
|
||||||
writer.Init(shell.GENERIC)
|
|
||||||
image := &ImageRenderer{
|
image := &ImageRenderer{
|
||||||
AnsiString: content,
|
AnsiString: content,
|
||||||
Ansi: writer,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
env := &platform.Shell{
|
env := &platform.Shell{
|
||||||
|
|
|
@ -24,18 +24,15 @@ func New(flags *platform.Flags) *Engine {
|
||||||
env.Var = cfg.Var
|
env.Var = cfg.Var
|
||||||
flags.HasTransient = cfg.TransientPrompt != nil
|
flags.HasTransient = cfg.TransientPrompt != nil
|
||||||
|
|
||||||
ansiWriter := &terminal.Writer{
|
terminal.Init(env.Shell())
|
||||||
BackgroundColor: shell.ConsoleBackgroundColor(env, cfg.TerminalBackground),
|
terminal.BackgroundColor = shell.ConsoleBackgroundColor(env, cfg.TerminalBackground)
|
||||||
AnsiColors: cfg.MakeColors(),
|
terminal.AnsiColors = cfg.MakeColors()
|
||||||
Plain: flags.Plain,
|
terminal.Plain = flags.Plain
|
||||||
TrueColor: env.CmdFlags.TrueColor,
|
terminal.TrueColor = env.CmdFlags.TrueColor
|
||||||
}
|
|
||||||
ansiWriter.Init(env.Shell())
|
|
||||||
|
|
||||||
eng := &Engine{
|
eng := &Engine{
|
||||||
Config: cfg,
|
Config: cfg,
|
||||||
Env: env,
|
Env: env,
|
||||||
Writer: ansiWriter,
|
|
||||||
Plain: flags.Plain,
|
Plain: flags.Plain,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,8 +22,8 @@ const (
|
||||||
func (e *Engine) Primary() string {
|
func (e *Engine) Primary() string {
|
||||||
if e.Config.ShellIntegration {
|
if e.Config.ShellIntegration {
|
||||||
exitCode, _ := e.Env.StatusCodes()
|
exitCode, _ := e.Env.StatusCodes()
|
||||||
e.write(e.Writer.CommandFinished(exitCode, e.Env.Flags().NoExitCode))
|
e.write(terminal.CommandFinished(exitCode, e.Env.Flags().NoExitCode))
|
||||||
e.write(e.Writer.PromptStart())
|
e.write(terminal.PromptStart())
|
||||||
}
|
}
|
||||||
|
|
||||||
// cache a pointer to the color cycle
|
// cache a pointer to the color cycle
|
||||||
|
@ -60,7 +60,7 @@ func (e *Engine) Primary() string {
|
||||||
|
|
||||||
if len(e.Config.ConsoleTitleTemplate) > 0 && !e.Env.Flags().Plain {
|
if len(e.Config.ConsoleTitleTemplate) > 0 && !e.Env.Flags().Plain {
|
||||||
title := e.getTitleTemplateText()
|
title := e.getTitleTemplateText()
|
||||||
e.write(e.Writer.FormatTitle(title))
|
e.write(terminal.FormatTitle(title))
|
||||||
}
|
}
|
||||||
|
|
||||||
if e.Config.FinalSpace {
|
if e.Config.FinalSpace {
|
||||||
|
@ -70,11 +70,11 @@ func (e *Engine) Primary() string {
|
||||||
|
|
||||||
if e.Config.ITermFeatures != nil && e.isIterm() {
|
if e.Config.ITermFeatures != nil && e.isIterm() {
|
||||||
host, _ := e.Env.Host()
|
host, _ := e.Env.Host()
|
||||||
e.write(e.Writer.RenderItermFeatures(e.Config.ITermFeatures, e.Env.Shell(), e.Env.Pwd(), e.Env.User(), host))
|
e.write(terminal.RenderItermFeatures(e.Config.ITermFeatures, e.Env.Shell(), e.Env.Pwd(), e.Env.User(), host))
|
||||||
}
|
}
|
||||||
|
|
||||||
if e.Config.ShellIntegration && e.Config.TransientPrompt == nil {
|
if e.Config.ShellIntegration && e.Config.TransientPrompt == nil {
|
||||||
e.write(e.Writer.CommandStart())
|
e.write(terminal.CommandStart())
|
||||||
}
|
}
|
||||||
|
|
||||||
e.pwd()
|
e.pwd()
|
||||||
|
@ -104,15 +104,15 @@ func (e *Engine) Primary() string {
|
||||||
}
|
}
|
||||||
// in bash, the entire rprompt needs to be escaped for the prompt to be interpreted correctly
|
// 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
|
// see https://github.com/jandedobbeleer/oh-my-posh/pull/2398
|
||||||
writer := &terminal.Writer{
|
|
||||||
TrueColor: e.Env.Flags().TrueColor,
|
terminal.Init(shell.GENERIC)
|
||||||
}
|
terminal.TrueColor = e.Env.Flags().TrueColor
|
||||||
writer.Init(shell.GENERIC)
|
|
||||||
prompt := writer.SaveCursorPosition()
|
prompt := terminal.SaveCursorPosition()
|
||||||
prompt += strings.Repeat(" ", space)
|
prompt += strings.Repeat(" ", space)
|
||||||
prompt += e.rprompt
|
prompt += e.rprompt
|
||||||
prompt += writer.RestoreCursorPosition()
|
prompt += terminal.RestoreCursorPosition()
|
||||||
prompt = e.Writer.EscapeText(prompt)
|
prompt = terminal.EscapeText(prompt)
|
||||||
e.write(prompt)
|
e.write(prompt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,16 +168,16 @@ func (e *Engine) ExtraPrompt(promptType ExtraPromptType) string {
|
||||||
|
|
||||||
if promptType == Transient && e.Config.ShellIntegration {
|
if promptType == Transient && e.Config.ShellIntegration {
|
||||||
exitCode, _ := e.Env.StatusCodes()
|
exitCode, _ := e.Env.StatusCodes()
|
||||||
e.write(e.Writer.CommandFinished(exitCode, e.Env.Flags().NoExitCode))
|
e.write(terminal.CommandFinished(exitCode, e.Env.Flags().NoExitCode))
|
||||||
e.write(e.Writer.PromptStart())
|
e.write(terminal.PromptStart())
|
||||||
}
|
}
|
||||||
|
|
||||||
foreground := prompt.ForegroundTemplates.FirstMatch(nil, e.Env, prompt.Foreground)
|
foreground := prompt.ForegroundTemplates.FirstMatch(nil, e.Env, prompt.Foreground)
|
||||||
background := prompt.BackgroundTemplates.FirstMatch(nil, e.Env, prompt.Background)
|
background := prompt.BackgroundTemplates.FirstMatch(nil, e.Env, prompt.Background)
|
||||||
e.Writer.SetColors(background, foreground)
|
terminal.SetColors(background, foreground)
|
||||||
e.Writer.Write(background, foreground, promptText)
|
terminal.Write(background, foreground, promptText)
|
||||||
|
|
||||||
str, length := e.Writer.String()
|
str, length := terminal.String()
|
||||||
if promptType == Transient {
|
if promptType == Transient {
|
||||||
consoleWidth, err := e.Env.TerminalWidth()
|
consoleWidth, err := e.Env.TerminalWidth()
|
||||||
if err == nil || consoleWidth != 0 {
|
if err == nil || consoleWidth != 0 {
|
||||||
|
@ -188,7 +188,7 @@ func (e *Engine) ExtraPrompt(promptType ExtraPromptType) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
if promptType == Transient && e.Config.ShellIntegration {
|
if promptType == Transient && e.Config.ShellIntegration {
|
||||||
str += e.Writer.CommandStart()
|
str += terminal.CommandStart()
|
||||||
}
|
}
|
||||||
|
|
||||||
switch e.Env.Shell() {
|
switch e.Env.Shell() {
|
||||||
|
@ -205,7 +205,7 @@ func (e *Engine) ExtraPrompt(promptType ExtraPromptType) string {
|
||||||
// Return the string and empty our buffer
|
// Return the string and empty our buffer
|
||||||
// clear the line afterwards to prevent text from being written on the same line
|
// clear the line afterwards to prevent text from being written on the same line
|
||||||
// see https://github.com/JanDeDobbeleer/oh-my-posh/issues/3628
|
// see https://github.com/JanDeDobbeleer/oh-my-posh/issues/3628
|
||||||
return str + e.Writer.ClearAfter()
|
return str + terminal.ClearAfter()
|
||||||
case shell.CMD, shell.BASH, shell.FISH, shell.NU, shell.GENERIC:
|
case shell.CMD, shell.BASH, shell.FISH, shell.NU, shell.GENERIC:
|
||||||
// Return the string and empty our buffer
|
// Return the string and empty our buffer
|
||||||
return str
|
return str
|
||||||
|
@ -229,7 +229,7 @@ func (e *Engine) RPrompt() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
block.Init(e.Env, e.Writer)
|
block.Init(e.Env)
|
||||||
if !block.Enabled() {
|
if !block.Enabled() {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/shell"
|
"github.com/jandedobbeleer/oh-my-posh/src/shell"
|
||||||
|
"github.com/jandedobbeleer/oh-my-posh/src/terminal"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (e *Engine) Tooltip(tip string) string {
|
func (e *Engine) Tooltip(tip string) string {
|
||||||
|
@ -38,7 +39,7 @@ func (e *Engine) Tooltip(tip string) string {
|
||||||
|
|
||||||
switch e.Env.Shell() {
|
switch e.Env.Shell() {
|
||||||
case shell.ZSH, shell.CMD, shell.FISH, shell.GENERIC:
|
case shell.ZSH, shell.CMD, shell.FISH, shell.GENERIC:
|
||||||
block.Init(e.Env, e.Writer)
|
block.Init(e.Env)
|
||||||
if !block.Enabled() {
|
if !block.Enabled() {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -63,7 +64,7 @@ func (e *Engine) Tooltip(tip string) string {
|
||||||
}
|
}
|
||||||
// clear from cursor to the end of the line in case a previous tooltip
|
// clear from cursor to the end of the line in case a previous tooltip
|
||||||
// is cut off and partially preserved, if the new one is shorter
|
// is cut off and partially preserved, if the new one is shorter
|
||||||
e.write(e.Writer.ClearAfter())
|
e.write(terminal.ClearAfter())
|
||||||
e.write(strings.Repeat(" ", space))
|
e.write(strings.Repeat(" ", space))
|
||||||
e.write(text)
|
e.write(text)
|
||||||
return e.string()
|
return e.string()
|
||||||
|
|
|
@ -8,7 +8,7 @@ func GetAccentColor(_ platform.Environment) (*RGB, error) {
|
||||||
return nil, &platform.NotImplemented{}
|
return nil, &platform.NotImplemented{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DefaultColors) SetAccentColor(env platform.Environment, defaultColor string) {
|
func (d *DefaultColors) SetAccentColor(_ platform.Environment, defaultColor string) {
|
||||||
if len(defaultColor) == 0 {
|
if len(defaultColor) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ func (f ITermFeatures) Contains(feature iTermFeature) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Writer) RenderItermFeatures(features ITermFeatures, sh, pwd, user, host string) string {
|
func RenderItermFeatures(features ITermFeatures, sh, pwd, user, host string) string {
|
||||||
supportedShells := []string{shell.BASH, shell.ZSH}
|
supportedShells := []string{shell.BASH, shell.ZSH}
|
||||||
|
|
||||||
var result strings.Builder
|
var result strings.Builder
|
||||||
|
@ -39,11 +39,11 @@ func (w *Writer) RenderItermFeatures(features ITermFeatures, sh, pwd, user, host
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
result.WriteString(w.formats.iTermPromptMark)
|
result.WriteString(formats.iTermPromptMark)
|
||||||
case CurrentDir:
|
case CurrentDir:
|
||||||
result.WriteString(fmt.Sprintf(w.formats.iTermCurrentDir, pwd))
|
result.WriteString(fmt.Sprintf(formats.iTermCurrentDir, pwd))
|
||||||
case RemoteHost:
|
case RemoteHost:
|
||||||
result.WriteString(fmt.Sprintf(w.formats.iTermRemoteHost, user, host))
|
result.WriteString(fmt.Sprintf(formats.iTermRemoteHost, user, host))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,33 @@ var (
|
||||||
|
|
||||||
resetStyle = &style{AnchorStart: "RESET", AnchorEnd: `</>`, End: "\x1b[0m"}
|
resetStyle = &style{AnchorStart: "RESET", AnchorEnd: `</>`, End: "\x1b[0m"}
|
||||||
backgroundStyle = &style{AnchorStart: "BACKGROUND", AnchorEnd: `</>`, End: "\x1b[49m"}
|
backgroundStyle = &style{AnchorStart: "BACKGROUND", AnchorEnd: `</>`, End: "\x1b[49m"}
|
||||||
|
|
||||||
|
BackgroundColor string
|
||||||
|
CurrentColors *Colors
|
||||||
|
ParentColors []*Colors
|
||||||
|
AnsiColors ColorString
|
||||||
|
|
||||||
|
Plain bool
|
||||||
|
TrueColor bool
|
||||||
|
Interactive bool
|
||||||
|
|
||||||
|
builder strings.Builder
|
||||||
|
length int
|
||||||
|
|
||||||
|
foregroundColor Color
|
||||||
|
backgroundColor Color
|
||||||
|
currentColor ColorHistory
|
||||||
|
runes []rune
|
||||||
|
|
||||||
|
isTransparent bool
|
||||||
|
isInvisible bool
|
||||||
|
isHyperlink bool
|
||||||
|
|
||||||
|
lastRune rune
|
||||||
|
|
||||||
|
shellName string
|
||||||
|
|
||||||
|
formats *shellFormats
|
||||||
)
|
)
|
||||||
|
|
||||||
type shellFormats struct {
|
type shellFormats struct {
|
||||||
|
@ -104,42 +131,12 @@ const (
|
||||||
hyperLinkTextEnd = "</TEXT>"
|
hyperLinkTextEnd = "</TEXT>"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Writer writes colorized ANSI strings
|
func Init(sh string) {
|
||||||
type Writer struct {
|
shellName = sh
|
||||||
BackgroundColor string
|
|
||||||
CurrentColors *Colors
|
|
||||||
ParentColors []*Colors
|
|
||||||
AnsiColors ColorString
|
|
||||||
|
|
||||||
Plain bool
|
switch shellName {
|
||||||
TrueColor bool
|
|
||||||
Interactive bool
|
|
||||||
|
|
||||||
builder strings.Builder
|
|
||||||
length int
|
|
||||||
|
|
||||||
foregroundColor Color
|
|
||||||
backgroundColor Color
|
|
||||||
currentColor ColorHistory
|
|
||||||
runes []rune
|
|
||||||
|
|
||||||
isTransparent bool
|
|
||||||
isInvisible bool
|
|
||||||
isHyperlink bool
|
|
||||||
|
|
||||||
lastRune rune
|
|
||||||
|
|
||||||
shellName string
|
|
||||||
|
|
||||||
formats *shellFormats
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *Writer) Init(shellName string) {
|
|
||||||
w.shellName = shellName
|
|
||||||
|
|
||||||
switch w.shellName {
|
|
||||||
case shell.BASH:
|
case shell.BASH:
|
||||||
w.formats = &shellFormats{
|
formats = &shellFormats{
|
||||||
escape: "\\[%s\\]",
|
escape: "\\[%s\\]",
|
||||||
linechange: "\\[\x1b[%d%s\\]",
|
linechange: "\\[\x1b[%d%s\\]",
|
||||||
left: "\\[\x1b[%dD\\]",
|
left: "\\[\x1b[%dD\\]",
|
||||||
|
@ -163,7 +160,7 @@ func (w *Writer) Init(shellName string) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
case shell.ZSH, shell.TCSH:
|
case shell.ZSH, shell.TCSH:
|
||||||
w.formats = &shellFormats{
|
formats = &shellFormats{
|
||||||
escape: "%%{%s%%}",
|
escape: "%%{%s%%}",
|
||||||
linechange: "%%{\x1b[%d%s%%}",
|
linechange: "%%{\x1b[%d%s%%}",
|
||||||
left: "%%{\x1b[%dD%%}",
|
left: "%%{\x1b[%dD%%}",
|
||||||
|
@ -183,7 +180,7 @@ func (w *Writer) Init(shellName string) {
|
||||||
iTermRemoteHost: "%%{\x1b]1337;RemoteHost=%s@%s\x07%%}",
|
iTermRemoteHost: "%%{\x1b]1337;RemoteHost=%s@%s\x07%%}",
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
w.formats = &shellFormats{
|
formats = &shellFormats{
|
||||||
escape: "%s",
|
escape: "%s",
|
||||||
linechange: "\x1b[%d%s",
|
linechange: "\x1b[%d%s",
|
||||||
left: "\x1b[%dD",
|
left: "\x1b[%dD",
|
||||||
|
@ -207,33 +204,33 @@ func (w *Writer) Init(shellName string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if shellName == shell.ZSH {
|
if shellName == shell.ZSH {
|
||||||
w.formats.escapeSequences = map[rune]rune{
|
formats.escapeSequences = map[rune]rune{
|
||||||
96: 92, // backtick
|
96: 92, // backtick
|
||||||
37: 37, // %
|
37: 37, // %
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Writer) SetColors(background, foreground string) {
|
func SetColors(background, foreground string) {
|
||||||
w.CurrentColors = &Colors{
|
CurrentColors = &Colors{
|
||||||
Background: background,
|
Background: background,
|
||||||
Foreground: foreground,
|
Foreground: foreground,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Writer) SetParentColors(background, foreground string) {
|
func SetParentColors(background, foreground string) {
|
||||||
if w.ParentColors == nil {
|
if ParentColors == nil {
|
||||||
w.ParentColors = make([]*Colors, 0)
|
ParentColors = make([]*Colors, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.ParentColors = append([]*Colors{{
|
ParentColors = append([]*Colors{{
|
||||||
Background: background,
|
Background: background,
|
||||||
Foreground: foreground,
|
Foreground: foreground,
|
||||||
}}, w.ParentColors...)
|
}}, ParentColors...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Writer) ChangeLine(numberOfLines int) string {
|
func ChangeLine(numberOfLines int) string {
|
||||||
if w.Plain {
|
if Plain {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,11 +241,11 @@ func (w *Writer) ChangeLine(numberOfLines int) string {
|
||||||
numberOfLines = -numberOfLines
|
numberOfLines = -numberOfLines
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf(w.formats.linechange, numberOfLines, position)
|
return fmt.Sprintf(formats.linechange, numberOfLines, position)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Writer) ConsolePwd(pwdType, userName, hostName, pwd string) string {
|
func ConsolePwd(pwdType, userName, hostName, pwd string) string {
|
||||||
if w.Plain {
|
if Plain {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,33 +255,33 @@ func (w *Writer) ConsolePwd(pwdType, userName, hostName, pwd string) string {
|
||||||
|
|
||||||
switch pwdType {
|
switch pwdType {
|
||||||
case OSC7:
|
case OSC7:
|
||||||
return fmt.Sprintf(w.formats.osc7, hostName, pwd)
|
return fmt.Sprintf(formats.osc7, hostName, pwd)
|
||||||
case OSC51:
|
case OSC51:
|
||||||
return fmt.Sprintf(w.formats.osc51, userName, hostName, pwd)
|
return fmt.Sprintf(formats.osc51, userName, hostName, pwd)
|
||||||
case OSC99:
|
case OSC99:
|
||||||
fallthrough
|
fallthrough
|
||||||
default:
|
default:
|
||||||
return fmt.Sprintf(w.formats.osc99, pwd)
|
return fmt.Sprintf(formats.osc99, pwd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Writer) ClearAfter() string {
|
func ClearAfter() string {
|
||||||
if w.Plain {
|
if Plain {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return w.formats.clearLine + w.formats.clearBelow
|
return formats.clearLine + formats.clearBelow
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Writer) FormatTitle(title string) string {
|
func FormatTitle(title string) string {
|
||||||
title = w.trimAnsi(title)
|
title = trimAnsi(title)
|
||||||
|
|
||||||
if w.Plain {
|
if Plain {
|
||||||
return title
|
return title
|
||||||
}
|
}
|
||||||
|
|
||||||
// we have to do this to prevent bash/zsh from misidentifying escape sequences
|
// we have to do this to prevent bash/zsh from misidentifying escape sequences
|
||||||
switch w.shellName {
|
switch shellName {
|
||||||
case shell.BASH:
|
case shell.BASH:
|
||||||
title = strings.NewReplacer("`", "\\`", `\`, `\\`).Replace(title)
|
title = strings.NewReplacer("`", "\\`", `\`, `\\`).Replace(title)
|
||||||
case shell.ZSH:
|
case shell.ZSH:
|
||||||
|
@ -294,55 +291,55 @@ func (w *Writer) FormatTitle(title string) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf(w.formats.title, title)
|
return fmt.Sprintf(formats.title, title)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Writer) EscapeText(text string) string {
|
func EscapeText(text string) string {
|
||||||
return fmt.Sprintf(w.formats.escape, text)
|
return fmt.Sprintf(formats.escape, text)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Writer) SaveCursorPosition() string {
|
func SaveCursorPosition() string {
|
||||||
return w.formats.saveCursorPosition
|
return formats.saveCursorPosition
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Writer) RestoreCursorPosition() string {
|
func RestoreCursorPosition() string {
|
||||||
return w.formats.restoreCursorPosition
|
return formats.restoreCursorPosition
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Writer) PromptStart() string {
|
func PromptStart() string {
|
||||||
return fmt.Sprintf(w.formats.escape, "\x1b]133;A\007")
|
return fmt.Sprintf(formats.escape, "\x1b]133;A\007")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Writer) CommandStart() string {
|
func CommandStart() string {
|
||||||
return fmt.Sprintf(w.formats.escape, "\x1b]133;B\007")
|
return fmt.Sprintf(formats.escape, "\x1b]133;B\007")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Writer) CommandFinished(code int, ignore bool) string {
|
func CommandFinished(code int, ignore bool) string {
|
||||||
if ignore {
|
if ignore {
|
||||||
return fmt.Sprintf(w.formats.escape, "\x1b]133;D\007")
|
return fmt.Sprintf(formats.escape, "\x1b]133;D\007")
|
||||||
}
|
}
|
||||||
|
|
||||||
mark := fmt.Sprintf("\x1b]133;D;%d\007", code)
|
mark := fmt.Sprintf("\x1b]133;D;%d\007", code)
|
||||||
|
|
||||||
return fmt.Sprintf(w.formats.escape, mark)
|
return fmt.Sprintf(formats.escape, mark)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Writer) LineBreak() string {
|
func LineBreak() string {
|
||||||
cr := fmt.Sprintf(w.formats.left, 1000)
|
cr := fmt.Sprintf(formats.left, 1000)
|
||||||
lf := fmt.Sprintf(w.formats.linechange, 1, "B")
|
lf := fmt.Sprintf(formats.linechange, 1, "B")
|
||||||
return cr + lf
|
return cr + lf
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Writer) Write(background, foreground, text string) {
|
func Write(background, foreground, text string) {
|
||||||
if len(text) == 0 {
|
if len(text) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w.backgroundColor, w.foregroundColor = w.asAnsiColors(background, foreground)
|
backgroundColor, foregroundColor = asAnsiColors(background, foreground)
|
||||||
|
|
||||||
// default to white foreground
|
// default to white foreground
|
||||||
if w.foregroundColor.IsEmpty() {
|
if foregroundColor.IsEmpty() {
|
||||||
w.foregroundColor = w.AnsiColors.ToColor("white", false, w.TrueColor)
|
foregroundColor = AnsiColors.ToColor("white", false, TrueColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate if we start with a color override
|
// validate if we start with a color override
|
||||||
|
@ -354,182 +351,185 @@ func (w *Writer) Write(background, foreground, text string) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
w.writeEscapedAnsiString(style.Start)
|
writeEscapedAnsiString(style.Start)
|
||||||
colorOverride = false
|
colorOverride = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if colorOverride {
|
if colorOverride {
|
||||||
w.currentColor.Add(w.asAnsiColors(match[BG], match[FG]))
|
currentColor.Add(asAnsiColors(match[BG], match[FG]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
w.writeSegmentColors()
|
writeSegmentColors()
|
||||||
|
|
||||||
// print the hyperlink part AFTER the coloring
|
// print the hyperlink part AFTER the coloring
|
||||||
if match[ANCHOR] == hyperLinkStart {
|
if match[ANCHOR] == hyperLinkStart {
|
||||||
w.isHyperlink = true
|
isHyperlink = true
|
||||||
w.builder.WriteString(w.formats.hyperlinkStart)
|
builder.WriteString(formats.hyperlinkStart)
|
||||||
}
|
}
|
||||||
|
|
||||||
text = text[len(match[ANCHOR]):]
|
text = text[len(match[ANCHOR]):]
|
||||||
w.runes = []rune(text)
|
runes = []rune(text)
|
||||||
hyperlinkTextPosition := 0
|
hyperlinkTextPosition := 0
|
||||||
|
|
||||||
for i := 0; i < len(w.runes); i++ {
|
for i := 0; i < len(runes); i++ {
|
||||||
s := w.runes[i]
|
s := runes[i]
|
||||||
// ignore everything which isn't overriding
|
// ignore everything which isn't overriding
|
||||||
if s != '<' {
|
if s != '<' {
|
||||||
w.write(s)
|
write(s)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// color/end overrides first
|
// color/end overrides first
|
||||||
text = string(w.runes[i:])
|
text = string(runes[i:])
|
||||||
match = regex.FindNamedRegexMatch(AnchorRegex, text)
|
match = regex.FindNamedRegexMatch(AnchorRegex, text)
|
||||||
if len(match) > 0 {
|
if len(match) > 0 {
|
||||||
// check for hyperlinks first
|
// check for hyperlinks first
|
||||||
switch match[ANCHOR] {
|
switch match[ANCHOR] {
|
||||||
case hyperLinkStart:
|
case hyperLinkStart:
|
||||||
w.isHyperlink = true
|
isHyperlink = true
|
||||||
i += len([]rune(match[ANCHOR])) - 1
|
i += len([]rune(match[ANCHOR])) - 1
|
||||||
w.builder.WriteString(w.formats.hyperlinkStart)
|
builder.WriteString(formats.hyperlinkStart)
|
||||||
continue
|
continue
|
||||||
case hyperLinkText:
|
case hyperLinkText:
|
||||||
w.isHyperlink = false
|
isHyperlink = false
|
||||||
i += len([]rune(match[ANCHOR])) - 1
|
i += len([]rune(match[ANCHOR])) - 1
|
||||||
hyperlinkTextPosition = i
|
hyperlinkTextPosition = i
|
||||||
w.builder.WriteString(w.formats.hyperlinkCenter)
|
builder.WriteString(formats.hyperlinkCenter)
|
||||||
continue
|
continue
|
||||||
case hyperLinkTextEnd:
|
case hyperLinkTextEnd:
|
||||||
// this implies there's no text in the hyperlink
|
// this implies there's no text in the hyperlink
|
||||||
if hyperlinkTextPosition+1 == i {
|
if hyperlinkTextPosition+1 == i {
|
||||||
w.builder.WriteString("link")
|
builder.WriteString("link")
|
||||||
w.length += 4
|
length += 4
|
||||||
}
|
}
|
||||||
i += len([]rune(match[ANCHOR])) - 1
|
i += len([]rune(match[ANCHOR])) - 1
|
||||||
continue
|
continue
|
||||||
case hyperLinkEnd:
|
case hyperLinkEnd:
|
||||||
i += len([]rune(match[ANCHOR])) - 1
|
i += len([]rune(match[ANCHOR])) - 1
|
||||||
w.builder.WriteString(w.formats.hyperlinkEnd)
|
builder.WriteString(formats.hyperlinkEnd)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
i = w.writeArchorOverride(match, background, i)
|
i = writeArchorOverride(match, background, i)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
w.length += runewidth.RuneWidth(s)
|
length += runewidth.RuneWidth(s)
|
||||||
w.write(s)
|
write(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset colors
|
// reset colors
|
||||||
w.writeEscapedAnsiString(resetStyle.End)
|
writeEscapedAnsiString(resetStyle.End)
|
||||||
|
|
||||||
// pop last color from the stack
|
// pop last color from the stack
|
||||||
w.currentColor.Pop()
|
currentColor.Pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Writer) String() (string, int) {
|
func String() (string, int) {
|
||||||
defer func() {
|
defer func() {
|
||||||
w.length = 0
|
length = 0
|
||||||
w.builder.Reset()
|
builder.Reset()
|
||||||
|
|
||||||
|
isTransparent = false
|
||||||
|
isInvisible = false
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return w.builder.String(), w.length
|
return builder.String(), length
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Writer) writeEscapedAnsiString(text string) {
|
func writeEscapedAnsiString(text string) {
|
||||||
if w.Plain {
|
if Plain {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(w.formats.escape) != 0 {
|
if len(formats.escape) != 0 {
|
||||||
text = fmt.Sprintf(w.formats.escape, text)
|
text = fmt.Sprintf(formats.escape, text)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.builder.WriteString(text)
|
builder.WriteString(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Writer) getAnsiFromColorString(colorString string, isBackground bool) Color {
|
func getAnsiFromColorString(colorString string, isBackground bool) Color {
|
||||||
return w.AnsiColors.ToColor(colorString, isBackground, w.TrueColor)
|
return AnsiColors.ToColor(colorString, isBackground, TrueColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Writer) write(s rune) {
|
func write(s rune) {
|
||||||
if w.isInvisible {
|
if isInvisible {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if w.isHyperlink {
|
if isHyperlink {
|
||||||
w.builder.WriteRune(s)
|
builder.WriteRune(s)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !w.Interactive {
|
if !Interactive {
|
||||||
for special, escape := range w.formats.escapeSequences {
|
for special, escape := range formats.escapeSequences {
|
||||||
if s == special && w.lastRune != escape {
|
if s == special && lastRune != escape {
|
||||||
w.builder.WriteRune(escape)
|
builder.WriteRune(escape)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
w.length += runewidth.RuneWidth(s)
|
length += runewidth.RuneWidth(s)
|
||||||
w.lastRune = s
|
lastRune = s
|
||||||
w.builder.WriteRune(s)
|
builder.WriteRune(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Writer) writeSegmentColors() {
|
func writeSegmentColors() {
|
||||||
// use correct starting colors
|
// use correct starting colors
|
||||||
bg := w.backgroundColor
|
bg := backgroundColor
|
||||||
fg := w.foregroundColor
|
fg := foregroundColor
|
||||||
if !w.currentColor.Background().IsEmpty() {
|
if !currentColor.Background().IsEmpty() {
|
||||||
bg = w.currentColor.Background()
|
bg = currentColor.Background()
|
||||||
}
|
}
|
||||||
if !w.currentColor.Foreground().IsEmpty() {
|
if !currentColor.Foreground().IsEmpty() {
|
||||||
fg = w.currentColor.Foreground()
|
fg = currentColor.Foreground()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore processing fully tranparent colors
|
// ignore processing fully tranparent colors
|
||||||
w.isInvisible = fg.IsTransparent() && bg.IsTransparent()
|
isInvisible = fg.IsTransparent() && bg.IsTransparent()
|
||||||
if w.isInvisible {
|
if isInvisible {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if fg.IsTransparent() && len(w.BackgroundColor) != 0 { //nolint: gocritic
|
if fg.IsTransparent() && len(BackgroundColor) != 0 { //nolint: gocritic
|
||||||
background := w.getAnsiFromColorString(w.BackgroundColor, false)
|
background := getAnsiFromColorString(BackgroundColor, false)
|
||||||
w.writeEscapedAnsiString(fmt.Sprintf(colorise, background))
|
writeEscapedAnsiString(fmt.Sprintf(colorise, background))
|
||||||
w.writeEscapedAnsiString(fmt.Sprintf(colorise, bg.ToForeground()))
|
writeEscapedAnsiString(fmt.Sprintf(colorise, bg.ToForeground()))
|
||||||
} else if fg.IsTransparent() && !bg.IsEmpty() {
|
} else if fg.IsTransparent() && !bg.IsEmpty() {
|
||||||
w.isTransparent = true
|
isTransparent = true
|
||||||
w.writeEscapedAnsiString(fmt.Sprintf(transparentStart, bg))
|
writeEscapedAnsiString(fmt.Sprintf(transparentStart, bg))
|
||||||
} else {
|
} else {
|
||||||
if !bg.IsEmpty() && !bg.IsTransparent() {
|
if !bg.IsEmpty() && !bg.IsTransparent() {
|
||||||
w.writeEscapedAnsiString(fmt.Sprintf(colorise, bg))
|
writeEscapedAnsiString(fmt.Sprintf(colorise, bg))
|
||||||
}
|
}
|
||||||
if !fg.IsEmpty() {
|
if !fg.IsEmpty() {
|
||||||
w.writeEscapedAnsiString(fmt.Sprintf(colorise, fg))
|
writeEscapedAnsiString(fmt.Sprintf(colorise, fg))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// set current colors
|
// set current colors
|
||||||
w.currentColor.Add(bg, fg)
|
currentColor.Add(bg, fg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Writer) writeArchorOverride(match map[string]string, background string, i int) int {
|
func writeArchorOverride(match map[string]string, background string, i int) int {
|
||||||
position := i
|
position := i
|
||||||
// check color reset first
|
// check color reset first
|
||||||
if match[ANCHOR] == resetStyle.AnchorEnd {
|
if match[ANCHOR] == resetStyle.AnchorEnd {
|
||||||
return w.endColorOverride(position)
|
return endColorOverride(position)
|
||||||
}
|
}
|
||||||
|
|
||||||
position += len([]rune(match[ANCHOR])) - 1
|
position += len([]rune(match[ANCHOR])) - 1
|
||||||
|
|
||||||
for _, style := range knownStyles {
|
for _, style := range knownStyles {
|
||||||
if style.AnchorEnd == match[ANCHOR] {
|
if style.AnchorEnd == match[ANCHOR] {
|
||||||
w.writeEscapedAnsiString(style.End)
|
writeEscapedAnsiString(style.End)
|
||||||
return position
|
return position
|
||||||
}
|
}
|
||||||
if style.AnchorStart == match[ANCHOR] {
|
if style.AnchorStart == match[ANCHOR] {
|
||||||
w.writeEscapedAnsiString(style.Start)
|
writeEscapedAnsiString(style.Start)
|
||||||
return position
|
return position
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -538,77 +538,77 @@ func (w *Writer) writeArchorOverride(match map[string]string, background string,
|
||||||
match[BG] = background
|
match[BG] = background
|
||||||
}
|
}
|
||||||
|
|
||||||
bg, fg := w.asAnsiColors(match[BG], match[FG])
|
bg, fg := asAnsiColors(match[BG], match[FG])
|
||||||
|
|
||||||
// ignore processing fully tranparent colors
|
// ignore processing fully tranparent colors
|
||||||
w.isInvisible = fg.IsTransparent() && bg.IsTransparent()
|
isInvisible = fg.IsTransparent() && bg.IsTransparent()
|
||||||
if w.isInvisible {
|
if isInvisible {
|
||||||
return position
|
return position
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure we have colors
|
// make sure we have colors
|
||||||
if fg.IsEmpty() {
|
if fg.IsEmpty() {
|
||||||
fg = w.foregroundColor
|
fg = foregroundColor
|
||||||
}
|
}
|
||||||
if bg.IsEmpty() {
|
if bg.IsEmpty() {
|
||||||
bg = w.backgroundColor
|
bg = backgroundColor
|
||||||
}
|
}
|
||||||
|
|
||||||
w.currentColor.Add(bg, fg)
|
currentColor.Add(bg, fg)
|
||||||
|
|
||||||
if w.currentColor.Foreground().IsTransparent() && len(w.BackgroundColor) != 0 {
|
if currentColor.Foreground().IsTransparent() && len(BackgroundColor) != 0 {
|
||||||
background := w.getAnsiFromColorString(w.BackgroundColor, false)
|
background := getAnsiFromColorString(BackgroundColor, false)
|
||||||
w.writeEscapedAnsiString(fmt.Sprintf(colorise, background))
|
writeEscapedAnsiString(fmt.Sprintf(colorise, background))
|
||||||
w.writeEscapedAnsiString(fmt.Sprintf(colorise, w.currentColor.Background().ToForeground()))
|
writeEscapedAnsiString(fmt.Sprintf(colorise, currentColor.Background().ToForeground()))
|
||||||
return position
|
return position
|
||||||
}
|
}
|
||||||
|
|
||||||
if w.currentColor.Foreground().IsTransparent() && !w.currentColor.Background().IsTransparent() {
|
if currentColor.Foreground().IsTransparent() && !currentColor.Background().IsTransparent() {
|
||||||
w.isTransparent = true
|
isTransparent = true
|
||||||
w.writeEscapedAnsiString(fmt.Sprintf(transparentStart, w.currentColor.Background()))
|
writeEscapedAnsiString(fmt.Sprintf(transparentStart, currentColor.Background()))
|
||||||
return position
|
return position
|
||||||
}
|
}
|
||||||
|
|
||||||
if w.currentColor.Background() != w.backgroundColor {
|
if currentColor.Background() != backgroundColor {
|
||||||
// end the colors in case we have a transparent background
|
// end the colors in case we have a transparent background
|
||||||
if w.currentColor.Background().IsTransparent() {
|
if currentColor.Background().IsTransparent() {
|
||||||
w.writeEscapedAnsiString(backgroundEnd)
|
writeEscapedAnsiString(backgroundEnd)
|
||||||
} else {
|
} else {
|
||||||
w.writeEscapedAnsiString(fmt.Sprintf(colorise, w.currentColor.Background()))
|
writeEscapedAnsiString(fmt.Sprintf(colorise, currentColor.Background()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if w.currentColor.Foreground() != w.foregroundColor {
|
if currentColor.Foreground() != foregroundColor {
|
||||||
w.writeEscapedAnsiString(fmt.Sprintf(colorise, w.currentColor.Foreground()))
|
writeEscapedAnsiString(fmt.Sprintf(colorise, currentColor.Foreground()))
|
||||||
}
|
}
|
||||||
|
|
||||||
return position
|
return position
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Writer) endColorOverride(position int) int {
|
func endColorOverride(position int) int {
|
||||||
// make sure to reset the colors if needed
|
// make sure to reset the colors if needed
|
||||||
position += len([]rune(resetStyle.AnchorEnd)) - 1
|
position += len([]rune(resetStyle.AnchorEnd)) - 1
|
||||||
|
|
||||||
// do not restore colors at the end of the string, we print it anyways
|
// do not restore colors at the end of the string, we print it anyways
|
||||||
if position == len(w.runes)-1 {
|
if position == len(runes)-1 {
|
||||||
w.currentColor.Pop()
|
currentColor.Pop()
|
||||||
return position
|
return position
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset colors to previous when we have more than 1 in stack
|
// reset colors to previous when we have more than 1 in stack
|
||||||
// as soon as we have more than 1, we can pop the last one
|
// as soon as we have more than 1, we can pop the last one
|
||||||
// and print the previous override as it wasn't ended yet
|
// and print the previous override as it wasn't ended yet
|
||||||
if w.currentColor.Len() > 1 {
|
if currentColor.Len() > 1 {
|
||||||
fg := w.currentColor.Foreground()
|
fg := currentColor.Foreground()
|
||||||
bg := w.currentColor.Background()
|
bg := currentColor.Background()
|
||||||
|
|
||||||
w.currentColor.Pop()
|
currentColor.Pop()
|
||||||
|
|
||||||
previousBg := w.currentColor.Background()
|
previousBg := currentColor.Background()
|
||||||
previousFg := w.currentColor.Foreground()
|
previousFg := currentColor.Foreground()
|
||||||
|
|
||||||
if w.isTransparent {
|
if isTransparent {
|
||||||
w.writeEscapedAnsiString(transparentEnd)
|
writeEscapedAnsiString(transparentEnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
if previousBg != bg {
|
if previousBg != bg {
|
||||||
|
@ -617,45 +617,45 @@ func (w *Writer) endColorOverride(position int) int {
|
||||||
background = backgroundStyle.End
|
background = backgroundStyle.End
|
||||||
}
|
}
|
||||||
|
|
||||||
w.writeEscapedAnsiString(background)
|
writeEscapedAnsiString(background)
|
||||||
}
|
}
|
||||||
|
|
||||||
if previousFg != fg {
|
if previousFg != fg {
|
||||||
w.writeEscapedAnsiString(fmt.Sprintf(colorise, previousFg))
|
writeEscapedAnsiString(fmt.Sprintf(colorise, previousFg))
|
||||||
}
|
}
|
||||||
|
|
||||||
return position
|
return position
|
||||||
}
|
}
|
||||||
|
|
||||||
// pop the last colors from the stack
|
// pop the last colors from the stack
|
||||||
defer w.currentColor.Pop()
|
defer currentColor.Pop()
|
||||||
|
|
||||||
// do not reset when colors are identical
|
// do not reset when colors are identical
|
||||||
if w.currentColor.Background() == w.backgroundColor && w.currentColor.Foreground() == w.foregroundColor {
|
if currentColor.Background() == backgroundColor && currentColor.Foreground() == foregroundColor {
|
||||||
return position
|
return position
|
||||||
}
|
}
|
||||||
|
|
||||||
if w.isTransparent {
|
if isTransparent {
|
||||||
w.writeEscapedAnsiString(transparentEnd)
|
writeEscapedAnsiString(transparentEnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
if w.backgroundColor.IsClear() {
|
if backgroundColor.IsClear() {
|
||||||
w.writeEscapedAnsiString(backgroundStyle.End)
|
writeEscapedAnsiString(backgroundStyle.End)
|
||||||
}
|
}
|
||||||
|
|
||||||
if w.currentColor.Background() != w.backgroundColor && !w.backgroundColor.IsClear() {
|
if currentColor.Background() != backgroundColor && !backgroundColor.IsClear() {
|
||||||
w.writeEscapedAnsiString(fmt.Sprintf(colorise, w.backgroundColor))
|
writeEscapedAnsiString(fmt.Sprintf(colorise, backgroundColor))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (w.currentColor.Foreground() != w.foregroundColor || w.isTransparent) && !w.foregroundColor.IsClear() {
|
if (currentColor.Foreground() != foregroundColor || isTransparent) && !foregroundColor.IsClear() {
|
||||||
w.writeEscapedAnsiString(fmt.Sprintf(colorise, w.foregroundColor))
|
writeEscapedAnsiString(fmt.Sprintf(colorise, foregroundColor))
|
||||||
}
|
}
|
||||||
|
|
||||||
w.isTransparent = false
|
isTransparent = false
|
||||||
return position
|
return position
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Writer) asAnsiColors(background, foreground string) (Color, Color) {
|
func asAnsiColors(background, foreground string) (Color, Color) {
|
||||||
if len(background) == 0 {
|
if len(background) == 0 {
|
||||||
background = Background
|
background = Background
|
||||||
}
|
}
|
||||||
|
@ -664,18 +664,18 @@ func (w *Writer) asAnsiColors(background, foreground string) (Color, Color) {
|
||||||
foreground = Foreground
|
foreground = Foreground
|
||||||
}
|
}
|
||||||
|
|
||||||
background = w.expandKeyword(background)
|
background = expandKeyword(background)
|
||||||
foreground = w.expandKeyword(foreground)
|
foreground = expandKeyword(foreground)
|
||||||
|
|
||||||
inverted := foreground == Transparent && len(background) != 0
|
inverted := foreground == Transparent && len(background) != 0
|
||||||
|
|
||||||
backgroundAnsi := w.getAnsiFromColorString(background, !inverted)
|
backgroundAnsi := getAnsiFromColorString(background, !inverted)
|
||||||
foregroundAnsi := w.getAnsiFromColorString(foreground, false)
|
foregroundAnsi := getAnsiFromColorString(foreground, false)
|
||||||
|
|
||||||
return backgroundAnsi, foregroundAnsi
|
return backgroundAnsi, foregroundAnsi
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Writer) isKeyword(color string) bool {
|
func isKeyword(color string) bool {
|
||||||
switch color {
|
switch color {
|
||||||
case Transparent, ParentBackground, ParentForeground, Background, Foreground:
|
case Transparent, ParentBackground, ParentForeground, Background, Foreground:
|
||||||
return true
|
return true
|
||||||
|
@ -684,9 +684,9 @@ func (w *Writer) isKeyword(color string) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Writer) expandKeyword(keyword string) string {
|
func expandKeyword(keyword string) string {
|
||||||
resolveParentColor := func(keyword string) string {
|
resolveParentColor := func(keyword string) string {
|
||||||
for _, color := range w.ParentColors {
|
for _, color := range ParentColors {
|
||||||
if color == nil {
|
if color == nil {
|
||||||
return Transparent
|
return Transparent
|
||||||
}
|
}
|
||||||
|
@ -712,18 +712,18 @@ func (w *Writer) expandKeyword(keyword string) string {
|
||||||
|
|
||||||
resolveKeyword := func(keyword string) string {
|
resolveKeyword := func(keyword string) string {
|
||||||
switch {
|
switch {
|
||||||
case keyword == Background && w.CurrentColors != nil:
|
case keyword == Background && CurrentColors != nil:
|
||||||
return w.CurrentColors.Background
|
return CurrentColors.Background
|
||||||
case keyword == Foreground && w.CurrentColors != nil:
|
case keyword == Foreground && CurrentColors != nil:
|
||||||
return w.CurrentColors.Foreground
|
return CurrentColors.Foreground
|
||||||
case (keyword == ParentBackground || keyword == ParentForeground) && w.ParentColors != nil:
|
case (keyword == ParentBackground || keyword == ParentForeground) && ParentColors != nil:
|
||||||
return resolveParentColor(keyword)
|
return resolveParentColor(keyword)
|
||||||
default:
|
default:
|
||||||
return Transparent
|
return Transparent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for ok := w.isKeyword(keyword); ok; ok = w.isKeyword(keyword) {
|
for ok := isKeyword(keyword); ok; ok = isKeyword(keyword) {
|
||||||
resolved := resolveKeyword(keyword)
|
resolved := resolveKeyword(keyword)
|
||||||
if resolved == keyword {
|
if resolved == keyword {
|
||||||
break
|
break
|
||||||
|
@ -735,7 +735,7 @@ func (w *Writer) expandKeyword(keyword string) string {
|
||||||
return keyword
|
return keyword
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Writer) trimAnsi(text string) string {
|
func trimAnsi(text string) string {
|
||||||
if len(text) == 0 || !strings.Contains(text, "\x1b") {
|
if len(text) == 0 || !strings.Contains(text, "\x1b") {
|
||||||
return text
|
return text
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,13 +20,14 @@ func TestGenerateHyperlinkNoUrl(t *testing.T) {
|
||||||
{Text: "sample text with no url [test]", ShellName: shell.BASH, Expected: "\\[\x1b[47m\\]\\[\x1b[30m\\]sample text with no url [test]\\[\x1b[0m\\]"},
|
{Text: "sample text with no url [test]", ShellName: shell.BASH, Expected: "\\[\x1b[47m\\]\\[\x1b[30m\\]sample text with no url [test]\\[\x1b[0m\\]"},
|
||||||
}
|
}
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
a := Writer{
|
Init(tc.ShellName)
|
||||||
AnsiColors: &DefaultColors{},
|
AnsiColors = &DefaultColors{}
|
||||||
}
|
|
||||||
a.Init(tc.ShellName)
|
Write("white", "black", tc.Text)
|
||||||
a.Write("white", "black", tc.Text)
|
|
||||||
hyperlinkText, _ := a.String()
|
got, _ := String()
|
||||||
assert.Equal(t, tc.Expected, hyperlinkText)
|
|
||||||
|
assert.Equal(t, tc.Expected, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,13 +94,14 @@ func TestGenerateHyperlinkWithUrl(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
a := Writer{
|
Init(tc.ShellName)
|
||||||
AnsiColors: &DefaultColors{},
|
AnsiColors = &DefaultColors{}
|
||||||
}
|
|
||||||
a.Init(tc.ShellName)
|
Write("white", "black", tc.Text)
|
||||||
a.Write("white", "black", tc.Text)
|
|
||||||
hyperlinkText, _ := a.String()
|
got, _ := String()
|
||||||
assert.Equal(t, tc.Expected, hyperlinkText)
|
|
||||||
|
assert.Equal(t, tc.Expected, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,12 +117,13 @@ func TestGenerateFileLink(t *testing.T) {
|
||||||
{Text: `<LINK>file:C:/Windows<TEXT>Windows</TEXT></LINK>`, Expected: "\x1b[47m\x1b[30m\x1b]8;;file:C:/Windows\x1b\\Windows\x1b]8;;\x1b\\\x1b[0m"},
|
{Text: `<LINK>file:C:/Windows<TEXT>Windows</TEXT></LINK>`, Expected: "\x1b[47m\x1b[30m\x1b]8;;file:C:/Windows\x1b\\Windows\x1b]8;;\x1b\\\x1b[0m"},
|
||||||
}
|
}
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
a := Writer{
|
Init(shell.PWSH)
|
||||||
AnsiColors: &DefaultColors{},
|
AnsiColors = &DefaultColors{}
|
||||||
}
|
|
||||||
a.Init(shell.PWSH)
|
Write("white", "black", tc.Text)
|
||||||
a.Write("white", "black", tc.Text)
|
|
||||||
hyperlinkText, _ := a.String()
|
got, _ := String()
|
||||||
assert.Equal(t, tc.Expected, hyperlinkText)
|
|
||||||
|
assert.Equal(t, tc.Expected, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -221,16 +221,17 @@ func TestWriteANSIColors(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
renderer := &Writer{
|
Init(shell.GENERIC)
|
||||||
ParentColors: []*Colors{tc.Parent},
|
ParentColors = []*Colors{tc.Parent}
|
||||||
CurrentColors: tc.Colors,
|
CurrentColors = tc.Colors
|
||||||
BackgroundColor: tc.TerminalBackground,
|
BackgroundColor = tc.TerminalBackground
|
||||||
AnsiColors: &DefaultColors{},
|
AnsiColors = &DefaultColors{}
|
||||||
TrueColor: true,
|
TrueColor = true
|
||||||
}
|
|
||||||
renderer.Init(shell.GENERIC)
|
Write(tc.Colors.Background, tc.Colors.Foreground, tc.Input)
|
||||||
renderer.Write(tc.Colors.Background, tc.Colors.Foreground, tc.Input)
|
|
||||||
got, _ := renderer.String()
|
got, _ := String()
|
||||||
|
|
||||||
assert.Equal(t, tc.Expected, got, tc.Case)
|
assert.Equal(t, tc.Expected, got, tc.Case)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -275,14 +276,17 @@ func TestWriteLength(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
renderer := &Writer{
|
Init(shell.GENERIC)
|
||||||
ParentColors: []*Colors{},
|
ParentColors = []*Colors{}
|
||||||
CurrentColors: tc.Colors,
|
CurrentColors = tc.Colors
|
||||||
AnsiColors: &DefaultColors{},
|
AnsiColors = &DefaultColors{}
|
||||||
}
|
|
||||||
renderer.Init(shell.GENERIC)
|
Init(shell.GENERIC)
|
||||||
renderer.Write(tc.Colors.Background, tc.Colors.Foreground, tc.Input)
|
|
||||||
_, got := renderer.String()
|
Write(tc.Colors.Background, tc.Colors.Foreground, tc.Input)
|
||||||
|
|
||||||
|
_, got := String()
|
||||||
|
|
||||||
assert.Equal(t, tc.Expected, got, tc.Case)
|
assert.Equal(t, tc.Expected, got, tc.Case)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue