ronantakizawa/codereview-bench huggingface dataset:
Repository: starship/starship
File: src/modules/typst.rs (Rust)

Code before:
            return None;
        }
    });

    Some(module)
}

fn get_typst_config(context: &Context) -> Option<String> {
    Some(
        context
            .exec_cmd("typst", &["--version"])?
            .stdout
            .trim()
            .to_string()
            .as_str()[6..11]
            .trim()
            .to_string(),
    )
}

fn get_version(context: &Context) -> Option<String> {
    get_typst_config(context)
}
#[cfg(test)]
mod tests {
    use crate::test::ModuleRenderer;
    use nu_ansi_term::Color;
    use std::fs::File;
    use std::io;
    #[test]
    fn read_typst_not_present() -> io::Result<()> {
        let dir = tempfile::tempdir()?;

        let actual = ModuleRenderer::new("typst").path(dir.path()).collect();

        let expected = None;
        assert_eq!(expected, actual);
        dir.close()
    }

    #[test]
    fn read_typst_present() -> io::Result<()> {
        let dir = tempfile::tempdir()?;

        File::create(dir.path().join("test.typ"))?.sync_all()?;

        let actual = ModuleRenderer::new("typst").path(dir.path()).collect();
        let expected = Some(format!(
            "via {}",
            Color::Rgb(0, 147, 167).bold().paint("𝐭 0.8.0 ")
        ));

Review comment (suggestion):
The length and position of the version number might change in the instance, for instance, once it hits `v0.10`. Please use `split_whitespace` instead (perhaps with `strip_prefix("typst ")` first).

Code after:
            .parse(None, Some(context))
    });

    module.set_segments(match parsed {
        Ok(segments) => segments,
        Err(error) => {
            log::warn!("Error in module `typst`:\n{}", error);
            return None;
        }
    });

    Some(module)
}

fn get_typst_config(context: &Context) -> Option<String> {
    context
        .exec_cmd("typst", &["--version"])?
        .stdout
        .trim()
        .strip_prefix("typst ")
        .and_then(|version| version.split_whitespace().next().map(ToOwned::to_owned))
}

#[cfg(test)]
mod tests {
    use crate::test::ModuleRenderer;
    use nu_ansi_term::Color;
    use std::fs::File;
    use std::io;
    #[test]
    fn read_typst_not_present() -> io::Result<()> {
        let dir = tempfile::tempdir()?;

        let actual = ModuleRenderer::new("typst").path(dir.path()).collect();

        let expected = None;
        assert_eq!(expected, actual);
        dir.close()
    }

    #[test]
    fn read_typst_present() -> io::Result<()> {
        let dir = tempfile::tempdir()?;

        File::create(dir.path().join("test.typ"))?.sync_all()?;

        let actual = ModuleRenderer::new("typst").path(dir.path()).collect();
        let expected = Some(format!(
            "via {}",
            Color::Rgb(0, 147, 167).bold().paint("t v0.10 ")
        ));
Repository: starship/starship
File: src/modules/typst.rs (Rust)

Code before:
    });

    module.set_segments(match parsed {
        Ok(segments) => segments,
        Err(error) => {
            log::warn!("Error in module `typst`:\n{}", error);
            return None;
        }
    });

    Some(module)
}

fn get_typst_config(context: &Context) -> Option<String> {
    Some(
        context
            .exec_cmd("typst", &["--version"])?
            .stdout
            .trim()
            .strip_prefix("typst ")
            .unwrap()
            .split_whitespace()
            .next()
            .unwrap()
            .to_string(),
    )
}

#[cfg(test)]
mod tests {
    use crate::test::ModuleRenderer;
    use nu_ansi_term::Color;
    use std::fs::File;
    use std::io;
    #[test]
    fn read_typst_not_present() -> io::Result<()> {
        let dir = tempfile::tempdir()?;

        let actual = ModuleRenderer::new("typst").path(dir.path()).collect();

        let expected = None;
        assert_eq!(expected, actual);
        dir.close()
    }

