From 85692d1bf6a8477b6879adaf8b51007389df4328 Mon Sep 17 00:00:00 2001 From: David Knaack Date: Mon, 1 Aug 2022 12:59:36 +0200 Subject: [PATCH] feat: add bun module (#4187) --- .github/config-schema.json | 69 +++++++++++ .../presets/toml/bracketed-segments.toml | 3 + .../presets/toml/no-runtime-versions.toml | 3 + .../presets/toml/plain-text-symbols.toml | 3 + docs/config/README.md | 40 +++++++ src/configs/bun.rs | 30 +++++ src/configs/mod.rs | 3 + src/configs/starship_root.rs | 1 + src/module.rs | 1 + src/modules/bun.rs | 109 ++++++++++++++++++ src/modules/mod.rs | 3 + src/utils.rs | 4 + 12 files changed, 269 insertions(+) create mode 100644 src/configs/bun.rs create mode 100644 src/modules/bun.rs diff --git a/.github/config-schema.json b/.github/config-schema.json index 351dd985..a2e019a7 100644 --- a/.github/config-schema.json +++ b/.github/config-schema.json @@ -82,6 +82,26 @@ } ] }, + "bun": { + "default": { + "detect_extensions": [], + "detect_files": [ + "bun.lockb", + "bunfig.toml" + ], + "detect_folders": [], + "disabled": false, + "format": "via [$symbol($version )]($style)", + "style": "bold red", + "symbol": "🍞 ", + "version_format": "v${raw}" + }, + "allOf": [ + { + "$ref": "#/definitions/BunConfig" + } + ] + }, "c": { "default": { "commands": [ @@ -1725,6 +1745,55 @@ } } }, + "BunConfig": { + "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 red", + "type": "string" + }, + "disabled": { + "default": false, + "type": "boolean" + }, + "detect_extensions": { + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "detect_files": { + "default": [ + "bun.lockb", + "bunfig.toml" + ], + "type": "array", + "items": { + "type": "string" + } + }, + "detect_folders": { + "default": [], + "type": "array", + "items": { + "type": "string" + } + } + } + }, "CConfig": { "type": "object", "properties": { diff --git a/docs/.vuepress/public/presets/toml/bracketed-segments.toml b/docs/.vuepress/public/presets/toml/bracketed-segments.toml index 1bd05a1c..76a7f382 100644 --- a/docs/.vuepress/public/presets/toml/bracketed-segments.toml +++ b/docs/.vuepress/public/presets/toml/bracketed-segments.toml @@ -1,6 +1,9 @@ [aws] format = '\[[$symbol($profile)(\($region\))(\[$duration\])]($style)\]' +[bun] +format = '\[[$symbol($version)]($style)\]' + [c] format = '\[[$symbol($version(-$name))]($style)\]' diff --git a/docs/.vuepress/public/presets/toml/no-runtime-versions.toml b/docs/.vuepress/public/presets/toml/no-runtime-versions.toml index 1728d816..156c4e76 100644 --- a/docs/.vuepress/public/presets/toml/no-runtime-versions.toml +++ b/docs/.vuepress/public/presets/toml/no-runtime-versions.toml @@ -1,3 +1,6 @@ +[bun] +format = "via [$symbol]($style)" + [buf] 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 297bb631..f64d25f5 100644 --- a/docs/.vuepress/public/presets/toml/plain-text-symbols.toml +++ b/docs/.vuepress/public/presets/toml/plain-text-symbols.toml @@ -16,6 +16,9 @@ deleted = "x" [aws] symbol = "aws " +[bun] +symbol = "bun " + [c] symbol = "C " diff --git a/docs/config/README.md b/docs/config/README.md index 762262db..0267ee1c 100644 --- a/docs/config/README.md +++ b/docs/config/README.md @@ -516,6 +516,46 @@ The `buf` module shows the currently installed version of [Buf](https://buf.buil symbol = "🦬 " ``` +## Bun + +The `bun` module shows the currently installed version of the [bun](https://bun.sh) JavaScript runtime. +By default the module will be shown if any of the following conditions are met: + +- The current directory contains a `bun.lockb` file +- The current directory contains a `bunfig.toml` file + +### 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 Node.js. | +| `detect_extensions` | `[]` | Which extensions should trigger this module. | +| `detect_files` | `["bun.lockb", "bunfig.toml"]` | Which filenames should trigger this module. | +| `detect_folders` | `[]` | Which folders should trigger this module. | +| `style` | `"bold red"` | The style for the module. | +| `disabled` | `false` | Disables the `bun` module. | + +### Variables + +| Variable | Example | Description | +| -------- | -------- | ------------------------------------ | +| version | `v0.1.4` | The version of `bun` | +| 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 + +[bun] +format = "via [🍔 $version](bold green) " +``` + ## C The `c` module shows some information about your C compiler. By default diff --git a/src/configs/bun.rs b/src/configs/bun.rs new file mode 100644 index 00000000..24c73e95 --- /dev/null +++ b/src/configs/bun.rs @@ -0,0 +1,30 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Deserialize, Serialize)] +#[cfg_attr(feature = "config-schema", derive(schemars::JsonSchema))] +#[serde(default)] +pub struct BunConfig<'a> { + pub format: &'a str, + pub version_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 BunConfig<'a> { + fn default() -> Self { + BunConfig { + format: "via [$symbol($version )]($style)", + version_format: "v${raw}", + symbol: "🍞 ", + style: "bold red", + disabled: false, + detect_extensions: vec![], + detect_files: vec!["bun.lockb", "bunfig.toml"], + detect_folders: vec![], + } + } +} diff --git a/src/configs/mod.rs b/src/configs/mod.rs index 9b24cbd1..bbd7ee73 100644 --- a/src/configs/mod.rs +++ b/src/configs/mod.rs @@ -5,6 +5,7 @@ pub mod aws; pub mod azure; pub mod battery; pub mod buf; +pub mod bun; pub mod c; pub mod character; pub mod cmake; @@ -100,6 +101,8 @@ pub struct FullConfig<'a> { #[serde(borrow)] buf: buf::BufConfig<'a>, #[serde(borrow)] + bun: bun::BunConfig<'a>, + #[serde(borrow)] c: c::CConfig<'a>, #[serde(borrow)] character: character::CharacterConfig<'a>, diff --git a/src/configs/starship_root.rs b/src/configs/starship_root.rs index e8b2ed74..ce93343b 100644 --- a/src/configs/starship_root.rs +++ b/src/configs/starship_root.rs @@ -36,6 +36,7 @@ pub const PROMPT_ORDER: &[&str] = &[ "package", // ↓ Toolchain version modules ↓ // (Let's keep these sorted alphabetically) + "bun", "c", "cmake", "cobol", diff --git a/src/module.rs b/src/module.rs index 79d5553b..e5b89625 100644 --- a/src/module.rs +++ b/src/module.rs @@ -14,6 +14,7 @@ pub const ALL_MODULES: &[&str] = &[ #[cfg(feature = "battery")] "battery", "buf", + "bun", "c", "character", "cmake", diff --git a/src/modules/bun.rs b/src/modules/bun.rs new file mode 100644 index 00000000..b3675bf1 --- /dev/null +++ b/src/modules/bun.rs @@ -0,0 +1,109 @@ +use super::{Context, Module, ModuleConfig}; + +use crate::configs::bun::BunConfig; +use crate::formatter::StringFormatter; +use crate::formatter::VersionFormatter; +use crate::utils::get_command_string_output; + +/// Creates a module with the current Bun version +pub fn module<'a>(context: &'a Context) -> Option> { + let mut module = context.new_module("bun"); + let config = BunConfig::try_load(module.config); + + let is_bun_project = context + .try_begin_scan()? + .set_files(&config.detect_files) + .set_extensions(&config.detect_extensions) + .set_folders(&config.detect_folders) + .is_match(); + + if !is_bun_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 bun_version = get_bun_version(context)?; + VersionFormatter::format_module_version( + module.get_name(), + &bun_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 `bun`:\n{}", error); + return None; + } + }); + + Some(module) +} + +fn get_bun_version(context: &Context) -> Option { + context + .exec_cmd("bun", &["--version"]) + .map(get_command_string_output) + .map(parse_bun_version) +} + +fn parse_bun_version(bun_version: String) -> String { + bun_version.trim_end().to_string() +} + +#[cfg(test)] +mod tests { + use crate::test::ModuleRenderer; + use ansi_term::Color; + use std::fs::File; + use std::io; + + #[test] + fn folder_without_bun_files() -> io::Result<()> { + let dir = tempfile::tempdir()?; + let actual = ModuleRenderer::new("bun").path(dir.path()).collect(); + let expected = None; + assert_eq!(expected, actual); + dir.close() + } + + #[test] + fn folder_with_bun_file() -> io::Result<()> { + let dir = tempfile::tempdir()?; + File::create(dir.path().join("bun.lockb"))?.sync_all()?; + let actual = ModuleRenderer::new("bun").path(dir.path()).collect(); + let expected = Some(format!("via {}", Color::Red.bold().paint("🍞 v0.1.4 "))); + assert_eq!(expected, actual); + dir.close() + } + + #[test] + fn no_bun_installed() -> io::Result<()> { + let dir = tempfile::tempdir()?; + File::create(dir.path().join("bun.lockb"))?.sync_all()?; + let actual = ModuleRenderer::new("bun") + .path(dir.path()) + .cmd("bun --version", None) + .collect(); + let expected = Some(format!("via {}", Color::Red.bold().paint("🍞 "))); + assert_eq!(expected, actual); + dir.close() + } +} diff --git a/src/modules/mod.rs b/src/modules/mod.rs index 07425cec..b6575281 100644 --- a/src/modules/mod.rs +++ b/src/modules/mod.rs @@ -2,6 +2,7 @@ mod aws; mod azure; mod buf; +mod bun; mod c; mod character; mod cmake; @@ -97,6 +98,7 @@ pub fn handle<'a>(module: &str, context: &'a Context) -> Option> { #[cfg(feature = "battery")] "battery" => battery::module(context), "buf" => buf::module(context), + "bun" => bun::module(context), "c" => c::module(context), "character" => character::module(context), "cmake" => cmake::module(context), @@ -198,6 +200,7 @@ pub fn description(module: &str) -> &'static str { "azure" => "The current Azure subscription", "battery" => "The current charge of the device's battery and its current charging status", "buf" => "The currently installed version of the Buf CLI", + "bun" => "The currently installed version of the Bun", "c" => "Your C compiler type", "character" => { "A character (usually an arrow) beside where the text is entered in your terminal" diff --git a/src/utils.rs b/src/utils.rs index 07b5bc2e..959c3706 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -129,6 +129,10 @@ pub fn mock_cmd + Debug, U: AsRef + Debug>( ) -> Option> { let command = display_command(&cmd, args); let out = match command.as_str() { + "bun --version"=> Some(CommandOutput { + stdout: String::from("0.1.4\n"), + stderr: String::default(), + }), "buf --version" => Some(CommandOutput { stdout: String::from("1.0.0"), stderr: String::default(),