add custom prompts with PS1 and PS2

PS1 and PS2 support the backslash escapes of bash (\u \h \w \W \$ \t \j
\e \[ \] ...) and expand $VAR, ${...}, $(...) and $((...)) before each
prompt. Values of escapes and expansions are sanitized. Lines before the
last one and non-SGR escape sequences are written before readline's
prompt. Without PS1, the default prompt is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Florian WaltherandClaude Opus 5.5 committed 2026-10-05 22:49:19 +02:00
1 parent af5281eed2
commit 82f9c90a39
6 files changed
+528 -13

No files matched your search

+21 -8
View File
@@ -668,8 +668,13 @@ func prepareHistoryFile(path string) error {
return f.Chmod(0600)
}
// getPrompt returns a dynamic prompt string like "user@host:dir $"
// getPrompt returns the expanded $PS1, or if it is not set the default
// prompt "user@host:dir $".
func getPrompt() string {
if prompt, ok := promptString("PS1"); ok {
return prompt
}
// Get current working directory
wd, err := os.Getwd()
if err != nil {
@@ -690,10 +695,7 @@ func getPrompt() string {
}
// Replace the home directory with ~
home := getHomeDir()
if home != "" && (wd == home || strings.HasPrefix(wd, home+"/")) {
wd = "~" + strings.TrimPrefix(wd, home)
}
wd = tildePath(wd, getHomeDir())
var colors *promptColors
if useColor() {
@@ -1369,19 +1371,25 @@ func interactive() {
defer l.Close()
// Main loop. A command that is not complete yet (e.g. if without fi)
// is continued on the next line with the prompt "> ".
// is continued on the next line with the prompt $PS2 (default "> ").
var buf strings.Builder
for {
var prompt string
if buf.Len() == 0 {
runPendingTraps()
// Report finished and stopped background jobs
reapJobs(true)
// Update prompt dynamically (in case directory changed)
reportCwd()
l.SetPrompt(getPrompt())
prompt = getPrompt()
} else if ps2, ok := promptString("PS2"); ok {
prompt = ps2
} else {
l.SetPrompt("> ")
prompt = "> "
}
prefix, prompt := splitPrompt(prompt)
fmt.Print(prefix)
l.SetPrompt(prompt)
line, err := l.Readline()
if err != nil {
@@ -2181,6 +2189,11 @@ Features:
GOSH_COLORS='user=1;33:path=36' (keys user, root, path, error; values
are ANSI SGR codes, empty = no color); disabled with $NO_COLOR,
TERM=dumb or when output is not a terminal
- Custom prompt with $PS1 (and $PS2 for continuation lines, default
"> ") using the escapes of bash: \u user, \h/\H host, \w/\W directory,
\$ (# for root), \t \T \@ \A \d time/date, \j jobs, \n newline,
\e escape, \[ \]; $VAR, $(...) and $((...)) are expanded, e.g.
PS1='\[\e[1;32m\]\u@\h\[\e[0m\]:\w\$ '
- Reports the working directory to the terminal (OSC 7) before each
prompt, so new tabs/windows open in the same directory
- Variables: name=value sets a variable (like set), name=value command