mirror of
https://github.com/JanDeDobbeleer/oh-my-posh.git
synced 2024-09-19 21:17:31 -07:00
9b9405978e
When using PowerShell, "\n" isn't recognized as a newline character. To resolve this, moving the cursor down 1 line is more interesting as it will work in any shell using ANSI escape sequences (which we depends upon).
160 lines
4.5 KiB
Go
160 lines
4.5 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"regexp"
|
|
|
|
"golang.org/x/text/unicode/norm"
|
|
)
|
|
|
|
type engine struct {
|
|
settings *Settings
|
|
env environmentInfo
|
|
renderer *ColorWriter
|
|
activeBlock *Block
|
|
activeSegment *Segment
|
|
previousActiveSegment *Segment
|
|
}
|
|
|
|
func (e *engine) getPowerlineColor(foreground bool) string {
|
|
if e.previousActiveSegment == nil {
|
|
return e.settings.ConsoleBackgroundColor
|
|
}
|
|
if !foreground && e.activeSegment.Style != Powerline {
|
|
return e.settings.ConsoleBackgroundColor
|
|
}
|
|
if foreground && e.previousActiveSegment.Style != Powerline {
|
|
return e.settings.ConsoleBackgroundColor
|
|
}
|
|
return e.previousActiveSegment.Background
|
|
}
|
|
|
|
func (e *engine) writePowerLineSeparator(background string, foreground string) {
|
|
if e.activeBlock.InvertPowerlineSeparatorColor {
|
|
e.renderer.write(foreground, background, e.activeBlock.PowerlineSeparator)
|
|
return
|
|
}
|
|
e.renderer.write(background, foreground, e.activeBlock.PowerlineSeparator)
|
|
}
|
|
|
|
func (e *engine) endPowerline() {
|
|
if e.activeSegment != nil &&
|
|
e.activeSegment.Style != Powerline &&
|
|
e.previousActiveSegment != nil &&
|
|
e.previousActiveSegment.Style == Powerline {
|
|
e.writePowerLineSeparator(e.getPowerlineColor(false), e.previousActiveSegment.Background)
|
|
}
|
|
}
|
|
|
|
func (e *engine) renderPowerLineSegment(text string) {
|
|
e.writePowerLineSeparator(e.activeSegment.Background, e.getPowerlineColor(true))
|
|
e.renderText(text)
|
|
}
|
|
|
|
func (e *engine) renderPlainSegment(text string) {
|
|
e.renderText(text)
|
|
}
|
|
|
|
func (e *engine) renderDiamondSegment(text string) {
|
|
e.renderer.write(e.settings.ConsoleBackgroundColor, e.activeSegment.Background, e.activeSegment.LeadingDiamond)
|
|
e.renderText(text)
|
|
e.renderer.write(e.settings.ConsoleBackgroundColor, e.activeSegment.Background, e.activeSegment.TrailingDiamond)
|
|
}
|
|
|
|
func (e *engine) getStringProperty(property Property, defaultValue string) string {
|
|
if value, ok := e.activeSegment.Properties[property]; ok {
|
|
return parseString(value, defaultValue)
|
|
}
|
|
return defaultValue
|
|
}
|
|
|
|
func (e *engine) renderText(text string) {
|
|
prefix := e.getStringProperty(Prefix, " ")
|
|
postfix := e.getStringProperty(Postfix, " ")
|
|
e.renderer.write(e.activeSegment.Background, e.activeSegment.Foreground, fmt.Sprintf("%s%s%s", prefix, text, postfix))
|
|
}
|
|
|
|
func (e *engine) renderSegmentText(text string) {
|
|
switch e.activeSegment.Style {
|
|
case Plain:
|
|
e.renderPlainSegment(text)
|
|
case Diamond:
|
|
e.renderDiamondSegment(text)
|
|
default:
|
|
e.renderPowerLineSegment(text)
|
|
}
|
|
e.previousActiveSegment = e.activeSegment
|
|
}
|
|
|
|
func (e *engine) renderBlockSegments(block *Block) string {
|
|
defer e.reset()
|
|
e.activeBlock = block
|
|
for _, segment := range block.Segments {
|
|
props := segment.mapSegmentWithWriter(e.env)
|
|
if !segment.enabled() {
|
|
continue
|
|
}
|
|
e.activeSegment = segment
|
|
e.endPowerline()
|
|
text := segment.string()
|
|
e.activeSegment.Background = props.background
|
|
e.activeSegment.Foreground = props.foreground
|
|
e.renderSegmentText(text)
|
|
}
|
|
if e.previousActiveSegment != nil && e.previousActiveSegment.Style == Powerline {
|
|
e.writePowerLineSeparator(e.settings.ConsoleBackgroundColor, e.previousActiveSegment.Background)
|
|
}
|
|
return e.renderer.string()
|
|
}
|
|
|
|
func (e *engine) lenWithoutANSI(str string) int {
|
|
ansi := "[\u001B\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))"
|
|
re := regexp.MustCompile(ansi)
|
|
stripped := re.ReplaceAllString(str, "")
|
|
var i norm.Iter
|
|
i.InitString(norm.NFD, stripped)
|
|
var count int
|
|
for !i.Done() {
|
|
i.Next()
|
|
count++
|
|
}
|
|
return count
|
|
}
|
|
|
|
func (e *engine) string() string {
|
|
var buffer bytes.Buffer
|
|
defer buffer.Reset()
|
|
for _, block := range e.settings.Blocks {
|
|
// if line break, append a line break
|
|
if block.Type == LineBreak {
|
|
buffer.WriteString("\x1b[1B")
|
|
continue
|
|
}
|
|
if block.LineOffset < 0 {
|
|
buffer.WriteString(fmt.Sprintf("\x1b[%dF", -block.LineOffset))
|
|
} else if block.LineOffset > 0 {
|
|
buffer.WriteString(fmt.Sprintf("\x1b[%dB", block.LineOffset))
|
|
}
|
|
switch block.Alignment {
|
|
case Right:
|
|
buffer.WriteString(fmt.Sprintf("\x1b[%dC", 1000))
|
|
blockText := e.renderBlockSegments(block)
|
|
buffer.WriteString(fmt.Sprintf("\x1b[%dD", e.lenWithoutANSI(blockText)+e.settings.RightSegmentOffset))
|
|
buffer.WriteString(blockText)
|
|
default:
|
|
buffer.WriteString(e.renderBlockSegments(block))
|
|
}
|
|
}
|
|
if e.settings.EndSpaceEnabled {
|
|
buffer.WriteString(" ")
|
|
}
|
|
return buffer.String()
|
|
}
|
|
|
|
func (e *engine) reset() {
|
|
e.renderer.reset()
|
|
e.previousActiveSegment = nil
|
|
e.activeBlock = nil
|
|
}
|