diff --git a/CHANGELOG.md b/CHANGELOG.md index 6447c1eb49..65d88d13e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Features - Correctly render tab stops in --show-all, see #2038 (@Synthetica9) +- Enable BusyBox less as pager, see #2162 (@nfisher1226) ## Bugfixes diff --git a/src/less.rs b/src/less.rs index 9de6d50823..66ec40689f 100644 --- a/src/less.rs +++ b/src/less.rs @@ -3,21 +3,38 @@ use std::ffi::OsStr; use std::process::Command; -pub fn retrieve_less_version(less_path: &dyn AsRef) -> Option { +#[derive(Debug, PartialEq)] +pub enum LessVersion { + Less(usize), + BusyBox, +} + +pub fn retrieve_less_version(less_path: &dyn AsRef) -> Option { let resolved_path = grep_cli::resolve_binary(less_path.as_ref()).ok()?; let cmd = Command::new(resolved_path).arg("--version").output().ok()?; - parse_less_version(&cmd.stdout) + if cmd.status.success() { + parse_less_version(&cmd.stdout) + } else { + parse_less_version_busybox(&cmd.stderr) + } } -fn parse_less_version(output: &[u8]) -> Option { +fn parse_less_version(output: &[u8]) -> Option { if !output.starts_with(b"less ") { return None; } let version = std::str::from_utf8(&output[5..]).ok()?; let end = version.find(|c: char| !c.is_ascii_digit())?; - version[..end].parse::().ok() + Some(LessVersion::Less(version[..end].parse::().ok()?)) +} + +fn parse_less_version_busybox(output: &[u8]) -> Option { + match std::str::from_utf8(output) { + Ok(version) if version.contains("BusyBox ") => Some(LessVersion::BusyBox), + _ => None, + } } #[test] @@ -30,7 +47,7 @@ For information about the terms of redistribution, see the file named README in the less distribution. Homepage: http://www.greenwoodsoftware.com/less"; - assert_eq!(Some(487), parse_less_version(output)); + assert_eq!(Some(LessVersion::Less(487)), parse_less_version(output)); } #[test] @@ -43,7 +60,7 @@ For information about the terms of redistribution, see the file named README in the less distribution. Homepage: http://www.greenwoodsoftware.com/less"; - assert_eq!(Some(529), parse_less_version(output)); + assert_eq!(Some(LessVersion::Less(529)), parse_less_version(output)); } #[test] @@ -56,7 +73,7 @@ For information about the terms of redistribution, see the file named README in the less distribution. Home page: http://www.greenwoodsoftware.com/less"; - assert_eq!(Some(551), parse_less_version(output)); + assert_eq!(Some(LessVersion::Less(551)), parse_less_version(output)); } #[test] @@ -69,7 +86,7 @@ For information about the terms of redistribution, see the file named README in the less distribution. Home page: https://greenwoodsoftware.com/less"; - assert_eq!(Some(581), parse_less_version(output)); + assert_eq!(Some(LessVersion::Less(581)), parse_less_version(output)); } #[test] @@ -77,4 +94,38 @@ fn test_parse_less_version_wrong_program() { let output = b"more from util-linux 2.34"; assert_eq!(None, parse_less_version(output)); + assert_eq!(None, parse_less_version_busybox(output)); +} + +#[test] +fn test_parse_less_version_busybox() { + let output = b"pkg/less: unrecognized option '--version' +BusyBox v1.35.0 (2022-04-21 10:38:11 EDT) multi-call binary. + +Usage: less [-EFIMmNSRh~] [FILE]... + +View FILE (or stdin) one screenful at a time + + -E Quit once the end of a file is reached + -F Quit if entire file fits on first screen + -I Ignore case in all searches + -M,-m Display status line with line numbers + and percentage through the file + -N Prefix line number to each line + -S Truncate long lines + -R Remove color escape codes in input + -~ Suppress ~s displayed past EOF"; + + assert_eq!( + Some(LessVersion::BusyBox), + parse_less_version_busybox(output) + ); +} + +#[test] +fn test_parse_less_version_invalid_utf_8() { + let output = b"\xff"; + + assert_eq!(None, parse_less_version(output)); + assert_eq!(None, parse_less_version_busybox(output)); } diff --git a/src/output.rs b/src/output.rs index 5ab3680bcd..55ec1cefc7 100644 --- a/src/output.rs +++ b/src/output.rs @@ -4,7 +4,7 @@ use std::process::Child; use crate::error::*; #[cfg(feature = "paging")] -use crate::less::retrieve_less_version; +use crate::less::{retrieve_less_version, LessVersion}; #[cfg(feature = "paging")] use crate::paging::PagingMode; #[cfg(feature = "paging")] @@ -83,13 +83,13 @@ impl OutputType { let replace_arguments_to_less = pager.source == PagerSource::EnvVarPager; if args.is_empty() || replace_arguments_to_less { - p.arg("--RAW-CONTROL-CHARS"); + p.arg("-R"); // Short version of --RAW-CONTROL-CHARS for maximum compatibility if single_screen_action == SingleScreenAction::Quit { - p.arg("--quit-if-one-screen"); + p.arg("-F"); // Short version of --quit-if-one-screen for compatibility } if wrapping_mode == WrappingMode::NoWrapping(true) { - p.arg("--chop-long-lines"); + p.arg("-S"); // Short version of --chop-long-lines for compatibility } // Passing '--no-init' fixes a bug with '--quit-if-one-screen' in older @@ -103,7 +103,9 @@ impl OutputType { None => { p.arg("--no-init"); } - Some(version) if (version < 530 || (cfg!(windows) && version < 558)) => { + Some(LessVersion::Less(version)) + if (version < 530 || (cfg!(windows) && version < 558)) => + { p.arg("--no-init"); } _ => {}