diff --git a/docs/src/config_search.md b/docs/src/config_search.md index 2d59d65..d368159 100644 --- a/docs/src/config_search.md +++ b/docs/src/config_search.md @@ -12,3 +12,18 @@ Either way, the language used can be overwritten using the `--language` command [search] # Show pages in German if available, otherwise show in English languages = ["de", "en"] + +## `platforms` + +The list of platforms that should be considered when searching. +In addition to the platforms listed in the help text of the `--platform` flag, there are two special platforms available: +- `"current"`: equals the platform that tealdeer was compiled for +- `"all"`: adds all remaining platforms to the list + +Tealdeer searches the platforms in order of appearance in this list. +The default list of platforms is `["current", "common", "all"]`. +The list of platforms can be overwritten using the `--platform` command line flag. + + [search] + # Search for linux and common, and then search windows before trying the remaining platforms + platforms = ["linux", "common", "windows", "all"] diff --git a/src/config.rs b/src/config.rs index 446b841..e5e85e8 100644 --- a/src/config.rs +++ b/src/config.rs @@ -9,11 +9,15 @@ use std::{ use anyhow::{anyhow, bail, ensure, Context, Result}; use app_dirs::{get_app_root, AppDataType}; +use clap::ValueEnum; use serde::Serialize as _; use serde_derive::{Deserialize, Serialize}; use yansi::{Color, Style}; -use crate::{extensions::Dedup as _, types::PathSource}; +use crate::{ + extensions::Dedup as _, + types::{PathSource, PlatformType}, +}; pub const CONFIG_FILE_NAME: &str = "config.toml"; pub const MAX_CACHE_AGE: Duration = Duration::from_secs(2_592_000); // 30 days @@ -217,9 +221,61 @@ struct RawDirectoriesConfig { pub custom_pages_dir: Option, } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +enum RawPlatformType { + Current, + All, + MacOs, // alias for Platform(PlatformType::OsX) + #[serde(untagged)] + Platform(PlatformType), +} + +impl RawPlatformType { + pub fn flatten(raw_platforms: impl IntoIterator) -> Vec { + let mut flattened = Vec::new(); + for raw_platform in raw_platforms { + match raw_platform { + RawPlatformType::Current => flattened.push(PlatformType::current()), + RawPlatformType::Platform(platform) => flattened.push(platform), + RawPlatformType::MacOs => flattened.push(PlatformType::OsX), + RawPlatformType::All => flattened.extend(PlatformType::value_variants()), + } + } + flattened.clear_duplicates(); + flattened + } +} + #[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq)] struct RawSearchConfig { pub languages: Option>, + pub platforms: Option>, +} + +impl<'a> From<&'a RawSearchConfig> for SearchConfig<'a> { + fn from(raw_search_config: &'a RawSearchConfig) -> Self { + let languages = raw_search_config + .languages + .as_ref() + .map_or_else(get_languages_from_env, |langs| { + langs.iter().map(|lang| Language(lang)).collect() + }); + let platforms = if let Some(raw_platforms) = raw_search_config.platforms.as_ref() { + RawPlatformType::flatten(raw_platforms.iter().copied()) + } else { + RawPlatformType::flatten([ + RawPlatformType::Current, + RawPlatformType::Platform(PlatformType::Common), + RawPlatformType::All, + ]) + }; + + Self { + languages, + platforms, + } + } } #[derive(Debug, Serialize, Deserialize, PartialEq, Eq)] @@ -305,6 +361,7 @@ pub struct DirectoriesConfig { #[derive(Clone, Debug, PartialEq, Eq)] pub struct SearchConfig<'a> { pub languages: Vec>, + pub platforms: Vec, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -427,16 +484,7 @@ impl<'a> Config<'a> { fn from_raw(raw_config: &'a RawConfig, config_file_path: PathWithSource) -> Result { let style = (&raw_config.style).into(); let display = (&raw_config.display).into(); - - let search = SearchConfig { - languages: raw_config - .search - .languages - .as_ref() - .map_or_else(get_languages_from_env, |langs| { - langs.iter().map(|lang| Language(lang)).collect() - }), - }; + let search: SearchConfig<'a> = (&raw_config.search).into(); let updates = UpdatesConfig { auto_update: raw_config.updates.auto_update, diff --git a/src/main.rs b/src/main.rs index 2f730a4..fcf3273 100644 --- a/src/main.rs +++ b/src/main.rs @@ -39,6 +39,7 @@ use cache::{CacheConfig, TLDR_OLD_PAGES_DIR}; use clap::Parser; use config::{ConfigLoader, Language, StyleConfig, TlsBackend}; use log::debug; +use types::PlatformType; mod cache; mod cli; @@ -55,7 +56,7 @@ use crate::{ cli::Cli, config::{get_config_dir, make_default_config, Config, PathWithSource}, output::print_page, - types::{ColorOptions, PlatformType}, + types::ColorOptions, utils::{print_error, print_warning}, }; @@ -259,7 +260,13 @@ fn try_main(args: Cli, enable_styles: bool) -> Result { return Ok(ExitCode::SUCCESS); } - let platforms = compute_platforms(args.platforms.as_ref()); + if let Some(platforms) = args.platforms { + config.search.platforms = platforms; + if !config.search.platforms.contains(&PlatformType::Common) { + config.search.platforms.push(PlatformType::Common); + } + } + let (search_languages, download_languages): (&[_], &[_]) = match args.language.as_deref() { Some(lang) => (&[Language(lang)], &[Language(lang)]), None => (&config.search.languages, &config.updates.download_languages), @@ -272,7 +279,7 @@ fn try_main(args: Cli, enable_styles: bool) -> Result { .custom_pages_dir .as_ref() .map(PathWithSource::path), - platforms: &platforms, + platforms: &config.search.platforms, search_languages, download_languages, }; @@ -394,17 +401,3 @@ fn try_main(args: Cli, enable_styles: bool) -> Result { Ok(ExitCode::SUCCESS) } - -/// Returns the passed or default platform types and appends `PlatformType::Common` as fallback. -fn compute_platforms(platforms: Option<&Vec>) -> Vec { - match platforms { - Some(p) => { - let mut result = p.clone(); - if !result.contains(&PlatformType::Common) { - result.push(PlatformType::Common); - } - result - } - None => vec![PlatformType::current(), PlatformType::Common], - } -} diff --git a/tests/lib.rs b/tests/lib.rs index ef5777d..cb987db 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -715,6 +715,36 @@ fn test_os_specific_page() { .success(); } +#[test] +fn test_config_platforms() { + let testenv = TestEnv::new(); + testenv.add_os_entry("sunos", "sunos-command", ""); + + let set_config_platforms = |platforms| { + testenv.delete_config(); + testenv.init_config(); + testenv.append_to_config(format!("search.platforms = {platforms}")); + }; + + // By default all platforms are searched + testenv.command().arg("sunos-command").assert().success(); + + set_config_platforms("[]"); + testenv.command().arg("sunos-command").assert().failure(); + + set_config_platforms("['linux']"); + testenv.command().arg("sunos-command").assert().failure(); + + set_config_platforms("['sunos']"); + testenv.command().arg("sunos-command").assert().success(); + + set_config_platforms("['linux', 'all']"); + testenv.command().arg("sunos-command").assert().success(); + + set_config_platforms("['current', 'all']"); + testenv.command().arg("sunos-command").assert().success(); +} + #[test] fn test_markdown_rendering() { let testenv = TestEnv::new().install_default_cache(); @@ -956,6 +986,14 @@ fn test_macos_is_alias_for_osx() { .args(["--platform", "osx", "--list"]) .assert() .stdout("maconly\n"); + + testenv.append_to_config("search.platforms = ['osx']\n"); + testenv.command().arg("--list").assert().stdout("maconly\n"); + + testenv.delete_config(); + testenv.init_config(); + testenv.append_to_config("search.platforms = ['macos']\n"); + testenv.command().arg("--list").assert().stdout("maconly\n"); } #[test]