From 3014284e952f75deae87973cbe2763b7a0a0aab5 Mon Sep 17 00:00:00 2001 From: oyanoya <55138489+oyanoya@users.noreply.github.com> Date: Sun, 3 Apr 2022 15:33:14 +0200 Subject: [PATCH] feat(spack): Add `Spack` module (#3639) * feat/add readme + presets * feat/add spack module * feat/add spack config * feat/spack to handle * feat/add spack to modules and root * fix/readme formattign * fix/readme typo * fix/readme formatting * feat/replace module_config_derive with serde * feat/add macros to generate schema + schema --- .github/config-schema.json | 41 +++++++++ .../presets/toml/bracketed-segments.toml | 3 + .../presets/toml/nerd-font-symbols.toml | 3 + .../presets/toml/plain-text-symbols.toml | 3 + docs/config/README.md | 34 ++++++++ src/configs/mod.rs | 3 + src/configs/spack.rs | 24 ++++++ src/configs/starship_root.rs | 1 + src/module.rs | 1 + src/modules/mod.rs | 3 + src/modules/spack.rs | 84 +++++++++++++++++++ 11 files changed, 200 insertions(+) create mode 100644 src/configs/spack.rs create mode 100644 src/modules/spack.rs diff --git a/.github/config-schema.json b/.github/config-schema.json index 8f24c71f..d92700e6 100644 --- a/.github/config-schema.json +++ b/.github/config-schema.json @@ -1237,6 +1237,20 @@ } ] }, + "spack": { + "default": { + "disabled": false, + "format": "via [$symbol$environment]($style) ", + "style": "blue bold", + "symbol": "🅢 ", + "truncation_length": 1 + }, + "allOf": [ + { + "$ref": "#/definitions/SpackConfig" + } + ] + }, "status": { "default": { "disabled": true, @@ -4220,6 +4234,33 @@ } } }, + "SpackConfig": { + "type": "object", + "properties": { + "truncation_length": { + "default": 1, + "type": "integer", + "format": "uint", + "minimum": 0.0 + }, + "format": { + "default": "via [$symbol$environment]($style) ", + "type": "string" + }, + "symbol": { + "default": "🅢 ", + "type": "string" + }, + "style": { + "default": "blue bold", + "type": "string" + }, + "disabled": { + "default": false, + "type": "boolean" + } + } + }, "StatusConfig": { "type": "object", "properties": { diff --git a/docs/.vuepress/public/presets/toml/bracketed-segments.toml b/docs/.vuepress/public/presets/toml/bracketed-segments.toml index 5415079c..f2a13918 100644 --- a/docs/.vuepress/public/presets/toml/bracketed-segments.toml +++ b/docs/.vuepress/public/presets/toml/bracketed-segments.toml @@ -124,6 +124,9 @@ format = '\[[$symbol($version)]($style)\]' [scala] format = '\[[$symbol($version)]($style)\]' +[spack] +format = '\[[$symbol$environment]($style)\]' + [sudo] format = '\[[as $symbol]\]' diff --git a/docs/.vuepress/public/presets/toml/nerd-font-symbols.toml b/docs/.vuepress/public/presets/toml/nerd-font-symbols.toml index 8f7ab949..fea95e97 100644 --- a/docs/.vuepress/public/presets/toml/nerd-font-symbols.toml +++ b/docs/.vuepress/public/presets/toml/nerd-font-symbols.toml @@ -58,5 +58,8 @@ symbol = " " [package] symbol = " " +[spack] +symbol = "🅢 " + [rust] symbol = " " diff --git a/docs/.vuepress/public/presets/toml/plain-text-symbols.toml b/docs/.vuepress/public/presets/toml/plain-text-symbols.toml index 7764535c..ed9499d2 100644 --- a/docs/.vuepress/public/presets/toml/plain-text-symbols.toml +++ b/docs/.vuepress/public/presets/toml/plain-text-symbols.toml @@ -112,6 +112,9 @@ symbol = "rs " [scala] symbol = "scala " +[spack] +symbol = "spack " + [sudo] symbol = "sudo " diff --git a/docs/config/README.md b/docs/config/README.md index ea0ced6e..0dec040b 100644 --- a/docs/config/README.md +++ b/docs/config/README.md @@ -247,6 +247,7 @@ $vagrant\ $zig\ $nix_shell\ $conda\ +$spack\ $memory_usage\ $aws\ $gcloud\ @@ -3167,6 +3168,39 @@ and `$SINGULARITY_NAME` is set. format = '[📦 \[$env\]]($style) ' ``` +## Spack + +The `spack` module shows the current [Spack](https://spack.readthedocs.io/en/latest/) environment, if `$SPACK_ENV` is set. + +### Options + +| Option | Default | Description | +| ------------------- | -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | +| `truncation_length` | `1` | The number of directories the environment path should be truncated to. `0` means no truncation. Also see the [`directory`](#directory) module. | +| `symbol` | `"🅢 "` | The symbol used before the environment name. | +| `style` | `"bold blue"` | The style for the module. | +| `format` | `"via [$symbol$environment]($style) "` | The format for the module. | +| `disabled` | `false` | Disables the `spack` module. | + +### Variables + +| Variable | Example | Description | +| ----------- | ------------ | ------------------------------------ | +| environment | `astronauts` | The current spack environment | +| 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 + +[spack] +format = "[$symbol$environment](dimmed blue) " +``` + ## Status The `status` module displays the exit code of the previous command. diff --git a/src/configs/mod.rs b/src/configs/mod.rs index 0dc0228f..c34d36e6 100644 --- a/src/configs/mod.rs +++ b/src/configs/mod.rs @@ -63,6 +63,7 @@ pub mod scala; pub mod shell; pub mod shlvl; pub mod singularity; +pub mod spack; mod starship_root; pub mod status; pub mod sudo; @@ -210,6 +211,8 @@ pub struct FullConfig<'a> { #[serde(borrow)] singularity: singularity::SingularityConfig<'a>, #[serde(borrow)] + spack: spack::SpackConfig<'a>, + #[serde(borrow)] status: status::StatusConfig<'a>, #[serde(borrow)] sudo: sudo::SudoConfig<'a>, diff --git a/src/configs/spack.rs b/src/configs/spack.rs new file mode 100644 index 00000000..dfbc5eae --- /dev/null +++ b/src/configs/spack.rs @@ -0,0 +1,24 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Deserialize, Serialize)] +#[cfg_attr(feature = "config-schema", derive(schemars::JsonSchema))] +#[serde(default)] +pub struct SpackConfig<'a> { + pub truncation_length: usize, + pub format: &'a str, + pub symbol: &'a str, + pub style: &'a str, + pub disabled: bool, +} + +impl<'a> Default for SpackConfig<'a> { + fn default() -> Self { + SpackConfig { + truncation_length: 1, + format: "via [$symbol$environment]($style) ", + symbol: "🅢 ", + style: "blue bold", + disabled: false, + } + } +} diff --git a/src/configs/starship_root.rs b/src/configs/starship_root.rs index b89557c6..e386b76a 100644 --- a/src/configs/starship_root.rs +++ b/src/configs/starship_root.rs @@ -74,6 +74,7 @@ pub const PROMPT_ORDER: &[&str] = &[ "buf", "nix_shell", "conda", + "spack", "memory_usage", "aws", "gcloud", diff --git a/src/module.rs b/src/module.rs index 1ef67674..0f2d01a8 100644 --- a/src/module.rs +++ b/src/module.rs @@ -70,6 +70,7 @@ pub const ALL_MODULES: &[&str] = &[ "shell", "shlvl", "singularity", + "spack", "status", "sudo", "swift", diff --git a/src/modules/mod.rs b/src/modules/mod.rs index bc14908a..7392272d 100644 --- a/src/modules/mod.rs +++ b/src/modules/mod.rs @@ -60,6 +60,7 @@ mod scala; mod shell; mod shlvl; mod singularity; +mod spack; mod status; mod sudo; mod swift; @@ -150,6 +151,7 @@ pub fn handle<'a>(module: &str, context: &'a Context) -> Option> { "shell" => shell::module(context), "shlvl" => shlvl::module(context), "singularity" => singularity::module(context), + "spack" => spack::module(context), "swift" => swift::module(context), "status" => status::module(context), "sudo" => sudo::module(context), @@ -245,6 +247,7 @@ pub fn description(module: &str) -> &'static str { "shell" => "The currently used shell indicator", "shlvl" => "The current value of SHLVL", "singularity" => "The currently used Singularity image", + "spack" => "The current spack environment, if $SPACK_ENV is set", "status" => "The status of the last command", "sudo" => "The sudo credentials are currently cached", "swift" => "The currently installed version of Swift", diff --git a/src/modules/spack.rs b/src/modules/spack.rs new file mode 100644 index 00000000..1ef6d1a8 --- /dev/null +++ b/src/modules/spack.rs @@ -0,0 +1,84 @@ +use super::{Context, Module, ModuleConfig}; + +use super::utils::directory::truncate; +use crate::configs::spack::SpackConfig; +use crate::formatter::StringFormatter; + +/// Creates a module with the current Spack environment +/// +/// Will display the Spack environment if `$SPACK_ENV` is set. +pub fn module<'a>(context: &'a Context) -> Option> { + let spack_env = context.get_env("SPACK_ENV").unwrap_or_default(); + if spack_env.trim().is_empty() { + return None; + } + + let mut module = context.new_module("spack"); + let config: SpackConfig = SpackConfig::try_load(module.config); + + let spack_env = truncate(&spack_env, config.truncation_length).unwrap_or(spack_env); + + let parsed = StringFormatter::new(config.format).and_then(|formatter| { + formatter + .map_meta(|variable, _| match variable { + "symbol" => Some(config.symbol), + _ => None, + }) + .map_style(|variable| match variable { + "style" => Some(Ok(config.style)), + _ => None, + }) + .map(|variable| match variable { + "environment" => Some(Ok(spack_env.as_str())), + _ => None, + }) + .parse(None, Some(context)) + }); + + module.set_segments(match parsed { + Ok(segments) => segments, + Err(error) => { + log::warn!("Error in module `spack`:\n{}", error); + return None; + } + }); + + Some(module) +} + +#[cfg(test)] +mod tests { + use crate::test::ModuleRenderer; + use ansi_term::Color; + + #[test] + fn not_in_env() { + let actual = ModuleRenderer::new("spack").collect(); + + let expected = None; + + assert_eq!(expected, actual); + } + + #[test] + fn env_set() { + let actual = ModuleRenderer::new("spack") + .env("SPACK_ENV", "astronauts") + .collect(); + + let expected = Some(format!("via {} ", Color::Blue.bold().paint("🅢 astronauts"))); + + assert_eq!(expected, actual); + } + + #[test] + fn truncate() { + let actual = ModuleRenderer::new("spack") + .env("SPACK_ENV", "/some/really/long/and/really/annoying/path/that/shouldnt/be/displayed/fully/spack/my_env") + .collect(); + + let expected = Some(format!("via {} ", Color::Blue.bold().paint("🅢 my_env"))); + + assert_eq!(expected, actual); + } +}