mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-04-06 07:38:21 +00:00
bash: fix extra newlines with readline vi mode indicator
Use OSC 133;P (prompt mark) instead of 133;A (fresh line + prompt mark) inside PS1 and PS2. Readline redraws the prompt on vi mode switches, Ctrl-L, and other events, and 133;A's fresh-line behavior would emit a CR+LF whenever the cursor wasn't at column 0, causing visible extra newlines. The one-time 133;A is now emitted via printf in __ghostty_precmd, which only runs once per prompt cycle via PROMPT_COMMAND. On SIGWINCH, bash redraws PS1 (firing the 133;P marks) but doesn't re-run PROMPT_COMMAND, so there's no unwanted fresh-line on resize either. The redraw=last flag persists from the initial printf. This is a little less optimal than our previous approach, in terms of number of prompt marks we emit, but it produces an overall more correct result, which is the important thing. Because readline prints its output outside the scope of PS1, those characters "inherit" the surrounded prompt scope. This is usually fine, but it can sometimes get out of sync (especially during redraws). This is inherently a limitation of the fact that it's a separate output channel, so we just have to accept that can happen. See: #11267
This commit is contained in:
@@ -195,11 +195,11 @@ function __ghostty_precmd() {
|
||||
_GHOSTTY_SAVE_PS1="$PS1"
|
||||
_GHOSTTY_SAVE_PS2="$PS2"
|
||||
|
||||
# Marks. We need to do fresh line (A) at the beginning of the prompt
|
||||
# since if the cursor is not at the beginning of a line, the terminal
|
||||
# will emit a newline.
|
||||
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\]'
|
||||
# Use 133;P (not 133;A) inside PS1 to avoid fresh-line behavior on
|
||||
# readline redraws (e.g., vi mode switches, Ctrl-L). The initial
|
||||
# 133;A with fresh-line is emitted once via printf below.
|
||||
PS1='\[\e]133;P;k=i\a\]'$PS1'\[\e]133;B\a\]'
|
||||
PS2='\[\e]133;P;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
|
||||
@@ -210,7 +210,7 @@ function __ghostty_precmd() {
|
||||
# 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\\]'}"
|
||||
PS1="${PS1//\\n/\\n$'\\[\\e]133;P;k=s\\a\\]'}"
|
||||
fi
|
||||
|
||||
# Cursor
|
||||
@@ -233,6 +233,9 @@ function __ghostty_precmd() {
|
||||
builtin printf "\e]133;D;%s;aid=%s\a" "$ret" "$BASHPID"
|
||||
fi
|
||||
|
||||
# Fresh line and start of prompt.
|
||||
builtin printf "\e]133;A;redraw=last;cl=line;aid=%s\a" "$BASHPID"
|
||||
|
||||
# unfortunately bash provides no hooks to detect cwd changes
|
||||
# in particular this means cwd reporting will not happen for a
|
||||
# command like cd /test && cat. PS0 is evaluated before cd is run.
|
||||
|
||||
Reference in New Issue
Block a user