From 5496247344974998ba3a13347a7fabab4f952f23 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Sat, 12 Oct 2024 18:19:13 +0200 Subject: [PATCH] Avoid erasing OSC 133 prompt start marker with clr_eol For multi-line prompts, we start each leading line with a clr_eol. Immediately before printing these prompt lines we emit the OSC 133 prompt start marker. Some terminals such as tmux interpret make clr_eol delete such markers, hence prompt navigation is broken. Fix this by printing the marker only after clr_eol. The scenario where this triggers is quite odd. I haven't looked into why the problem doesn't exist if I remove the recursive repaint request. See https://github.com/tmux/tmux/issues/4183 Closes #10776 --- src/screen.rs | 11 ++++-- .../checks/tmux-signal-multiline-prompt.fish | 34 +++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 tests/checks/tmux-signal-multiline-prompt.fish diff --git a/src/screen.rs b/src/screen.rs index ff4f923c3..cda33cebd 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -821,12 +821,19 @@ impl Screen { // Output the left prompt if it has changed. if left_prompt != zelf.actual_left_prompt { zelf.r#move(0, 0); - zelf.write_bytes(b"\x1b]133;A;special_key=1\x07"); let mut start = 0; - for line_break in left_prompt_layout.line_breaks { + let osc_133_prompt_start = + |zelf: &mut Screen| zelf.write_bytes(b"\x1b]133;A;special_key=1\x07"); + if left_prompt_layout.line_breaks.is_empty() { + osc_133_prompt_start(&mut zelf); + } + for (i, &line_break) in left_prompt_layout.line_breaks.iter().enumerate() { zelf.outp .borrow_mut() .tputs_if_some(&term.and_then(|term| term.clr_eol.as_ref())); + if i == 0 { + osc_133_prompt_start(&mut zelf); + } zelf.write_str(&left_prompt[start..=line_break]); start = line_break + 1; } diff --git a/tests/checks/tmux-signal-multiline-prompt.fish b/tests/checks/tmux-signal-multiline-prompt.fish new file mode 100644 index 000000000..613c7d5d4 --- /dev/null +++ b/tests/checks/tmux-signal-multiline-prompt.fish @@ -0,0 +1,34 @@ +#RUN: %fish %s +#REQUIRES: command -v tmux + +isolated-tmux-start + +isolated-tmux send-keys ' + function fish_prompt + printf "prompt-line-1\\nprompt-line-2> " + commandline -f repaint + end +' Enter +isolated-tmux send-keys C-l \ + ': 1' Enter \ + ': 3' Enter \ + ': 5' Enter +tmux-sleep + +# Screen looks like + +# [y=0] prompt-line-1 +# [y=1] prompt-line-2> : 1 +# [y=2] prompt-line-1 +# [y=3] prompt-line-2> : 3 +# [y=4] prompt-line-1 +# [y=5] prompt-line-2> : 5 +# [y=6] prompt-line-1 +# [y=7] prompt-line-2> + +isolated-tmux copy-mode +isolated-tmux send-keys -X previous-prompt +isolated-tmux send-keys -X previous-prompt +tmux-sleep +isolated-tmux display-message -p '#{copy_cursor_y} #{copy_cursor_line}' +# CHECK: 4 prompt-line-1