fix(rprompt): position using spaces instead of ANSI

This commit is contained in:
Jan De Dobbeleer 2023-08-04 12:39:47 +02:00 committed by Jan De Dobbeleer
parent 2007f9d1ab
commit 181b789186
3 changed files with 44 additions and 27 deletions

View file

@ -35,27 +35,48 @@ func (e *Engine) string() string {
return text
}
func (e *Engine) canWriteRightBlock(rprompt bool) bool {
if rprompt && (e.rprompt == "" || e.Plain) {
return false
func (e *Engine) canWriteRightBlock(rprompt bool) (int, bool) {
if rprompt && (len(e.rprompt) == 0 || e.Plain) {
return 0, false
}
consoleWidth, err := e.Env.TerminalWidth()
if err != nil || consoleWidth == 0 {
return true
return 0, false
}
promptWidth := e.currentLineLength
availableSpace := consoleWidth - promptWidth
// spanning multiple lines
if availableSpace < 0 {
overflow := promptWidth % consoleWidth
availableSpace = consoleWidth - overflow
}
if rprompt {
availableSpace -= e.rpromptLength
}
promptBreathingRoom := 5
if rprompt {
promptBreathingRoom = 30
}
canWrite := (availableSpace - e.rpromptLength) >= promptBreathingRoom
return canWrite
canWrite := availableSpace >= promptBreathingRoom
return availableSpace, canWrite
}
func (e *Engine) writeRPrompt() {
space, OK := e.canWriteRightBlock(true)
if !OK {
return
}
e.write(e.Writer.SaveCursorPosition())
e.write(strings.Repeat(" ", space))
e.write(e.rprompt)
e.write(e.Writer.RestoreCursorPosition())
}
func (e *Engine) pwd() {
@ -105,23 +126,28 @@ func (e *Engine) isWarp() bool {
return e.Env.Getenv("TERM_PROGRAM") == "WarpTerminal"
}
func (e *Engine) shouldFill(filler string, length int) (string, bool) {
func (e *Engine) shouldFill(filler string, blockLength int) (string, bool) {
if len(filler) == 0 {
return "", false
}
terminalWidth, err := e.Env.TerminalWidth()
if err != nil || terminalWidth == 0 {
return "", false
}
padLength := terminalWidth - e.currentLineLength - length
padLength := terminalWidth - e.currentLineLength - blockLength
if padLength <= 0 {
return "", false
}
// allow for easy color overrides and templates
e.Writer.Write("", "", filler)
filler, lenFiller := e.Writer.String()
if lenFiller == 0 {
return "", false
}
repeat := padLength / lenFiller
return strings.Repeat(filler, repeat), true
}
@ -197,7 +223,7 @@ func (e *Engine) renderBlock(block *Block, cancelNewline bool) {
text, length := block.RenderSegments()
e.rpromptLength = length
if !e.canWriteRightBlock(false) {
if _, OK := e.canWriteRightBlock(false); OK {
switch block.Overflow {
case Break:
e.newline()
@ -216,6 +242,7 @@ func (e *Engine) renderBlock(block *Block, cancelNewline bool) {
e.write(text)
return
}
prompt := e.Writer.CarriageForward()
prompt += e.Writer.GetCursorForRightWrite(length, block.HorizontalOffset)
prompt += text

View file

@ -21,7 +21,7 @@ func TestCanWriteRPrompt(t *testing.T) {
PromptLength int
RPromptLength int
}{
{Case: "Width Error", Expected: true, TerminalWidthError: errors.New("burp")},
{Case: "Width Error", Expected: false, TerminalWidthError: errors.New("burp")},
{Case: "Terminal > Prompt enabled", Expected: true, TerminalWidth: 200, PromptLength: 100, RPromptLength: 10},
{Case: "Terminal > Prompt enabled edge", Expected: true, TerminalWidth: 200, PromptLength: 100, RPromptLength: 70},
{Case: "Prompt > Terminal enabled", Expected: true, TerminalWidth: 200, PromptLength: 300, RPromptLength: 70},
@ -39,7 +39,7 @@ func TestCanWriteRPrompt(t *testing.T) {
currentLineLength: tc.PromptLength,
rprompt: "hello",
}
got := engine.canWriteRightBlock(true)
_, got := engine.canWriteRightBlock(true)
assert.Equal(t, tc.Expected, got, tc.Case)
}
}

View file

@ -44,6 +44,7 @@ func (e *Engine) Primary() string {
if e.Config.FinalSpace {
e.write(" ")
e.currentLineLength++
}
if e.Config.ShellIntegration && e.Config.TransientPrompt == nil {
@ -59,11 +60,7 @@ func (e *Engine) Primary() string {
}
// Warp doesn't support RPROMPT so we need to write it manually
if e.isWarp() {
e.write(e.Writer.SaveCursorPosition())
e.write(e.Writer.CarriageForward())
e.write(e.Writer.GetCursorForRightWrite(e.rpromptLength, 0))
e.write(e.rprompt)
e.write(e.Writer.RestoreCursorPosition())
e.writeRPrompt()
// escape double quotes contained in the prompt
prompt := fmt.Sprintf("PS1=\"%s\"", strings.ReplaceAll(e.string(), `"`, `\"`))
return prompt
@ -73,16 +70,10 @@ func (e *Engine) Primary() string {
prompt += fmt.Sprintf("\nRPROMPT=\"%s\"", e.rprompt)
return prompt
case shell.PWSH, shell.PWSH5, shell.GENERIC, shell.NU:
if !e.canWriteRightBlock(true) {
break
}
e.write(e.Writer.SaveCursorPosition())
e.write(e.Writer.CarriageForward())
e.write(e.Writer.GetCursorForRightWrite(e.rpromptLength, 0))
e.write(e.rprompt)
e.write(e.Writer.RestoreCursorPosition())
e.writeRPrompt()
case shell.BASH:
if !e.canWriteRightBlock(true) {
space, OK := e.canWriteRightBlock(true)
if !OK {
break
}
// in bash, the entire rprompt needs to be escaped for the prompt to be interpreted correctly
@ -92,8 +83,7 @@ func (e *Engine) Primary() string {
}
writer.Init(shell.GENERIC)
prompt := writer.SaveCursorPosition()
prompt += writer.CarriageForward()
prompt += writer.GetCursorForRightWrite(e.rpromptLength, 0)
prompt += strings.Repeat(" ", space)
prompt += e.rprompt
prompt += writer.RestoreCursorPosition()
prompt = e.Writer.FormatText(prompt)