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