    #[test]
    fn read_typst_present() -> io::Result<()> {
        let dir = tempfile::tempdir()?;

        File::create(dir.path().join("test.typ"))?.sync_all()?;


Review comment (suggestion):
Please avoid calling `unwrap()` to prevent the program from exiting on error:

```suggestion
    context
        .exec_cmd("typst", &["--version"])?
        .stdout
        .trim()
        .strip_prefix("typst ")
        .and_then(|version| version.split_whitespace().next().map(ToOwned::to_owned))
```

Code after:
    });

    module.set_segments(match parsed {
        Ok(segments) => segments,
        Err(error) => {
            log::warn!("Error in module `typst`:\n{}", error);
            return None;
        }
    });

    Some(module)
}

fn get_typst_config(context: &Context) -> Option<String> {
    context
        .exec_cmd("typst", &["--version"])?
        .stdout
        .trim()
        .strip_prefix("typst ")
        .and_then(|version| version.split_whitespace().next().map(ToOwned::to_owned))
}

#[cfg(test)]
mod tests {
    use crate::test::ModuleRenderer;
    use nu_ansi_term::Color;
    use std::fs::File;
    use std::io;
    #[test]
    fn read_typst_not_present() -> io::Result<()> {
        let dir = tempfile::tempdir()?;

        let actual = ModuleRenderer::new("typst").path(dir.path()).collect();

        let expected = None;
        assert_eq!(expected, actual);
        dir.close()
    }

    #[test]
    fn read_typst_present() -> io::Result<()> {
        let dir = tempfile::tempdir()?;

        File::create(dir.path().join("test.typ"))?.sync_all()?;

        let actual = ModuleRenderer::new("typst").path(dir.path()).collect();
        let expected = Some(format!(
            "via {}",
            Color::Rgb(0, 147, 167).bold().paint("t v0.10 ")
        ));
        assert_eq!(expected, actual);
Repository: starship/starship
File: src/configs/mise.rs (Rust)

Code before:
use serde::{Deserialize, Serialize};

#[derive(Clone, Deserialize, Serialize)]
#[cfg_attr(
    feature = "config-schema",
    derive(schemars::JsonSchema),
    schemars(deny_unknown_fields)
)]
#[serde(default)]
pub struct MiseConfig<'a> {
    pub format: &'a str,
    pub symbol: &'a str,
    pub style: &'a str,
    pub disabled: bool,
    pub detect_extensions: Vec<&'a str>,
    pub detect_files: Vec<&'a str>,
    pub detect_folders: Vec<&'a str>,
    pub healthy_symbol: &'a str,
    pub unhealthy_symbol: &'a str,
}

impl<'a> Default for MiseConfig<'a> {
    fn default() -> Self {
        Self {
            format: "[$symbol$health]($style) ",
            symbol: "mise ",
            style: "bold purple",
            disabled: true,
            detect_extensions: vec![],
            detect_files: vec![
                "mise.toml",
                "mise.local.toml",
                ".mise.toml",
                ".mise.local.toml",
            ],
            detect_folders: vec![".mise"],
            healthy_symbol: "healthy",
            unhealthy_symbol: "unhealthy",
        }
    }
}


Review comment (suggestion):
To make current clippy happy:
```suggestion
impl Default for MiseConfig<'_> {
```

Code after:
use serde::{Deserialize, Serialize};

#[derive(Clone, Deserialize, Serialize)]
#[cfg_attr(
    feature = "config-schema",
    derive(schemars::JsonSchema),
    schemars(deny_unknown_fields)
)]
#[serde(default)]
pub struct MiseConfig<'a> {
    pub format: &'a str,
    pub symbol: &'a str,
    pub style: &'a str,
    pub disabled: bool,
    pub detect_extensions: Vec<&'a str>,
    pub detect_files: Vec<&'a str>,
    pub detect_folders: Vec<&'a str>,
    pub healthy_symbol: &'a str,
    pub unhealthy_symbol: &'a str,
}

