From 26d8bd9e71c27f1f7f31a1079bee3ca79e79b205 Mon Sep 17 00:00:00 2001 From: Jon Parise Date: Wed, 11 Mar 2026 10:41:57 -0400 Subject: [PATCH] bash: fix multiline PS1 with command substitutions Only replace the \n prompt escape when inserting secondary prompt marks, not literal newlines ($'\n'). Literal newlines may appear inside $(...) or `...` command substitutions, and inserting escape sequences there breaks the shell syntax. For example: PS1='$(if [ $? -eq 0 ]; then echo -e "P"; else echo -e "F"; fi) $ ' The literal newlines between the if/else/fi are part of the shell syntax inside the command substitution. The previous code replaced all literal newlines in PS1 with newline + OSC 133 escape sequences, which injected terminal escapes into the middle of the command substitution and caused bash to report a syntax error when evaluating it. The \n prompt escape is PS1-specific and safe to replace globally. This means prompts using literal newlines for line breaks (rather than \n) won't get per-line secondary marks, but this is the conventional form and avoids the need for complex shell parsing. Fixes: #11267 --- src/shell-integration/bash/ghostty.bash | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/shell-integration/bash/ghostty.bash b/src/shell-integration/bash/ghostty.bash index a369e8f75..6e516c730 100644 --- a/src/shell-integration/bash/ghostty.bash +++ b/src/shell-integration/bash/ghostty.bash @@ -201,14 +201,16 @@ function __ghostty_precmd() { PS1='\[\e]133;A;redraw=last;cl=line;aid='"$BASHPID"'\a\]'$PS1'\[\e]133;B\a\]' PS2='\[\e]133;A;k=s\a\]'$PS2'\[\e]133;B\a\]' - # Bash doesn't redraw the leading lines in a multiline prompt so - # we mark the start of each line (after each newline) as a secondary - # prompt. This correctly handles multiline prompts by setting the first - # to primary and the subsequent lines to secondary. - if [[ "${PS1}" == *"\n"* || "${PS1}" == *$'\n'* ]]; then - builtin local __ghostty_mark=$'\\[\\e]133;A;k=s\\a\\]' - PS1="${PS1//$'\n'/$'\n'$__ghostty_mark}" - PS1="${PS1//\\n/\\n$__ghostty_mark}" + # Bash doesn't redraw the leading lines in a multiline prompt so we mark + # the start of each line (after each newline) as a secondary prompt. This + # correctly handles multiline prompts by setting the first to primary and + # the subsequent lines to secondary. + # + # We only replace the \n prompt escape, not literal newlines ($'\n'), + # because literal newlines may appear inside $(...) command substitutions + # where inserting escape sequences would break shell syntax. + if [[ "$PS1" == *"\n"* ]]; then + PS1="${PS1//\\n/\\n$'\\[\\e]133;A;k=s\\a\\]'}" fi # Cursor