mirror of
https://github.com/JanDeDobbeleer/oh-my-posh.git
synced 2025-02-21 02:55:37 -08:00
refactor: move engine to module
This commit is contained in:
parent
c0f4b6d6f0
commit
fee29f4b2e
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -9,8 +9,6 @@
|
||||||
*.dll
|
*.dll
|
||||||
*.so
|
*.so
|
||||||
*.dylib
|
*.dylib
|
||||||
# Initialization scripts generated by https://github.com/kevinburke/go-bindata
|
|
||||||
init.go
|
|
||||||
|
|
||||||
# Test binary, built with `go test -c`
|
# Test binary, built with `go test -c`
|
||||||
*.test
|
*.test
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package engine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"oh-my-posh/color"
|
"oh-my-posh/color"
|
||||||
|
@ -56,7 +56,7 @@ func (b *Block) initPlain(env environment.Environment, config *Config) {
|
||||||
b.ansi.Init(plain)
|
b.ansi.Init(plain)
|
||||||
b.writer = &color.AnsiWriter{
|
b.writer = &color.AnsiWriter{
|
||||||
Ansi: b.ansi,
|
Ansi: b.ansi,
|
||||||
TerminalBackground: getConsoleBackgroundColor(env, config.TerminalBackground),
|
TerminalBackground: GetConsoleBackgroundColor(env, config.TerminalBackground),
|
||||||
AnsiColors: config.MakeColors(env),
|
AnsiColors: config.MakeColors(env),
|
||||||
}
|
}
|
||||||
b.env = env
|
b.env = env
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package engine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package engine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
// "encoding/json"
|
// "encoding/json"
|
||||||
|
@ -108,7 +108,7 @@ func loadConfig(env environment.Environment) (*Config, error) {
|
||||||
return &cfg, nil
|
return &cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func exportConfig(configFile, format string) string {
|
func ExportConfig(configFile, format string) string {
|
||||||
if len(format) == 0 {
|
if len(format) == 0 {
|
||||||
format = config.JSON
|
format = config.JSON
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package engine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"oh-my-posh/segments"
|
"oh-my-posh/segments"
|
||||||
|
@ -11,7 +11,7 @@ import (
|
||||||
|
|
||||||
func TestSettingsExportJSON(t *testing.T) {
|
func TestSettingsExportJSON(t *testing.T) {
|
||||||
defer testClearDefaultConfig()
|
defer testClearDefaultConfig()
|
||||||
content := exportConfig("../themes/jandedobbeleer.omp.json", "json")
|
content := ExportConfig("../themes/jandedobbeleer.omp.json", "json")
|
||||||
assert.NotContains(t, content, "\\u003ctransparent\\u003e")
|
assert.NotContains(t, content, "\\u003ctransparent\\u003e")
|
||||||
assert.Contains(t, content, "<transparent>")
|
assert.Contains(t, content, "<transparent>")
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package engine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -10,40 +10,40 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type engine struct {
|
type Engine struct {
|
||||||
config *Config
|
Config *Config
|
||||||
env environment.Environment
|
Env environment.Environment
|
||||||
writer color.Writer
|
Writer color.Writer
|
||||||
ansi *color.Ansi
|
Ansi *color.Ansi
|
||||||
consoleTitle *console.Title
|
ConsoleTitle *console.Title
|
||||||
plain bool
|
Plain bool
|
||||||
|
|
||||||
console strings.Builder
|
console strings.Builder
|
||||||
rprompt string
|
rprompt string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *engine) write(text string) {
|
func (e *Engine) write(text string) {
|
||||||
e.console.WriteString(text)
|
e.console.WriteString(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *engine) writeANSI(text string) {
|
func (e *Engine) writeANSI(text string) {
|
||||||
if e.plain {
|
if e.Plain {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
e.console.WriteString(text)
|
e.console.WriteString(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *engine) string() string {
|
func (e *Engine) string() string {
|
||||||
return e.console.String()
|
return e.console.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *engine) canWriteRPrompt() bool {
|
func (e *Engine) canWriteRPrompt() bool {
|
||||||
prompt := e.string()
|
prompt := e.string()
|
||||||
consoleWidth, err := e.env.TerminalWidth()
|
consoleWidth, err := e.Env.TerminalWidth()
|
||||||
if err != nil || consoleWidth == 0 {
|
if err != nil || consoleWidth == 0 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
promptWidth := e.ansi.LenWithoutANSI(prompt)
|
promptWidth := e.Ansi.LenWithoutANSI(prompt)
|
||||||
availableSpace := consoleWidth - promptWidth
|
availableSpace := consoleWidth - promptWidth
|
||||||
// spanning multiple lines
|
// spanning multiple lines
|
||||||
if availableSpace < 0 {
|
if availableSpace < 0 {
|
||||||
|
@ -51,37 +51,37 @@ func (e *engine) canWriteRPrompt() bool {
|
||||||
availableSpace = consoleWidth - overflow
|
availableSpace = consoleWidth - overflow
|
||||||
}
|
}
|
||||||
promptBreathingRoom := 30
|
promptBreathingRoom := 30
|
||||||
canWrite := (availableSpace - e.ansi.LenWithoutANSI(e.rprompt)) >= promptBreathingRoom
|
canWrite := (availableSpace - e.Ansi.LenWithoutANSI(e.rprompt)) >= promptBreathingRoom
|
||||||
return canWrite
|
return canWrite
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *engine) render() string {
|
func (e *Engine) Render() string {
|
||||||
for _, block := range e.config.Blocks {
|
for _, block := range e.Config.Blocks {
|
||||||
e.renderBlock(block)
|
e.renderBlock(block)
|
||||||
}
|
}
|
||||||
if e.config.ConsoleTitle {
|
if e.Config.ConsoleTitle {
|
||||||
e.writeANSI(e.consoleTitle.GetTitle())
|
e.writeANSI(e.ConsoleTitle.GetTitle())
|
||||||
}
|
}
|
||||||
e.writeANSI(e.ansi.ColorReset())
|
e.writeANSI(e.Ansi.ColorReset())
|
||||||
if e.config.FinalSpace {
|
if e.Config.FinalSpace {
|
||||||
e.write(" ")
|
e.write(" ")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !e.config.OSC99 {
|
if !e.Config.OSC99 {
|
||||||
return e.print()
|
return e.print()
|
||||||
}
|
}
|
||||||
cwd := e.env.Pwd()
|
cwd := e.Env.Pwd()
|
||||||
e.writeANSI(e.ansi.ConsolePwd(cwd))
|
e.writeANSI(e.Ansi.ConsolePwd(cwd))
|
||||||
return e.print()
|
return e.print()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *engine) renderBlock(block *Block) {
|
func (e *Engine) renderBlock(block *Block) {
|
||||||
// when in bash, for rprompt blocks we need to write plain
|
// when in bash, for rprompt blocks we need to write plain
|
||||||
// and wrap in escaped mode or the prompt will not render correctly
|
// and wrap in escaped mode or the prompt will not render correctly
|
||||||
if block.Type == RPrompt && e.env.Shell() == bash {
|
if block.Type == RPrompt && e.Env.Shell() == bash {
|
||||||
block.initPlain(e.env, e.config)
|
block.initPlain(e.Env, e.Config)
|
||||||
} else {
|
} else {
|
||||||
block.init(e.env, e.writer, e.ansi)
|
block.init(e.Env, e.Writer, e.Ansi)
|
||||||
}
|
}
|
||||||
block.setStringValues()
|
block.setStringValues()
|
||||||
if !block.enabled() {
|
if !block.enabled() {
|
||||||
|
@ -98,21 +98,21 @@ func (e *engine) renderBlock(block *Block) {
|
||||||
e.write("\n")
|
e.write("\n")
|
||||||
case Prompt:
|
case Prompt:
|
||||||
if block.VerticalOffset != 0 {
|
if block.VerticalOffset != 0 {
|
||||||
e.writeANSI(e.ansi.ChangeLine(block.VerticalOffset))
|
e.writeANSI(e.Ansi.ChangeLine(block.VerticalOffset))
|
||||||
}
|
}
|
||||||
switch block.Alignment {
|
switch block.Alignment {
|
||||||
case Right:
|
case Right:
|
||||||
e.writeANSI(e.ansi.CarriageForward())
|
e.writeANSI(e.Ansi.CarriageForward())
|
||||||
blockText := block.renderSegments()
|
blockText := block.renderSegments()
|
||||||
e.writeANSI(e.ansi.GetCursorForRightWrite(blockText, block.HorizontalOffset))
|
e.writeANSI(e.Ansi.GetCursorForRightWrite(blockText, block.HorizontalOffset))
|
||||||
e.write(blockText)
|
e.write(blockText)
|
||||||
case Left:
|
case Left:
|
||||||
e.write(block.renderSegments())
|
e.write(block.renderSegments())
|
||||||
}
|
}
|
||||||
case RPrompt:
|
case RPrompt:
|
||||||
blockText := block.renderSegments()
|
blockText := block.renderSegments()
|
||||||
if e.env.Shell() == bash {
|
if e.Env.Shell() == bash {
|
||||||
blockText = e.ansi.FormatText(blockText)
|
blockText = e.Ansi.FormatText(blockText)
|
||||||
}
|
}
|
||||||
e.rprompt = blockText
|
e.rprompt = blockText
|
||||||
}
|
}
|
||||||
|
@ -120,33 +120,33 @@ func (e *engine) renderBlock(block *Block) {
|
||||||
// If this doesn't happen, the portion after the prompt gets colored in the background
|
// If this doesn't happen, the portion after the prompt gets colored in the background
|
||||||
// color of the line above the new input line. Clearing the line fixes this,
|
// color of the line above the new input line. Clearing the line fixes this,
|
||||||
// but can hopefully one day be removed when this is resolved natively.
|
// but can hopefully one day be removed when this is resolved natively.
|
||||||
if e.env.Shell() == pwsh || e.env.Shell() == powershell5 {
|
if e.Env.Shell() == pwsh || e.Env.Shell() == powershell5 {
|
||||||
e.writeANSI(e.ansi.ClearAfter())
|
e.writeANSI(e.Ansi.ClearAfter())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// debug will loop through your config file and output the timings for each segments
|
// debug will loop through your config file and output the timings for each segments
|
||||||
func (e *engine) debug() string {
|
func (e *Engine) Debug(version string) string {
|
||||||
var segmentTimings []*SegmentTiming
|
var segmentTimings []*SegmentTiming
|
||||||
largestSegmentNameLength := 0
|
largestSegmentNameLength := 0
|
||||||
e.write(fmt.Sprintf("\n\x1b[1mVersion:\x1b[0m %s\n", Version))
|
e.write(fmt.Sprintf("\n\x1b[1mVersion:\x1b[0m %s\n", version))
|
||||||
e.write("\n\x1b[1mSegments:\x1b[0m\n\n")
|
e.write("\n\x1b[1mSegments:\x1b[0m\n\n")
|
||||||
// console title timing
|
// console title timing
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
consoleTitle := e.consoleTitle.GetTitle()
|
consoleTitle := e.ConsoleTitle.GetTitle()
|
||||||
duration := time.Since(start)
|
duration := time.Since(start)
|
||||||
segmentTiming := &SegmentTiming{
|
segmentTiming := &SegmentTiming{
|
||||||
name: "ConsoleTitle",
|
name: "ConsoleTitle",
|
||||||
nameLength: 12,
|
nameLength: 12,
|
||||||
enabled: e.config.ConsoleTitle,
|
enabled: e.Config.ConsoleTitle,
|
||||||
stringValue: consoleTitle,
|
stringValue: consoleTitle,
|
||||||
enabledDuration: 0,
|
enabledDuration: 0,
|
||||||
stringDuration: duration,
|
stringDuration: duration,
|
||||||
}
|
}
|
||||||
segmentTimings = append(segmentTimings, segmentTiming)
|
segmentTimings = append(segmentTimings, segmentTiming)
|
||||||
// loop each segments of each blocks
|
// loop each segments of each blocks
|
||||||
for _, block := range e.config.Blocks {
|
for _, block := range e.Config.Blocks {
|
||||||
block.init(e.env, e.writer, e.ansi)
|
block.init(e.Env, e.Writer, e.Ansi)
|
||||||
longestSegmentName, timings := block.debug()
|
longestSegmentName, timings := block.debug()
|
||||||
segmentTimings = append(segmentTimings, timings...)
|
segmentTimings = append(segmentTimings, timings...)
|
||||||
if longestSegmentName > largestSegmentNameLength {
|
if longestSegmentName > largestSegmentNameLength {
|
||||||
|
@ -165,16 +165,16 @@ func (e *engine) debug() string {
|
||||||
e.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))
|
||||||
}
|
}
|
||||||
e.write(fmt.Sprintf("\n\x1b[1mRun duration:\x1b[0m %s\n", time.Since(start)))
|
e.write(fmt.Sprintf("\n\x1b[1mRun duration:\x1b[0m %s\n", time.Since(start)))
|
||||||
e.write(fmt.Sprintf("\n\x1b[1mCache path:\x1b[0m %s\n", e.env.CachePath()))
|
e.write(fmt.Sprintf("\n\x1b[1mCache path:\x1b[0m %s\n", e.Env.CachePath()))
|
||||||
e.write("\n\x1b[1mLogs:\x1b[0m\n\n")
|
e.write("\n\x1b[1mLogs:\x1b[0m\n\n")
|
||||||
e.write(e.env.Logs())
|
e.write(e.Env.Logs())
|
||||||
return e.string()
|
return e.string()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *engine) print() string {
|
func (e *Engine) print() string {
|
||||||
switch e.env.Shell() {
|
switch e.Env.Shell() {
|
||||||
case zsh:
|
case zsh:
|
||||||
if !*e.env.Args().Eval {
|
if !*e.Env.Args().Eval {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// escape double quotes contained in the prompt
|
// escape double quotes contained in the prompt
|
||||||
|
@ -182,22 +182,22 @@ func (e *engine) print() string {
|
||||||
prompt += fmt.Sprintf("\nRPROMPT=\"%s\"", e.rprompt)
|
prompt += fmt.Sprintf("\nRPROMPT=\"%s\"", e.rprompt)
|
||||||
return prompt
|
return prompt
|
||||||
case pwsh, powershell5, bash, plain:
|
case pwsh, powershell5, bash, plain:
|
||||||
if e.rprompt == "" || !e.canWriteRPrompt() || e.plain {
|
if e.rprompt == "" || !e.canWriteRPrompt() || e.Plain {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
e.write(e.ansi.SaveCursorPosition())
|
e.write(e.Ansi.SaveCursorPosition())
|
||||||
e.write(e.ansi.CarriageForward())
|
e.write(e.Ansi.CarriageForward())
|
||||||
e.write(e.ansi.GetCursorForRightWrite(e.rprompt, 0))
|
e.write(e.Ansi.GetCursorForRightWrite(e.rprompt, 0))
|
||||||
e.write(e.rprompt)
|
e.write(e.rprompt)
|
||||||
e.write(e.ansi.RestoreCursorPosition())
|
e.write(e.Ansi.RestoreCursorPosition())
|
||||||
}
|
}
|
||||||
return e.string()
|
return e.string()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *engine) renderTooltip(tip string) string {
|
func (e *Engine) RenderTooltip(tip string) string {
|
||||||
tip = strings.Trim(tip, " ")
|
tip = strings.Trim(tip, " ")
|
||||||
var tooltip *Segment
|
var tooltip *Segment
|
||||||
for _, tp := range e.config.Tooltips {
|
for _, tp := range e.Config.Tooltips {
|
||||||
if !tp.shouldInvokeWithTip(tip) {
|
if !tp.shouldInvokeWithTip(tip) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -206,7 +206,7 @@ func (e *engine) renderTooltip(tip string) string {
|
||||||
if tooltip == nil {
|
if tooltip == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
if err := tooltip.mapSegmentWithWriter(e.env); err != nil {
|
if err := tooltip.mapSegmentWithWriter(e.Env); err != nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
if !tooltip.enabled() {
|
if !tooltip.enabled() {
|
||||||
|
@ -218,53 +218,53 @@ func (e *engine) renderTooltip(tip string) string {
|
||||||
Alignment: Right,
|
Alignment: Right,
|
||||||
Segments: []*Segment{tooltip},
|
Segments: []*Segment{tooltip},
|
||||||
}
|
}
|
||||||
switch e.env.Shell() {
|
switch e.Env.Shell() {
|
||||||
case zsh, winCMD:
|
case zsh, winCMD:
|
||||||
block.init(e.env, e.writer, e.ansi)
|
block.init(e.Env, e.Writer, e.Ansi)
|
||||||
return block.renderSegments()
|
return block.renderSegments()
|
||||||
case pwsh, powershell5:
|
case pwsh, powershell5:
|
||||||
block.initPlain(e.env, e.config)
|
block.initPlain(e.Env, e.Config)
|
||||||
tooltipText := block.renderSegments()
|
tooltipText := block.renderSegments()
|
||||||
e.write(e.ansi.ClearAfter())
|
e.write(e.Ansi.ClearAfter())
|
||||||
e.write(e.ansi.CarriageForward())
|
e.write(e.Ansi.CarriageForward())
|
||||||
e.write(e.ansi.GetCursorForRightWrite(tooltipText, 0))
|
e.write(e.Ansi.GetCursorForRightWrite(tooltipText, 0))
|
||||||
e.write(tooltipText)
|
e.write(tooltipText)
|
||||||
return e.string()
|
return e.string()
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *engine) renderTransientPrompt() string {
|
func (e *Engine) RenderTransientPrompt() string {
|
||||||
if e.config.TransientPrompt == nil {
|
if e.Config.TransientPrompt == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
promptTemplate := e.config.TransientPrompt.Template
|
promptTemplate := e.Config.TransientPrompt.Template
|
||||||
if len(promptTemplate) == 0 {
|
if len(promptTemplate) == 0 {
|
||||||
promptTemplate = "{{ .Shell }}> "
|
promptTemplate = "{{ .Shell }}> "
|
||||||
}
|
}
|
||||||
tmpl := &template.Text{
|
tmpl := &template.Text{
|
||||||
Template: promptTemplate,
|
Template: promptTemplate,
|
||||||
Env: e.env,
|
Env: e.Env,
|
||||||
}
|
}
|
||||||
prompt, err := tmpl.Render()
|
prompt, err := tmpl.Render()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
prompt = err.Error()
|
prompt = err.Error()
|
||||||
}
|
}
|
||||||
e.writer.SetColors(e.config.TransientPrompt.Background, e.config.TransientPrompt.Foreground)
|
e.Writer.SetColors(e.Config.TransientPrompt.Background, e.Config.TransientPrompt.Foreground)
|
||||||
e.writer.Write(e.config.TransientPrompt.Background, e.config.TransientPrompt.Foreground, prompt)
|
e.Writer.Write(e.Config.TransientPrompt.Background, e.Config.TransientPrompt.Foreground, prompt)
|
||||||
switch e.env.Shell() {
|
switch e.Env.Shell() {
|
||||||
case zsh:
|
case zsh:
|
||||||
// escape double quotes contained in the prompt
|
// escape double quotes contained in the prompt
|
||||||
prompt := fmt.Sprintf("PS1=\"%s\"", strings.ReplaceAll(e.writer.String(), "\"", "\"\""))
|
prompt := fmt.Sprintf("PS1=\"%s\"", strings.ReplaceAll(e.Writer.String(), "\"", "\"\""))
|
||||||
prompt += "\nRPROMPT=\"\""
|
prompt += "\nRPROMPT=\"\""
|
||||||
return prompt
|
return prompt
|
||||||
case pwsh, powershell5, winCMD:
|
case pwsh, powershell5, winCMD:
|
||||||
return e.writer.String()
|
return e.Writer.String()
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *engine) renderRPrompt() string {
|
func (e *Engine) RenderRPrompt() string {
|
||||||
filterRPromptBlock := func(blocks []*Block) *Block {
|
filterRPromptBlock := func(blocks []*Block) *Block {
|
||||||
for _, block := range blocks {
|
for _, block := range blocks {
|
||||||
if block.Type == RPrompt {
|
if block.Type == RPrompt {
|
||||||
|
@ -273,11 +273,11 @@ func (e *engine) renderRPrompt() string {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
block := filterRPromptBlock(e.config.Blocks)
|
block := filterRPromptBlock(e.Config.Blocks)
|
||||||
if block == nil {
|
if block == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
block.init(e.env, e.writer, e.ansi)
|
block.init(e.Env, e.Writer, e.Ansi)
|
||||||
block.setStringValues()
|
block.setStringValues()
|
||||||
if !block.enabled() {
|
if !block.enabled() {
|
||||||
return ""
|
return ""
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package engine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
@ -37,9 +37,9 @@ func TestCanWriteRPrompt(t *testing.T) {
|
||||||
env.On("TerminalWidth").Return(tc.TerminalWidth, tc.TerminalWidthError)
|
env.On("TerminalWidth").Return(tc.TerminalWidth, tc.TerminalWidthError)
|
||||||
ansi := &color.Ansi{}
|
ansi := &color.Ansi{}
|
||||||
ansi.Init(plain)
|
ansi.Init(plain)
|
||||||
engine := &engine{
|
engine := &Engine{
|
||||||
env: env,
|
Env: env,
|
||||||
ansi: ansi,
|
Ansi: ansi,
|
||||||
}
|
}
|
||||||
engine.rprompt = strings.Repeat("x", tc.RPromptLength)
|
engine.rprompt = strings.Repeat("x", tc.RPromptLength)
|
||||||
engine.console.WriteString(strings.Repeat("x", tc.PromptLength))
|
engine.console.WriteString(strings.Repeat("x", tc.PromptLength))
|
||||||
|
@ -101,7 +101,7 @@ func engineRender(configPath string) error {
|
||||||
writerColors := cfg.MakeColors(env)
|
writerColors := cfg.MakeColors(env)
|
||||||
writer := &color.AnsiWriter{
|
writer := &color.AnsiWriter{
|
||||||
Ansi: ansi,
|
Ansi: ansi,
|
||||||
TerminalBackground: getConsoleBackgroundColor(env, cfg.TerminalBackground),
|
TerminalBackground: GetConsoleBackgroundColor(env, cfg.TerminalBackground),
|
||||||
AnsiColors: writerColors,
|
AnsiColors: writerColors,
|
||||||
}
|
}
|
||||||
consoleTitle := &console.Title{
|
consoleTitle := &console.Title{
|
||||||
|
@ -110,16 +110,16 @@ func engineRender(configPath string) error {
|
||||||
Style: cfg.ConsoleTitleStyle,
|
Style: cfg.ConsoleTitleStyle,
|
||||||
Template: cfg.ConsoleTitleTemplate,
|
Template: cfg.ConsoleTitleTemplate,
|
||||||
}
|
}
|
||||||
engine := &engine{
|
engine := &Engine{
|
||||||
config: cfg,
|
Config: cfg,
|
||||||
env: env,
|
Env: env,
|
||||||
writer: writer,
|
Writer: writer,
|
||||||
consoleTitle: consoleTitle,
|
ConsoleTitle: consoleTitle,
|
||||||
ansi: ansi,
|
Ansi: ansi,
|
||||||
plain: *args.Plain,
|
Plain: *args.Plain,
|
||||||
}
|
}
|
||||||
|
|
||||||
engine.render()
|
engine.Render()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
// https://github.com/homeport/termshot
|
// https://github.com/homeport/termshot
|
||||||
|
|
||||||
package main
|
package engine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
_ "embed"
|
_ "embed"
|
||||||
|
@ -97,10 +97,14 @@ func NewRGBColor(ansiColor string) *RGB {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ImageRenderer struct {
|
type ImageRenderer struct {
|
||||||
ansiString string
|
AnsiString string
|
||||||
author string
|
Author string
|
||||||
ansi *color.Ansi
|
CursorPadding int
|
||||||
bgColor string
|
RPromptOffset int
|
||||||
|
BgColor string
|
||||||
|
Ansi *color.Ansi
|
||||||
|
|
||||||
|
path string
|
||||||
|
|
||||||
factor float64
|
factor float64
|
||||||
|
|
||||||
|
@ -128,11 +132,12 @@ type ImageRenderer struct {
|
||||||
backgroundColor *RGB
|
backgroundColor *RGB
|
||||||
foregroundColor *RGB
|
foregroundColor *RGB
|
||||||
ansiSequenceRegexMap map[string]string
|
ansiSequenceRegexMap map[string]string
|
||||||
rPromptOffset int
|
|
||||||
cursorPadding int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ir *ImageRenderer) init() {
|
func (ir *ImageRenderer) Init(config string) {
|
||||||
|
match := regex.FindNamedRegexMatch(`.*(\/|\\)(?P<STR>.+).omp.(json|yaml|toml)`, config)
|
||||||
|
ir.path = fmt.Sprintf("%s.png", match[str])
|
||||||
|
|
||||||
f := 2.0
|
f := 2.0
|
||||||
|
|
||||||
ir.cleanContent()
|
ir.cleanContent()
|
||||||
|
@ -244,8 +249,8 @@ func (ir *ImageRenderer) runeAdditionalWidth(r rune) int {
|
||||||
|
|
||||||
func (ir *ImageRenderer) calculateWidth() int {
|
func (ir *ImageRenderer) calculateWidth() int {
|
||||||
longest := 0
|
longest := 0
|
||||||
for _, line := range strings.Split(ir.ansiString, "\n") {
|
for _, line := range strings.Split(ir.AnsiString, "\n") {
|
||||||
length := ir.ansi.LenWithoutANSI(line)
|
length := ir.Ansi.LenWithoutANSI(line)
|
||||||
for _, char := range line {
|
for _, char := range line {
|
||||||
length += ir.runeAdditionalWidth(char)
|
length += ir.runeAdditionalWidth(char)
|
||||||
}
|
}
|
||||||
|
@ -258,27 +263,27 @@ func (ir *ImageRenderer) calculateWidth() int {
|
||||||
|
|
||||||
func (ir *ImageRenderer) cleanContent() {
|
func (ir *ImageRenderer) cleanContent() {
|
||||||
rPromptAnsi := "\x1b7\x1b[1000C"
|
rPromptAnsi := "\x1b7\x1b[1000C"
|
||||||
hasRPrompt := strings.Contains(ir.ansiString, rPromptAnsi)
|
hasRPrompt := strings.Contains(ir.AnsiString, rPromptAnsi)
|
||||||
// clean abundance of empty lines
|
// clean abundance of empty lines
|
||||||
ir.ansiString = strings.Trim(ir.ansiString, "\n")
|
ir.AnsiString = strings.Trim(ir.AnsiString, "\n")
|
||||||
ir.ansiString = "\n" + ir.ansiString
|
ir.AnsiString = "\n" + ir.AnsiString
|
||||||
// clean string before render
|
// clean string before render
|
||||||
ir.ansiString = strings.ReplaceAll(ir.ansiString, "\x1b[m", "\x1b[0m")
|
ir.AnsiString = strings.ReplaceAll(ir.AnsiString, "\x1b[m", "\x1b[0m")
|
||||||
ir.ansiString = strings.ReplaceAll(ir.ansiString, "\x1b[K", "")
|
ir.AnsiString = strings.ReplaceAll(ir.AnsiString, "\x1b[K", "")
|
||||||
ir.ansiString = strings.ReplaceAll(ir.ansiString, "\x1b[1F", "")
|
ir.AnsiString = strings.ReplaceAll(ir.AnsiString, "\x1b[1F", "")
|
||||||
ir.ansiString = strings.ReplaceAll(ir.ansiString, "\x1b8", "")
|
ir.AnsiString = strings.ReplaceAll(ir.AnsiString, "\x1b8", "")
|
||||||
ir.ansiString = strings.ReplaceAll(ir.ansiString, "\u2800", " ")
|
ir.AnsiString = strings.ReplaceAll(ir.AnsiString, "\u2800", " ")
|
||||||
// replace rprompt with adding and mark right aligned blocks with a pointer
|
// replace rprompt with adding and mark right aligned blocks with a pointer
|
||||||
ir.ansiString = strings.ReplaceAll(ir.ansiString, rPromptAnsi, fmt.Sprintf("_%s", strings.Repeat(" ", ir.cursorPadding)))
|
ir.AnsiString = strings.ReplaceAll(ir.AnsiString, rPromptAnsi, fmt.Sprintf("_%s", strings.Repeat(" ", ir.CursorPadding)))
|
||||||
ir.ansiString = strings.ReplaceAll(ir.ansiString, "\x1b[1000C", strings.Repeat(" ", ir.rPromptOffset))
|
ir.AnsiString = strings.ReplaceAll(ir.AnsiString, "\x1b[1000C", strings.Repeat(" ", ir.RPromptOffset))
|
||||||
if !hasRPrompt {
|
if !hasRPrompt {
|
||||||
ir.ansiString += fmt.Sprintf("_%s", strings.Repeat(" ", ir.cursorPadding))
|
ir.AnsiString += fmt.Sprintf("_%s", strings.Repeat(" ", ir.CursorPadding))
|
||||||
}
|
}
|
||||||
// add watermarks
|
// add watermarks
|
||||||
ir.ansiString += "\n\n\x1b[1mhttps://ohmyposh.dev\x1b[22m"
|
ir.AnsiString += "\n\n\x1b[1mhttps://ohmyposh.dev\x1b[22m"
|
||||||
if len(ir.author) > 0 {
|
if len(ir.Author) > 0 {
|
||||||
createdBy := fmt.Sprintf(" by \x1b[1m%s\x1b[22m", ir.author)
|
createdBy := fmt.Sprintf(" by \x1b[1m%s\x1b[22m", ir.Author)
|
||||||
ir.ansiString += createdBy
|
ir.AnsiString += createdBy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,11 +295,11 @@ func (ir *ImageRenderer) measureContent() (width, height float64) {
|
||||||
advance := tmpDrawer.MeasureString(strings.Repeat(" ", linewidth))
|
advance := tmpDrawer.MeasureString(strings.Repeat(" ", linewidth))
|
||||||
width = float64(advance >> 6)
|
width = float64(advance >> 6)
|
||||||
// height, lines times font height and line spacing
|
// height, lines times font height and line spacing
|
||||||
height = float64(len(strings.Split(ir.ansiString, "\n"))) * ir.fontHeight() * ir.lineSpacing
|
height = float64(len(strings.Split(ir.AnsiString, "\n"))) * ir.fontHeight() * ir.lineSpacing
|
||||||
return width, height
|
return width, height
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ir *ImageRenderer) SavePNG(path string) error {
|
func (ir *ImageRenderer) SavePNG() error {
|
||||||
var f = func(value float64) float64 { return ir.factor * value }
|
var f = func(value float64) float64 { return ir.factor * value }
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -345,7 +350,7 @@ func (ir *ImageRenderer) SavePNG(path string) error {
|
||||||
// Draw rounded rectangle with outline and three button to produce the
|
// Draw rounded rectangle with outline and three button to produce the
|
||||||
// impression of a window with controls and a content area
|
// impression of a window with controls and a content area
|
||||||
dc.DrawRoundedRectangle(xOffset, yOffset, width-2*marginX, height-2*marginY, corner)
|
dc.DrawRoundedRectangle(xOffset, yOffset, width-2*marginX, height-2*marginY, corner)
|
||||||
dc.SetHexColor(ir.bgColor)
|
dc.SetHexColor(ir.BgColor)
|
||||||
dc.Fill()
|
dc.Fill()
|
||||||
|
|
||||||
dc.DrawRoundedRectangle(xOffset, yOffset, width-2*marginX, height-2*marginY, corner)
|
dc.DrawRoundedRectangle(xOffset, yOffset, width-2*marginX, height-2*marginY, corner)
|
||||||
|
@ -362,16 +367,16 @@ func (ir *ImageRenderer) SavePNG(path string) error {
|
||||||
// Apply the actual text into the prepared content area of the window
|
// Apply the actual text into the prepared content area of the window
|
||||||
var x, y float64 = xOffset + paddingX, yOffset + paddingY + titleOffset + ir.fontHeight()
|
var x, y float64 = xOffset + paddingX, yOffset + paddingY + titleOffset + ir.fontHeight()
|
||||||
|
|
||||||
for len(ir.ansiString) != 0 {
|
for len(ir.AnsiString) != 0 {
|
||||||
if !ir.shouldPrint() {
|
if !ir.shouldPrint() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
runes := []rune(ir.ansiString)
|
runes := []rune(ir.AnsiString)
|
||||||
if len(runes) == 0 {
|
if len(runes) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
str := string(runes[0:1])
|
str := string(runes[0:1])
|
||||||
ir.ansiString = string(runes[1:])
|
ir.AnsiString = string(runes[1:])
|
||||||
switch ir.style {
|
switch ir.style {
|
||||||
case bold:
|
case bold:
|
||||||
dc.SetFontFace(ir.bold)
|
dc.SetFontFace(ir.bold)
|
||||||
|
@ -419,16 +424,16 @@ func (ir *ImageRenderer) SavePNG(path string) error {
|
||||||
x += w
|
x += w
|
||||||
}
|
}
|
||||||
|
|
||||||
return dc.SavePNG(path)
|
return dc.SavePNG(ir.path)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ir *ImageRenderer) shouldPrint() bool {
|
func (ir *ImageRenderer) shouldPrint() bool {
|
||||||
for sequence, re := range ir.ansiSequenceRegexMap {
|
for sequence, re := range ir.ansiSequenceRegexMap {
|
||||||
match := regex.FindNamedRegexMatch(re, ir.ansiString)
|
match := regex.FindNamedRegexMatch(re, ir.AnsiString)
|
||||||
if len(match) == 0 {
|
if len(match) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ir.ansiString = strings.TrimPrefix(ir.ansiString, match[str])
|
ir.AnsiString = strings.TrimPrefix(ir.AnsiString, match[str])
|
||||||
switch sequence {
|
switch sequence {
|
||||||
case invertedColor:
|
case invertedColor:
|
||||||
ir.foregroundColor = ir.defaultBackgroundColor
|
ir.foregroundColor = ir.defaultBackgroundColor
|
||||||
|
@ -463,7 +468,7 @@ func (ir *ImageRenderer) shouldPrint() bool {
|
||||||
ir.setBase16Color(match[fg])
|
ir.setBase16Color(match[fg])
|
||||||
return false
|
return false
|
||||||
case link:
|
case link:
|
||||||
ir.ansiString = match[url] + ir.ansiString
|
ir.AnsiString = match[url] + ir.AnsiString
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package engine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
@ -10,7 +10,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func runImageTest(content string) error {
|
func runImageTest(content string) error {
|
||||||
poshImagePath := "ohmyposh.png"
|
poshImagePath := "jandedobbeleer.png"
|
||||||
file, err := ioutil.TempFile("", poshImagePath)
|
file, err := ioutil.TempFile("", poshImagePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -19,11 +19,11 @@ func runImageTest(content string) error {
|
||||||
ansi := &color.Ansi{}
|
ansi := &color.Ansi{}
|
||||||
ansi.Init(plain)
|
ansi.Init(plain)
|
||||||
image := &ImageRenderer{
|
image := &ImageRenderer{
|
||||||
ansiString: content,
|
AnsiString: content,
|
||||||
ansi: ansi,
|
Ansi: ansi,
|
||||||
}
|
}
|
||||||
image.init()
|
image.Init("~/jandedobbeleer.omp.json")
|
||||||
err = image.SavePNG(poshImagePath)
|
err = image.SavePNG()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
112
src/engine/init.go
Normal file
112
src/engine/init.go
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
package engine
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "embed"
|
||||||
|
|
||||||
|
"fmt"
|
||||||
|
"oh-my-posh/environment"
|
||||||
|
"oh-my-posh/template"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed init/omp.ps1
|
||||||
|
var pwshInit string
|
||||||
|
|
||||||
|
//go:embed init/omp.fish
|
||||||
|
var fishInit string
|
||||||
|
|
||||||
|
//go:embed init/omp.bash
|
||||||
|
var bashInit string
|
||||||
|
|
||||||
|
//go:embed init/omp.zsh
|
||||||
|
var zshInit string
|
||||||
|
|
||||||
|
//go:embed init/omp.lua
|
||||||
|
var cmdInit string
|
||||||
|
|
||||||
|
const (
|
||||||
|
noExe = "echo \"Unable to find Oh My Posh executable\""
|
||||||
|
|
||||||
|
zsh = "zsh"
|
||||||
|
bash = "bash"
|
||||||
|
pwsh = "pwsh"
|
||||||
|
fish = "fish"
|
||||||
|
powershell5 = "powershell"
|
||||||
|
winCMD = "cmd"
|
||||||
|
plain = "shell"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getExecutablePath(shell string) (string, error) {
|
||||||
|
executable, err := os.Executable()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
// On Windows, it fails when the excutable is called in MSYS2 for example
|
||||||
|
// which uses unix style paths to resolve the executable's location.
|
||||||
|
// PowerShell knows how to resolve both, so we can swap this without any issue.
|
||||||
|
executable = strings.ReplaceAll(executable, "\\", "/")
|
||||||
|
switch shell {
|
||||||
|
case bash, zsh:
|
||||||
|
return strings.ReplaceAll(executable, " ", "\\ "), nil
|
||||||
|
}
|
||||||
|
return executable, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitShell(shell, configFile string) string {
|
||||||
|
executable, err := getExecutablePath(shell)
|
||||||
|
if err != nil {
|
||||||
|
return noExe
|
||||||
|
}
|
||||||
|
switch shell {
|
||||||
|
case pwsh, powershell5:
|
||||||
|
return fmt.Sprintf("(@(&\"%s\" --print-init --shell=%s --config=\"%s\") -join \"`n\") | Invoke-Expression", executable, shell, configFile)
|
||||||
|
case zsh, bash, fish, winCMD:
|
||||||
|
return PrintShellInit(shell, configFile)
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("echo \"No initialization script available for %s\"", shell)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PrintShellInit(shell, configFile string) string {
|
||||||
|
executable, err := getExecutablePath(shell)
|
||||||
|
if err != nil {
|
||||||
|
return noExe
|
||||||
|
}
|
||||||
|
switch shell {
|
||||||
|
case pwsh, powershell5:
|
||||||
|
return getShellInitScript(executable, configFile, pwshInit)
|
||||||
|
case zsh:
|
||||||
|
return getShellInitScript(executable, configFile, zshInit)
|
||||||
|
case bash:
|
||||||
|
return getShellInitScript(executable, configFile, bashInit)
|
||||||
|
case fish:
|
||||||
|
return getShellInitScript(executable, configFile, fishInit)
|
||||||
|
case winCMD:
|
||||||
|
return getShellInitScript(executable, configFile, cmdInit)
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("echo \"No initialization script available for %s\"", shell)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getShellInitScript(executable, configFile, script string) string {
|
||||||
|
script = strings.ReplaceAll(script, "::OMP::", executable)
|
||||||
|
script = strings.ReplaceAll(script, "::CONFIG::", configFile)
|
||||||
|
return script
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetConsoleBackgroundColor(env environment.Environment, backgroundColorTemplate string) string {
|
||||||
|
if len(backgroundColorTemplate) == 0 {
|
||||||
|
return backgroundColorTemplate
|
||||||
|
}
|
||||||
|
tmpl := &template.Text{
|
||||||
|
Template: backgroundColorTemplate,
|
||||||
|
Context: nil,
|
||||||
|
Env: env,
|
||||||
|
}
|
||||||
|
text, err := tmpl.Render()
|
||||||
|
if err != nil {
|
||||||
|
return err.Error()
|
||||||
|
}
|
||||||
|
return text
|
||||||
|
}
|
31
src/engine/init_test.go
Normal file
31
src/engine/init_test.go
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
package engine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"oh-my-posh/environment"
|
||||||
|
"oh-my-posh/mock"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestConsoleBackgroundColorTemplate(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
Case string
|
||||||
|
Expected string
|
||||||
|
Term string
|
||||||
|
}{
|
||||||
|
{Case: "Inside vscode", Expected: "#123456", Term: "vscode"},
|
||||||
|
{Case: "Outside vscode", Expected: "", Term: "windowsterminal"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range cases {
|
||||||
|
env := new(mock.MockedEnvironment)
|
||||||
|
env.On("TemplateCache").Return(&environment.TemplateCache{
|
||||||
|
Env: map[string]string{
|
||||||
|
"TERM_PROGRAM": tc.Term,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
color := GetConsoleBackgroundColor(env, "{{ if eq \"vscode\" .Env.TERM_PROGRAM }}#123456{{end}}")
|
||||||
|
assert.Equal(t, tc.Expected, color, tc.Case)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package engine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package engine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
160
src/main.go
160
src/main.go
|
@ -1,16 +1,12 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
_ "embed"
|
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"oh-my-posh/color"
|
"oh-my-posh/color"
|
||||||
"oh-my-posh/console"
|
"oh-my-posh/console"
|
||||||
|
"oh-my-posh/engine"
|
||||||
"oh-my-posh/environment"
|
"oh-my-posh/environment"
|
||||||
"oh-my-posh/regex"
|
|
||||||
"oh-my-posh/template"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gookit/config/v2"
|
"github.com/gookit/config/v2"
|
||||||
|
@ -19,33 +15,6 @@ import (
|
||||||
// Version number of oh-my-posh
|
// Version number of oh-my-posh
|
||||||
var Version = "development"
|
var Version = "development"
|
||||||
|
|
||||||
//go:embed init/omp.ps1
|
|
||||||
var pwshInit string
|
|
||||||
|
|
||||||
//go:embed init/omp.fish
|
|
||||||
var fishInit string
|
|
||||||
|
|
||||||
//go:embed init/omp.bash
|
|
||||||
var bashInit string
|
|
||||||
|
|
||||||
//go:embed init/omp.zsh
|
|
||||||
var zshInit string
|
|
||||||
|
|
||||||
//go:embed init/omp.lua
|
|
||||||
var cmdInit string
|
|
||||||
|
|
||||||
const (
|
|
||||||
noExe = "echo \"Unable to find Oh My Posh executable\""
|
|
||||||
|
|
||||||
zsh = "zsh"
|
|
||||||
bash = "bash"
|
|
||||||
pwsh = "pwsh"
|
|
||||||
fish = "fish"
|
|
||||||
powershell5 = "powershell"
|
|
||||||
winCMD = "cmd"
|
|
||||||
plain = "shell"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
args := &environment.Args{
|
args := &environment.Args{
|
||||||
ErrorCode: flag.Int(
|
ErrorCode: flag.Int(
|
||||||
|
@ -174,20 +143,20 @@ func main() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if *args.Init {
|
if *args.Init {
|
||||||
init := initShell(*args.Shell, *args.Config)
|
init := engine.InitShell(*args.Shell, *args.Config)
|
||||||
fmt.Print(init)
|
fmt.Print(init)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if *args.PrintInit {
|
if *args.PrintInit {
|
||||||
init := printShellInit(*args.Shell, *args.Config)
|
init := engine.PrintShellInit(*args.Shell, *args.Config)
|
||||||
fmt.Print(init)
|
fmt.Print(init)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if *args.PrintConfig {
|
if *args.PrintConfig {
|
||||||
fmt.Print(exportConfig(*args.Config, *args.ConfigFormat))
|
fmt.Print(engine.ExportConfig(*args.Config, *args.ConfigFormat))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cfg := GetConfig(env)
|
cfg := engine.GetConfig(env)
|
||||||
ansi := &color.Ansi{}
|
ansi := &color.Ansi{}
|
||||||
ansi.Init(env.Shell())
|
ansi.Init(env.Shell())
|
||||||
var writer color.Writer
|
var writer color.Writer
|
||||||
|
@ -197,7 +166,7 @@ func main() {
|
||||||
writerColors := cfg.MakeColors(env)
|
writerColors := cfg.MakeColors(env)
|
||||||
writer = &color.AnsiWriter{
|
writer = &color.AnsiWriter{
|
||||||
Ansi: ansi,
|
Ansi: ansi,
|
||||||
TerminalBackground: getConsoleBackgroundColor(env, cfg.TerminalBackground),
|
TerminalBackground: engine.GetConsoleBackgroundColor(env, cfg.TerminalBackground),
|
||||||
AnsiColors: writerColors,
|
AnsiColors: writerColors,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -207,121 +176,46 @@ func main() {
|
||||||
Template: cfg.ConsoleTitleTemplate,
|
Template: cfg.ConsoleTitleTemplate,
|
||||||
Style: cfg.ConsoleTitleStyle,
|
Style: cfg.ConsoleTitleStyle,
|
||||||
}
|
}
|
||||||
engine := &engine{
|
eng := &engine.Engine{
|
||||||
config: cfg,
|
Config: cfg,
|
||||||
env: env,
|
Env: env,
|
||||||
writer: writer,
|
Writer: writer,
|
||||||
consoleTitle: consoleTitle,
|
ConsoleTitle: consoleTitle,
|
||||||
ansi: ansi,
|
Ansi: ansi,
|
||||||
plain: *args.Plain,
|
Plain: *args.Plain,
|
||||||
}
|
}
|
||||||
if *args.Debug {
|
if *args.Debug {
|
||||||
fmt.Print(engine.debug())
|
fmt.Print(eng.Debug(Version))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if *args.PrintTransient {
|
if *args.PrintTransient {
|
||||||
fmt.Print(engine.renderTransientPrompt())
|
fmt.Print(eng.RenderTransientPrompt())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(*args.Command) != 0 {
|
if len(*args.Command) != 0 {
|
||||||
fmt.Print(engine.renderTooltip(*args.Command))
|
fmt.Print(eng.RenderTooltip(*args.Command))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if *args.RPrompt {
|
if *args.RPrompt {
|
||||||
fmt.Print(engine.renderRPrompt())
|
fmt.Print(eng.RenderRPrompt())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
prompt := engine.render()
|
prompt := eng.Render()
|
||||||
if !*args.ExportPNG {
|
if !*args.ExportPNG {
|
||||||
fmt.Print(prompt)
|
fmt.Print(prompt)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
imageCreator := &ImageRenderer{
|
imageCreator := &engine.ImageRenderer{
|
||||||
ansiString: prompt,
|
AnsiString: prompt,
|
||||||
author: *args.Author,
|
Author: *args.Author,
|
||||||
cursorPadding: *args.CursorPadding,
|
CursorPadding: *args.CursorPadding,
|
||||||
rPromptOffset: *args.RPromptOffset,
|
RPromptOffset: *args.RPromptOffset,
|
||||||
bgColor: *args.BGColor,
|
BgColor: *args.BGColor,
|
||||||
ansi: ansi,
|
Ansi: ansi,
|
||||||
}
|
}
|
||||||
imageCreator.init()
|
imageCreator.Init(*args.Config)
|
||||||
match := regex.FindNamedRegexMatch(`.*(\/|\\)(?P<STR>.+).omp.(json|yaml|toml)`, *args.Config)
|
err := imageCreator.SavePNG()
|
||||||
err := imageCreator.SavePNG(fmt.Sprintf("%s.png", match[str]))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Print(err.Error())
|
fmt.Print(err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getExecutablePath(shell string) (string, error) {
|
|
||||||
executable, err := os.Executable()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
// On Windows, it fails when the excutable is called in MSYS2 for example
|
|
||||||
// which uses unix style paths to resolve the executable's location.
|
|
||||||
// PowerShell knows how to resolve both, so we can swap this without any issue.
|
|
||||||
executable = strings.ReplaceAll(executable, "\\", "/")
|
|
||||||
switch shell {
|
|
||||||
case bash, zsh:
|
|
||||||
return strings.ReplaceAll(executable, " ", "\\ "), nil
|
|
||||||
}
|
|
||||||
return executable, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func initShell(shell, configFile string) string {
|
|
||||||
executable, err := getExecutablePath(shell)
|
|
||||||
if err != nil {
|
|
||||||
return noExe
|
|
||||||
}
|
|
||||||
switch shell {
|
|
||||||
case pwsh, powershell5:
|
|
||||||
return fmt.Sprintf("(@(&\"%s\" --print-init --shell=%s --config=\"%s\") -join \"`n\") | Invoke-Expression", executable, shell, configFile)
|
|
||||||
case zsh, bash, fish, winCMD:
|
|
||||||
return printShellInit(shell, configFile)
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("echo \"No initialization script available for %s\"", shell)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func printShellInit(shell, configFile string) string {
|
|
||||||
executable, err := getExecutablePath(shell)
|
|
||||||
if err != nil {
|
|
||||||
return noExe
|
|
||||||
}
|
|
||||||
switch shell {
|
|
||||||
case pwsh, powershell5:
|
|
||||||
return getShellInitScript(executable, configFile, pwshInit)
|
|
||||||
case zsh:
|
|
||||||
return getShellInitScript(executable, configFile, zshInit)
|
|
||||||
case bash:
|
|
||||||
return getShellInitScript(executable, configFile, bashInit)
|
|
||||||
case fish:
|
|
||||||
return getShellInitScript(executable, configFile, fishInit)
|
|
||||||
case winCMD:
|
|
||||||
return getShellInitScript(executable, configFile, cmdInit)
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("echo \"No initialization script available for %s\"", shell)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getShellInitScript(executable, configFile, script string) string {
|
|
||||||
script = strings.ReplaceAll(script, "::OMP::", executable)
|
|
||||||
script = strings.ReplaceAll(script, "::CONFIG::", configFile)
|
|
||||||
return script
|
|
||||||
}
|
|
||||||
|
|
||||||
func getConsoleBackgroundColor(env environment.Environment, backgroundColorTemplate string) string {
|
|
||||||
if len(backgroundColorTemplate) == 0 {
|
|
||||||
return backgroundColorTemplate
|
|
||||||
}
|
|
||||||
tmpl := &template.Text{
|
|
||||||
Template: backgroundColorTemplate,
|
|
||||||
Context: nil,
|
|
||||||
Env: env,
|
|
||||||
}
|
|
||||||
text, err := tmpl.Render()
|
|
||||||
if err != nil {
|
|
||||||
return err.Error()
|
|
||||||
}
|
|
||||||
return text
|
|
||||||
}
|
|
||||||
|
|
|
@ -8,28 +8,6 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestConsoleBackgroundColorTemplate(t *testing.T) {
|
|
||||||
cases := []struct {
|
|
||||||
Case string
|
|
||||||
Expected string
|
|
||||||
Term string
|
|
||||||
}{
|
|
||||||
{Case: "Inside vscode", Expected: "#123456", Term: "vscode"},
|
|
||||||
{Case: "Outside vscode", Expected: "", Term: "windowsterminal"},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range cases {
|
|
||||||
env := new(mock.MockedEnvironment)
|
|
||||||
env.On("TemplateCache").Return(&environment.TemplateCache{
|
|
||||||
Env: map[string]string{
|
|
||||||
"TERM_PROGRAM": tc.Term,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
color := getConsoleBackgroundColor(env, "{{ if eq \"vscode\" .Env.TERM_PROGRAM }}#123456{{end}}")
|
|
||||||
assert.Equal(t, tc.Expected, color, tc.Case)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This can only be tested here due to circular dependencies
|
// This can only be tested here due to circular dependencies
|
||||||
// Which might be an indaction of a fault architecture but
|
// Which might be an indaction of a fault architecture but
|
||||||
// I honestly could not figure out how to do this better
|
// I honestly could not figure out how to do this better
|
||||||
|
|
Loading…
Reference in a new issue