Repository: starship/starship
File: src/modules/c.rs (Rust)

Code before:
use std::ops::Deref;

/// Creates a module with the current c version
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
    let mut module = context.new_module("c");
    let config: CConfig = CConfig::try_load(module.config);
    let is_c_project = context
        .try_begin_scan()?
        .set_extensions(&config.detect_extensions)
        .set_files(&config.detect_files)
        .set_folders(&config.detect_folders)
        .is_match();

    if !is_c_project {
        return None;
    }

    let parsed = StringFormatter::new(config.format).and_then(|formatter| {
        let c_compiler_info = Lazy::new(|| {
            context.exec_cmds_return_first(&[
                // the compiler is usually cc, and --version works on gcc and clang
                &["cc", "--version"],
                // but on some platforms gcc is installed as *gcc*, not cc
                &["gcc", "--version"],
                // for completeness, although I've never seen a clang that wasn't cc
                &["clang", "--version"],
            ])
        });

        formatter
            .map_meta(|var, _| match var {
                "symbol" => Some(config.symbol),
                _ => None,
            })
            .map_style(|variable| match variable {
                "style" => Some(Ok(config.style)),
                _ => None,
            })
            .map(|variable| match variable {
                "compiler_name" => {
                    let c_compiler_info = &c_compiler_info.deref().as_ref()?.stdout;

                    let c_compiler = if c_compiler_info.contains("clang") {
                        "clang"
                    } else if c_compiler_info.contains("Free Software Foundation") {
                        "gcc"
                    } else {
                        "Unknown compiler"
                    };
                    Some(c_compiler).map(Cow::Borrowed).map(Ok)
                }

Review comment (suggestion):
I think it might be nice to make this configurable. Some people might use compiler variants like `zig cc` and `arm-none-eabi-gcc`.

Code after:
use std::borrow::Cow;
use std::ops::Deref;

/// Creates a module with the current C compiler and version
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
    let mut module = context.new_module("c");
    let config: CConfig = CConfig::try_load(module.config);
    let is_c_project = context
        .try_begin_scan()?
        .set_extensions(&config.detect_extensions)
        .set_files(&config.detect_files)
        .set_folders(&config.detect_folders)
        .is_match();

    if !is_c_project {
        return None;
    }

    let parsed = StringFormatter::new(config.format).and_then(|formatter| {
        let c_compiler_info = Lazy::new(|| context.exec_cmds_return_first(config.commands));

        formatter
            .map_meta(|var, _| match var {
                "symbol" => Some(config.symbol),
                _ => None,
            })
            .map_style(|variable| match variable {
                "style" => Some(Ok(config.style)),
                _ => None,
            })
            .map(|variable| match variable {
                "name" => {
                    let c_compiler_info = &c_compiler_info.deref().as_ref()?.stdout;

                    let c_compiler = if c_compiler_info.contains("clang") {
                        "clang"
                    } else if c_compiler_info.contains("Free Software Foundation") {
                        "gcc"
                    } else {
                        return None;
                    };
                    Some(c_compiler).map(Cow::Borrowed).map(Ok)
                }
                "version" => {
                    let c_compiler_info = &c_compiler_info.deref().as_ref()?.stdout;

                    // Clang says ...
                    //   Apple clang version 13.0.0 ...\n
                    //   OpenBSD clang version 11.1.0\n...
                    //   FreeBSD clang version 11.0.1 ...\n
                    // so we always want the first semver-ish whitespace-