From 0b7ab5a1b5f8ede944aaadb4a3351c85a1001fd8 Mon Sep 17 00:00:00 2001 From: kerty Date: Sun, 19 Oct 2025 17:09:00 +0300 Subject: [PATCH] Fix not preserving empty last line in multiline prompts Reproduction: fish -C ' function fish_prompt echo left-prompt\n end function fish_right_prompt echo right-prompt end ' and pressing Enter would not preserve the line with right prompt. This occurred because Screen::cursor_is_wrapped_to_own_line assumed the last prompt line always had index 0. However, commit 606802daa (Make ScreenData track multiline prompt, 2025-10-15) changed this so the last prompt line's index is now `Screen.actual.visible_prompt_lines - 1`. Screen::cursor_is_wrapped_to_own_line also didn't account for situations where commandline indentation was 0. Fix Screen::cursor_is_wrapped_to_own_line and add tests for prompts with empty last lines. --- src/screen.rs | 3 +- tests/checks/tmux-empty-prompt.fish | 80 +++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 tests/checks/tmux-empty-prompt.fish diff --git a/src/screen.rs b/src/screen.rs index 56aa23e2d..8ad70b4b8 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -753,8 +753,9 @@ pub fn save_status(&mut self) { pub fn cursor_is_wrapped_to_own_line(&self) -> bool { // Don't consider dumb terminals to have wrapping for the purposes of this function. self.actual.cursor.x == 0 - && self.actual.cursor.y != 0 + && self.actual.cursor.y + 1 != self.actual.visible_prompt_lines && self.actual.cursor.y + 1 == self.actual.line_count() + && self.actual.line(self.actual.cursor.y - 1).is_soft_wrapped && !is_dumb() } diff --git a/tests/checks/tmux-empty-prompt.fish b/tests/checks/tmux-empty-prompt.fish new file mode 100644 index 000000000..508f7ea61 --- /dev/null +++ b/tests/checks/tmux-empty-prompt.fish @@ -0,0 +1,80 @@ +#RUN: %fish %s +#REQUIRES: command -v tmux + +isolated-tmux-start +isolated-tmux send-keys ' + function fish_prompt; end + function fish_right_prompt + set -q right_prompt + and echo right-prompt + end + set right_prompt 1 + bind ctrl-g "set right_prompt 1" repaint + bind alt-g "set -e right_prompt" repaint +' +tmux-sleep +isolated-tmux send-keys M-g C-l Enter +tmux-sleep +isolated-tmux send-keys C-g Enter +tmux-sleep +isolated-tmux capture-pane -p | string replace -r '$' '+' +#CHECK: + +#CHECK: right-prompt+ +#CHECK: right-prompt+ +#CHECK: + +#CHECK: + +#CHECK: + +#CHECK: + +#CHECK: + +#CHECK: + +#CHECK: + + +isolated-tmux send-keys M-g Tab Tab +tmux-sleep +isolated-tmux capture-pane -p | string replace -r '$' '+' +#CHECK: + +#CHECK: {{.*}}+ +#CHECK: {{.*}}+ +#CHECK: {{.*}}+ +#CHECK: {{.*}}+ +#CHECK: {{.*}}+ +#CHECK: {{.*}}+ +#CHECK: {{.*}}+ +#CHECK: {{.*}}+ +#CHECK: {{.*}}+ + +isolated-tmux send-keys ' + function fish_prompt + echo left-prompt\n + end +' +tmux-sleep +isolated-tmux send-keys C-l Enter +tmux-sleep +isolated-tmux send-keys C-g Enter +tmux-sleep +isolated-tmux capture-pane -p | string replace -r '$' '+' +#CHECK: left-prompt+ +#CHECK: + +#CHECK: left-prompt+ +#CHECK: right-prompt+ +#CHECK: left-prompt+ +#CHECK: right-prompt+ +#CHECK: + +#CHECK: + +#CHECK: + +#CHECK: + + +isolated-tmux send-keys M-g Tab Tab +tmux-sleep +isolated-tmux capture-pane -p | string replace -r '$' '+' +#CHECK: left-prompt+ +#CHECK: + +#CHECK: {{.*}}+ +#CHECK: {{.*}}+ +#CHECK: {{.*}}+ +#CHECK: {{.*}}+ +#CHECK: {{.*}}+ +#CHECK: {{.*}}+ +#CHECK: {{.*}}+ +#CHECK: {{.*}}+