From b676875c0c92ae84f74c03d551c7e6fdf2eb43d1 Mon Sep 17 00:00:00 2001 From: Ideflop Date: Wed, 17 May 2023 20:38:03 +0200 Subject: [PATCH] more: add arguments print over and clean print --- src/uu/more/src/more.rs | 81 +++++++++++++++++++++++++++----------- tests/by-util/test_more.rs | 9 +++++ 2 files changed, 67 insertions(+), 23 deletions(-) diff --git a/src/uu/more/src/more.rs b/src/uu/more/src/more.rs index 6cf9df1ab..2b6bde9da 100644 --- a/src/uu/more/src/more.rs +++ b/src/uu/more/src/more.rs @@ -14,13 +14,14 @@ use std::{ time::Duration, }; -use clap::{crate_version, Arg, ArgAction, Command}; +use clap::{crate_version, Arg, ArgAction, ArgMatches, Command}; use crossterm::event::KeyEventKind; use crossterm::{ + cursor::MoveTo, event::{self, Event, KeyCode, KeyEvent, KeyModifiers}, execute, queue, style::Attribute, - terminal, + terminal::{self, Clear, ClearType}, }; use is_terminal::IsTerminal; @@ -51,12 +52,34 @@ pub mod options { const MULTI_FILE_TOP_PROMPT: &str = "::::::::::::::\n{}\n::::::::::::::\n"; +struct Options { + silent: bool, + clean_print: bool, + print_over: bool, +} + +impl Options { + fn from(matches: &ArgMatches) -> Self { + Self { + silent: matches.get_flag(options::SILENT), + clean_print: matches.get_flag(options::CLEAN_PRINT), + print_over: matches.get_flag(options::PRINT_OVER), + } + } +} + #[uucore::main] pub fn uumain(args: impl uucore::Args) -> UResult<()> { - let matches = uu_app().get_matches_from(args); + let args = args.collect_lossy(); + let matches = match uu_app().try_get_matches_from(&args) { + Ok(m) => m, + Err(e) => return Err(e.into()), + }; + + let options = Options::from(&matches); let mut buff = String::new(); - let silent = matches.get_flag(options::SILENT); + if let Some(files) = matches.get_many::(options::FILES) { let mut stdout = setup_term(); let length = files.len(); @@ -83,14 +106,14 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { } let mut reader = BufReader::new(File::open(file).unwrap()); reader.read_to_string(&mut buff).unwrap(); - more(&buff, &mut stdout, next_file.copied(), silent)?; + more(&buff, &mut stdout, next_file.copied(), &options)?; buff.clear(); } reset_term(&mut stdout); } else if !std::io::stdin().is_terminal() { stdin().read_to_string(&mut buff).unwrap(); let mut stdout = setup_term(); - more(&buff, &mut stdout, None, silent)?; + more(&buff, &mut stdout, None, &options)?; reset_term(&mut stdout); } else { return Err(UUsageError::new(1, "bad usage")); @@ -104,6 +127,13 @@ pub fn uu_app() -> Command { .override_usage(format_usage(USAGE)) .version(crate_version!()) .infer_long_args(true) + .arg( + Arg::new(options::PRINT_OVER) + .short('c') + .long(options::PRINT_OVER) + .help("Do not scroll, display text and clean line ends") + .action(ArgAction::SetTrue), + ) .arg( Arg::new(options::SILENT) .short('d') @@ -111,6 +141,13 @@ pub fn uu_app() -> Command { .help("Display help instead of ringing bell") .action(ArgAction::SetTrue), ) + .arg( + Arg::new(options::CLEAN_PRINT) + .short('p') + .long(options::CLEAN_PRINT) + .help("Do not scroll, clean screen and display text") + .action(ArgAction::SetTrue), + ) // The commented arguments below are unimplemented: /* .arg( @@ -125,18 +162,6 @@ pub fn uu_app() -> Command { .long(options::NO_PAUSE) .help("Suppress pause after form feed"), ) - .arg( - Arg::new(options::PRINT_OVER) - .short('c') - .long(options::PRINT_OVER) - .help("Do not scroll, display text and clean line ends"), - ) - .arg( - Arg::new(options::CLEAN_PRINT) - .short('p') - .long(options::CLEAN_PRINT) - .help("Do not scroll, clean screen and display text"), - ) .arg( Arg::new(options::SQUEEZE) .short('s') @@ -209,7 +234,7 @@ fn setup_term() -> usize { fn reset_term(stdout: &mut std::io::Stdout) { terminal::disable_raw_mode().unwrap(); // Clear the prompt - queue!(stdout, terminal::Clear(terminal::ClearType::CurrentLine)).unwrap(); + queue!(stdout, terminal::Clear(ClearType::CurrentLine)).unwrap(); // Move cursor to the beginning without printing new line print!("\r"); stdout.flush().unwrap(); @@ -219,11 +244,16 @@ fn reset_term(stdout: &mut std::io::Stdout) { #[inline(always)] fn reset_term(_: &mut usize) {} -fn more(buff: &str, stdout: &mut Stdout, next_file: Option<&str>, silent: bool) -> UResult<()> { +fn more( + buff: &str, + stdout: &mut Stdout, + next_file: Option<&str>, + options: &Options, +) -> UResult<()> { let (cols, rows) = terminal::size().unwrap(); let lines = break_buff(buff, usize::from(cols)); - let mut pager = Pager::new(rows, lines, next_file, silent); + let mut pager = Pager::new(rows, lines, next_file, options); pager.draw(stdout, None); if pager.should_close() { return Ok(()); @@ -303,6 +333,11 @@ fn more(buff: &str, stdout: &mut Stdout, next_file: Option<&str>, silent: bool) _ => continue, } + if options.clean_print { + execute!(std::io::stdout(), Clear(ClearType::Purge), MoveTo(0, 0)).unwrap(); + } else if options.print_over { + execute!(std::io::stdout(), Clear(ClearType::All), MoveTo(0, 0)).unwrap(); + } pager.draw(stdout, wrong_key); } } @@ -320,7 +355,7 @@ struct Pager<'a> { } impl<'a> Pager<'a> { - fn new(rows: u16, lines: Vec, next_file: Option<&'a str>, silent: bool) -> Self { + fn new(rows: u16, lines: Vec, next_file: Option<&'a str>, options: &Options) -> Self { let line_count = lines.len(); Self { upper_mark: 0, @@ -328,7 +363,7 @@ impl<'a> Pager<'a> { lines, next_file, line_count, - silent, + silent: options.silent, } } diff --git a/tests/by-util/test_more.rs b/tests/by-util/test_more.rs index bdf80a27c..5b4fa1ca3 100644 --- a/tests/by-util/test_more.rs +++ b/tests/by-util/test_more.rs @@ -10,6 +10,15 @@ fn test_more_no_arg() { } } +#[test] +fn test_valid_arg() { + new_ucmd!().arg("-c").succeeds().code_is(0); + new_ucmd!().arg("--print-over").succeeds().code_is(0); + + new_ucmd!().arg("-p").succeeds().code_is(0); + new_ucmd!().arg("--clean-print").succeeds().code_is(0); +} + #[test] fn test_more_dir_arg() { // Run the test only if there's a valid terminal, else do nothing