Fix spurious blank lines when executing scrolled commandline

The result of

	commandline -i ": '$(seq $LINES)"\n"first scrolled line'"

is a commandline that is scrolled by one line.

Before executing that commandline, we move the cursor down by one
too many line. This is a regression from 610338cc70 (On undo after
execute, restore the cursor position, 2024-12-21). Fix that.

The test also demonstrates an unrelated problem, probably specific
to tmux.
This commit is contained in:
Johannes Altmanninger 2025-01-08 21:50:40 +01:00
parent 8304fd0fd0
commit 0e512f8033
3 changed files with 36 additions and 11 deletions

View file

@ -2134,7 +2134,9 @@ impl<'a> Reader<'a> {
// Redraw the command line. This is what ensures the autosuggestion is hidden, etc. after the
// user presses enter.
if zelf.is_repaint_needed(None) || zelf.screen.scrolled || zelf.conf.inputfd != STDIN_FILENO
if zelf.is_repaint_needed(None)
|| zelf.screen.scrolled()
|| zelf.conf.inputfd != STDIN_FILENO
{
zelf.layout_and_repaint_before_execution();
}

View file

@ -189,8 +189,9 @@ impl ScreenData {
pub struct Screen {
/// Whether the last-drawn autosuggestion (if any) is truncated, or hidden entirely.
pub autosuggestion_is_truncated: bool,
/// True if the last rendering was so large we could only display part of the command line.
pub scrolled: bool,
/// If the last rendering was so large we could only display part of the command line,
/// this is the number of lines that were pushed to scrollback.
pub scroll_amount: usize,
/// Receiver for our output.
outp: &'static RefCell<Outputter>,
@ -227,7 +228,7 @@ impl Screen {
Self {
outp: Outputter::stdoutput(),
autosuggestion_is_truncated: Default::default(),
scrolled: Default::default(),
scroll_amount: Default::default(),
desired: Default::default(),
actual: Default::default(),
actual_left_prompt: Default::default(),
@ -241,6 +242,10 @@ impl Screen {
}
}
pub fn scrolled(&self) -> bool {
self.scroll_amount != 0
}
/// This is the main function for the screen output library. It is used to define the desired
/// contents of the screen. The screen command will use its knowledge of the current contents of
/// the screen in order to render the desired output using as few terminal commands as possible.
@ -459,7 +464,7 @@ impl Screen {
// Append pager_data (none if empty).
self.desired.append_lines(&page_rendering.screen_data);
self.scrolled = scrolled_cursor.scroll_amount != 0;
self.scroll_amount = scrolled_cursor.scroll_amount;
self.update(
vars,
@ -500,7 +505,7 @@ impl Screen {
}
pub fn move_to_end(&mut self) {
self.r#move(0, self.actual.line_count());
self.r#move(0, self.actual.line_count() - self.scroll_amount);
}
pub fn push_to_scrollback(&mut self, cursor_y: usize) {
@ -1035,14 +1040,15 @@ impl Screen {
let term = term.as_ref();
// Output the left prompt if it has changed.
if zelf.scrolled && !is_final_rendering {
if zelf.scrolled() && !is_final_rendering {
zelf.r#move(0, 0);
zelf.outp
.borrow_mut()
.tputs_if_some(&term.and_then(|term| term.clr_eol.as_ref()));
zelf.actual_left_prompt.clear();
zelf.actual.cursor.x = 0;
} else if left_prompt != zelf.actual_left_prompt || (zelf.scrolled && is_final_rendering) {
} else if left_prompt != zelf.actual_left_prompt || (zelf.scrolled() && is_final_rendering)
{
zelf.r#move(0, 0);
let mut start = 0;
let osc_133_prompt_start =
@ -1092,7 +1098,7 @@ impl Screen {
// Note that skip_remaining is a width, not a character count.
let mut skip_remaining = start_pos;
let shared_prefix = if zelf.scrolled {
let shared_prefix = if zelf.scrolled() {
0
} else {
line_shared_prefix(o_line(&zelf, i), s_line(&zelf, i))

View file

@ -32,6 +32,23 @@ isolated-tmux capture-pane -p
# CHECK: 10
# CHECK: scroll_here
# The output is broken here (seems tmux specific).
isolated-tmux send-keys C-c
tmux-sleep
isolated-tmux send-keys C-l 'commandline -i ": \'$(seq $LINES)" A B "C\'"' Enter Enter
tmux-sleep
isolated-tmux capture-pane -p
# CHECK: 4
# CHECK: 5
# CHECK: 6
# CHECK: 7
# CHECK: 8
# CHECK: 9
# CHECK: 10
# CHECK: prompt 5>
# CHECK: B
# CHECK: C'
# Soft-wrapped commandline with omitted right prompt.
isolated-tmux send-keys C-c
tmux-sleep
@ -43,7 +60,7 @@ isolated-tmux send-keys C-l '
' Enter
tmux-sleep
isolated-tmux capture-pane -p | sed 1,5d
# CHECK: prompt 5> echo 00000000000000000000000000000000000000000000000000000000000000000
# CHECK: prompt {{\d+}}> echo 00000000000000000000000000000000000000000000000000000000000000000
# CHECK: 000000000000000
# CHECK: 00000000000000000000000000000000000000000000000000000000000000000000000000000000
# CHECK: prompt 6> right-prompt
# CHECK: prompt {{\d+}}> right-prompt