fix(bash): escape entire rprompt

resolves #717
This commit is contained in:
Jan De Dobbeleer 2021-05-21 22:10:20 +02:00 committed by Jan De Dobbeleer
parent 50473767a7
commit b67f625740
5 changed files with 40 additions and 16 deletions

View file

@ -30,10 +30,12 @@ type ansiUtils struct {
italic string
underline string
strikethrough string
bashFormat string
}
func (a *ansiUtils) init(shell string) {
a.shell = shell
a.bashFormat = "\\[%s\\]"
switch shell {
case zsh:
a.linechange = "%%{\x1b[%d%s%%}"

View file

@ -47,6 +47,16 @@ func (b *Block) init(env environmentInfo, writer colorWriter, ansi *ansiUtils) {
b.ansi = ansi
}
func (b *Block) initPlain(env environmentInfo, config *Config) {
b.ansi = &ansiUtils{}
b.ansi.init(plain)
b.writer = &AnsiColor{
ansi: b.ansi,
terminalBackground: getConsoleBackgroundColor(env, config.TerminalBackground),
}
b.env = env
}
func (b *Block) enabled() bool {
if b.Type == LineBreak {
return true

View file

@ -49,7 +49,13 @@ func (e *engine) render() string {
}
func (e *engine) renderBlock(block *Block) {
block.init(e.env, e.colorWriter, e.ansi)
// when in bash, for rprompt blocks we need to write plain
// and wrap in escaped mode or the prompt will not render correctly
if block.Type == RPrompt && e.env.getShellName() == bash {
block.initPlain(e.env, e.config)
} else {
block.init(e.env, e.colorWriter, e.ansi)
}
block.setStringValues()
if !block.enabled() {
return
@ -77,7 +83,11 @@ func (e *engine) renderBlock(block *Block) {
e.write(block.renderSegments())
}
case RPrompt:
e.rprompt = block.renderSegments()
blockText := block.renderSegments()
if e.env.getShellName() == bash {
blockText = fmt.Sprintf(e.ansi.bashFormat, blockText)
}
e.rprompt = blockText
}
// Due to a bug in Powershell, the end of the line needs to be cleared.
// If this doesn't happen, the portion after the prompt gets colored in the background
@ -133,20 +143,22 @@ func (e *engine) debug() string {
func (e *engine) print() string {
switch e.env.getShellName() {
case zsh:
if *e.env.getArgs().Eval {
// escape double quotes contained in the prompt
prompt := fmt.Sprintf("PS1=\"%s\"", strings.ReplaceAll(e.string(), "\"", "\"\""))
prompt += fmt.Sprintf("\nRPROMPT=\"%s\"", e.rprompt)
return prompt
if !*e.env.getArgs().Eval {
break
}
case pwsh, powershell5, bash, shelly:
if e.rprompt != "" {
e.write(e.ansi.saveCursorPosition)
e.write(e.ansi.carriageForward())
e.write(e.ansi.getCursorForRightWrite(e.rprompt, 0))
e.write(e.rprompt)
e.write(e.ansi.restoreCursorPosition)
// escape double quotes contained in the prompt
prompt := fmt.Sprintf("PS1=\"%s\"", strings.ReplaceAll(e.string(), "\"", "\"\""))
prompt += fmt.Sprintf("\nRPROMPT=\"%s\"", e.rprompt)
return prompt
case pwsh, powershell5, bash, plain:
if e.rprompt == "" {
break
}
e.write(e.ansi.saveCursorPosition)
e.write(e.ansi.carriageForward())
e.write(e.ansi.getCursorForRightWrite(e.rprompt, 0))
e.write(e.rprompt)
e.write(e.ansi.restoreCursorPosition)
}
return e.string()
}

View file

@ -16,7 +16,7 @@ func runImageTest(content string) error {
}
defer os.Remove(file.Name())
ansi := &ansiUtils{}
ansi.init(shelly)
ansi.init(plain)
image := &ImageRenderer{
ansiString: content,
ansi: ansi,

View file

@ -33,7 +33,7 @@ const (
pwsh = "pwsh"
fish = "fish"
powershell5 = "powershell"
shelly = "shell"
plain = "shell"
)
type args struct {