starship 1.12.0

The minimal, blazing-fast, and infinitely customizable prompt for any shell! โ˜„๐ŸŒŒ๏ธ
Documentation
use super::{Context, Module, ModuleConfig};

use crate::configs::os::OSConfig;
use crate::formatter::StringFormatter;

/// Creates a module with the current operating system
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
    let mut module = context.new_module("os");
    let config: OSConfig = OSConfig::try_load(module.config);

    if config.disabled {
        return None;
    }

    #[cfg(not(test))]
    let os = os_info::get();

    #[cfg(test)]
    let os = os_info::Info::default();

    let parsed = StringFormatter::new(config.format).and_then(|formatter| {
        formatter
            .map_meta(|variable, _| match variable {
                "symbol" => get_symbol(&config, &os.os_type()),
                _ => None,
            })
            .map_style(|variable| match variable {
                "style" => Some(Ok(config.style)),
                _ => None,
            })
            .map(|variable| match variable {
                "codename" => get_codename(&os).map(Ok),
                "edition" => get_edition(&os).map(Ok),
                "name" => get_name(&os).map(Ok),
                "type" => get_type(&os).map(Ok),
                "version" => get_version(&os).map(Ok),
                _ => None,
            })
            .parse(None, Some(context))
    });
    module.set_segments(match parsed {
        Ok(segments) => segments,
        Err(error) => {
            log::warn!("Error in module `os`:\n{}", error);
            return None;
        }
    });

    Some(module)
}

// Get the operating system symbol from user config, or else default config
// when user has not defined a symbol for the operating system.
fn get_symbol<'a>(config: &'a OSConfig, os_type: &os_info::Type) -> Option<&'a str> {
    config
        .get_symbol(os_type)
        .or_else(|| OSConfig::default().get_symbol(os_type))
}

fn get_codename(os: &os_info::Info) -> Option<String> {
    os.codename().map(String::from)
}

fn get_edition(os: &os_info::Info) -> Option<String> {
    os.edition().map(String::from)
}

fn get_name(os: &os_info::Info) -> Option<String> {
    Some(os.os_type().to_string())
}

fn get_type(os: &os_info::Info) -> Option<String> {
    // String from os_info::Type
    Some(format!("{:?}", os.os_type()))
}

