2019-03-13 04:14:30 -07:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2020-10-12 23:57:46 -07:00
|
|
|
"sync"
|
2020-12-27 08:53:58 -08:00
|
|
|
"time"
|
2019-03-13 04:14:30 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
type engine struct {
|
|
|
|
settings *Settings
|
|
|
|
env environmentInfo
|
2020-12-17 23:59:45 -08:00
|
|
|
color *AnsiColor
|
|
|
|
renderer *AnsiRenderer
|
2020-12-26 10:51:21 -08:00
|
|
|
consoleTitle *consoleTitle
|
2019-03-13 04:14:30 -07:00
|
|
|
activeBlock *Block
|
|
|
|
activeSegment *Segment
|
|
|
|
previousActiveSegment *Segment
|
2020-12-17 23:59:45 -08:00
|
|
|
rprompt string
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
|
2021-01-05 03:28:33 -08:00
|
|
|
// SegmentTiming holds the timing context for a segment
|
2020-12-27 08:53:58 -08:00
|
|
|
type SegmentTiming struct {
|
|
|
|
name string
|
|
|
|
nameLength int
|
|
|
|
enabled bool
|
|
|
|
stringValue string
|
|
|
|
enabledDuration time.Duration
|
|
|
|
stringDuration time.Duration
|
|
|
|
}
|
|
|
|
|
2019-03-13 04:14:30 -07:00
|
|
|
func (e *engine) getPowerlineColor(foreground bool) string {
|
|
|
|
if e.previousActiveSegment == nil {
|
2020-09-21 06:44:09 -07:00
|
|
|
return Transparent
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
if !foreground && e.activeSegment.Style != Powerline {
|
2020-09-21 06:44:09 -07:00
|
|
|
return Transparent
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
if foreground && e.previousActiveSegment.Style != Powerline {
|
2020-09-21 06:44:09 -07:00
|
|
|
return Transparent
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
2021-02-13 07:27:31 -08:00
|
|
|
return e.previousActiveSegment.background()
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
|
2020-11-12 00:43:32 -08:00
|
|
|
func (e *engine) writePowerLineSeparator(background, foreground string, end bool) {
|
2020-09-26 04:41:28 -07:00
|
|
|
symbol := e.activeSegment.PowerlineSymbol
|
|
|
|
if end {
|
|
|
|
symbol = e.previousActiveSegment.PowerlineSymbol
|
|
|
|
}
|
2020-09-27 00:37:50 -07:00
|
|
|
if e.activeSegment.InvertPowerline {
|
2020-12-17 23:59:45 -08:00
|
|
|
e.color.write(foreground, background, symbol)
|
2019-03-13 04:14:30 -07:00
|
|
|
return
|
|
|
|
}
|
2020-12-17 23:59:45 -08:00
|
|
|
e.color.write(background, foreground, symbol)
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func (e *engine) endPowerline() {
|
|
|
|
if e.activeSegment != nil &&
|
|
|
|
e.activeSegment.Style != Powerline &&
|
|
|
|
e.previousActiveSegment != nil &&
|
|
|
|
e.previousActiveSegment.Style == Powerline {
|
2021-02-13 07:27:31 -08:00
|
|
|
e.writePowerLineSeparator(e.getPowerlineColor(false), e.previousActiveSegment.background(), true)
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *engine) renderPowerLineSegment(text string) {
|
2021-02-13 07:27:31 -08:00
|
|
|
e.writePowerLineSeparator(e.activeSegment.background(), e.getPowerlineColor(true), false)
|
2019-03-13 04:14:30 -07:00
|
|
|
e.renderText(text)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *engine) renderPlainSegment(text string) {
|
|
|
|
e.renderText(text)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *engine) renderDiamondSegment(text string) {
|
2021-02-13 07:27:31 -08:00
|
|
|
e.color.write(Transparent, e.activeSegment.background(), e.activeSegment.LeadingDiamond)
|
2019-03-13 04:14:30 -07:00
|
|
|
e.renderText(text)
|
2021-02-13 07:27:31 -08:00
|
|
|
e.color.write(Transparent, e.activeSegment.background(), e.activeSegment.TrailingDiamond)
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func (e *engine) renderText(text string) {
|
2020-12-02 09:40:10 -08:00
|
|
|
defaultValue := " "
|
2021-02-13 07:27:31 -08:00
|
|
|
if e.activeSegment.background() != "" {
|
|
|
|
defaultValue = fmt.Sprintf("<%s>\u2588</>", e.activeSegment.background())
|
2020-12-02 09:40:10 -08:00
|
|
|
}
|
2021-01-09 07:18:37 -08:00
|
|
|
|
|
|
|
text = e.color.formats.generateHyperlink(text)
|
|
|
|
|
2020-12-02 00:20:58 -08:00
|
|
|
prefix := e.activeSegment.getValue(Prefix, defaultValue)
|
|
|
|
postfix := e.activeSegment.getValue(Postfix, defaultValue)
|
2021-02-13 07:27:31 -08:00
|
|
|
e.color.write(e.activeSegment.background(), e.activeSegment.foreground(), fmt.Sprintf("%s%s%s", prefix, text, postfix))
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func (e *engine) renderSegmentText(text string) {
|
|
|
|
switch e.activeSegment.Style {
|
|
|
|
case Plain:
|
|
|
|
e.renderPlainSegment(text)
|
|
|
|
case Diamond:
|
|
|
|
e.renderDiamondSegment(text)
|
2020-11-12 00:43:32 -08:00
|
|
|
case Powerline:
|
2019-03-13 04:14:30 -07:00
|
|
|
e.renderPowerLineSegment(text)
|
|
|
|
}
|
|
|
|
e.previousActiveSegment = e.activeSegment
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *engine) renderBlockSegments(block *Block) string {
|
2020-12-17 23:59:45 -08:00
|
|
|
defer e.resetBlock()
|
2019-03-13 04:14:30 -07:00
|
|
|
e.activeBlock = block
|
2020-10-12 23:57:46 -07:00
|
|
|
e.setStringValues(block.Segments)
|
2019-03-13 04:14:30 -07:00
|
|
|
for _, segment := range block.Segments {
|
2020-10-12 23:57:46 -07:00
|
|
|
if !segment.active {
|
2019-03-13 04:14:30 -07:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
e.activeSegment = segment
|
|
|
|
e.endPowerline()
|
2021-01-09 07:18:37 -08:00
|
|
|
e.renderSegmentText(segment.stringValue)
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
if e.previousActiveSegment != nil && e.previousActiveSegment.Style == Powerline {
|
2021-02-13 07:27:31 -08:00
|
|
|
e.writePowerLineSeparator(Transparent, e.previousActiveSegment.background(), true)
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
2020-12-17 23:59:45 -08:00
|
|
|
return e.color.string()
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
|
2020-10-12 23:57:46 -07:00
|
|
|
func (e *engine) setStringValues(segments []*Segment) {
|
|
|
|
wg := sync.WaitGroup{}
|
|
|
|
wg.Add(len(segments))
|
|
|
|
defer wg.Wait()
|
|
|
|
cwd := e.env.getcwd()
|
|
|
|
for _, segment := range segments {
|
|
|
|
go func(s *Segment) {
|
|
|
|
defer wg.Done()
|
2020-12-27 08:53:58 -08:00
|
|
|
s.setStringValue(e.env, cwd)
|
2020-10-12 23:57:46 -07:00
|
|
|
}(segment)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-16 04:08:28 -07:00
|
|
|
func (e *engine) render() {
|
2019-03-13 04:14:30 -07:00
|
|
|
for _, block := range e.settings.Blocks {
|
|
|
|
// if line break, append a line break
|
2020-12-17 23:59:45 -08:00
|
|
|
switch block.Type {
|
|
|
|
case LineBreak:
|
2021-02-14 05:09:43 -08:00
|
|
|
e.renderer.write("\n")
|
2020-12-17 23:59:45 -08:00
|
|
|
case Prompt:
|
|
|
|
if block.VerticalOffset != 0 {
|
|
|
|
e.renderer.changeLine(block.VerticalOffset)
|
|
|
|
}
|
|
|
|
switch block.Alignment {
|
|
|
|
case Right:
|
|
|
|
e.renderer.carriageForward()
|
|
|
|
blockText := e.renderBlockSegments(block)
|
|
|
|
e.renderer.setCursorForRightWrite(blockText, block.HorizontalOffset)
|
2021-02-14 05:09:43 -08:00
|
|
|
e.renderer.write(blockText)
|
2020-12-17 23:59:45 -08:00
|
|
|
case Left:
|
2021-02-14 05:09:43 -08:00
|
|
|
e.renderer.write(e.renderBlockSegments(block))
|
2020-12-17 23:59:45 -08:00
|
|
|
}
|
|
|
|
case RPrompt:
|
|
|
|
e.rprompt = e.renderBlockSegments(block)
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
}
|
2020-10-12 00:02:33 -07:00
|
|
|
if e.settings.ConsoleTitle {
|
2021-02-14 05:09:43 -08:00
|
|
|
e.renderer.write(e.consoleTitle.getConsoleTitle())
|
2020-10-12 00:02:33 -07:00
|
|
|
}
|
2020-10-14 07:25:18 -07:00
|
|
|
e.renderer.creset()
|
2020-09-26 11:00:28 -07:00
|
|
|
if e.settings.FinalSpace {
|
2021-02-14 05:09:43 -08:00
|
|
|
e.renderer.write(" ")
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
2021-02-14 23:26:52 -08:00
|
|
|
|
|
|
|
cwd := e.env.getcwd()
|
|
|
|
|
|
|
|
// temp to fix 3.89 issue and add wsl support
|
|
|
|
if e.env.isWsl() {
|
|
|
|
// transform path
|
|
|
|
cwd, _ = e.env.runCommand("wslpath", "-m", cwd)
|
|
|
|
}
|
|
|
|
e.renderer.osc99(cwd)
|
2021-02-14 05:09:43 -08:00
|
|
|
e.print()
|
2020-12-17 23:59:45 -08:00
|
|
|
}
|
|
|
|
|
2021-01-09 07:18:37 -08:00
|
|
|
// debug will loop through your config file and output the timings for each segments
|
2020-12-27 08:53:58 -08:00
|
|
|
func (e *engine) debug() {
|
|
|
|
var segmentTimings []SegmentTiming
|
2020-12-31 05:00:46 -08:00
|
|
|
largestSegmentNameLength := 0
|
2021-02-14 05:09:43 -08:00
|
|
|
e.renderer.write("\n\x1b[1mHere are the timings of segments in your prompt:\x1b[0m\n\n")
|
2021-01-14 21:10:36 -08:00
|
|
|
|
|
|
|
// console title timing
|
|
|
|
start := time.Now()
|
|
|
|
consoleTitle := e.consoleTitle.getTemplateText()
|
|
|
|
duration := time.Since(start)
|
|
|
|
segmentTiming := SegmentTiming{
|
|
|
|
name: "ConsoleTitle",
|
|
|
|
nameLength: 12,
|
|
|
|
enabled: e.settings.ConsoleTitle,
|
|
|
|
stringValue: consoleTitle,
|
|
|
|
enabledDuration: 0,
|
|
|
|
stringDuration: duration,
|
|
|
|
}
|
|
|
|
segmentTimings = append(segmentTimings, segmentTiming)
|
2020-12-27 08:53:58 -08:00
|
|
|
// loop each segments of each blocks
|
|
|
|
for _, block := range e.settings.Blocks {
|
|
|
|
for _, segment := range block.Segments {
|
|
|
|
err := segment.mapSegmentWithWriter(e.env)
|
|
|
|
if err != nil || segment.shouldIgnoreFolder(e.env.getcwd()) {
|
2021-01-04 06:49:31 -08:00
|
|
|
continue
|
2020-12-27 08:53:58 -08:00
|
|
|
}
|
|
|
|
var segmentTiming SegmentTiming
|
|
|
|
segmentTiming.name = string(segment.Type)
|
|
|
|
segmentTiming.nameLength = len(segmentTiming.name)
|
2020-12-31 05:00:46 -08:00
|
|
|
if segmentTiming.nameLength > largestSegmentNameLength {
|
|
|
|
largestSegmentNameLength = segmentTiming.nameLength
|
2020-12-27 08:53:58 -08:00
|
|
|
}
|
2020-12-31 05:00:46 -08:00
|
|
|
// enabled() timing
|
2020-12-27 08:53:58 -08:00
|
|
|
start := time.Now()
|
|
|
|
segmentTiming.enabled = segment.enabled()
|
|
|
|
segmentTiming.enabledDuration = time.Since(start)
|
2020-12-31 05:00:46 -08:00
|
|
|
// string() timing
|
2020-12-27 08:53:58 -08:00
|
|
|
if segmentTiming.enabled {
|
|
|
|
start = time.Now()
|
|
|
|
segmentTiming.stringValue = segment.string()
|
|
|
|
segmentTiming.stringDuration = time.Since(start)
|
2020-12-31 05:00:46 -08:00
|
|
|
e.previousActiveSegment = nil
|
2020-12-27 08:53:58 -08:00
|
|
|
e.activeSegment = segment
|
|
|
|
e.renderSegmentText(segmentTiming.stringValue)
|
2020-12-31 05:00:46 -08:00
|
|
|
if e.activeSegment.Style == Powerline {
|
2021-02-13 07:27:31 -08:00
|
|
|
e.writePowerLineSeparator(Transparent, e.activeSegment.background(), true)
|
2020-12-31 05:00:46 -08:00
|
|
|
}
|
2020-12-27 08:53:58 -08:00
|
|
|
segmentTiming.stringValue = e.color.string()
|
2021-01-05 23:52:43 -08:00
|
|
|
e.color.builder.Reset()
|
2020-12-27 08:53:58 -08:00
|
|
|
}
|
|
|
|
segmentTimings = append(segmentTimings, segmentTiming)
|
|
|
|
}
|
|
|
|
}
|
2021-01-14 21:10:36 -08:00
|
|
|
|
2020-12-31 05:00:46 -08:00
|
|
|
// pad the output so the tabs render correctly
|
|
|
|
largestSegmentNameLength += 7
|
2020-12-27 08:53:58 -08:00
|
|
|
for _, segment := range segmentTimings {
|
|
|
|
duration := segment.enabledDuration.Milliseconds()
|
|
|
|
if segment.enabled {
|
|
|
|
duration += segment.stringDuration.Milliseconds()
|
|
|
|
}
|
2020-12-31 05:00:46 -08:00
|
|
|
segmentName := fmt.Sprintf("%s(%t)", segment.name, segment.enabled)
|
2021-02-14 05:09:43 -08:00
|
|
|
e.renderer.write(fmt.Sprintf("%-*s - %3d ms - %s\n", largestSegmentNameLength, segmentName, duration, segment.stringValue))
|
2020-12-27 08:53:58 -08:00
|
|
|
}
|
|
|
|
fmt.Print(e.renderer.string())
|
|
|
|
}
|
|
|
|
|
2021-02-14 05:09:43 -08:00
|
|
|
func (e *engine) print() {
|
2020-12-23 04:31:21 -08:00
|
|
|
switch e.env.getShellName() {
|
|
|
|
case zsh:
|
|
|
|
if *e.env.getArgs().Eval {
|
|
|
|
fmt.Printf("PS1=\"%s\"", e.renderer.string())
|
2020-12-17 23:59:45 -08:00
|
|
|
fmt.Printf("\nRPROMPT=\"%s\"", e.rprompt)
|
2020-12-23 04:31:21 -08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
case pwsh, powershell5, bash:
|
|
|
|
if e.rprompt != "" {
|
|
|
|
e.renderer.saveCursorPosition()
|
|
|
|
e.renderer.carriageForward()
|
|
|
|
e.renderer.setCursorForRightWrite(e.rprompt, 0)
|
2021-02-14 05:09:43 -08:00
|
|
|
e.renderer.write(e.rprompt)
|
2020-12-23 04:31:21 -08:00
|
|
|
e.renderer.restoreCursorPosition()
|
2020-12-17 23:59:45 -08:00
|
|
|
}
|
2020-12-15 05:58:15 -08:00
|
|
|
}
|
2020-12-17 23:59:45 -08:00
|
|
|
fmt.Print(e.renderer.string())
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
|
2020-12-17 23:59:45 -08:00
|
|
|
func (e *engine) resetBlock() {
|
|
|
|
e.color.reset()
|
2019-03-13 04:14:30 -07:00
|
|
|
e.previousActiveSegment = nil
|
|
|
|
e.activeBlock = nil
|
|
|
|
}
|