feat: plain text prompt

resolves #1142
This commit is contained in:
Jan De Dobbeleer 2021-11-02 15:53:46 +02:00 committed by Jan De Dobbeleer
parent aa94042bd5
commit 8b20d8fd81
3 changed files with 79 additions and 19 deletions

View file

@ -9,9 +9,10 @@ import (
type engine struct {
config *Config
env environmentInfo
colorWriter promptWriter
writer promptWriter
ansi *ansiUtils
consoleTitle *consoleTitle
plain bool
console strings.Builder
rprompt string
@ -21,6 +22,13 @@ func (e *engine) write(text string) {
e.console.WriteString(text)
}
func (e *engine) writeANSI(text string) {
if e.plain {
return
}
e.console.WriteString(text)
}
func (e *engine) string() string {
return e.console.String()
}
@ -48,9 +56,9 @@ func (e *engine) render() string {
e.renderBlock(block)
}
if e.config.ConsoleTitle {
e.write(e.consoleTitle.getConsoleTitle())
e.writeANSI(e.consoleTitle.getConsoleTitle())
}
e.write(e.ansi.creset)
e.writeANSI(e.ansi.creset)
if e.config.FinalSpace {
e.write(" ")
}
@ -62,7 +70,7 @@ func (e *engine) render() string {
if e.env.isWsl() {
cwd, _ = e.env.runCommand("wslpath", "-m", cwd)
}
e.write(e.ansi.consolePwd(cwd))
e.writeANSI(e.ansi.consolePwd(cwd))
return e.print()
}
@ -72,7 +80,7 @@ func (e *engine) renderBlock(block *Block) {
if block.Type == RPrompt && e.env.getShellName() == bash {
block.initPlain(e.env, e.config)
} else {
block.init(e.env, e.colorWriter, e.ansi)
block.init(e.env, e.writer, e.ansi)
}
block.setStringValues()
if !block.enabled() {
@ -89,13 +97,13 @@ func (e *engine) renderBlock(block *Block) {
e.write("\n")
case Prompt:
if block.VerticalOffset != 0 {
e.write(e.ansi.changeLine(block.VerticalOffset))
e.writeANSI(e.ansi.changeLine(block.VerticalOffset))
}
switch block.Alignment {
case Right:
e.write(e.ansi.carriageForward())
e.writeANSI(e.ansi.carriageForward())
blockText := block.renderSegments()
e.write(e.ansi.getCursorForRightWrite(blockText, block.HorizontalOffset))
e.writeANSI(e.ansi.getCursorForRightWrite(blockText, block.HorizontalOffset))
e.write(blockText)
case Left:
e.write(block.renderSegments())
@ -112,7 +120,7 @@ func (e *engine) renderBlock(block *Block) {
// color of the line above the new input line. Clearing the line fixes this,
// but can hopefully one day be removed when this is resolved natively.
if e.ansi.shell == pwsh || e.ansi.shell == powershell5 {
e.write(e.ansi.clearAfter())
e.writeANSI(e.ansi.clearAfter())
}
}
@ -137,7 +145,7 @@ func (e *engine) debug() string {
segmentTimings = append(segmentTimings, segmentTiming)
// loop each segments of each blocks
for _, block := range e.config.Blocks {
block.init(e.env, e.colorWriter, e.ansi)
block.init(e.env, e.writer, e.ansi)
longestSegmentName, timings := block.debug()
segmentTimings = append(segmentTimings, timings...)
if longestSegmentName > largestSegmentNameLength {
@ -169,7 +177,7 @@ func (e *engine) print() string {
prompt += fmt.Sprintf("\nRPROMPT=\"%s\"", e.rprompt)
return prompt
case pwsh, powershell5, bash, plain:
if e.rprompt == "" || !e.canWriteRPrompt() {
if e.rprompt == "" || !e.canWriteRPrompt() || e.plain {
break
}
e.write(e.ansi.saveCursorPosition)
@ -207,7 +215,7 @@ func (e *engine) renderTooltip(tip string) string {
}
switch e.env.getShellName() {
case zsh:
block.init(e.env, e.colorWriter, e.ansi)
block.init(e.env, e.writer, e.ansi)
return block.renderSegments()
case pwsh, powershell5:
block.initPlain(e.env, e.config)
@ -234,15 +242,15 @@ func (e *engine) renderTransientPrompt() string {
Env: e.env,
}
prompt := template.renderPlainContextTemplate(nil)
e.colorWriter.write(e.config.TransientPrompt.Background, e.config.TransientPrompt.Foreground, prompt)
e.writer.write(e.config.TransientPrompt.Background, e.config.TransientPrompt.Foreground, prompt)
switch e.env.getShellName() {
case zsh:
// escape double quotes contained in the prompt
prompt := fmt.Sprintf("PS1=\"%s\"", strings.ReplaceAll(e.colorWriter.string(), "\"", "\"\""))
prompt := fmt.Sprintf("PS1=\"%s\"", strings.ReplaceAll(e.writer.string(), "\"", "\"\""))
prompt += "\nRPROMPT=\"\""
return prompt
case pwsh, powershell5:
return e.colorWriter.string()
return e.writer.string()
}
return ""
}

View file

@ -60,6 +60,7 @@ type args struct {
StackCount *int
Command *string
PrintTransient *bool
Plain *bool
}
func main() {
@ -156,6 +157,10 @@ func main() {
"print-transient",
false,
"Print the transient prompt"),
Plain: flag.Bool(
"plain",
false,
"Print a plain prompt without ANSI"),
}
flag.Parse()
env := &environment{}
@ -191,9 +196,14 @@ func main() {
ansi := &ansiUtils{}
ansi.init(env.getShellName())
colorer := &AnsiWriter{
ansi: ansi,
terminalBackground: getConsoleBackgroundColor(env, cfg.TerminalBackground),
var writer promptWriter
if *args.Plain {
writer = &PlainWriter{}
} else {
writer = &AnsiWriter{
ansi: ansi,
terminalBackground: getConsoleBackgroundColor(env, cfg.TerminalBackground),
}
}
title := &consoleTitle{
env: env,
@ -203,9 +213,10 @@ func main() {
engine := &engine{
config: cfg,
env: env,
colorWriter: colorer,
writer: writer,
consoleTitle: title,
ansi: ansi,
plain: *args.Plain,
}
if *args.Debug {
fmt.Print(engine.debug())

41
src/writer_plain.go Normal file
View file

@ -0,0 +1,41 @@
package main
import (
"strings"
)
// PlainWriter writes a plain string
type PlainWriter struct {
builder strings.Builder
}
func (a *PlainWriter) setColors(background, foreground string) {}
func (a *PlainWriter) setParentColors(background, foreground string) {}
func (a *PlainWriter) clearParentColors() {}
func (a *PlainWriter) write(background, foreground, text string) {
if len(text) == 0 {
return
}
writeAndRemoveText := func(text, textToRemove, parentText string) string {
a.builder.WriteString(text)
return strings.Replace(parentText, textToRemove, "", 1)
}
match := findAllNamedRegexMatch(colorRegex, text)
for i := range match {
escapedTextSegment := match[i]["text"]
innerText := match[i]["content"]
textBeforeColorOverride := strings.Split(text, escapedTextSegment)[0]
text = writeAndRemoveText(textBeforeColorOverride, textBeforeColorOverride, text)
text = writeAndRemoveText(innerText, escapedTextSegment, text)
}
a.builder.WriteString(text)
}
func (a *PlainWriter) string() string {
return a.builder.String()
}
func (a *PlainWriter) reset() {
a.builder.Reset()
}