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
This commit is contained in:
Johannes Altmanninger 2024-10-12 18:19:13 +02:00
parent 69380c6c92
commit 5496247344
2 changed files with 43 additions and 2 deletions

View file

@ -821,12 +821,19 @@ impl Screen {
// Output the left prompt if it has changed. // Output the left prompt if it has changed.
if left_prompt != zelf.actual_left_prompt { if left_prompt != zelf.actual_left_prompt {
zelf.r#move(0, 0); zelf.r#move(0, 0);
zelf.write_bytes(b"\x1b]133;A;special_key=1\x07");
let mut start = 0; 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 zelf.outp
.borrow_mut() .borrow_mut()
.tputs_if_some(&term.and_then(|term| term.clr_eol.as_ref())); .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]); zelf.write_str(&left_prompt[start..=line_break]);
start = line_break + 1; start = line_break + 1;
} }

View file

@ -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