Also handle overflown screens if editing pager search field

As mentioned in 04c913427 (Limit command line rendering to $LINES
lines, 2024-10-25) our rendering breaks when the command line overflows
the screen and we have a pager search field.

Let's also apply the overflow logic in this case.

Note that the search field still works, it's just not visible.

In future we should maybe show a small search field (~4 lines) in
this case (removing 4 screen lines worth of command line).  But again,
this is not really important.
This commit is contained in:
Johannes Altmanninger 2024-10-27 07:12:53 +01:00
parent adfa87d141
commit f89909ae31
3 changed files with 43 additions and 38 deletions

View File

@ -71,7 +71,7 @@ const PAGER_UNDISCLOSED_MAX_ROWS: usize = 4;
const PAGER_MIN_WIDTH: usize = 16; const PAGER_MIN_WIDTH: usize = 16;
/// Minimum height to show completions /// Minimum height to show completions
const PAGER_MIN_HEIGHT: usize = 4; pub const PAGER_MIN_HEIGHT: usize = 4;
/// The maximum number of columns of completion to attempt to fit onto the screen. /// The maximum number of columns of completion to attempt to fit onto the screen.
const PAGER_MAX_COLS: usize = 6; const PAGER_MAX_COLS: usize = 6;

View File

@ -427,8 +427,8 @@ struct LayoutData {
/// Position of the cursor in the command line. /// Position of the cursor in the command line.
position: usize, position: usize,
/// Whether the cursor is focused on the pager or not. /// The cursor position in the pager search field.
focused_on_pager: bool, pager_search_field_position: Option<usize>,
/// Visual selection of the command line, or none if none. /// Visual selection of the command line, or none if none.
selection: Option<SelectionData>, selection: Option<SelectionData>,
@ -1386,6 +1386,7 @@ impl<'a> Reader<'a> {
}; };
let focused_on_pager = self.active_edit_line_tag() == EditableLineTag::SearchField; let focused_on_pager = self.active_edit_line_tag() == EditableLineTag::SearchField;
let pager_search_field_position = focused_on_pager.then_some(self.pager.cursor_position());
let last = &self.rendered_layout; let last = &self.rendered_layout;
check(self.force_exec_prompt_and_repaint, "forced") check(self.force_exec_prompt_and_repaint, "forced")
|| check(self.command_line.text() != last.text, "text") || check(self.command_line.text() != last.text, "text")
@ -1394,8 +1395,11 @@ impl<'a> Reader<'a> {
"highlight", "highlight",
) )
|| check(self.selection != last.selection, "selection") || check(self.selection != last.selection, "selection")
|| check(focused_on_pager != last.focused_on_pager, "focus")
|| check(self.command_line.position() != last.position, "position") || check(self.command_line.position() != last.position, "position")
|| check(
pager_search_field_position != last.pager_search_field_position,
"pager_search_field_position",
)
|| check( || check(
self.history_search.search_range_if_active() != last.history_search_range, self.history_search.search_range_if_active() != last.history_search_range,
"history search", "history search",
@ -1431,13 +1435,10 @@ impl<'a> Reader<'a> {
result.text = self.command_line.text().to_owned(); result.text = self.command_line.text().to_owned();
result.colors = self.command_line.colors().to_vec(); result.colors = self.command_line.colors().to_vec();
assert!(result.text.len() == result.colors.len()); assert!(result.text.len() == result.colors.len());
result.position = if focused_on_pager { result.position = self.command_line.position();
self.pager.cursor_position() result.pager_search_field_position =
} else { focused_on_pager.then_some(self.pager.cursor_position());
self.command_line.position()
};
result.selection = self.selection; result.selection = self.selection;
result.focused_on_pager = focused_on_pager;
result.history_search_range = self.history_search.search_range_if_active(); result.history_search_range = self.history_search.search_range_if_active();
result.autosuggestion = self.autosuggestion.text.clone(); result.autosuggestion = self.autosuggestion.text.clone();
result.left_prompt_buff = self.left_prompt_buff.clone(); result.left_prompt_buff = self.left_prompt_buff.clone();
@ -1516,10 +1517,10 @@ impl<'a> Reader<'a> {
&colors, &colors,
&indents, &indents,
data.position, data.position,
data.pager_search_field_position,
self.parser.vars(), self.parser.vars(),
pager, pager,
current_page_rendering, current_page_rendering,
data.focused_on_pager,
); );
} }
} }

View File

