From 2510f8030357d3a1d0aed420492a69b0553e9da9 Mon Sep 17 00:00:00 2001 From: Nathan Fisher Date: Thu, 29 Dec 2022 23:20:55 -0500 Subject: [PATCH] Head - allow `head -1` type arguments --- src/cmd/bootstrap/mod.rs | 2 ++ src/cmd/head/mod.rs | 50 ++++++++++++++++++++++++++++++++-------- 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/src/cmd/bootstrap/mod.rs b/src/cmd/bootstrap/mod.rs index 8f1cf93..6026117 100644 --- a/src/cmd/bootstrap/mod.rs +++ b/src/cmd/bootstrap/mod.rs @@ -32,6 +32,7 @@ impl Bootstrap { .help("Install completions for all supported shells") .short('a') .long("all") + .conflicts_with_all(["bash", "fish", "nu", "pwsh", "zsh"]) .action(ArgAction::SetTrue), Arg::new("bash") .help("Bash shell completions") @@ -88,6 +89,7 @@ impl Bootstrap { .help("Install completions for all supported shells") .short('a') .long("all") + .exclusive(true) .action(ArgAction::SetTrue), Arg::new("bash") .help("Bash shell completions") diff --git a/src/cmd/head/mod.rs b/src/cmd/head/mod.rs index 472336d..0c7e6e3 100644 --- a/src/cmd/head/mod.rs +++ b/src/cmd/head/mod.rs @@ -5,7 +5,7 @@ use std::{ error::Error, fs, io::{self, stdin, Read}, - process, + process, env, }; #[derive(Debug)] @@ -31,9 +31,8 @@ impl Cmd for Head { .about("Display first lines of a file") .long_about( "Print the first 10 lines of each FILE to standard output.\n\ - With more than one FILE, precede each with a header giving the file name.\n\ - With no FILE, or when FILE is -, read standard input.\n\ - Mandatory arguments to long options are mandatory for short options too." + With more than one FILE, precede each with a header giving the file name.\n\n\ + With no FILE, or when FILE is -, read standard input." ) .args([ Arg::new("FILES") @@ -58,18 +57,52 @@ impl Cmd for Head { .help("Count n number of lines (or bytes if -c is specified).") .short('n') .long("lines") - .default_value("10") .allow_negative_numbers(false) - .value_parser(value_parser!(usize)) + .conflicts_with("num") + .value_parser(value_parser!(usize)), + Arg::new("num") + .short('1') + .short_aliases(['2', '3', '4', '5', '6', '7', '8', '9']) + .hide(true) + .action(ArgAction::Append) ]) } fn run(&self, matches: Option<&ArgMatches>) -> Result<(), Box> { + let args: Vec<_> = env::args().collect(); + let idx = match crate::progname() { + Some(s) if s.as_str() == "head" => 1, + _ => 2, + }; + let mut lines = 10; + if args.len() > idx { + let arg1 = &args[idx]; + if arg1.starts_with('-') && arg1.len() > 1 { + let lines: usize = arg1[1..].parse()?; + let files: Vec<_> = if args.len() > idx + 1 { + args[idx + 1..].iter().map(|x| x.as_str()).collect() + } else { + vec!["-"] + }; + for file in &files { + head( + &file, + lines, + false, + false, + ); + } + return Ok(()); + } + } let matches = if let Some(m) = matches { m } else { return Err(io::Error::new(io::ErrorKind::Other, "No input").into()); }; + if let Some(l) = matches.get_one("LINES") { + lines = *l; + } let files = match matches.get_many::("FILES") { Some(c) => c.map(std::string::ToString::to_string).collect(), None => vec!["-".to_string()], @@ -82,10 +115,7 @@ impl Cmd for Head { } head( &file, - match matches.get_one("LINES") { - Some(c) => *c, - None => 10, - }, + lines, header, matches.get_flag("BYTES"), );