From e93dbf86301e19a89bd64997d95ba63a64f473aa Mon Sep 17 00:00:00 2001 From: fold-squirrel <90027154+fold-squirrel@users.noreply.github.com> Date: Wed, 21 Dec 2022 18:53:53 +0200 Subject: [PATCH] feat(fennel): add fennel module (#4717) --- .github/config-schema.json | 68 +++++++++++ .../presets/toml/bracketed-segments.toml | 3 + .../public/presets/toml/no-empty-icons.toml | 3 + .../presets/toml/no-runtime-versions.toml | 3 + .../presets/toml/plain-text-symbols.toml | 3 + docs/config/README.md | 40 +++++++ src/configs/fennel.rs | 34 ++++++ src/configs/mod.rs | 3 + src/configs/starship_root.rs | 1 + src/module.rs | 1 + src/modules/fennel.rs | 107 ++++++++++++++++++ src/modules/mod.rs | 3 + src/utils.rs | 4 + 13 files changed, 273 insertions(+) create mode 100644 src/configs/fennel.rs create mode 100644 src/modules/fennel.rs diff --git a/.github/config-schema.json b/.github/config-schema.json index 404cdd6a..e7fb0af1 100644 --- a/.github/config-schema.json +++ b/.github/config-schema.json @@ -473,6 +473,25 @@ } ] }, + "fennel": { + "default": { + "detect_extentions": [ + "fnl" + ], + "detect_files": [], + "detect_folders": [], + "disabled": true, + "format": "via [$symbol($version )]($style)", + "style": "bold green", + "symbol": "🧅 ", + "version_format": "v${raw}" + }, + "allOf": [ + { + "$ref": "#/definitions/FennelConfig" + } + ] + }, "fill": { "default": { "disabled": false, @@ -2867,6 +2886,55 @@ }, "additionalProperties": false }, + "FennelConfig": { + "type": "object", + "properties": { + "format": { + "default": "via [$symbol($version )]($style)", + "type": "string" + }, + "version_format": { + "default": "v${raw}", + "type": "string" + }, + "symbol": { + "default": "🧅 ", + "type": "string" + }, + "style": { + "default": "bold green", + "type": "string" + }, + "disabled": { + "default": true, + "type": "boolean" + }, + "detect_extentions": { + "default": [ + "fnl" + ], + "type": "array", + "items": { + "type": "string" + } + }, + "detect_files": { + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "detect_folders": { + "default": [], + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, "FillConfig": { "type": "object", "properties": { diff --git a/docs/.vuepress/public/presets/toml/bracketed-segments.toml b/docs/.vuepress/public/presets/toml/bracketed-segments.toml index c86ed047..deaa6ae8 100644 --- a/docs/.vuepress/public/presets/toml/bracketed-segments.toml +++ b/docs/.vuepress/public/presets/toml/bracketed-segments.toml @@ -46,6 +46,9 @@ format = '\[[$symbol($version)]($style)\]' [erlang] format = '\[[$symbol($version)]($style)\]' +[fennel] +format = '\[[$symbol($version)]($style)\]' + [gcloud] format = '\[[$symbol$account(@$domain)(\($region\))]($style)\]' diff --git a/docs/.vuepress/public/presets/toml/no-empty-icons.toml b/docs/.vuepress/public/presets/toml/no-empty-icons.toml index 5b98fb7f..eb94f1a3 100644 --- a/docs/.vuepress/public/presets/toml/no-empty-icons.toml +++ b/docs/.vuepress/public/presets/toml/no-empty-icons.toml @@ -37,6 +37,9 @@ format = '(via [$symbol($version )]($style))' [erlang] format = '(via [$symbol($version )]($style))' +[fennel] +format = '(via [$symbol($version )]($style))' + [golang] format = '(via [$symbol($version )]($style))' diff --git a/docs/.vuepress/public/presets/toml/no-runtime-versions.toml b/docs/.vuepress/public/presets/toml/no-runtime-versions.toml index 97b6a3ed..09accea7 100644 --- a/docs/.vuepress/public/presets/toml/no-runtime-versions.toml +++ b/docs/.vuepress/public/presets/toml/no-runtime-versions.toml @@ -34,6 +34,9 @@ format = 'via [$symbol]($style)' [erlang] format = 'via [$symbol]($style)' +[fennel] +format = 'via [$symbol]($style)' + [golang] format = 'via [$symbol]($style)' diff --git a/docs/.vuepress/public/presets/toml/plain-text-symbols.toml b/docs/.vuepress/public/presets/toml/plain-text-symbols.toml index 1efccd24..66eca654 100644 --- a/docs/.vuepress/public/presets/toml/plain-text-symbols.toml +++ b/docs/.vuepress/public/presets/toml/plain-text-symbols.toml @@ -58,6 +58,9 @@ symbol = "exs " [elm] symbol = "elm " +[fennel] +symbol = "fnl " + [git_branch] symbol = "git " diff --git a/docs/config/README.md b/docs/config/README.md index 5cd20bad..904504b2 100644 --- a/docs/config/README.md +++ b/docs/config/README.md @@ -283,6 +283,7 @@ $dotnet\ $elixir\ $elm\ $erlang\ +$fennel\ $golang\ $guix_shell\ $haskell\ @@ -1475,6 +1476,45 @@ By default the module will be shown if any of the following conditions are met: format = 'via [e $version](bold red) ' ``` +## Fennel + +The `fennel` module shows the currently installed version of [Fennel](https://fennel-lang.org). +By default the module will be shown if any of the following conditions are met: + +- The current directory contains a file with the `.fnl` 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` | `'🧅 '` | The symbol used before displaying the version of fennel. | +| `style` | `'bold green'` | The style for the module. | +| `detect_extensions` | `[fnl]` | Which extensions should trigger this module. | +| `detect_files` | `[]` | Which filenames should trigger this module. | +| `detect_folders` | `[]` | Which folders should trigger this modules. | +| `disabled` | `false` | Disables the `fennel` module. | + +### Variables + +| Variable | Example | Description | +| -------- | -------- | ------------------------------------ | +| version | `v1.2.1` | The version of `fennel` | +| 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 + +[fennel] +symbol = '⫰ ' +``` + ## Fill The `fill` module fills any extra space on the line with a symbol. If multiple `fill` modules are diff --git a/src/configs/fennel.rs b/src/configs/fennel.rs new file mode 100644 index 00000000..e0564c9e --- /dev/null +++ b/src/configs/fennel.rs @@ -0,0 +1,34 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Deserialize, Serialize)] +#[cfg_attr( + feature = "config-schema", + derive(schemars::JsonSchema), + schemars(deny_unknown_fields) +)] +#[serde(default)] +pub struct FennelConfig<'a> { + pub format: &'a str, + pub version_format: &'a str, + pub symbol: &'a str, + pub style: &'a str, + pub disabled: bool, + pub detect_extentions: Vec<&'a str>, + pub detect_files: Vec<&'a str>, + pub detect_folders: Vec<&'a str>, +} + +impl<'a> Default for FennelConfig<'a> { + fn default() -> Self { + FennelConfig { + format: "via [$symbol($version )]($style)", + version_format: "v${raw}", + symbol: "🧅 ", + style: "bold green", + disabled: true, + detect_extentions: vec!["fnl"], + detect_files: vec![], + detect_folders: vec![], + } + } +} diff --git a/src/configs/mod.rs b/src/configs/mod.rs index 88d1d8d9..8a712e5f 100644 --- a/src/configs/mod.rs +++ b/src/configs/mod.rs @@ -25,6 +25,7 @@ pub mod elixir; pub mod elm; pub mod env_var; pub mod erlang; +pub mod fennel; pub mod fill; pub mod gcloud; pub mod git_branch; @@ -149,6 +150,8 @@ pub struct FullConfig<'a> { #[serde(borrow)] erlang: erlang::ErlangConfig<'a>, #[serde(borrow)] + fennel: fennel::FennelConfig<'a>, + #[serde(borrow)] fill: fill::FillConfig<'a>, #[serde(borrow)] gcloud: gcloud::GcloudConfig<'a>, diff --git a/src/configs/starship_root.rs b/src/configs/starship_root.rs index 3fdd06f6..891e9074 100644 --- a/src/configs/starship_root.rs +++ b/src/configs/starship_root.rs @@ -57,6 +57,7 @@ pub const PROMPT_ORDER: &[&str] = &[ "elixir", "elm", "erlang", + "fennel", "golang", "gradle", "haskell", diff --git a/src/module.rs b/src/module.rs index a2b2f1b2..77508f14 100644 --- a/src/module.rs +++ b/src/module.rs @@ -33,6 +33,7 @@ pub const ALL_MODULES: &[&str] = &[ "elm", "env_var", "erlang", + "fennel", "fill", "gcloud", "git_branch", diff --git a/src/modules/fennel.rs b/src/modules/fennel.rs new file mode 100644 index 00000000..4b8a2fc9 --- /dev/null +++ b/src/modules/fennel.rs @@ -0,0 +1,107 @@ +use super::{Context, Module, ModuleConfig}; + +use crate::configs::fennel::FennelConfig; +use crate::formatter::{StringFormatter, VersionFormatter}; +use crate::utils::get_command_string_output; + +pub fn module<'a>(context: &'a Context) -> Option> { + let mut module = context.new_module("fennel"); + let config = FennelConfig::try_load(module.config); + + let is_fnl_project = context + .try_begin_scan()? + .set_files(&config.detect_files) + .set_extensions(&config.detect_extentions) + .set_folders(&config.detect_folders) + .is_match(); + + if !is_fnl_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" => { + let fennel_version_string = + get_command_string_output(context.exec_cmd("fennel", &["--version"])?); + let fennel_version = parse_fennel_version(&fennel_version_string)?; + VersionFormatter::format_module_version( + module.get_name(), + &fennel_version, + config.version_format, + ) + .map(Ok) + } + _ => None, + }) + .parse(None, Some(context)) + }); + + module.set_segments(match parsed { + Ok(segments) => segments, + Err(error) => { + log::warn!("Error in module `fennel`:\n{}", error); + return None; + } + }); + + Some(module) +} + +fn parse_fennel_version(fennel_version: &str) -> Option { + // fennel -v output looks like this: + // Fennel 1.2.1 on PUC Lua 5.4 + let version = fennel_version + // split into ["Fennel", "1.2.1", "on", ...] + .split_whitespace() + // take "1.2.1" + .nth(1)?; + + Some(version.to_string()) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::test::ModuleRenderer; + use nu_ansi_term::Color; + use std::fs::File; + use std::io; + + #[test] + fn folder_without_fennel_files() -> io::Result<()> { + let dir = tempfile::tempdir()?; + let actual = ModuleRenderer::new("fennel").path(dir.path()).collect(); + let expected = None; + assert_eq!(expected, actual); + dir.close() + } + + #[test] + fn folder_with_fennel_files() -> io::Result<()> { + let dir = tempfile::tempdir()?; + File::create(dir.path().join("man.fnl"))?.sync_all()?; + let actual = ModuleRenderer::new("fennel").path(dir.path()).collect(); + let expected = Some(format!("via {}", Color::Green.bold().paint("🧅 v1.2.1 "))); + assert_eq!(expected, actual); + dir.close() + } + + #[test] + fn test_parse_fennel_version() { + let fennel_input = "Fennel 1.2.1 on PUC Lua 5.4"; + assert_eq!( + parse_fennel_version(fennel_input), + Some("1.2.1".to_string()) + ); + } +} diff --git a/src/modules/mod.rs b/src/modules/mod.rs index e9117054..8c8c5b6b 100644 --- a/src/modules/mod.rs +++ b/src/modules/mod.rs @@ -22,6 +22,7 @@ mod elixir; mod elm; mod env_var; mod erlang; +mod fennel; mod fill; mod gcloud; mod git_branch; @@ -121,6 +122,7 @@ pub fn handle<'a>(module: &str, context: &'a Context) -> Option> { "elixir" => elixir::module(context), "elm" => elm::module(context), "erlang" => erlang::module(context), + "fennel" => fennel::module(context), "env_var" => env_var::module(context), "fill" => fill::module(context), "gcloud" => gcloud::module(context), @@ -233,6 +235,7 @@ pub fn description(module: &str) -> &'static str { "elm" => "The currently installed version of Elm", "env_var" => "Displays the current value of a selected environment variable", "erlang" => "Current OTP version", + "fennel" => "The currently installed version of Fennel", "fill" => "Fills the remaining space on the line with a pad string", "gcloud" => "The current GCP client configuration", "git_branch" => "The active branch of the repo in your current directory", diff --git a/src/utils.rs b/src/utils.rs index 06a5c270..1d035dac 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -245,6 +245,10 @@ Elixir 1.10 (compiled with Erlang/OTP 22)\n", stdout: String::from("0.19.1\n"), stderr: String::default(), }), + "fennel --version" => Some(CommandOutput { + stdout: String::from("Fennel 1.2.1 on PUC Lua 5.4\n"), + stderr: String::default(), + }), "go version" => Some(CommandOutput { stdout: String::from("go version go1.12.1 linux/amd64\n"), stderr: String::default(),