@ -7,7 +7,7 @@
//! The current implementation is less smart than ncurses allows and can not for example move blocks //! The current implementation is less smart than ncurses allows and can not for example move blocks
//! of text around to handle text insertion. //! of text around to handle text insertion.
use crate::pager::{PageRendering, Pager}; use crate::pager::{PageRendering, Pager, PAGER_MIN_HEIGHT};
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::LinkedList; use std::collections::LinkedList;
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
@ -237,7 +237,6 @@ impl Screen {
/// of the command line \param colors the colors to use for the commanad line \param indent the /// of the command line \param colors the colors to use for the commanad line \param indent the
/// indent to use for the command line \param cursor_pos where the cursor is \param pager the /// indent to use for the command line \param cursor_pos where the cursor is \param pager the
/// pager to render below the command line \param page_rendering to cache the current pager view /// pager to render below the command line \param page_rendering to cache the current pager view
/// \param cursor_is_within_pager whether the position is within the pager line (first line)
pub fn write( pub fn write(
&mut self, &mut self,
left_prompt: &wstr, left_prompt: &wstr,
@ -247,10 +246,10 @@ impl Screen {
colors: &[HighlightSpec], colors: &[HighlightSpec],
indent: &[i32], indent: &[i32],
cursor_pos: usize, cursor_pos: usize,
pager_search_field_position: Option<usize>,
vars: &dyn Environment, vars: &dyn Environment,
pager: &mut Pager, pager: &mut Pager,
page_rendering: &mut PageRendering, page_rendering: &mut PageRendering,
cursor_is_within_pager: bool,
) { ) {
let curr_termsize = termsize_last(); let curr_termsize = termsize_last();
let screen_width = curr_termsize.width; let screen_width = curr_termsize.width;
@ -337,7 +336,7 @@ impl Screen {
let mut i = 0; let mut i = 0;
loop { loop {
// Grab the current cursor's x,y position if this character matches the cursor's offset. // Grab the current cursor's x,y position if this character matches the cursor's offset.
if !cursor_is_within_pager && i == cursor_pos { if i == cursor_pos {
cursor_arr = Some(ScrolledCursor { cursor_arr = Some(ScrolledCursor {
cursor: self.desired.cursor, cursor: self.desired.cursor,
scroll_amount: (self.desired.line_count() scroll_amount: (self.desired.line_count()
@ -379,39 +378,44 @@ impl Screen {
} }
i += 1; i += 1;
} }
cursor_arr.as_mut().map(
|ScrolledCursor {
ref mut cursor,
scroll_amount,
}| {
if *scroll_amount != 0 {
self.desired.line_datas = self.desired.line_datas.split_off(*scroll_amount);
cursor.y -= *scroll_amount;
}
},
);
let full_line_count = self.desired.cursor.y + 1; let full_line_count = self.desired.cursor.y + 1;
let pager_available_height = std::cmp::max(
1,
curr_termsize
.height
.saturating_sub_unsigned(full_line_count),
);
// Now that we've output everything, set the cursor to the position that we saved in the loop // Now that we've output everything, set the cursor to the position that we saved in the loop
// above. // above.
self.desired.cursor = cursor_arr.as_ref().map(|sc| sc.cursor).unwrap_or_default(); self.desired.cursor = match pager_search_field_position {
Some(pager_cursor_pos)
if cursor_is_within_pager { if pager_available_height >= isize::try_from(PAGER_MIN_HEIGHT).unwrap() =>
self.desired.cursor.x = cursor_pos; {
self.desired.cursor.y = self.desired.line_count(); Cursor {
x: pager_cursor_pos,
y: self.desired.line_count(),
} }
}
_ => {
let ScrolledCursor {
mut cursor,
scroll_amount,
} = cursor_arr.unwrap();
if scroll_amount != 0 {
self.desired.line_datas = self.desired.line_datas.split_off(scroll_amount);
cursor.y -= scroll_amount;
}
cursor
}
};
// Re-render our completions page if necessary. Limit the term size of the pager to the true // Re-render our completions page if necessary. Limit the term size of the pager to the true
// term size, minus the number of lines consumed by our string. // term size, minus the number of lines consumed by our string.
pager.set_term_size(&Termsize::new( pager.set_term_size(&Termsize::new(
std::cmp::max(1, curr_termsize.width), std::cmp::max(1, curr_termsize.width),
std::cmp::max( pager_available_height,
1,
curr_termsize
.height
.saturating_sub_unsigned(full_line_count),
),
)); ));
pager.update_rendering(page_rendering); pager.update_rendering(page_rendering);