fn get_version(os: &os_info::Info) -> Option<String> {
    Some(os.version())
        .filter(|&x| x != &os_info::Version::Unknown)
        .map(|x| x.to_string())
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::test::ModuleRenderer;
    use nu_ansi_term::Color;
    use os_info::Type;

    #[test]
    fn default() {
        let actual = ModuleRenderer::new("os").collect();

        assert_eq!(actual, None);
    }

    #[test]
    fn default_enabled() {
        let actual = ModuleRenderer::new("os")
            .config(toml::toml! {
                [os]
                disabled = false
            })
            .collect();

        let expected = Some(format!("{}", Color::White.bold().paint("โ“ ")));

        assert_eq!(actual, expected);
    }

    #[test]
    fn all_segments() {
        let actual = ModuleRenderer::new("os")
            .config(toml::toml! {
                [os]
                disabled = false
                format = "[$symbol($codename )($edition )($name )($type )($version )]($style)"
            })
            .collect();

        let expected = Some(format!(
            "{}",
            Color::White.bold().paint("โ“ Unknown Unknown ")
        ));

        assert_eq!(actual, expected);
    }

    #[test]
    fn get_symbol_default() {
        let config = OSConfig::try_load(None);

        let type_expected_pairs = [
            (Type::Alpine, Some("๐Ÿ”๏ธ ")),
            (Type::Amazon, Some("๐Ÿ™‚ ")),
            (Type::Android, Some("๐Ÿค– ")),
            (Type::Arch, Some("๐ŸŽ—๏ธ ")),
            (Type::CentOS, Some("๐Ÿ’  ")),
            (Type::Debian, Some("๐ŸŒ€ ")),
            (Type::DragonFly, Some("๐Ÿ‰ ")),
            (Type::Emscripten, Some("๐Ÿ”— ")),
            (Type::EndeavourOS, Some("๐Ÿš€ ")),
            (Type::Fedora, Some("๐ŸŽฉ ")),
            (Type::FreeBSD, Some("๐Ÿ˜ˆ ")),
            (Type::Garuda, Some("๐Ÿฆ… ")),
            (Type::Gentoo, Some("๐Ÿ—œ๏ธ ")),
            (Type::HardenedBSD, Some("๐Ÿ›ก๏ธ ")),
            (Type::Illumos, Some("๐Ÿฆ ")),
            (Type::Linux, Some("๐Ÿง ")),
            (Type::Macos, Some("๐ŸŽ ")),
            (Type::Manjaro, Some("๐Ÿฅญ ")),
            (Type::Mariner, Some("๐ŸŒŠ ")),
            (Type::MidnightBSD, Some("๐ŸŒ˜ ")),
            (Type::Mint, Some("๐ŸŒฟ ")),
            (Type::NetBSD, Some("๐Ÿšฉ ")),
            (Type::NixOS, Some("โ„๏ธ ")),
            (Type::OpenBSD, Some("๐Ÿก ")),
            (Type::openSUSE, Some("๐ŸฆŽ ")),
            (Type::OracleLinux, Some("๐Ÿฆด ")),
            (Type::Pop, Some("๐Ÿญ ")),
            (Type::Raspbian, Some("๐Ÿ“ ")),
            (Type::Redhat, Some("๐ŸŽฉ ")),
            (Type::RedHatEnterprise, Some("๐ŸŽฉ ")),
            (Type::Redox, Some("๐Ÿงช ")),
            (Type::Solus, Some("โ›ต ")),
            (Type::SUSE, Some("๐ŸฆŽ ")),
            (Type::Ubuntu, Some("๐ŸŽฏ ")),
            (Type::Unknown, Some("โ“ ")),
            (Type::Windows, Some("๐ŸชŸ ")),
        ];

        for (t, e) in type_expected_pairs {
            assert_eq!(get_symbol(&config, &t), e);
        }
    }

    #[test]
    fn get_symbol_custom() {
        let config_toml = toml::toml! {
            [symbols]
            Alpine = "๏Œ€ "
            Amazon = "๏‰ฐ "
            Android = "๏…ป "
            Arch = "๏Œƒ "
            CentOS = "๏Œ„ "
            Debian = "๏Œ† "
            DragonFly = "๎ŠŽ "
            Emscripten = "๏ˆ… "
            EndeavourOS = "๏†— "
            Fedora = "๏ŒŠ "
            FreeBSD = "๏ŒŒ "
            Garuda = "๏ฏ‘ "
            Gentoo = "๏Œ "
            HardenedBSD = "๏ฒŠ "
            Illumos = "๏œท "
            Linux = "๏Œš "
            Macos = "๏Œ‚ "
            Manjaro = "๏Œ’ "
            Mariner = "๏‡ "
            MidnightBSD = "๏†† "
            Mint = "๏ŒŽ "
            NetBSD = "๏€ค "
            NixOS = "๏Œ“ "
            OpenBSD = "๏œน "
            SUSE = "๏Œ” "
            OracleLinux = "๏ ถ "
            Pop = "๎Šฃ "
            Raspbian = "๏Œ• "
            Redhat = "๏Œ– "
            RedHatEnterprise = "๏Œ– "
            Redox = "๏”— "
            Solus = "๏ดฑ "
            openSUSE = "๏Œ” "
            Ubuntu = "๏Œ› "
            Unknown = "๏ˆญ "
            Windows = "๏กฑ "
        };

        let config = OSConfig::load(&config_toml);

        let type_expected_pairs = [
            (Type::Alpine, Some("๏Œ€ ")),
            (Type::Amazon, Some("๏‰ฐ ")),
            (Type::Android, Some("๏…ป ")),
            (Type::Arch, Some("๏Œƒ ")),
            (Type::CentOS, Some("๏Œ„ ")),
            (Type::Debian, Some("๏Œ† ")),
            (Type::DragonFly, Some("๎ŠŽ ")),
            (Type::Emscripten, Some("๏ˆ… ")),
            (Type::EndeavourOS, Some("๏†— ")),
            (Type::Fedora, Some("๏ŒŠ ")),
            (Type::FreeBSD, Some("๏ŒŒ ")),
            (Type::Garuda, Some("๏ฏ‘ ")),
            (Type::Gentoo, Some("๏Œ ")),
            (Type::HardenedBSD, Some("๏ฒŠ ")),
            (Type::Illumos, Some("๏œท ")),
            (Type::Linux, Some("๏Œš ")),
            (Type::Macos, Some("๏Œ‚ ")),
            (Type::Manjaro, Some("๏Œ’ ")),
            (Type::Mariner, Some("๏‡ ")),
            (Type::MidnightBSD, Some("๏†† ")),
            (Type::Mint, Some("๏ŒŽ ")),
            (Type::NetBSD, Some("๏€ค ")),
            (Type::NixOS, Some("๏Œ“ ")),
            (Type::OpenBSD, Some("๏œน ")),
            (Type::SUSE, Some("๏Œ” ")),
            (Type::OracleLinux, Some("๏ ถ ")),
            (Type::Pop, Some("๎Šฃ ")),
            (Type::Raspbian, Some("๏Œ• ")),
            (Type::Redhat, Some("๏Œ– ")),
            (Type::RedHatEnterprise, Some("๏Œ– ")),
            (Type::Redox, Some("๏”— ")),
            (Type::Solus, Some("๏ดฑ ")),
            (Type::openSUSE, Some("๏Œ” ")),
            (Type::Ubuntu, Some("๏Œ› ")),
            (Type::Unknown, Some("๏ˆญ ")),
            (Type::Windows, Some("๏กฑ ")),
        ];

        for (t, e) in type_expected_pairs {
            assert_eq!(get_symbol(&config, &t), e);
        }
    }

    #[test]
    fn get_symbol_fallback() {
        let config_toml = toml::toml! {
            [symbols]
            Unknown = ""
            Arch = "Arch is the best!"
        };

        let config = OSConfig::load(&config_toml);

        let type_expected_pairs = [
            (Type::Alpine, Some("๐Ÿ”๏ธ ")),
            (Type::Amazon, Some("๐Ÿ™‚ ")),
            (Type::Android, Some("๐Ÿค– ")),
            (Type::Arch, Some("Arch is the best!")),
            (Type::CentOS, Some("๐Ÿ’  ")),
            (Type::Debian, Some("๐ŸŒ€ ")),
            (Type::DragonFly, Some("๐Ÿ‰ ")),
            (Type::Emscripten, Some("๐Ÿ”— ")),
            (Type::EndeavourOS, Some("๐Ÿš€ ")),
            (Type::Fedora, Some("๐ŸŽฉ ")),
            (Type::FreeBSD, Some("๐Ÿ˜ˆ ")),
            (Type::Garuda, Some("๐Ÿฆ… ")),
            (Type::Gentoo, Some("๐Ÿ—œ๏ธ ")),
            (Type::HardenedBSD, Some("๐Ÿ›ก๏ธ ")),
            (Type::Illumos, Some("๐Ÿฆ ")),
            (Type::Linux, Some("๐Ÿง ")),
            (Type::Macos, Some("๐ŸŽ ")),
            (Type::Manjaro, Some("๐Ÿฅญ ")),
            (Type::Mariner, Some("๐ŸŒŠ ")),
            (Type::MidnightBSD, Some("๐ŸŒ˜ ")),
            (Type::Mint, Some("๐ŸŒฟ ")),
            (Type::NetBSD, Some("๐Ÿšฉ ")),
            (Type::NixOS, Some("โ„๏ธ ")),
            (Type::OpenBSD, Some("๐Ÿก ")),
            (Type::openSUSE, Some("๐ŸฆŽ ")),
            (Type::OracleLinux, Some("๐Ÿฆด ")),
            (Type::Pop, Some("๐Ÿญ ")),
            (Type::Raspbian, Some("๐Ÿ“ ")),
            (Type::Redhat, Some("๐ŸŽฉ ")),
            (Type::RedHatEnterprise, Some("๐ŸŽฉ ")),
            (Type::Redox, Some("๐Ÿงช ")),
            (Type::Solus, Some("โ›ต ")),
            (Type::SUSE, Some("๐ŸฆŽ ")),
            (Type::Ubuntu, Some("๐ŸŽฏ ")),
            (Type::Unknown, Some("")),
            (Type::Windows, Some("๐ŸชŸ ")),
        ];

        for (t, e) in type_expected_pairs {
            assert_eq!(get_symbol(&config, &t), e);
        }
    }

    #[test]
    fn warn_on_os_info_update() {
        #[warn(clippy::wildcard_enum_match_arm)]
        // This closure is the same as the default config symbols list.
        // When this clippy test fails, a new default symbol should be added to
        // `config/os.rs` to exhaustively match new possible `os_info::Type` cases.
        // Affects:
        // - crate::configs::os::OSConfig::default()
        // - crate::modules::os::tests
        // - docs/config/README.md/#Configuration/#OS/#Options
        // - docs/config/README.md/#Configuration/#OS/#Example
        // - docs/.vuepress/public/presets/toml/plain-text-symbols.toml
        // - dosc/.vuepress/public/presets/toml/nerd-font-symbols.toml
        // - .github/config-schema.json
        let _ = |t: Type| match t {
            Type::Alpine => "๐Ÿ”๏ธ ",
            Type::Amazon => "๐Ÿ™‚ ",
            Type::Android => "๐Ÿค– ",
            Type::Arch => "๐ŸŽ—๏ธ ",
            Type::CentOS => "๐Ÿ’  ",
            Type::Debian => "๐ŸŒ€ ",
            Type::DragonFly => "๐Ÿ‰ ",
            Type::Emscripten => "๐Ÿ”— ",
            Type::EndeavourOS => "๐Ÿš€ ",
            Type::Fedora => "๐ŸŽฉ ",
            Type::FreeBSD => "๐Ÿ˜ˆ ",
            Type::Garuda => "๐Ÿฆ… ",
            Type::Gentoo => "๐Ÿ—œ๏ธ ",
            Type::HardenedBSD => "๐Ÿ›ก๏ธ ",
            Type::Illumos => "๐Ÿฆ ",
            Type::Linux => "๐Ÿง ",
            Type::Macos => "๐ŸŽ ",
            Type::Manjaro => "๐Ÿฅญ ",
            Type::Mariner => "๐ŸŒŠ ",
            Type::MidnightBSD => "๐ŸŒ˜ ",
            Type::Mint => "๐ŸŒฟ ",
            Type::NetBSD => "๐Ÿšฉ ",
            Type::NixOS => "โ„๏ธ ",
            Type::OpenBSD => "๐Ÿก ",
            Type::openSUSE => "๐ŸฆŽ ",
            Type::OracleLinux => "๐Ÿฆด ",
            Type::Pop => "๐Ÿญ ",
            Type::Raspbian => "๐Ÿ“ ",
            Type::Redhat => "๐ŸŽฉ ",
            Type::RedHatEnterprise => "๐ŸŽฉ ",
            Type::Redox => "๐Ÿงช ",
            Type::Solus => "โ›ต ",
            Type::SUSE => "๐ŸฆŽ ",
            Type::Ubuntu => "๐ŸŽฏ ",
            Type::Unknown => "โ“ ",
            Type::Windows => "๐ŸชŸ ",
            _ => "",
        };
    }
}