diff --git a/src/ansi/ansi_writer.go b/src/ansi/ansi_writer.go index 18eeeed0be65..38e14a48fa26 100644 --- a/src/ansi/ansi_writer.go +++ b/src/ansi/ansi_writer.go @@ -82,8 +82,10 @@ type Writer struct { Colors *Colors ParentColors []*Colors AnsiColors ColorString - Plain bool - TrueColor bool + + Plain bool + TrueColor bool + Interactive bool builder strings.Builder length int @@ -111,6 +113,9 @@ type Writer struct { osc7 string osc51 string + lastRune rune + escapeSequences map[rune]rune + hyperlinkStart string hyperlinkCenter string hyperlinkEnd string @@ -144,6 +149,10 @@ func (w *Writer) Init(shellName string) { w.iTermPromptMark = "\\[$(iterm2_prompt_mark)\\]" w.iTermCurrentDir = "\\[\x1b]1337;CurrentDir=%s\x07\\]" w.iTermRemoteHost = "\\[\x1b]1337;RemoteHost=%s@%s\x07\\]" + w.escapeSequences = map[rune]rune{ + 96: 92, // backtick + 92: 92, // backslash + } case shell.ZSH, shell.TCSH: w.format = "%%{%s%%}" w.linechange = "%%{\x1b[%d%s%%}" @@ -184,6 +193,13 @@ func (w *Writer) Init(shellName string) { w.iTermCurrentDir = "\x1b]1337;CurrentDir=%s\x07" w.iTermRemoteHost = "\x1b]1337;RemoteHost=%s@%s\x07" } + + if shellName == shell.ZSH { + w.escapeSequences = map[rune]rune{ + 96: 92, // backtick + 37: 37, // % + } + } } func (w *Writer) SetColors(background, foreground string) { @@ -207,11 +223,14 @@ func (w *Writer) ChangeLine(numberOfLines int) string { if w.Plain { return "" } + position := "B" + if numberOfLines < 0 { position = "F" numberOfLines = -numberOfLines } + return fmt.Sprintf(w.linechange, numberOfLines, position) } @@ -219,9 +238,11 @@ func (w *Writer) ConsolePwd(pwdType, userName, hostName, pwd string) string { if w.Plain { return "" } + if strings.HasSuffix(pwd, ":") { pwd += "\\" } + switch pwdType { case OSC7: return fmt.Sprintf(w.osc7, hostName, pwd) @@ -238,6 +259,7 @@ func (w *Writer) ClearAfter() string { if w.Plain { return "" } + return w.clearLine + w.clearBelow } @@ -246,6 +268,7 @@ func (w *Writer) FormatTitle(title string) string { if w.Plain { return title } + // we have to do this to prevent bash/zsh from misidentifying escape sequences switch w.shell { case shell.BASH: @@ -256,6 +279,7 @@ func (w *Writer) FormatTitle(title string) string { // these shells don't support setting the title return "" } + return fmt.Sprintf(w.title, title) } @@ -416,10 +440,21 @@ func (w *Writer) write(s rune) { return } - if !w.hyperlink { - w.length += runewidth.RuneWidth(s) + if w.hyperlink { + w.builder.WriteRune(s) + return + } + + if !w.Interactive { + for special, escape := range w.escapeSequences { + if s == special && w.lastRune != escape { + w.builder.WriteRune(escape) + } + } } + w.length += runewidth.RuneWidth(s) + w.lastRune = s w.builder.WriteRune(s) } diff --git a/src/engine/block.go b/src/engine/block.go index 21410507a858..3a3c6684f85a 100644 --- a/src/engine/block.go +++ b/src/engine/block.go @@ -70,6 +70,7 @@ func (b *Block) InitPlain(env platform.Environment, config *Config) { AnsiColors: config.MakeColors(), TrueColor: env.Flags().TrueColor, } + b.writer.Init(shell.GENERIC) b.env = env b.executeSegmentLogic() @@ -79,12 +80,14 @@ func (b *Block) executeSegmentLogic() { if shouldHideForWidth(b.env, b.MinWidth, b.MaxWidth) { return } + b.setEnabledSegments() b.setSegmentsText() } func (b *Block) setActiveSegment(segment *Segment) { b.activeSegment = segment + b.writer.Interactive = segment.Interactive b.writer.SetColors(segment.background(), segment.foreground()) } diff --git a/src/engine/engine.go b/src/engine/engine.go index 6de862021055..40d4bdeca747 100644 --- a/src/engine/engine.go +++ b/src/engine/engine.go @@ -92,16 +92,12 @@ func (e *Engine) pwd() { cwd := e.Env.Pwd() - // in BASH, we need to escape the path - if e.Env.Shell() == shell.BASH { - cwd = strings.ReplaceAll(cwd, `\`, `\\`) - } - // Backwards compatibility for deprecated OSC99 if e.Config.OSC99 { e.write(e.Writer.ConsolePwd(ansi.OSC99, "", "", cwd)) return } + // Allow template logic to define when to enable the PWD (when supported) tmpl := &template.Text{ Template: e.Config.PWD, diff --git a/src/engine/engine_test.go b/src/engine/engine_test.go index 6e8a912867ec..8975f885429f 100644 --- a/src/engine/engine_test.go +++ b/src/engine/engine_test.go @@ -66,7 +66,7 @@ func TestPrintPWD(t *testing.T) { Pwd: `C:\Users\user\Documents\GitHub\oh-my-posh`, Config: ansi.OSC99, Shell: shell.BASH, - Expected: "\x1b]9;9;C:\\\\Users\\\\user\\\\Documents\\\\GitHub\\\\oh-my-posh\x1b\\", + Expected: "\x1b]9;9;C:\\Users\\user\\Documents\\GitHub\\oh-my-posh\x1b\\", }, } diff --git a/src/engine/segment.go b/src/engine/segment.go index eb281b8f5ba3..497b63987639 100644 --- a/src/engine/segment.go +++ b/src/engine/segment.go @@ -11,7 +11,6 @@ import ( "github.com/jandedobbeleer/oh-my-posh/src/platform" "github.com/jandedobbeleer/oh-my-posh/src/properties" "github.com/jandedobbeleer/oh-my-posh/src/segments" - "github.com/jandedobbeleer/oh-my-posh/src/shell" "github.com/jandedobbeleer/oh-my-posh/src/template" c "golang.org/x/text/cases" @@ -371,7 +370,9 @@ func (segment *Segment) style() SegmentStyle { if len(segment.styleCache) != 0 { return segment.styleCache } + segment.styleCache = segment.Style.Resolve(segment.env, segment.writer) + return segment.styleCache } @@ -379,8 +380,10 @@ func (segment *Segment) shouldIncludeFolder() bool { if segment.env == nil { return true } + cwdIncluded := segment.cwdIncluded() cwdExcluded := segment.cwdExcluded() + return cwdIncluded && !cwdExcluded } @@ -419,6 +422,7 @@ func (segment *Segment) cwdExcluded() bool { if !ok { value = segment.Properties[properties.IgnoreFolders] } + list := properties.ParseStringArray(value) return segment.env.DirMatchesOneOf(segment.env.Pwd(), list) } @@ -429,6 +433,7 @@ func (segment *Segment) shouldInvokeWithTip(tip string) bool { return true } } + return false } @@ -436,9 +441,11 @@ func (segment *Segment) foreground() string { if segment.colors == nil { segment.colors = &ansi.Colors{} } + if len(segment.colors.Foreground) == 0 { segment.colors.Foreground = segment.ForegroundTemplates.FirstMatch(segment.writer, segment.env, segment.Foreground) } + return segment.colors.Foreground } @@ -446,9 +453,11 @@ func (segment *Segment) background() string { if segment.colors == nil { segment.colors = &ansi.Colors{} } + if len(segment.colors.Background) == 0 { segment.colors.Background = segment.BackgroundTemplates.FirstMatch(segment.writer, segment.env, segment.Background) } + return segment.colors.Background } @@ -481,19 +490,23 @@ func (segment *Segment) string() string { return templatesResult } } + if len(segment.Template) == 0 { segment.Template = segment.writer.Template() } + tmpl := &template.Text{ Template: segment.Template, Context: segment.writer, Env: segment.env, TemplatesResult: templatesResult, } + text, err := tmpl.Render() if err != nil { return err.Error() } + return text } @@ -501,10 +514,12 @@ func (segment *Segment) Name() string { if len(segment.name) != 0 { return segment.name } + name := segment.Alias if len(name) == 0 { name = c.Title(language.English).String(string(segment.Type)) } + segment.name = name return name } @@ -562,20 +577,11 @@ func (segment *Segment) SetText() { if !segment.Enabled { return } + segment.text = segment.string() segment.Enabled = len(strings.ReplaceAll(segment.text, " ", "")) > 0 + if !segment.Enabled { segment.env.TemplateCache().RemoveSegmentData(segment.Name()) } - - if segment.Interactive { - return - } - // we have to do this to prevent bash/zsh from misidentifying escape sequences - switch segment.env.Shell() { - case shell.BASH: - segment.text = strings.NewReplacer("`", "\\`", `\`, `\\`).Replace(segment.text) - case shell.ZSH: - segment.text = strings.NewReplacer("`", "\\`", `%`, `%%`).Replace(segment.text) - } }