impl Default for MiseConfig<'_> {
    fn default() -> Self {
        Self {
            format: "[$symbol$health]($style) ",
            symbol: "mise ",
            style: "bold purple",
            disabled: true,
            detect_extensions: vec![],
            detect_files: vec![
                "mise.toml",
                "mise.local.toml",
                ".mise.toml",
                ".mise.local.toml",
            ],
            detect_folders: vec![".mise"],
            healthy_symbol: "healthy",
            unhealthy_symbol: "unhealthy",
        }
    }
}
Repository: starship/starship
File: src/modules/odin.rs (Rust)

Code before:
    Some(module)
}

#[cfg(test)]
mod tests {
    use crate::test::ModuleRenderer;
    use nu_ansi_term::Color;
    use std::fs::File;
    use std::io;

    #[test]
    fn folder_without_odin() -> io::Result<()> {
        let dir = tempfile::tempdir()?;
        File::create(dir.path().join("odin.txt"))?.sync_all()?;
        let actual = ModuleRenderer::new("odin").path(dir.path()).collect();
        let expected = None;
        assert_eq!(expected, actual);
        dir.close()
    }

    #[test]
    fn folder_with_odin_file() -> io::Result<()> {
        let dir = tempfile::tempdir()?;
        File::create(dir.path().join("main.odin"))?.sync_all()?;
        let actual = ModuleRenderer::new("odin").path(dir.path()).collect();
        let expected = Some(format!(
            "via {}",
            Color::LightBlue.bold().paint("Ø dev-2024-03 ")
        ));
        assert_eq!(expected, actual);
        dir.close()
    }
}


Review comment (suggestion):
Please add a test that mocks the odin command to an output without the extra hash (my build does not have it), e.g. `"odin version dev-2024-03\n"`. You can use `cmd` from `ModuleRenderer`

Code after:
    Some(module)
}

#[cfg(test)]
mod tests {
    use crate::test::ModuleRenderer;
    use crate::utils::CommandOutput;
    use nu_ansi_term::Color;
    use std::fs::File;
    use std::io;

    #[test]
    fn folder_without_odin() -> io::Result<()> {
        let dir = tempfile::tempdir()?;
        File::create(dir.path().join("odin.txt"))?.sync_all()?;
        let actual = ModuleRenderer::new("odin").path(dir.path()).collect();
        let expected = None;
        assert_eq!(expected, actual);
        dir.close()
    }

    #[test]
    fn folder_with_odin_file() -> io::Result<()> {
        let dir = tempfile::tempdir()?;
        File::create(dir.path().join("main.odin"))?.sync_all()?;
        let actual = ModuleRenderer::new("odin").path(dir.path()).collect();
        let expected = Some(format!(
            "via {}",
            Color::LightBlue.bold().paint("Ø dev-2024-03 ")
        ));
        assert_eq!(expected, actual);
        dir.close()
    }

