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

View file

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

View file

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