mirror of
https://github.com/fish-shell/fish-shell.git
synced 2025-03-15 23:22:53 +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.
|
||||
fn layout_and_repaint(&mut self, reason: &wstr) {
|
||||
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.
|
||||
/// `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);
|
||||
let data = &self.data.rendered_layout;
|
||||
let cmd_line = &self.data.command_line;
|
||||
@ -1526,6 +1531,7 @@ impl<'a> Reader<'a> {
|
||||
self.parser.vars(),
|
||||
pager,
|
||||
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
|
||||
// user presses enter.
|
||||
if zelf.is_repaint_needed(None) || zelf.conf.inputfd != STDIN_FILENO {
|
||||
zelf.layout_and_repaint(L!("prepare to execute"));
|
||||
if zelf.is_repaint_needed(None) || zelf.screen.scrolled || zelf.conf.inputfd != STDIN_FILENO
|
||||
{
|
||||
zelf.layout_and_repaint_before_execution();
|
||||
}
|
||||
|
||||
// Finish syntax highlighting (but do not wait forever).
|
||||
@ -3635,7 +3642,7 @@ impl<'a> Reader<'a> {
|
||||
data.colors[i].background = HighlightRole::search_match;
|
||||
}
|
||||
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);
|
||||
|
||||
@ -3644,7 +3651,7 @@ impl<'a> Reader<'a> {
|
||||
// Re-render with our saved data.
|
||||
data.colors = saved_colors;
|
||||
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
|
||||
// increment the old `now` value because the sleep is non-deterministic.
|
||||
|
@ -177,6 +177,8 @@ 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,
|
||||
|
||||
/// Receiver for our output.
|
||||
outp: &'static RefCell<Outputter>,
|
||||
@ -213,6 +215,7 @@ impl Screen {
|
||||
Self {
|
||||
outp: Outputter::stdoutput(),
|
||||
autosuggestion_is_truncated: Default::default(),
|
||||
scrolled: Default::default(),
|
||||
desired: Default::default(),
|
||||
actual: Default::default(),
|
||||
actual_left_prompt: Default::default(),
|
||||
@ -250,6 +253,7 @@ impl Screen {
|
||||
vars: &dyn Environment,
|
||||
pager: &mut Pager,
|
||||
page_rendering: &mut PageRendering,
|
||||
is_final_rendering: bool,
|
||||
) {
|
||||
let curr_termsize = termsize_last();
|
||||
let screen_width = curr_termsize.width;
|
||||
@ -360,15 +364,19 @@ impl Screen {
|
||||
break scrolled_cursor.unwrap();
|
||||
}
|
||||
if !self.desired_append_char(
|
||||
scrolled_cursor
|
||||
.map(|sc| {
|
||||
if sc.scroll_amount != 0 {
|
||||
sc.cursor.y
|
||||
} else {
|
||||
screen_height - 1
|
||||
}
|
||||
})
|
||||
.unwrap_or(usize::MAX),
|
||||
if is_final_rendering {
|
||||
usize::MAX
|
||||
} else {
|
||||
scrolled_cursor
|
||||
.map(|sc| {
|
||||
if sc.scroll_amount != 0 {
|
||||
sc.cursor.y
|
||||
} else {
|
||||
screen_height - 1
|
||||
}
|
||||
})
|
||||
.unwrap_or(usize::MAX)
|
||||
},
|
||||
effective_commandline.as_char_slice()[i],
|
||||
colors[i],
|
||||
usize::try_from(indent[i]).unwrap(),
|
||||
@ -405,7 +413,9 @@ impl Screen {
|
||||
scroll_amount,
|
||||
} = scrolled_cursor;
|
||||
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
|
||||
@ -423,11 +433,13 @@ impl Screen {
|
||||
// Append pager_data (none if empty).
|
||||
self.desired.append_lines(&page_rendering.screen_data);
|
||||
|
||||
self.scrolled = scrolled_cursor.scroll_amount != 0;
|
||||
|
||||
self.update(
|
||||
vars,
|
||||
&layout.left_prompt,
|
||||
&layout.right_prompt,
|
||||
scrolled_cursor.scroll_amount != 0,
|
||||
is_final_rendering,
|
||||
);
|
||||
self.save_status();
|
||||
}
|
||||
@ -852,7 +864,7 @@ impl Screen {
|
||||
vars: &dyn Environment,
|
||||
left_prompt: &wstr,
|
||||
right_prompt: &wstr,
|
||||
scrolled: bool,
|
||||
is_final_rendering: bool,
|
||||
) {
|
||||
// Helper function to set a resolved color, using the caching resolver.
|
||||
let mut color_resolver = HighlightColorResolver::new();
|
||||
@ -909,14 +921,14 @@ impl Screen {
|
||||
let term = term.as_ref();
|
||||
|
||||
// Output the left prompt if it has changed.
|
||||
if scrolled {
|
||||
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 {
|
||||
} 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 =
|
||||
@ -966,7 +978,7 @@ impl Screen {
|
||||
// Note that skip_remaining is a width, not a character count.
|
||||
let mut skip_remaining = start_pos;
|
||||
|
||||
let shared_prefix = if scrolled {
|
||||
let shared_prefix = if zelf.scrolled {
|
||||
0
|
||||
} else {
|
||||
line_shared_prefix(o_line(&zelf, i), s_line(&zelf, i))
|
||||
|
Loading…
x
Reference in New Issue
Block a user