    #[test]
    fn folder_with_odin_file_without_commit() -> io::Result<()> {
        let dir = tempfile::tempdir()?;
        File::create(dir.path().join("main.odin"))?.sync_all()?;
        let actual = ModuleRenderer::new("odin")
            .cmd(
                "odin version",
                Some(CommandOutput {
                    stdout: String::from("odin version dev-2024-03\n"),
                    stderr: String::default(),
                }),
            )
            .path(dir.path())
            .collect();
        let expected = Some(format!(
            "via {}",
            Color::LightBlue.bold().paint("Ø dev-2024-03 ")
Repository: starship/starship
File: src/modules/nats.rs (Rust)

Code before:
use super::{Context, Module, ModuleConfig};
use serde_json as json;

use crate::configs::nats::NatsConfig;
use crate::formatter::StringFormatter;

pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
    let mut module = context.new_module("nats");
    let config = NatsConfig::try_load(module.config);

    if config.disabled {
        return None;
    };

    let ctx_str = context
        .exec_cmd("nats", &["context", "info", "--json"])?
        .stdout;
    let nats_context: json::Value = json::from_str(&ctx_str).ok()?;
    let name = nats_context.get("name")?.as_str()?;

    let parsed = StringFormatter::new(config.format).and_then(|formatter| {
        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" => Some(Ok(name)),
                _ => None,
            })
            .parse(None, Some(context))
    });

    module.set_segments(match parsed {
        Ok(segments) => segments,
        Err(error) => {
            log::warn!("Error in module `nats`:\n{}", error);
            return None;
        }
    });

Review comment (bug):
I feel like failure to parse the JSON should be logged here.
Additionally, I would prefer to move the `nats_context.get("name")` into the `name =>` `match`, but you can skip that if that causes any issues.

Code after:
use super::{Context, Module, ModuleConfig};
use serde_json as json;

use crate::configs::nats::NatsConfig;
use crate::formatter::StringFormatter;

pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
    let mut module = context.new_module("nats");
    let config = NatsConfig::try_load(module.config);

    if config.disabled {
        return None;
    };

    let ctx_str = context
        .exec_cmd("nats", &["context", "info", "--json"])?
        .stdout;
    let nats_context: json::Value = json::from_str(&ctx_str)
        .map_err(|e| {
            log::warn!("Error parsing nats context JSON: {}\n", e);
            drop(e);
        })
        .ok()?;

    let parsed = StringFormatter::new(config.format).and_then(|formatter| {
        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" => Some(Ok(nats_context.get("name")?.as_str()?)),
                _ => None,
            })
            .parse(None, Some(context))
    });

    module.set_segments(match parsed {
        Ok(segments) => segments,
        Err(error) => {
Repository: starship/starship
File: src/modules/nats.rs (Rust)

Code before:
    });

    Some(module)
}

#[cfg(test)]
mod tests {
    use nu_ansi_term::Color;
    use std::io;

    use crate::test::ModuleRenderer;

    #[test]
    fn show_context() -> io::Result<()> {
        let actual = ModuleRenderer::new("nats")
            .config(
                toml::from_str(&format!(
                    "
                [nats]
                format = \"[$symbol$name](bold purple)\"
                symbol = \"\"
                disabled = false
                "
                ))
                .unwrap(),
            )
            .collect();
        let expected = Some(format!("{}", Color::Purple.bold().paint("localhost")));
        assert_eq!(expected, actual);
        Ok(())
    }

    #[test]
    fn test_with_symbol() -> io::Result<()> {
        let actual = ModuleRenderer::new("nats")
            .config(
                toml::from_str(&format!(
                    "
                [nats]
                format = \"[$symbol$name](bold red)\"
                symbol = \"N \"
                disabled = false
                "
                ))
                .unwrap(),
            )
            .collect();
        let expected = Some(format!("{}", Color::Red.bold().paint("N localhost")));
        assert_eq!(expected, actual);
        Ok(())
    }

Review comment (suggestion):
```suggestion
            .config(toml::toml! {
                [nats]
                format = "[$symbol$name](bold purple)"
                symbol = ""
                disabled = false
            })
```

Code after:
    });

    Some(module)
}

#[cfg(test)]
mod tests {
    use nu_ansi_term::Color;
    use std::io;

    use crate::test::ModuleRenderer;

    #[test]
    fn show_context() -> io::Result<()> {
        let actual = ModuleRenderer::new("nats")
            .config(toml::toml! {
                [nats]
                format = "[$symbol$name](bold purple)"
                symbol = ""
                disabled = false
            })
            .collect();
        let expected = Some(format!("{}", Color::Purple.bold().paint("localhost")));
        assert_eq!(expected, actual);
        Ok(())
    }

    #[test]
    fn test_with_symbol() -> io::Result<()> {
        let actual = ModuleRenderer::new("nats")
            .config(toml::toml! {
                [nats]
                format = "[$symbol$name](bold red)"
                symbol = "✉️ "
                disabled = false
            })
            .collect();
        let expected = Some(format!("{}", Color::Red.bold().paint("✉️ localhost")));
        assert_eq!(expected, actual);
        Ok(())
    }
}
Repository: starship/starship
File: src/configs/nats.rs (Rust)

