use clap::{App, Arg}; pub fn build() -> App<'static, 'static> { App::new("lsd") .version(crate_version!()) .about(crate_description!()) .arg(Arg::with_name("FILE").multiple(true).default_value(".")) .arg( Arg::with_name("all") .short("a") .overrides_with("almost-all") .long("all") .multiple(true) .help("Do not ignore entries starting with ."), ) .arg( Arg::with_name("almost-all") .short("A") .overrides_with("all") .long("almost-all") .multiple(true) .help("Do not list implied . and .."), ) .arg( Arg::with_name("color") .long("color") .possible_value("always") .possible_value("auto") .possible_value("never") .default_value("auto") .multiple(true) .number_of_values(1) .help("When to use terminal colours"), ) .arg( Arg::with_name("icon") .long("icon") .possible_value("always") .possible_value("auto") .possible_value("never") .default_value("auto") .multiple(true) .number_of_values(1) .help("When to print the icons"), ) .arg( Arg::with_name("icon-theme") .long("icon-theme") .possible_value("fancy") .possible_value("unicode") .default_value("fancy") .multiple(true) .number_of_values(1) .help("Whether to use fancy or unicode icons"), ) .arg( Arg::with_name("indicators") .short("F") .long("classify") .multiple(true) .help("Append indicator (one of */=>@|) at the end of the file names"), ) .arg( Arg::with_name("long") .short("l") .long("long") .multiple(true) .help("Display extended file metadata as a table"), ) .arg( Arg::with_name("oneline") .short("1") .long("oneline") .multiple(true) .help("Display one entry per line"), ) .arg( Arg::with_name("recursive") .short("R") .long("recursive") .multiple(true) .conflicts_with("tree") .help("Recurse into directories"), ) .arg( Arg::with_name("human_readable") .short("h") .long("human-readable") .help("For ls compatibility purposes ONLY, currently set by default"), ) .arg( Arg::with_name("tree") .long("tree") .multiple(true) .conflicts_with("recursive") .help("Recurse into directories and present the result as a tree"), ) .arg( Arg::with_name("depth") .long("depth") .multiple(true) .takes_value(true) .value_name("num") .help("Stop recursing into directories after reaching specified depth"), ) .arg( Arg::with_name("directory-only") .short("d") .long("directory-only") .conflicts_with("all") .conflicts_with("almost-all") .conflicts_with("depth") .conflicts_with("recursive") .conflicts_with("tree") .help("Display directories themselves, and not their contents"), ) .arg( Arg::with_name("size") .long("size") .possible_value("default") .possible_value("short") .possible_value("bytes") .default_value("default") .multiple(true) .number_of_values(1) .help("How to display size"), ) .arg( Arg::with_name("total-size") .long("total-size") .multiple(true) .help("Display the total size of directories"), ) .arg( Arg::with_name("date") .long("date") .validator(validate_date_argument) .default_value("date") .multiple(true) .number_of_values(1) .help("How to display date [possible values: date, relative, +date-time-format]"), ) .arg( Arg::with_name("timesort") .short("t") .long("timesort") .multiple(true) .help("Sort by time modified"), ) .arg( Arg::with_name("sizesort") .short("S") .long("sizesort") .multiple(true) .help("Sort by size"), ) .arg( Arg::with_name("reverse") .short("r") .long("reverse") .multiple(true) .help("Reverse the order of the sort"), ) .arg( Arg::with_name("group-dirs") .long("group-dirs") .possible_value("none") .possible_value("first") .possible_value("last") .default_value("none") .multiple(true) .number_of_values(1) .help("Sort the directories then the files"), ) .arg( Arg::with_name("blocks") .long("blocks") .multiple(true) .number_of_values(1) .require_delimiter(true) .possible_values(&["permission", "user", "group", "size", "date", "name"]) .help("Specify the blocks that will be displayed and in what order"), ) .arg( Arg::with_name("classic") .long("classic") .help("Enable classic mode (no colors or icons)"), ) .arg( Arg::with_name("no-symlink") .long("no-symlink") .multiple(true) .help("Do not display symlink target"), ) .arg( Arg::with_name("ignore-glob") .short("I") .long("ignore-glob") .multiple(true) .number_of_values(1) .value_name("pattern") .default_value("") .help("Do not display files/directories with names matching the glob pattern(s)"), ) } fn validate_date_argument(arg: String) -> Result<(), String> { use std::error::Error; if arg.starts_with('+') { validate_time_format(&arg).map_err(|err| err.description().to_string()) } else if &arg == "date" || &arg == "relative" { Result::Ok(()) } else { Result::Err("possible values: date, relative, +date-time-format".to_owned()) } } fn validate_time_format(formatter: &str) -> Result<(), time::ParseError> { let mut chars = formatter.chars(); loop { match chars.next() { Some('%') => match chars.next() { Some('A') | Some('a') | Some('B') | Some('b') | Some('C') | Some('c') | Some('D') | Some('d') | Some('e') | Some('F') | Some('f') | Some('G') | Some('g') | Some('H') | Some('h') | Some('I') | Some('j') | Some('k') | Some('l') | Some('M') | Some('m') | Some('n') | Some('P') | Some('p') | Some('R') | Some('r') | Some('S') | Some('s') | Some('T') | Some('t') | Some('U') | Some('u') | Some('V') | Some('v') | Some('W') | Some('w') | Some('X') | Some('x') | Some('Y') | Some('y') | Some('Z') | Some('z') | Some('+') | Some('%') => (), Some(c) => return Err(time::ParseError::InvalidFormatSpecifier(c)), None => return Err(time::ParseError::MissingFormatConverter), }, None => break, _ => continue, } } Ok(()) }