From 479340306ee339705dd8c15ebf549bf2a5d7ce24 Mon Sep 17 00:00:00 2001 From: Ideflop <94184575+Ideflop@users.noreply.github.com> Date: Mon, 5 Jun 2023 18:48:45 +0200 Subject: [PATCH 1/3] more: implement arguments -u/--plain and -F/--from-line --- src/uu/more/src/more.rs | 78 +++++++++++++++++++++++++------------- tests/by-util/test_more.rs | 8 ++++ 2 files changed, 60 insertions(+), 26 deletions(-) diff --git a/src/uu/more/src/more.rs b/src/uu/more/src/more.rs index a43489566c..43c5c5163e 100644 --- a/src/uu/more/src/more.rs +++ b/src/uu/more/src/more.rs @@ -50,10 +50,11 @@ pub mod options { pub const FILES: &str = "files"; } -const MULTI_FILE_TOP_PROMPT: &str = "::::::::::::::\n{}\n::::::::::::::\n"; +const MULTI_FILE_TOP_PROMPT: &str = "\r::::::::::::::\n\r{}\n\r::::::::::::::\n"; struct Options { clean_print: bool, + from_line: usize, lines: Option, print_over: bool, silent: bool, @@ -72,8 +73,13 @@ impl Options { (None, Some(number)) if number > 0 => Some(number + 1), (_, _) => None, }; + let from_line = match matches.get_one::(options::FROM_LINE).copied() { + Some(number) if number > 1 => number - 1, + _ => 0, + }; Self { clean_print: matches.get_flag(options::CLEAN_PRINT), + from_line, lines, print_over: matches.get_flag(options::PRINT_OVER), silent: matches.get_flag(options::SILENT), @@ -90,7 +96,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { Err(e) => return Err(e.into()), }; - let options = Options::from(&matches); + let mut options = Options::from(&matches); let mut buff = String::new(); @@ -115,9 +121,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { format!("cannot open {}: No such file or directory", file.quote()), )); } - if length > 1 { - buff.push_str(&MULTI_FILE_TOP_PROMPT.replace("{}", file.to_str().unwrap())); - } let opened_file = match File::open(file) { Err(why) => { terminal::disable_raw_mode().unwrap(); @@ -130,14 +133,21 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { }; let mut reader = BufReader::new(opened_file); reader.read_to_string(&mut buff).unwrap(); - more(&buff, &mut stdout, next_file.copied(), &options)?; + more( + &buff, + &mut stdout, + length > 1, + file.to_str(), + next_file.copied(), + &mut 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, &options)?; + more(&buff, &mut stdout, false, None, None, &mut options)?; reset_term(&mut stdout); } else { return Err(UUsageError::new(1, "bad usage")); @@ -179,6 +189,22 @@ pub fn uu_app() -> Command { .help("Squeeze multiple blank lines into one") .action(ArgAction::SetTrue), ) + .arg( + Arg::new(options::PLAIN) + .short('u') + .long(options::PLAIN) + .action(ArgAction::SetTrue) + .hide(true), + ) + .arg( + Arg::new(options::FROM_LINE) + .short('F') + .long(options::FROM_LINE) + .num_args(1) + .value_name("number") + .value_parser(value_parser!(usize)) + .help("Display file beginning from line number"), + ) .arg( Arg::new(options::LINES) .short('n') @@ -191,7 +217,6 @@ pub fn uu_app() -> Command { .arg( Arg::new(options::NUMBER) .long(options::NUMBER) - .required(false) .num_args(1) .value_parser(value_parser!(u16).range(0..)) .help("Same as --lines"), @@ -210,21 +235,6 @@ pub fn uu_app() -> Command { .long(options::NO_PAUSE) .help("Suppress pause after form feed"), ) - .arg( - Arg::new(options::PLAIN) - .short('u') - .long(options::PLAIN) - .help("Suppress underlining and bold"), - ) - .arg( - Arg::new(options::FROM_LINE) - .short('F') - .allow_hyphen_values(true) - .required(false) - .takes_value(true) - .value_name("number") - .help("Display file beginning from line number"), - ) .arg( Arg::new(options::PATTERN) .short('P') @@ -273,8 +283,10 @@ fn reset_term(_: &mut usize) {} fn more( buff: &str, stdout: &mut Stdout, + multiple_file: bool, + file: Option<&str>, next_file: Option<&str>, - options: &Options, + options: &mut Options, ) -> UResult<()> { let (cols, mut rows) = terminal::size().unwrap(); if let Some(number) = options.lines { @@ -284,7 +296,22 @@ fn more( let lines = break_buff(buff, usize::from(cols)); let mut pager = Pager::new(rows, lines, next_file, options); + + if multiple_file { + execute!(stdout, terminal::Clear(terminal::ClearType::CurrentLine)).unwrap(); + stdout.write_all( + MULTI_FILE_TOP_PROMPT + .replace("{}", file.unwrap_or_default()) + .as_bytes(), + )?; + pager.content_rows -= 3; + } pager.draw(stdout, None); + if multiple_file { + options.from_line = 0; + pager.content_rows += 3; + } + if pager.should_close() { return Ok(()); } @@ -406,7 +433,7 @@ impl<'a> Pager<'a> { fn new(rows: u16, lines: Vec, next_file: Option<&'a str>, options: &Options) -> Self { let line_count = lines.len(); Self { - upper_mark: 0, + upper_mark: options.from_line, content_rows: rows.saturating_sub(1), lines, next_file, @@ -535,7 +562,6 @@ impl<'a> Pager<'a> { }; let status = format!("--More--({status_inner})"); - let banner = match (self.silent, wrong_key) { (true, Some(key)) => format!( "{status} [Unknown key: '{key}'. Press 'h' for instructions. (unimplemented)]" diff --git a/tests/by-util/test_more.rs b/tests/by-util/test_more.rs index 95a4818b52..15388bbf6c 100644 --- a/tests/by-util/test_more.rs +++ b/tests/by-util/test_more.rs @@ -21,9 +21,15 @@ fn test_valid_arg() { new_ucmd!().arg("-s").succeeds(); new_ucmd!().arg("--squeeze").succeeds(); + new_ucmd!().arg("-u").succeeds(); + new_ucmd!().arg("--plain").succeeds(); + new_ucmd!().arg("-n").arg("10").succeeds(); new_ucmd!().arg("--lines").arg("0").succeeds(); new_ucmd!().arg("--number").arg("0").succeeds(); + + new_ucmd!().arg("-F").arg("10").succeeds(); + new_ucmd!().arg("--from-line").arg("0").succeeds(); } } @@ -34,6 +40,8 @@ fn test_invalid_arg() { new_ucmd!().arg("--lines").arg("-10").fails(); new_ucmd!().arg("--number").arg("-10").fails(); + + new_ucmd!().arg("--from-line").arg("-10").fails(); } } From 77f8201fb8ab48e8f290c564e0c3dfe68b2a7687 Mon Sep 17 00:00:00 2001 From: Ideflop <94184575+Ideflop@users.noreply.github.com> Date: Mon, 5 Jun 2023 18:55:44 +0200 Subject: [PATCH 2/3] more: fix bug not displaying next file message and not stopping at end of file --- src/uu/more/src/more.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/uu/more/src/more.rs b/src/uu/more/src/more.rs index 43c5c5163e..c488ba8afe 100644 --- a/src/uu/more/src/more.rs +++ b/src/uu/more/src/more.rs @@ -312,7 +312,7 @@ fn more( pager.content_rows += 3; } - if pager.should_close() { + if pager.should_close() && next_file.is_none() { return Ok(()); } @@ -499,10 +499,10 @@ impl<'a> Pager<'a> { } fn draw(&mut self, stdout: &mut std::io::Stdout, wrong_key: Option) { + self.draw_lines(stdout); let lower_mark = self .line_count .min(self.upper_mark.saturating_add(self.content_rows.into())); - self.draw_lines(stdout); self.draw_prompt(stdout, lower_mark, wrong_key); stdout.flush().unwrap(); } From c4c3a354f84ff9786453b1d7ae5cda2e328ddcf4 Mon Sep 17 00:00:00 2001 From: Ideflop <94184575+Ideflop@users.noreply.github.com> Date: Tue, 6 Jun 2023 22:03:44 +0200 Subject: [PATCH 3/3] tests/more: test argument --from-line --- tests/by-util/test_more.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/by-util/test_more.rs b/tests/by-util/test_more.rs index 15388bbf6c..d94a921853 100644 --- a/tests/by-util/test_more.rs +++ b/tests/by-util/test_more.rs @@ -45,6 +45,40 @@ fn test_invalid_arg() { } } +#[test] +fn test_argument_from_file() { + if std::io::stdout().is_terminal() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + + let file = "test_file"; + + at.write(file, "1\n2"); + + // output all lines + scene + .ucmd() + .arg("-F") + .arg("0") + .arg(file) + .succeeds() + .no_stderr() + .stdout_contains("1") + .stdout_contains("2"); + + // output only the second line + scene + .ucmd() + .arg("-F") + .arg("2") + .arg(file) + .succeeds() + .no_stderr() + .stdout_contains("2") + .stdout_does_not_contain("1"); + } +} + #[test] fn test_more_dir_arg() { // Run the test only if there's a valid terminal, else do nothing