Code before:
use serde::{Deserialize, Serialize};

#[derive(Clone, Deserialize, Serialize)]
#[cfg_attr(
    feature = "config-schema",
    derive(schemars::JsonSchema),
    schemars(deny_unknown_fields)
)]
#[serde(default)]
pub struct NatsConfig<'a> {
    pub format: &'a str,
    pub symbol: &'a str,
    pub style: &'a str,
    pub disabled: bool,
}

impl<'a> Default for NatsConfig<'a> {
    fn default() -> Self {
        NatsConfig {
            format: "[$symbol$name]($style)",
            symbol: "✉️ ",
            style: "bold purple",
            disabled: true,
        }
    }
}


Review comment (suggestion):
This should have more space, please also update the docs and config schema:
```suggestion
            format: "[$symbol($name )]($style)",
```

Code after:
use serde::{Deserialize, Serialize};

#[derive(Clone, Deserialize, Serialize)]
#[cfg_attr(
    feature = "config-schema",
    derive(schemars::JsonSchema),
    schemars(deny_unknown_fields)
)]
#[serde(default)]
pub struct NatsConfig<'a> {
    pub format: &'a str,
    pub symbol: &'a str,
    pub style: &'a str,
    pub disabled: bool,
}

impl<'a> Default for NatsConfig<'a> {
    fn default() -> Self {
        NatsConfig {
            format: "[$symbol($name )]($style)",
            symbol: "✉️ ",
            style: "bold purple",
            disabled: true,
        }
    }
}
Repository: starship/starship
File: src/modules/kubernetes.rs (Rust)

Code before:
                _ => None,
            })
            .parse(None, Some(context))
    });

    module.set_segments(match parsed {
        Ok(segments) => segments,
        Err(error) => {
            log::warn!("Error in module `kubernetes`: \n{}", error);
            return None;
        }
    });

    Some(module)
}

fn parse_kubeconfigs<I>(raw_kubeconfigs: I) -> Vec<Document>
where
    I: Iterator<Item = Option<String>>,
{
    raw_kubeconfigs
        .filter_map(|content| match content {
            Some(value) => match value.chars().next() {
                // Parsing as json is about an order of magnitude faster than parsing
                // as yaml, so do that if possible.
                Some('{') => serde_json::from_str(&value).ok().map(Document::Json),
                _ => YamlLoader::load_from_str(&value)
                    .ok()
                    .into_iter()
                    .find_map(|yaml| yaml.first().map(|yaml| Document::Yaml(yaml.clone()))),
            },
            _ => None,
        })
        .collect()
}

mod deprecated {
    use std::borrow::Cow;
    use std::collections::HashMap;

    pub fn get_alias<'a>(
        current_value: String,
        aliases: &'a HashMap<String, &'a str>,
        name: &'a str,
    ) -> Option<String> {
        let alias = if let Some(val) = aliases.get(current_value.as_str()) {
            // simple match without regex
            Some((*val).to_string())
        } else {
            // regex match
            aliases.iter().find_map(|(k, v)| {

Review comment (bug):
I would prefer to fall back to `YamlLoader::load_from_str` if `serde_json::from_str` fails, even if the first character is `{`.

Code after:
                _ => None,
            })
            .parse(None, Some(context))
    });

    module.set_segments(match parsed {
        Ok(segments) => segments,
        Err(error) => {
            log::warn!("Error in module `kubernetes`: \n{}", error);
            return None;
        }
    });

    Some(module)
}

