1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-08-01 13:37:48 +00:00

Merge pull request #2407 from hbina/hbina-more-terminal-resize

Improvements to `more`.
This commit is contained in:
Sylvestre Ledru 2021-06-21 22:30:07 +02:00 committed by GitHub
commit 97ce44b102
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -210,14 +210,14 @@ fn more(buff: &str, mut stdout: &mut Stdout, next_file: Option<&str>, silent: bo
let (cols, rows) = terminal::size().unwrap(); let (cols, rows) = terminal::size().unwrap();
let lines = break_buff(buff, usize::from(cols)); let lines = break_buff(buff, usize::from(cols));
let mut pager = Pager::new(rows as usize, lines, next_file, silent); let mut pager = Pager::new(rows, lines, next_file, silent);
pager.draw(stdout, false); pager.draw(stdout, None);
if pager.should_close() { if pager.should_close() {
return; return;
} }
loop { loop {
let mut wrong_key = false; let mut wrong_key = None;
if event::poll(Duration::from_millis(10)).unwrap() { if event::poll(Duration::from_millis(10)).unwrap() {
match event::read().unwrap() { match event::read().unwrap() {
Event::Key(KeyEvent { Event::Key(KeyEvent {
@ -239,23 +239,29 @@ fn more(buff: &str, mut stdout: &mut Stdout, next_file: Option<&str>, silent: bo
code: KeyCode::Char(' '), code: KeyCode::Char(' '),
modifiers: KeyModifiers::NONE, modifiers: KeyModifiers::NONE,
}) => { }) => {
if pager.should_close() {
return;
} else {
pager.page_down(); pager.page_down();
} }
}
Event::Key(KeyEvent { Event::Key(KeyEvent {
code: KeyCode::Up, code: KeyCode::Up,
modifiers: KeyModifiers::NONE, modifiers: KeyModifiers::NONE,
}) => { }) => {
pager.page_up(); pager.page_up();
} }
_ => { Event::Resize(col, row) => {
wrong_key = true; pager.page_resize(col, row);
} }
Event::Key(KeyEvent {
code: KeyCode::Char(k),
..
}) => wrong_key = Some(k),
_ => continue,
} }
pager.draw(stdout, wrong_key); pager.draw(stdout, wrong_key);
if pager.should_close() {
return;
}
} }
} }
} }
@ -264,54 +270,49 @@ struct Pager<'a> {
// The current line at the top of the screen // The current line at the top of the screen
upper_mark: usize, upper_mark: usize,
// The number of rows that fit on the screen // The number of rows that fit on the screen
content_rows: usize, content_rows: u16,
lines: Vec<String>, lines: Vec<String>,
next_file: Option<&'a str>, next_file: Option<&'a str>,
line_count: usize, line_count: usize,
close_on_down: bool,
silent: bool, silent: bool,
} }
impl<'a> Pager<'a> { impl<'a> Pager<'a> {
fn new(rows: usize, lines: Vec<String>, next_file: Option<&'a str>, silent: bool) -> Self { fn new(rows: u16, lines: Vec<String>, next_file: Option<&'a str>, silent: bool) -> Self {
let line_count = lines.len(); let line_count = lines.len();
Self { Self {
upper_mark: 0, upper_mark: 0,
content_rows: rows - 1, content_rows: rows.saturating_sub(1),
lines, lines,
next_file, next_file,
line_count, line_count,
close_on_down: false,
silent, silent,
} }
} }
fn should_close(&mut self) -> bool { fn should_close(&mut self) -> bool {
if self.upper_mark + self.content_rows >= self.line_count { self.upper_mark
if self.close_on_down { .saturating_add(self.content_rows.into())
return true; .ge(&self.line_count)
}
if self.next_file.is_none() {
return true;
} else {
self.close_on_down = true;
}
} else {
self.close_on_down = false;
}
false
} }
fn page_down(&mut self) { fn page_down(&mut self) {
self.upper_mark += self.content_rows; self.upper_mark = self.upper_mark.saturating_add(self.content_rows.into());
} }
fn page_up(&mut self) { fn page_up(&mut self) {
self.upper_mark = self.upper_mark.saturating_sub(self.content_rows); self.upper_mark = self.upper_mark.saturating_sub(self.content_rows.into());
} }
fn draw(&self, stdout: &mut std::io::Stdout, wrong_key: bool) { // TODO: Deal with column size changes.
let lower_mark = self.line_count.min(self.upper_mark + self.content_rows); fn page_resize(&mut self, _: u16, row: u16) {
self.content_rows = row.saturating_sub(1);
}
fn draw(&self, stdout: &mut std::io::Stdout, wrong_key: Option<char>) {
let lower_mark = self
.line_count
.min(self.upper_mark.saturating_add(self.content_rows.into()));
self.draw_lines(stdout); self.draw_lines(stdout);
self.draw_prompt(stdout, lower_mark, wrong_key); self.draw_prompt(stdout, lower_mark, wrong_key);
stdout.flush().unwrap(); stdout.flush().unwrap();
@ -323,7 +324,7 @@ impl<'a> Pager<'a> {
.lines .lines
.iter() .iter()
.skip(self.upper_mark) .skip(self.upper_mark)
.take(self.content_rows); .take(self.content_rows.into());
for line in displayed_lines { for line in displayed_lines {
stdout stdout
@ -332,7 +333,7 @@ impl<'a> Pager<'a> {
} }
} }
fn draw_prompt(&self, stdout: &mut Stdout, lower_mark: usize, wrong_key: bool) { fn draw_prompt(&self, stdout: &mut Stdout, lower_mark: usize, wrong_key: Option<char>) {
let status_inner = if lower_mark == self.line_count { let status_inner = if lower_mark == self.line_count {
format!("Next file: {}", self.next_file.unwrap_or_default()) format!("Next file: {}", self.next_file.unwrap_or_default())
} else { } else {
@ -345,10 +346,15 @@ impl<'a> Pager<'a> {
let status = format!("--More--({})", status_inner); let status = format!("--More--({})", status_inner);
let banner = match (self.silent, wrong_key) { let banner = match (self.silent, wrong_key) {
(true, true) => "[Press 'h' for instructions. (unimplemented)]".to_string(), (true, Some(key)) => {
(true, false) => format!("{}[Press space to continue, 'q' to quit.]", status), format!(
(false, true) => format!("{}{}", status, BELL), "{} [Unknown key: '{}'. Press 'h' for instructions. (unimplemented)]",
(false, false) => status, status, key
)
}
(true, None) => format!("{}[Press space to continue, 'q' to quit.]", status),
(false, Some(_)) => format!("{}{}", status, BELL),
(false, None) => status,
}; };
write!( write!(
@ -364,7 +370,7 @@ impl<'a> Pager<'a> {
// Break the lines on the cols of the terminal // Break the lines on the cols of the terminal
fn break_buff(buff: &str, cols: usize) -> Vec<String> { fn break_buff(buff: &str, cols: usize) -> Vec<String> {
let mut lines = Vec::new(); let mut lines = Vec::with_capacity(buff.lines().count());
for l in buff.lines() { for l in buff.lines() {
lines.append(&mut break_line(l, cols)); lines.append(&mut break_line(l, cols));