diff --git a/docs/config/README.md b/docs/config/README.md index b7e53246b245..643867c6c2a1 100644 --- a/docs/config/README.md +++ b/docs/config/README.md @@ -217,6 +217,7 @@ $perl\ $php\ $purescript\ $python\ +$red\ $ruby\ $rust\ $scala\ @@ -2243,6 +2244,45 @@ python_binary = "python3" detect_extensions = [] ``` +## Red + +By default the `red` module shows the currently installed version of Red. +The module will be shown if any of the following conditions are met: + +- The current directory contains a file with `.red` or `.reds` extension + +### Options + +| Option | Default | Description | +| ------------------- | ------------------------------------ | ------------------------------------------------------------------------- | +| `format` | `"via [$symbol($version )]($style)"` | The format for the module. | +| `version_format` | `v{raw}` | The version format. Available vars are `raw`, `major`, `minor`, & `patch` | +| `symbol` | `"🔺 "` | A format string representing the symbol of Red. | +| `detect_extensions` | `["red"]` | Which extensions should trigger this module. | +| `detect_files` | `[]` | Which filenames should trigger this module. | +| `detect_folders` | `[]` | Which folders should trigger this module. | +| `style` | `"red bold"` | The style for the module. | +| `disabled` | `false` | Disables the `red` module. | + +### Variables + +| Variable | Example | Description | +| -------- | -------- | ------------------------------------ | +| version | `v2.5.1` | The version of `red` | +| symbol | | Mirrors the value of option `symbol` | +| style\* | | Mirrors the value of option `style` | + +\*: This variable can only be used as a part of a style string + +### Example + +```toml +# ~/.config/starship.toml + +[red] +symbol = "🔴 " +``` + ## Ruby By default the `ruby` module shows the currently installed version of Ruby. diff --git a/src/configs/mod.rs b/src/configs/mod.rs index 636284835b9b..1204bd87bf36 100644 --- a/src/configs/mod.rs +++ b/src/configs/mod.rs @@ -46,6 +46,7 @@ pub mod perl; pub mod php; pub mod purescript; pub mod python; +pub mod red; pub mod ruby; pub mod rust; pub mod scala; @@ -115,6 +116,7 @@ pub struct FullConfig<'a> { php: php::PhpConfig<'a>, purescript: purescript::PureScriptConfig<'a>, python: python::PythonConfig<'a>, + red: red::RedConfig<'a>, ruby: ruby::RubyConfig<'a>, rust: rust::RustConfig<'a>, scala: scala::ScalaConfig<'a>, diff --git a/src/configs/red.rs b/src/configs/red.rs new file mode 100644 index 000000000000..2f18bc95b384 --- /dev/null +++ b/src/configs/red.rs @@ -0,0 +1,29 @@ +use crate::config::ModuleConfig; + +use serde::Serialize; +use starship_module_config_derive::ModuleConfig; + +#[derive(Clone, ModuleConfig, Serialize)] +pub struct RedConfig<'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>, +} + +impl<'a> Default for RedConfig<'a> { + fn default() -> Self { + RedConfig { + format: "via [$symbol($version )]($style)", + symbol: "🔺 ", + style: "red bold", + disabled: false, + detect_extensions: vec!["red", "reds"], + detect_files: vec![], + detect_folders: vec![], + } + } +} diff --git a/src/configs/starship_root.rs b/src/configs/starship_root.rs index b727aaf1597a..b04d0cfef8f7 100644 --- a/src/configs/starship_root.rs +++ b/src/configs/starship_root.rs @@ -52,6 +52,7 @@ pub const PROMPT_ORDER: &[&str] = &[ "php", "purescript", "python", + "red", "ruby", "rust", "scala", diff --git a/src/module.rs b/src/module.rs index 7cd593f26839..cee9f357fc9b 100644 --- a/src/module.rs +++ b/src/module.rs @@ -52,6 +52,7 @@ pub const ALL_MODULES: &[&str] = &[ "perl", "purescript", "python", + "red", "ruby", "crystal", "rust", diff --git a/src/modules/mod.rs b/src/modules/mod.rs index c3fd6e6587ac..1d5eac0e506d 100644 --- a/src/modules/mod.rs +++ b/src/modules/mod.rs @@ -42,6 +42,7 @@ mod perl; mod php; mod purescript; mod python; +mod red; mod ruby; mod rust; mod scala; @@ -116,6 +117,7 @@ pub fn handle<'a>(module: &str, context: &'a Context) -> Option> { "php" => php::module(context), "purescript" => purescript::module(context), "python" => python::module(context), + "red" => red::module(context), "ruby" => ruby::module(context), "rust" => rust::module(context), "scala" => scala::module(context), @@ -197,6 +199,7 @@ pub fn description(module: &str) -> &'static str { "php" => "The currently installed version of PHP", "purescript" => "The currently installed version of PureScript", "python" => "The currently installed version of Python", + "red" => "The currently installed version of Red", "ruby" => "The currently installed version of Ruby", "rust" => "The currently installed version of Rust", "scala" => "The currently installed version of Scala", diff --git a/src/modules/red.rs b/src/modules/red.rs new file mode 100644 index 000000000000..5d2095339765 --- /dev/null +++ b/src/modules/red.rs @@ -0,0 +1,96 @@ +use super::{Context, Module, RootModuleConfig}; + +use crate::configs::red::RedConfig; +use crate::formatter::StringFormatter; + +/// Creates a module with the current Red version +pub fn module<'a>(context: &'a Context) -> Option> { + let mut module = context.new_module("red"); + let config = RedConfig::try_load(module.config); + let is_red_project = context + .try_begin_scan()? + .set_extensions(&config.detect_extensions) + .is_match(); + + if !is_red_project { + return None; + } + + 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 { + "version" => context + .exec_cmd("red", &["--version"]) + .map(|output| parse_red_version(output.stdout.trim())) + .map(Ok), + _ => None, + }) + .parse(None) + }); + + module.set_segments(match parsed { + Ok(segments) => segments, + Err(error) => { + log::warn!("Error in module `red`:\n{}", error); + return None; + } + }); + + Some(module) +} + +fn parse_red_version(red_version: &str) -> String { + format!("v{}", red_version) +} + +#[cfg(test)] +mod tests { + use super::parse_red_version; + use crate::test::ModuleRenderer; + use ansi_term::Color; + use std::fs::File; + use std::io; + + #[test] + fn test_parse_red_version() { + const OUTPUT: &str = "0.6.4\n"; + assert_eq!(parse_red_version(OUTPUT.trim()), "v0.6.4".to_string()) + } + + #[test] + fn folder_without_red_files() -> io::Result<()> { + let dir = tempfile::tempdir()?; + let actual = ModuleRenderer::new("red").path(dir.path()).collect(); + let expected = None; + assert_eq!(expected, actual); + dir.close() + } + + #[test] + fn folder_with_red_files() -> io::Result<()> { + let dir = tempfile::tempdir()?; + File::create(dir.path().join("hello.red"))?.sync_all()?; + let actual = ModuleRenderer::new("red").path(dir.path()).collect(); + let expected = Some(format!("via {}", Color::Red.bold().paint("🔺 v0.6.4 "))); + assert_eq!(expected, actual); + dir.close() + } + + #[test] + fn folder_with_reds_files() -> io::Result<()> { + let dir = tempfile::tempdir()?; + File::create(dir.path().join("hello.reds"))?.sync_all()?; + let actual = ModuleRenderer::new("red").path(dir.path()).collect(); + let expected = Some(format!("via {}", Color::Red.bold().paint("🔺 v0.6.4 "))); + assert_eq!(expected, actual); + dir.close() + } +} diff --git a/src/utils.rs b/src/utils.rs index 45ea07f2aa6f..32fd342f581f 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -168,6 +168,10 @@ active boot switches: -d:release\n", stdout: String::from("Python 3.8.0\n"), stderr: String::default(), }), + "red --version" => Some(CommandOutput { + stdout: String::from("0.6.4\n"), + stderr: String::default() + }), "ruby -v" => Some(CommandOutput { stdout: String::from("ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux-gnu]\n"), stderr: String::default(),