diff --git a/docs/src/usage.txt b/docs/src/usage.txt index 4f88bc9..66c45c3 100644 --- a/docs/src/usage.txt +++ b/docs/src/usage.txt @@ -14,7 +14,7 @@ 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] + windows, sunos, all] -o, --os Deprecated alias of `platform` -L, --language Override the language -u, --update Update the local cache diff --git a/src/cache.rs b/src/cache.rs index ac6347c..1d94d89 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -16,7 +16,7 @@ use zip::ZipArchive; use crate::{ error::TealdeerError::{self, CacheError, UpdateError}, - types::{PathSource, PlatformType}, + types::{PathSource, PlatformStrategy, PlatformType}, }; static CACHE_DIR_ENV_VAR: &str = "TEALDEER_CACHE_DIR"; @@ -27,7 +27,7 @@ static TLDR_OLD_PAGES_DIR: &str = "tldr-master"; #[derive(Debug)] pub struct Cache { url: String, - platform: PlatformType, + platform: PlatformStrategy, } #[derive(Debug)] @@ -64,7 +64,7 @@ pub enum CacheFreshness { } impl Cache { - pub fn new(url: S, platform: PlatformType) -> Self + pub fn new(url: S, platform: PlatformStrategy) -> Self where S: Into, { @@ -196,11 +196,11 @@ impl Cache { /// Return the platform directory. fn get_platform_dir(&self) -> &'static str { - match self.platform { - PlatformType::Linux => "linux", - PlatformType::OsX => "osx", - PlatformType::SunOs => "sunos", - PlatformType::Windows => "windows", + match self.platform.platform_type { + PlatformType::Linux { .. } => "linux", + PlatformType::OsX { .. } => "osx", + PlatformType::SunOs { .. } => "sunos", + PlatformType::Windows { .. } => "windows", } } @@ -305,7 +305,7 @@ impl Cache { let mut pages = WalkDir::new(platforms_dir) .min_depth(1) // Skip root directory .into_iter() - .filter_entry(|e| should_walk(e)) // Filter out pages for other architectures + .filter_entry(|e| self.platform.list_all || should_walk(e)) // Filter out pages for other architectures .filter_map(Result::ok) // Convert results to options, filter out errors .filter_map(|e| { let path = e.path(); diff --git a/src/main.rs b/src/main.rs index 45aa050..4c9e676 100644 --- a/src/main.rs +++ b/src/main.rs @@ -40,7 +40,7 @@ use crate::{ error::TealdeerError::ConfigError, extensions::Dedup, output::print_page, - types::{ColorOptions, PlatformType}, + types::{ColorOptions, PlatformStrategy, PlatformType}, utils::{print_error, print_warning}, }; @@ -80,22 +80,28 @@ struct Args { )] render: Option, - /// Override the operating system + /// Override the operating system [possible values: linux, macos, windows, sunos, all] #[clap( short = 'p', long = "platform", - possible_values = ["linux", "macos", "windows", "sunos", "osx"], + possible_values = ["linux", "macos", "windows", "sunos", "osx", "current", "all"], + default_value = "current", + hide_possible_values = true, + hide_default_value = true, )] - platform: Option, + platform: PlatformStrategy, /// Deprecated alias of `platform` #[clap( short = 'o', long = "os", - possible_values = ["linux", "macos", "windows", "sunos", "osx"], + conflicts_with = "platform", + possible_values = ["linux", "macos", "windows", "sunos", "osx", "current", "all"], + default_value = "current", hide_possible_values = true, + hide_default_value = true, )] - os: Option, + os: PlatformStrategy, /// Override the language #[clap(short = 'L', long = "language")] @@ -400,13 +406,14 @@ fn main() { "The -m / --markdown flag is deprecated, use -r / --raw instead", ); } - if args.os.is_some() { + let default_platform = PlatformType::current(); + if args.os.platform_type != default_platform || args.os.list_all { print_warning( enable_styles, "The -o / --os flag is deprecated, use -p / --platform instead", ); + args.platform = args.os; } - args.platform = args.platform.or(args.os); // Show config file and path, pass through if args.config_path { @@ -442,9 +449,6 @@ fn main() { configure_pager(enable_styles); } - // Specify target OS - let platform: PlatformType = args.platform.unwrap_or_else(PlatformType::current); - // If a local file was passed in, render it and exit if let Some(file) = args.render { let path = PageLookupResult::with_page(file); @@ -457,7 +461,7 @@ fn main() { } // Initialize cache - let cache = Cache::new(ARCHIVE_URL, platform); + let cache = Cache::new(ARCHIVE_URL, args.platform); // Clear cache, pass through if args.clear_cache { diff --git a/src/types.rs b/src/types.rs index 3981776..72d5b92 100644 --- a/src/types.rs +++ b/src/types.rs @@ -2,10 +2,10 @@ use std::{fmt, str}; -use serde_derive::{Deserialize, Serialize}; +use serde::Deserialize; -#[derive(Debug, Eq, PartialEq, Copy, Clone, Serialize, Deserialize)] -#[serde(rename_all = "lowercase")] +/// The platform types supported by tldr. +#[derive(Debug, Eq, PartialEq, Copy, Clone)] #[allow(dead_code)] pub enum PlatformType { Linux, @@ -25,17 +25,58 @@ impl fmt::Display for PlatformType { } } -impl str::FromStr for PlatformType { +/// The platform lookup strategy. +/// +/// Includes both the platform type, as well as +#[derive(Debug, Copy, Clone)] +pub struct PlatformStrategy { + /// The platform type that should be looked up. + pub platform_type: PlatformType, + /// Flag indicating whether all pages should be listed or not. This is only + /// used when the special platform type `all` is specified by the user. + pub list_all: bool, +} + +impl PlatformStrategy { + pub fn new(platform_type: PlatformType) -> Self { + Self { + platform_type, + list_all: false, + } + } + + /// Return a `PlatformStrategy` containing the current platform as the + /// target platform type. + pub fn current() -> Self { + Self { + platform_type: PlatformType::current(), + list_all: false, + } + } + + /// Like `current()`, but when listing the pages, return the pages for all + /// platforms, not just for the current platform. + pub fn all() -> Self { + Self { + platform_type: PlatformType::current(), + list_all: true, + } + } +} + +impl str::FromStr for PlatformStrategy { type Err = String; 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), + "linux" => Ok(PlatformStrategy::new(PlatformType::Linux)), + "osx" | "macos" => Ok(PlatformStrategy::new(PlatformType::OsX)), + "windows" => Ok(PlatformStrategy::new(PlatformType::Windows)), + "sunos" => Ok(PlatformStrategy::new(PlatformType::SunOs)), + "current" => Ok(PlatformStrategy::current()), + "all" => Ok(PlatformStrategy::all()), other => Err(format!( - "Unknown OS: {}. Possible values: linux, macos, osx, sunos, windows", + "Unknown platform: {}. Possible values: linux, macos, osx, windows, sunos, current, all", other )), } diff --git a/tests/lib.rs b/tests/lib.rs index de6d346..e79d9aa 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -523,6 +523,40 @@ fn test_list_flag_rendering() { .stdout("bar\nbaz\nfoo\nqux\n"); } +#[test] +fn test_list_platform_filtering() { + let testenv = TestEnv::new(); + + testenv.add_os_entry("common", "a-common", ""); + testenv.add_os_entry("windows", "a-windows", ""); + testenv.add_os_entry("linux", "a-linux", ""); + testenv.add_os_entry("linux", "b-linux", ""); + + // Filter: linux + testenv + .command() + .args(["--list", "--platform", "linux"]) + .assert() + .success() + .stdout("a-common\na-linux\nb-linux\n"); + + // Filter: windows + testenv + .command() + .args(["--list", "--platform", "windows"]) + .assert() + .success() + .stdout("a-common\na-windows\n"); + + // Filter: all + testenv + .command() + .args(["--list", "--platform", "all"]) + .assert() + .success() + .stdout("a-common\na-linux\na-windows\nb-linux\n"); +} + #[test] fn test_autoupdate_cache() { let testenv = TestEnv::new();