mirror of
https://github.com/fish-shell/fish-shell.git
synced 2025-03-27 14:45:13 +08:00
Render overflown commandline in entirety just before executing
Some checks are pending
make test / ubuntu (push) Waiting to run
make test / ubuntu-32bit-static-pcre2 (push) Waiting to run
make test / ubuntu-asan (push) Waiting to run
make test / macos (push) Waiting to run
Rust checks / rustfmt (push) Waiting to run
Rust checks / clippy (push) Waiting to run
Some checks are pending
make test / ubuntu (push) Waiting to run
make test / ubuntu-32bit-static-pcre2 (push) Waiting to run
make test / ubuntu-asan (push) Waiting to run
make test / macos (push) Waiting to run
Rust checks / rustfmt (push) Waiting to run
Rust checks / clippy (push) Waiting to run
As of 04c913427 (Limit command line rendering to $LINES lines, 2024-10-25), we only render a part of the command line. This removes valuable information from scrollback. The reasons for the limit were 1. to enable redrawing the commandline (can't do that if part of it is off-screen). 2. if the cursor is at the beginning of the command-line, we can't really render the off-screen suffix (unless we can tell the terminal to scroll back after doing that). Fortunately these don't matter for the very last rendering of a command line. Let's render the entire command just before executing, fixing the scrollback for executed commands. In future, we should fix it also for pre-execution renderings. This needs a terminal command to clear part of the scrollback. Can't find anything on https://invisible-island.net/xterm/ctlseqs/ctlseqs.html There is "Erase Saved Lines" but that deletes the entire scrollback. See the discussion in #10827
This commit is contained in:
parent
04d97e936a
commit
cfcf415db7
@ -1456,12 +1456,17 @@ impl<'a> Reader<'a> {
|
|||||||
/// If `mcolors` has a value, then apply it; otherwise extend existing colors.
|
/// If `mcolors` has a value, then apply it; otherwise extend existing colors.
|
||||||
fn layout_and_repaint(&mut self, reason: &wstr) {
|
fn layout_and_repaint(&mut self, reason: &wstr) {
|
||||||
self.rendered_layout = self.make_layout_data();
|
self.rendered_layout = self.make_layout_data();
|
||||||
self.paint_layout(reason);
|
self.paint_layout(reason, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn layout_and_repaint_before_execution(&mut self) {
|
||||||
|
self.rendered_layout = self.make_layout_data();
|
||||||
|
self.paint_layout(L!("prepare to execute"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Paint the last rendered layout.
|
/// Paint the last rendered layout.
|
||||||
/// `reason` is used in FLOG to explain why.
|
/// `reason` is used in FLOG to explain why.
|
||||||
fn paint_layout(&mut self, reason: &wstr) {
|
fn paint_layout(&mut self, reason: &wstr, is_final_rendering: bool) {
|
||||||
FLOGF!(reader_render, "Repainting from %ls", reason);
|
FLOGF!(reader_render, "Repainting from %ls", reason);
|
||||||
let data = &self.data.rendered_layout;
|
let data = &self.data.rendered_layout;
|
||||||
let cmd_line = &self.data.command_line;
|
let cmd_line = &self.data.command_line;
|
||||||
@ -1526,6 +1531,7 @@ impl<'a> Reader<'a> {
|
|||||||
self.parser.vars(),
|
self.parser.vars(),
|
||||||
pager,
|
pager,
|
||||||
current_page_rendering,
|
current_page_rendering,
|
||||||
|
is_final_rendering,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1949,8 +1955,9 @@ impl<'a> Reader<'a> {
|
|||||||
|
|
||||||
// Redraw the command line. This is what ensures the autosuggestion is hidden, etc. after the
|
// Redraw the command line. This is what ensures the autosuggestion is hidden, etc. after the
|
||||||
// user presses enter.
|
// user presses enter.
|
||||||
if zelf.is_repaint_needed(None) || zelf.conf.inputfd != STDIN_FILENO {
|
if zelf.is_repaint_needed(None) || zelf.screen.scrolled || zelf.conf.inputfd != STDIN_FILENO
|
||||||
zelf.layout_and_repaint(L!("prepare to execute"));
|
{
|
||||||
|
zelf.layout_and_repaint_before_execution();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finish syntax highlighting (but do not wait forever).
|
// Finish syntax highlighting (but do not wait forever).
|
||||||
@ -3635,7 +3642,7 @@ impl<'a> Reader<'a> {
|
|||||||
data.colors[i].background = HighlightRole::search_match;
|
data.colors[i].background = HighlightRole::search_match;
|
||||||
}
|
}
|
||||||
self.rendered_layout = data.clone(); // need to copy the data since we will use it again.
|
self.rendered_layout = data.clone(); // need to copy the data since we will use it again.
|
||||||
self.paint_layout(L!("flash"));
|
self.paint_layout(L!("flash"), false);
|
||||||
|
|
||||||
let _old_data = std::mem::take(&mut self.rendered_layout);
|
let _old_data = std::mem::take(&mut self.rendered_layout);
|
||||||
|
|
||||||
@ -3644,7 +3651,7 @@ impl<'a> Reader<'a> {
|
|||||||
// Re-render with our saved data.
|
// Re-render with our saved data.
|
||||||
data.colors = saved_colors;
|
data.colors = saved_colors;
|
||||||
self.rendered_layout = data;
|
self.rendered_layout = data;
|
||||||
self.paint_layout(L!("unflash"));
|
self.paint_layout(L!("unflash"), false);
|
||||||
|
|
||||||
// Save the time we stopped flashing as the time of the most recent flash. We can't just
|
// Save the time we stopped flashing as the time of the most recent flash. We can't just
|
||||||
// increment the old `now` value because the sleep is non-deterministic.
|
// increment the old `now` value because the sleep is non-deterministic.
|
||||||
|
@ -177,6 +177,8 @@ impl ScreenData {
|
|||||||
pub struct Screen {
|
pub struct Screen {
|
||||||
/// Whether the last-drawn autosuggestion (if any) is truncated, or hidden entirely.
|
/// Whether the last-drawn autosuggestion (if any) is truncated, or hidden entirely.
|
||||||
pub autosuggestion_is_truncated: bool,
|
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,
|
||||||
|
|
||||||
/// Receiver for our output.
|
/// Receiver for our output.
|
||||||
outp: &'static RefCell<Outputter>,
|
outp: &'static RefCell<Outputter>,
|
||||||
@ -213,6 +215,7 @@ impl Screen {
|
|||||||
Self {
|
Self {
|
||||||
outp: Outputter::stdoutput(),
|
outp: Outputter::stdoutput(),
|
||||||
autosuggestion_is_truncated: Default::default(),
|
autosuggestion_is_truncated: Default::default(),
|
||||||
|
scrolled: Default::default(),
|
||||||
desired: Default::default(),
|
desired: Default::default(),
|
||||||
actual: Default::default(),
|
actual: Default::default(),
|
||||||
actual_left_prompt: Default::default(),
|
actual_left_prompt: Default::default(),
|
||||||
@ -250,6 +253,7 @@ impl Screen {
|
|||||||
vars: &dyn Environment,
|
vars: &dyn Environment,
|
||||||
pager: &mut Pager,
|
pager: &mut Pager,
|
||||||
page_rendering: &mut PageRendering,
|
page_rendering: &mut PageRendering,
|
||||||
|
is_final_rendering: bool,
|
||||||
) {
|
) {
|
||||||
let curr_termsize = termsize_last();
|
let curr_termsize = termsize_last();
|
||||||
let screen_width = curr_termsize.width;
|
let screen_width = curr_termsize.width;
|
||||||
@ -360,15 +364,19 @@ impl Screen {
|
|||||||
break scrolled_cursor.unwrap();
|
break scrolled_cursor.unwrap();
|
||||||
}
|
}
|
||||||
if !self.desired_append_char(
|
if !self.desired_append_char(
|
||||||
scrolled_cursor
|
if is_final_rendering {
|
||||||
.map(|sc| {
|
usize::MAX
|
||||||
if sc.scroll_amount != 0 {
|
} else {
|
||||||
sc.cursor.y
|
scrolled_cursor
|
||||||
} else {
|
.map(|sc| {
|
||||||
screen_height - 1
|
if sc.scroll_amount != 0 {
|
||||||
}
|
sc.cursor.y
|
||||||
})
|
} else {
|
||||||
.unwrap_or(usize::MAX),
|
screen_height - 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap_or(usize::MAX)
|
||||||
|
},
|
||||||
effective_commandline.as_char_slice()[i],
|
effective_commandline.as_char_slice()[i],
|
||||||
colors[i],
|
colors[i],
|
||||||
usize::try_from(indent[i]).unwrap(),
|
usize::try_from(indent[i]).unwrap(),
|
||||||
@ -405,7 +413,9 @@ impl Screen {
|
|||||||
scroll_amount,
|
scroll_amount,
|
||||||
} = scrolled_cursor;
|
} = scrolled_cursor;
|
||||||
if scroll_amount != 0 {
|
if scroll_amount != 0 {
|
||||||
self.desired.line_datas = self.desired.line_datas.split_off(scroll_amount);
|
if !is_final_rendering {
|
||||||
|
self.desired.line_datas = self.desired.line_datas.split_off(scroll_amount);
|
||||||
|
}
|
||||||
cursor.y -= scroll_amount;
|
cursor.y -= scroll_amount;
|
||||||
}
|
}
|
||||||
cursor
|
cursor
|
||||||
@ -423,11 +433,13 @@ impl Screen {
|
|||||||
// Append pager_data (none if empty).
|
// Append pager_data (none if empty).
|
||||||
self.desired.append_lines(&page_rendering.screen_data);
|
self.desired.append_lines(&page_rendering.screen_data);
|
||||||
|
|
||||||
|
self.scrolled = scrolled_cursor.scroll_amount != 0;
|
||||||
|
|
||||||
self.update(
|
self.update(
|
||||||
vars,
|
vars,
|
||||||
&layout.left_prompt,
|
&layout.left_prompt,
|
||||||
&layout.right_prompt,
|
&layout.right_prompt,
|
||||||
scrolled_cursor.scroll_amount != 0,
|
is_final_rendering,
|
||||||
);
|
);
|
||||||
self.save_status();
|
self.save_status();
|
||||||
}
|
}
|
||||||
@ -852,7 +864,7 @@ impl Screen {
|
|||||||
vars: &dyn Environment,
|
vars: &dyn Environment,
|
||||||
left_prompt: &wstr,
|
left_prompt: &wstr,
|
||||||
right_prompt: &wstr,
|
right_prompt: &wstr,
|
||||||
scrolled: bool,
|
is_final_rendering: bool,
|
||||||
) {
|
) {
|
||||||
// Helper function to set a resolved color, using the caching resolver.
|
// Helper function to set a resolved color, using the caching resolver.
|
||||||
let mut color_resolver = HighlightColorResolver::new();
|
let mut color_resolver = HighlightColorResolver::new();
|
||||||
@ -909,14 +921,14 @@ impl Screen {
|
|||||||
let term = term.as_ref();
|
let term = term.as_ref();
|
||||||
|
|
||||||
// Output the left prompt if it has changed.
|
// Output the left prompt if it has changed.
|
||||||
if scrolled {
|
if zelf.scrolled && !is_final_rendering {
|
||||||
zelf.r#move(0, 0);
|
zelf.r#move(0, 0);
|
||||||
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()));
|
||||||
zelf.actual_left_prompt.clear();
|
zelf.actual_left_prompt.clear();
|
||||||
zelf.actual.cursor.x = 0;
|
zelf.actual.cursor.x = 0;
|
||||||
} else if left_prompt != zelf.actual_left_prompt {
|
} else if left_prompt != zelf.actual_left_prompt || (zelf.scrolled && is_final_rendering) {
|
||||||
zelf.r#move(0, 0);
|
zelf.r#move(0, 0);
|
||||||
let mut start = 0;
|
let mut start = 0;
|
||||||
let osc_133_prompt_start =
|
let osc_133_prompt_start =
|
||||||
@ -966,7 +978,7 @@ impl Screen {
|
|||||||
// Note that skip_remaining is a width, not a character count.
|
// Note that skip_remaining is a width, not a character count.
|
||||||
let mut skip_remaining = start_pos;
|
let mut skip_remaining = start_pos;
|
||||||
|
|
||||||
let shared_prefix = if scrolled {
|
let shared_prefix = if zelf.scrolled {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
line_shared_prefix(o_line(&zelf, i), s_line(&zelf, i))
|
line_shared_prefix(o_line(&zelf, i), s_line(&zelf, i))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user