From 6c98b23e80d73f051de94d3f85129af94c96a2e3 Mon Sep 17 00:00:00 2001 From: Ideflop <94184575+Ideflop@users.noreply.github.com> Date: Mon, 29 May 2023 14:36:18 +0200 Subject: [PATCH 1/2] more: implement arguments -n/--lines and --number --- src/uu/more/src/more.rs | 73 ++++++++++++++++++++++++++------------ tests/by-util/test_more.rs | 14 ++++++++ 2 files changed, 64 insertions(+), 23 deletions(-) diff --git a/src/uu/more/src/more.rs b/src/uu/more/src/more.rs index 996a1dc615d..9be9b557670 100644 --- a/src/uu/more/src/more.rs +++ b/src/uu/more/src/more.rs @@ -14,10 +14,10 @@ use std::{ time::Duration, }; -use clap::{crate_version, Arg, ArgAction, ArgMatches, Command}; +use clap::{crate_version, value_parser, Arg, ArgAction, ArgMatches, Command}; use crossterm::event::KeyEventKind; use crossterm::{ - cursor::MoveTo, + cursor::{MoveTo, MoveUp}, event::{self, Event, KeyCode, KeyEvent, KeyModifiers}, execute, queue, style::Attribute, @@ -53,16 +53,28 @@ pub mod options { const MULTI_FILE_TOP_PROMPT: &str = "::::::::::::::\n{}\n::::::::::::::\n"; struct Options { - silent: bool, clean_print: bool, + lines: Option, print_over: bool, + silent: bool, squeeze: bool, } impl Options { fn from(matches: &ArgMatches) -> Self { + let lines = match ( + matches.get_one::(options::LINES).copied(), + matches.get_one::(options::NUMBER).copied(), + ) { + // We add 1 to the number of lines to display because the last line + // is used for the banner + (Some(number), _) if number > 0 => Some(number + 1), + (None, Some(number)) if number > 0 => Some(number + 1), + (_, _) => None, + }; Self { clean_print: matches.get_flag(options::CLEAN_PRINT), + lines, print_over: matches.get_flag(options::PRINT_OVER), silent: matches.get_flag(options::SILENT), squeeze: matches.get_flag(options::SQUEEZE), @@ -167,6 +179,23 @@ pub fn uu_app() -> Command { .help("Squeeze multiple blank lines into one") .action(ArgAction::SetTrue), ) + .arg( + Arg::new(options::LINES) + .short('n') + .long(options::LINES) + .value_name("number") + .num_args(1) + .value_parser(value_parser!(u16).range(0..)) + .help("The number of lines per screen full"), + ) + .arg( + Arg::new(options::NUMBER) + .long(options::NUMBER) + .required(false) + .num_args(1) + .value_parser(value_parser!(u16).range(0..)) + .help("Same as --lines"), + ) // The commented arguments below are unimplemented: /* .arg( @@ -187,22 +216,6 @@ pub fn uu_app() -> Command { .long(options::PLAIN) .help("Suppress underlining and bold"), ) - .arg( - Arg::new(options::LINES) - .short('n') - .long(options::LINES) - .value_name("number") - .takes_value(true) - .help("The number of lines per screen full"), - ) - .arg( - Arg::new(options::NUMBER) - .allow_hyphen_values(true) - .long(options::NUMBER) - .required(false) - .takes_value(true) - .help("Same as --lines"), - ) .arg( Arg::new(options::FROM_LINE) .short('F') @@ -263,7 +276,11 @@ fn more( next_file: Option<&str>, options: &Options, ) -> UResult<()> { - let (cols, rows) = terminal::size().unwrap(); + let (cols, mut rows) = terminal::size().unwrap(); + if let Some(number) = options.lines { + rows = number; + } + let lines = break_buff(buff, usize::from(cols)); let mut pager = Pager::new(rows, lines, next_file, options); @@ -327,6 +344,7 @@ fn more( .. }) => { pager.page_up(); + paging_add_back_message(options, stdout); } Event::Key(KeyEvent { code: KeyCode::Char('j'), @@ -347,7 +365,7 @@ fn more( pager.prev_line(); } Event::Resize(col, row) => { - pager.page_resize(col, row); + pager.page_resize(col, row, options.lines); } Event::Key(KeyEvent { code: KeyCode::Char(k), @@ -447,8 +465,10 @@ impl<'a> Pager<'a> { } // TODO: Deal with column size changes. - fn page_resize(&mut self, _: u16, row: u16) { - self.content_rows = row.saturating_sub(1); + fn page_resize(&mut self, _: u16, row: u16, option_line: Option) { + if option_line.is_none() { + self.content_rows = row.saturating_sub(1); + }; } fn draw(&mut self, stdout: &mut std::io::Stdout, wrong_key: Option) { @@ -536,6 +556,13 @@ impl<'a> Pager<'a> { } } +fn paging_add_back_message(options: &Options, stdout: &mut std::io::Stdout) { + if options.lines.is_some() { + execute!(stdout, MoveUp(1)).unwrap(); + stdout.write_all("\n\r...back 1 page\n".as_bytes()).unwrap(); + } +} + // Break the lines on the cols of the terminal fn break_buff(buff: &str, cols: usize) -> Vec { let mut lines = Vec::with_capacity(buff.lines().count()); diff --git a/tests/by-util/test_more.rs b/tests/by-util/test_more.rs index 43f405d9a84..95a4818b529 100644 --- a/tests/by-util/test_more.rs +++ b/tests/by-util/test_more.rs @@ -20,6 +20,20 @@ fn test_valid_arg() { new_ucmd!().arg("-s").succeeds(); new_ucmd!().arg("--squeeze").succeeds(); + + new_ucmd!().arg("-n").arg("10").succeeds(); + new_ucmd!().arg("--lines").arg("0").succeeds(); + new_ucmd!().arg("--number").arg("0").succeeds(); + } +} + +#[test] +fn test_invalid_arg() { + if std::io::stdout().is_terminal() { + new_ucmd!().arg("--invalid").fails(); + + new_ucmd!().arg("--lines").arg("-10").fails(); + new_ucmd!().arg("--number").arg("-10").fails(); } } From f1c943ed31d9d44cc1316f05042ec9f0505edec7 Mon Sep 17 00:00:00 2001 From: Ideflop <94184575+Ideflop@users.noreply.github.com> Date: Tue, 30 May 2023 09:03:00 +0200 Subject: [PATCH 2/2] more: error handling for write_all in function paging_add_back_message --- src/uu/more/src/more.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/uu/more/src/more.rs b/src/uu/more/src/more.rs index 9be9b557670..a43489566c5 100644 --- a/src/uu/more/src/more.rs +++ b/src/uu/more/src/more.rs @@ -344,7 +344,7 @@ fn more( .. }) => { pager.page_up(); - paging_add_back_message(options, stdout); + paging_add_back_message(options, stdout)?; } Event::Key(KeyEvent { code: KeyCode::Char('j'), @@ -556,11 +556,12 @@ impl<'a> Pager<'a> { } } -fn paging_add_back_message(options: &Options, stdout: &mut std::io::Stdout) { +fn paging_add_back_message(options: &Options, stdout: &mut std::io::Stdout) -> UResult<()> { if options.lines.is_some() { - execute!(stdout, MoveUp(1)).unwrap(); - stdout.write_all("\n\r...back 1 page\n".as_bytes()).unwrap(); + execute!(stdout, MoveUp(1))?; + stdout.write_all("\n\r...back 1 page\n".as_bytes())?; } + Ok(()) } // Break the lines on the cols of the terminal