fn parse_kubeconfigs<I>(raw_kubeconfigs: I) -> Vec<Document>
where
    I: Iterator<Item = Option<String>>,
{
    raw_kubeconfigs
        .filter_map(|content| match content {
            Some(value) => match value.chars().next() {
                // Parsing as json is about an order of magnitude faster than parsing
                // as yaml, so do that if possible.
                Some('{') => match serde_json::from_str(&value) {
                    Ok(json) => Some(Document::Json(json)),
                    Err(_) => parse_yaml(&value),
                },
                _ => parse_yaml(&value),
            },
            _ => None,
        })
        .collect()
}

fn parse_yaml(s: &str) -> Option<Document> {
    YamlLoader::load_from_str(s)
        .ok()
        .and_then(|yaml| yaml.into_iter().next().map(Document::Yaml))
}

mod deprecated {
    use std::borrow::Cow;
    use std::collections::HashMap;

    pub fn get_alias<'a>(
        current_value: String,
        aliases: &'a HashMap<String, &'a str>,
        name: &'a str,
    ) -> Option<String> {
Repository: starship/starship
File: src/modules/python.rs (Rust)

Code before:
fn parse_python_version(python_version_string: &str) -> Option<String> {
    let version = python_version_string
        // split into ["Python", "3.8.6", ...]
        .split_whitespace()
        // get down to "3.8.6"
        .nth(1)?;

    Some(version.to_string())
}

fn get_python_virtual_env(context: &Context) -> Option<String> {
    context.get_env("VIRTUAL_ENV").and_then(|venv| {
        get_prompt_from_venv(Path::new(&venv)).or_else(|| {
            Path::new(&venv)
                .file_name()
                .map(|filename| String::from(filename.to_str().unwrap_or("")))
        })
    })
}

fn get_prompt_from_venv(venv_path: &Path) -> Option<String> {
    Ini::load_from_file_noescape(venv_path.join("pyvenv.cfg"))
        .ok()?
        .general_section()
        .get("prompt")
        .map(|prompt| String::from(prompt.replace("\\", "/").trim_matches(&['(', ')'] as &[_])))
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::test::ModuleRenderer;
    use nu_ansi_term::Color;
    use std::fs::{create_dir_all, File};
    use std::io;
    use std::io::Write;

    #[test]
    fn test_parse_python_version() {
        assert_eq!(
            parse_python_version("Python 3.7.2"),
            Some("3.7.2".to_string())
        );
    }

    #[test]
    fn test_parse_python_version_is_malformed() {
        assert_eq!(parse_python_version("Python 3.7"), Some("3.7".to_string()));
    }

    #[test]

Review comment (security):
This should not be necessary with `load_from_file_noescape`
```suggestion
        .map(|prompt| String::from(prompt.trim_matches(&['(', ')'] as &[_])))
```

Code after:
fn parse_python_version(python_version_string: &str) -> Option<String> {
    let version = python_version_string
        // split into ["Python", "3.8.6", ...]
        .split_whitespace()
        // get down to "3.8.6"
        .nth(1)?;

    Some(version.to_string())
}

fn get_python_virtual_env(context: &Context) -> Option<String> {
    context.get_env("VIRTUAL_ENV").and_then(|venv| {
        get_prompt_from_venv(Path::new(&venv)).or_else(|| {
            Path::new(&venv)
                .file_name()
                .map(|filename| String::from(filename.to_str().unwrap_or("")))
        })
    })
}

fn get_prompt_from_venv(venv_path: &Path) -> Option<String> {
    Ini::load_from_file_noescape(venv_path.join("pyvenv.cfg"))
        .ok()?
        .general_section()
        .get("prompt")
        .map(|prompt| String::from(prompt.trim_matches(&['(', ')'] as &[_])))
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::test::ModuleRenderer;
    use nu_ansi_term::Color;
    use std::fs::{create_dir_all, File};
    use std::io;
    use std::io::Write;

    #[test]
    fn test_parse_python_version() {
        assert_eq!(
            parse_python_version("Python 3.7.2"),
            Some("3.7.2".to_string())
        );
    }

    #[test]
    fn test_parse_python_version_is_malformed() {
        assert_eq!(parse_python_version("Python 3.7"), Some("3.7".to_string()));
    }

    #[test]