diff --git a/Cargo.lock b/Cargo.lock index 972c24ed..b372d6b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -78,6 +78,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" + [[package]] name = "bstr" version = "1.1.0" @@ -128,26 +134,24 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "3.2.23" +version = "4.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" +checksum = "42dfd32784433290c51d92c438bb72ea5063797fc3cc9a21a8c4346bebbb2098" dependencies = [ - "atty", - "bitflags", + "bitflags 2.4.2", "clap_derive", "clap_lex", - "indexmap", + "is-terminal", "once_cell", - "strsim", "termcolor", - "textwrap", + "terminal_size", ] [[package]] name = "clap_derive" -version = "3.2.18" +version = "4.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" +checksum = "fddf67631444a3a3e3e5ac51c36a5e01335302de677bd78759eaa90ab1f46644" dependencies = [ "heck", "proc-macro-error", @@ -158,9 +162,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.2.4" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +checksum = "033f6b7a4acb1f358c742aaca805c939ee73b4c6209ae4318ec7aca81c42e646" dependencies = [ "os_str_bytes", ] @@ -792,7 +796,7 @@ version = "0.10.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29d971fd5722fec23977260f6e81aa67d2f22cadbdc2aa049f1022d9a3be1566" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "foreign-types", "libc", @@ -949,7 +953,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1059,7 +1063,7 @@ version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588" dependencies = [ - "bitflags", + "bitflags 1.3.2", "errno", "io-lifetimes", "libc", @@ -1141,7 +1145,7 @@ version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "core-foundation-sys", "libc", @@ -1226,12 +1230,6 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - [[package]] name = "syn" version = "1.0.107" @@ -1292,16 +1290,20 @@ dependencies = [ ] [[package]] -name = "termtree" -version = "0.4.0" +name = "terminal_size" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95059e91184749cb66be6dc994f67f182b6d897cb3df74a5bf66b5e709295fd8" +checksum = "cb20089a8ba2b69debd491f8d2d023761cbf196e999218c591fa1e7e15a21907" +dependencies = [ + "rustix", + "windows-sys 0.42.0", +] [[package]] -name = "textwrap" -version = "0.16.0" +name = "termtree" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" +checksum = "95059e91184749cb66be6dc994f67f182b6d897cb3df74a5bf66b5e709295fd8" [[package]] name = "thiserror" diff --git a/Cargo.toml b/Cargo.toml index 5f9d0198..def03e97 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ path = "src/main.rs" anyhow = "1" app_dirs = { version = "2", package = "app_dirs2" } atty = "0.2" -clap = { version = "3", features = ["std", "derive", "suggestions", "color"], default-features = false } +clap = { version = "4", features = ["std", "derive", "help", "usage", "cargo", "error-context", "color", "wrap_help"], default-features = false } env_logger = { version = "0.10", optional = true } log = "0.4" reqwest = { version = "0.11.3", features = ["blocking"], default-features = false } diff --git a/docs/src/usage.txt b/docs/src/usage.txt index 74b3b2eb..281ff9ff 100644 --- a/docs/src/usage.txt +++ b/docs/src/usage.txt @@ -1,30 +1,26 @@ -tealdeer 1.6.1 -Danilo Bargen , Niklas Mohrin -A fast TLDR client +tealdeer 1.2.3: A fast TLDR client -USAGE: - tldr [OPTIONS] [COMMAND]... +Usage: tldr [OPTIONS] [COMMAND]... -ARGS: - ... The command to show (e.g. `tar` or `git log`) +Arguments: + [COMMAND]... The command to show (e.g. `tar` or `git log`) -OPTIONS: - -l, --list List all commands in the cache - -f, --render Render a specific markdown file - -p, --platform Override the operating system [possible values: linux, macos, - windows, sunos, osx, android] - -L, --language Override the language - -u, --update Update the local cache - --no-auto-update If auto update is configured, disable it for this run - -c, --clear-cache Clear the local cache - --pager Use a pager to page output - -r, --raw Display the raw markdown instead of rendering it - -q, --quiet Suppress informational messages - --show-paths Show file and directory paths used by tealdeer - --seed-config Create a basic config - --color Control whether to use color [possible values: always, auto, - never] - -v, --version Print the version - -h, --help Print help information +Options: + -l, --list List all commands in the cache + -f, --render Render a specific markdown file + -p, --platform Override the operating system [possible values: linux, macos, windows, + sunos, android] + -L, --language Override the language + -u, --update Update the local cache + --no-auto-update If auto update is configured, disable it for this run + -c, --clear-cache Clear the local cache + --pager Use a pager to page output + -r, --raw Display the raw markdown instead of rendering it + -q, --quiet Suppress informational messages + --show-paths Show file and directory paths used by tealdeer + --seed-config Create a basic config + --color Control whether to use color [possible values: always, auto, never] + -v, --version Print the version + -h, --help Print help To view the user documentation, please visit https://dbrgn.github.io/tealdeer/. diff --git a/src/cli.rs b/src/cli.rs index ed71ef87..87192046 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -2,32 +2,42 @@ use std::path::PathBuf; -use clap::{AppSettings, ArgAction, ArgGroup, Parser}; +use clap::{ + arg, + builder::{ArgAction, EnumValueParser}, + command, ArgGroup, Parser, +}; use crate::types::{ColorOptions, PlatformType}; // Note: flag names are specified explicitly in clap attributes // to improve readability and allow contributors to grep names like "clear-cache" #[derive(Parser, Debug)] -#[clap(about = "A fast TLDR client", author, version)] -#[clap( - after_help = "To view the user documentation, please visit https://dbrgn.github.io/tealdeer/." +#[command( + about = "A fast TLDR client", + version = "1.2.3", + disable_version_flag = true, + author, + help_template = "{before-help}{name} {version}: {about-with-newline} +{usage-heading} {usage} + +{all-args}{after-help}", + after_help = "To view the user documentation, please visit https://dbrgn.github.io/tealdeer/.", + arg_required_else_help = true, + help_expected = true, + group = ArgGroup::new("command_or_file").args(&["command", "render"]), )] -#[clap(setting = AppSettings::DeriveDisplayOrder)] -#[clap(arg_required_else_help(true))] -#[clap(disable_colored_help(true))] -#[clap(group = ArgGroup::new("command_or_file").args(&["command", "render"]))] -pub(crate) struct Args { +pub(crate) struct Cli { /// The command to show (e.g. `tar` or `git log`) - #[clap(min_values = 1)] + #[arg(num_args(1..))] pub command: Vec, /// List all commands in the cache - #[clap(short = 'l', long = "list")] + #[arg(short = 'l', long = "list")] pub list: bool, /// Render a specific markdown file - #[clap( + #[arg( short = 'f', long = "render", value_name = "FILE", @@ -36,61 +46,62 @@ pub(crate) struct Args { pub render: Option, /// Override the operating system - #[clap( + #[arg( short = 'p', long = "platform", action = ArgAction::Append, - possible_values = ["linux", "macos", "windows", "sunos", "osx", "android"], + value_parser = EnumValueParser::::new(), )] pub platforms: Option>, /// Override the language - #[clap(short = 'L', long = "language")] + #[arg(short = 'L', long = "language")] pub language: Option, /// Update the local cache - #[clap(short = 'u', long = "update")] + #[arg(short = 'u', long = "update")] pub update: bool, /// If auto update is configured, disable it for this run - #[clap(long = "no-auto-update", requires = "command_or_file")] + #[arg(long = "no-auto-update", requires = "command_or_file")] pub no_auto_update: bool, /// Clear the local cache - #[clap(short = 'c', long = "clear-cache")] + #[arg(short = 'c', long = "clear-cache")] pub clear_cache: bool, /// Use a pager to page output - #[clap(long = "pager", requires = "command_or_file")] + #[arg(long = "pager", requires = "command_or_file")] pub pager: bool, /// Display the raw markdown instead of rendering it - #[clap(short = 'r', long = "--raw", requires = "command_or_file")] + #[arg(short = 'r', long = "raw", requires = "command_or_file")] pub raw: bool, /// Suppress informational messages - #[clap(short = 'q', long = "quiet")] + #[arg(short = 'q', long = "quiet")] pub quiet: bool, /// Show file and directory paths used by tealdeer - #[clap(long = "show-paths")] + #[arg(long = "show-paths")] pub show_paths: bool, /// Create a basic config - #[clap(long = "seed-config")] + #[arg(long = "seed-config")] pub seed_config: bool, /// Control whether to use color - #[clap( + #[arg( long = "color", value_name = "WHEN", - possible_values = ["always", "auto", "never"] + value_parser = EnumValueParser::::new(), )] + //possible_values = ["always", "auto", "never"] pub color: Option, /// Print the version // Note: We override the version flag because clap uses `-V` by default, // while TLDR specification requires `-v` to be used. - #[clap(short = 'v', long = "version")] - pub version: bool, + #[arg(short = 'v', long = "version", action = ArgAction::Version)] + pub version: Option, } diff --git a/src/main.rs b/src/main.rs index 15110e64..6a38205b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -48,7 +48,7 @@ mod utils; use crate::{ cache::{Cache, CacheFreshness, PageLookupResult, TLDR_PAGES_DIR}, - cli::Args, + cli::Cli, config::{get_config_dir, get_config_path, make_default_config, Config, PathWithSource}, extensions::Dedup, output::print_page, @@ -65,7 +65,7 @@ const ARCHIVE_URL: &str = "https://tldr.sh/assets/tldr.zip"; /// The cache should be updated if it was explicitly requested, /// or if an automatic update is due and allowed. -fn should_update_cache(cache: &Cache, args: &Args, config: &Config) -> bool { +fn should_update_cache(cache: &Cache, args: &Cli, config: &Config) -> bool { args.update || (!args.no_auto_update && config.updates.auto_update @@ -81,7 +81,7 @@ enum CheckCacheResult { } /// Check the cache for freshness. If it's stale or missing, show a warning. -fn check_cache(cache: &Cache, args: &Args, enable_styles: bool) -> CheckCacheResult { +fn check_cache(cache: &Cache, args: &Cli, enable_styles: bool) -> CheckCacheResult { match cache.freshness() { CacheFreshness::Fresh => CheckCacheResult::CacheFound, CacheFreshness::Stale(_) if args.quiet => CheckCacheResult::CacheFound, @@ -243,7 +243,7 @@ fn main() { init_log(); // Parse arguments - let args = Args::parse(); + let args = Cli::parse(); // Determine the usage of styles #[cfg(target_os = "windows")] diff --git a/src/types.rs b/src/types.rs index f3318a92..d4b539a2 100644 --- a/src/types.rs +++ b/src/types.rs @@ -2,7 +2,6 @@ use std::{fmt, str}; -use anyhow::{anyhow, Result}; use serde_derive::{Deserialize, Serialize}; #[derive(Debug, Eq, PartialEq, Copy, Clone, Serialize, Deserialize)] @@ -11,8 +10,8 @@ use serde_derive::{Deserialize, Serialize}; pub enum PlatformType { Linux, OsX, - SunOs, Windows, + SunOs, Android, } @@ -28,20 +27,24 @@ impl fmt::Display for PlatformType { } } -impl str::FromStr for PlatformType { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - match s { - "linux" => Ok(Self::Linux), - "osx" | "macos" => Ok(Self::OsX), - "sunos" => Ok(Self::SunOs), - "windows" => Ok(Self::Windows), - "android" => Ok(Self::Android), - other => Err(anyhow!( - "Unknown OS: {}. Possible values: linux, macos, osx, sunos, windows, android", - other - )), +impl clap::ValueEnum for PlatformType { + fn value_variants<'a>() -> &'a [Self] { + &[ + Self::Linux, + Self::OsX, + Self::Windows, + Self::SunOs, + Self::Android, + ] + } + + fn to_possible_value<'a>(&self) -> Option { + match self { + Self::Linux => Some(clap::builder::PossibleValue::new("linux")), + Self::OsX => Some(clap::builder::PossibleValue::new("macos").alias("osx")), + Self::Windows => Some(clap::builder::PossibleValue::new("windows")), + Self::SunOs => Some(clap::builder::PossibleValue::new("sunos")), + Self::Android => Some(clap::builder::PossibleValue::new("android")), } } } @@ -96,18 +99,16 @@ pub enum ColorOptions { Never, } -impl str::FromStr for ColorOptions { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - match s { - "always" => Ok(Self::Always), - "auto" => Ok(Self::Auto), - "never" => Ok(Self::Never), - other => Err(anyhow!( - "Unknown color option: {}. Possible values: always, auto, never", - other - )), +impl clap::ValueEnum for ColorOptions { + fn value_variants<'a>() -> &'a [Self] { + &[Self::Always, Self::Auto, Self::Never] + } + + fn to_possible_value<'a>(&self) -> Option { + match self { + Self::Always => Some(clap::builder::PossibleValue::new("always")), + Self::Auto => Some(clap::builder::PossibleValue::new("auto")), + Self::Never => Some(clap::builder::PossibleValue::new("never")), } } }