diff --git a/docs/config/README.md b/docs/config/README.md index 6b9a6c1324ee..911d819a95cb 100644 --- a/docs/config/README.md +++ b/docs/config/README.md @@ -199,6 +199,7 @@ $docker_context\ $package\ $cmake\ $dart\ +$deno\ $dotnet\ $elixir\ $elm\ @@ -650,6 +651,41 @@ By default the module will be shown if any of the following conditions are met: format = "via [🔰 $version](bold red) " ``` +## Deno + +The `deno` module shows you your currently installed version of Deno. +By default the module will be shown if any of the following conditions are met: +- The current directory contains a `mod.ts`, `mod.js`, `deps.ts` or `deps.js` file + +### Options + +| Option | Default | Description | +| ------------------- | ------------------------------------------------- | ----------------------------------------------- | +| `format` | `"via [$symbol($version )]($style)"` | The format for the module. | +| `symbol` | `"🦕 "` | A format string representing the symbol of Deno | +| `detect_extensions` | `[]` | Which extensions should trigger this module. | +| `detect_files` | `["mod.ts", "mod.js", "deps.ts", "deps.js"]` | Which filenames should trigger this module. | +| `detect_folders` | `[]` | Which folders should trigger this module. | +| `style` | `"green bold"` | The style for the module. | +| `disabled` | `false` | Disables the `deno` module. | + +### Variables + +| Variable | Example | Description | +| -------- | -------- | ------------------------------------ | +| version | `v1.8.3` | The version of `deno` | +| symbol | | Mirrors the value of option `symbol` | +| style\* | | Mirrors the value of option `style` | + +### Example + +```toml +# ~/.config/starship.toml + +[deno] +format = "via [🦕 $version](green bold) " +``` + ## Directory The `directory` module shows the path to your current directory, truncated to diff --git a/src/configs/deno.rs b/src/configs/deno.rs new file mode 100644 index 000000000000..398178430cdf --- /dev/null +++ b/src/configs/deno.rs @@ -0,0 +1,29 @@ +use crate::config::ModuleConfig; + +use serde::Serialize; +use starship_module_config_derive::ModuleConfig; + +#[derive(Clone, ModuleConfig, Serialize)] +pub struct DenoConfig<'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 DenoConfig<'a> { + fn default() -> Self { + DenoConfig { + format: "via [$symbol($version )]($style)", + symbol: "🦕 ", + style: "green bold", + disabled: false, + detect_extensions: vec![], + detect_files: vec!["mod.ts", "deps.ts", "mod.js", "deps.js"], + detect_folders: vec![], + } + } +} diff --git a/src/configs/mod.rs b/src/configs/mod.rs index 559d0040d4d8..636284835b9b 100644 --- a/src/configs/mod.rs +++ b/src/configs/mod.rs @@ -12,6 +12,7 @@ pub mod conda; pub mod crystal; pub mod custom; pub mod dart; +pub mod deno; pub mod directory; pub mod docker_context; pub mod dotnet; @@ -80,6 +81,7 @@ pub struct FullConfig<'a> { conda: conda::CondaConfig<'a>, crystal: crystal::CrystalConfig<'a>, dart: dart::DartConfig<'a>, + deno: deno::DenoConfig<'a>, directory: directory::DirectoryConfig<'a>, docker_context: docker_context::DockerContextConfig<'a>, dotnet: dotnet::DotnetConfig<'a>, diff --git a/src/configs/starship_root.rs b/src/configs/starship_root.rs index add0734ba8eb..b727aaf1597a 100644 --- a/src/configs/starship_root.rs +++ b/src/configs/starship_root.rs @@ -34,6 +34,7 @@ pub const PROMPT_ORDER: &[&str] = &[ // (Let's keep these sorted alphabetically) "cmake", "dart", + "deno", "dotnet", "elixir", "elm", diff --git a/src/module.rs b/src/module.rs index 63eaef4df304..7cd593f26839 100644 --- a/src/module.rs +++ b/src/module.rs @@ -17,6 +17,7 @@ pub const ALL_MODULES: &[&str] = &[ "cmd_duration", "conda", "dart", + "deno", "directory", "docker_context", "dotnet", diff --git a/src/modules/deno.rs b/src/modules/deno.rs new file mode 100644 index 000000000000..8b1fac5fe376 --- /dev/null +++ b/src/modules/deno.rs @@ -0,0 +1,125 @@ +use super::{Context, Module, RootModuleConfig}; + +use crate::configs::deno::DenoConfig; +use crate::formatter::StringFormatter; + +/// Creates a module with the current Deno version +pub fn module<'a>(context: &'a Context) -> Option> { + let mut module = context.new_module("deno"); + let config = DenoConfig::try_load(module.config); + let is_deno_project = context + .try_begin_scan()? + .set_files(&config.detect_files) + .is_match(); + + if !is_deno_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("deno", &["-V"]) + .and_then(|output| parse_deno_version(output.stdout.trim())) + .map(Ok), + _ => None, + }) + .parse(None) + }); + + module.set_segments(match parsed { + Ok(segments) => segments, + Err(error) => { + log::warn!("Error in module `deno`:\n{}", error); + return None; + } + }); + + Some(module) +} + +fn parse_deno_version(deno_version: &str) -> Option { + let version = deno_version + // split into ["deno", "1.8.3"] + .split_whitespace() + // return "1.8.3" + .nth(1)?; + + Some(format!("v{}", version)) +} + +#[cfg(test)] +mod tests { + use super::parse_deno_version; + use crate::test::ModuleRenderer; + use ansi_term::Color; + use std::fs::File; + use std::io; + + #[test] + fn test_parse_deno_version() { + const OUTPUT: &str = "deno 1.8.3\n"; + assert_eq!( + parse_deno_version(OUTPUT.trim()), + Some("v1.8.3".to_string()) + ) + } + + #[test] + fn folder_without_deno_files() -> io::Result<()> { + let dir = tempfile::tempdir()?; + let actual = ModuleRenderer::new("deno").path(dir.path()).collect(); + let expected = None; + assert_eq!(expected, actual); + dir.close() + } + + #[test] + fn folder_with_mod_ts() -> io::Result<()> { + let dir = tempfile::tempdir()?; + File::create(dir.path().join("mod.ts"))?.sync_all()?; + let actual = ModuleRenderer::new("deno").path(dir.path()).collect(); + let expected = Some(format!("via {}", Color::Green.bold().paint("🦕 v1.8.3 "))); + assert_eq!(expected, actual); + dir.close() + } + + #[test] + fn folder_with_mod_js() -> io::Result<()> { + let dir = tempfile::tempdir()?; + File::create(dir.path().join("mod.js"))?.sync_all()?; + let actual = ModuleRenderer::new("deno").path(dir.path()).collect(); + let expected = Some(format!("via {}", Color::Green.bold().paint("🦕 v1.8.3 "))); + assert_eq!(expected, actual); + dir.close() + } + + #[test] + fn folder_with_deps_ts() -> io::Result<()> { + let dir = tempfile::tempdir()?; + File::create(dir.path().join("deps.ts"))?.sync_all()?; + let actual = ModuleRenderer::new("deno").path(dir.path()).collect(); + let expected = Some(format!("via {}", Color::Green.bold().paint("🦕 v1.8.3 "))); + assert_eq!(expected, actual); + dir.close() + } + + #[test] + fn folder_with_deps_js() -> io::Result<()> { + let dir = tempfile::tempdir()?; + File::create(dir.path().join("deps.js"))?.sync_all()?; + let actual = ModuleRenderer::new("deno").path(dir.path()).collect(); + let expected = Some(format!("via {}", Color::Green.bold().paint("🦕 v1.8.3 "))); + assert_eq!(expected, actual); + dir.close() + } +} diff --git a/src/modules/mod.rs b/src/modules/mod.rs index 39e3b86d126b..c3fd6e6587ac 100644 --- a/src/modules/mod.rs +++ b/src/modules/mod.rs @@ -7,6 +7,7 @@ mod conda; mod crystal; pub(crate) mod custom; mod dart; +mod deno; mod directory; mod docker_context; mod dotnet; @@ -80,6 +81,7 @@ pub fn handle<'a>(module: &str, context: &'a Context) -> Option> { "cmd_duration" => cmd_duration::module(context), "conda" => conda::module(context), "dart" => dart::module(context), + "deno" => deno::module(context), "directory" => directory::module(context), "docker_context" => docker_context::module(context), "dotnet" => dotnet::module(context), @@ -162,6 +164,7 @@ pub fn description(module: &str) -> &'static str { "conda" => "The current conda environment, if $CONDA_DEFAULT_ENV is set", "crystal" => "The currently installed version of Crystal", "dart" => "The currently installed version of Dart", + "deno" => "The currently installed version of Deno", "directory" => "The current working directory", "docker_context" => "The current docker context", "dotnet" => "The relevant version of the .NET Core SDK for the current directory", diff --git a/src/utils.rs b/src/utils.rs index 381a628fdc7a..45ea07f2aa6f 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -57,6 +57,10 @@ Default target: x86_64-apple-macosx\n", "Dart VM version: 2.8.4 (stable) (Wed Jun 3 12:26:04 2020 +0200) on \"macos_x64\"", ), }), + "deno -V" => Some(CommandOutput { + stdout: String::from("deno 1.8.3\n"), + stderr: String::default() + }), "dummy_command" => Some(CommandOutput { stdout: String::from("stdout ok!\n"), stderr: String::from("stderr ok!\n"),