diff --git a/.github/config-schema.json b/.github/config-schema.json index f293dd26..f1f9c86b 100644 --- a/.github/config-schema.json +++ b/.github/config-schema.json @@ -1365,6 +1365,27 @@ } ] }, + "quarto": { + "default": { + "detect_extensions": [ + "qmd" + ], + "detect_files": [ + "_quarto.yml" + ], + "detect_folders": [], + "disabled": false, + "format": "via [$symbol($version )]($style)", + "style": "bold #75AADB", + "symbol": "⨁ ", + "version_format": "v${raw}" + }, + "allOf": [ + { + "$ref": "#/definitions/QuartoConfig" + } + ] + }, "raku": { "default": { "detect_extensions": [ @@ -5046,6 +5067,57 @@ } ] }, + "QuartoConfig": { + "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 #75AADB", + "type": "string" + }, + "disabled": { + "default": false, + "type": "boolean" + }, + "detect_extensions": { + "default": [ + "qmd" + ], + "type": "array", + "items": { + "type": "string" + } + }, + "detect_files": { + "default": [ + "_quarto.yml" + ], + "type": "array", + "items": { + "type": "string" + } + }, + "detect_folders": { + "default": [], + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, "RakuConfig": { "type": "object", "properties": { diff --git a/docs/config/README.md b/docs/config/README.md index 34beb729..21343951 100644 --- a/docs/config/README.md +++ b/docs/config/README.md @@ -314,6 +314,7 @@ $php\ $pulumi\ $purescript\ $python\ +$quarto\ $raku\ $rlang\ $red\ @@ -3590,6 +3591,38 @@ python_binary = 'python3' detect_extensions = [] ``` +## Quarto + +The `quarto` module shows the current installed version of Quarto used in a project. + +By default, the module will be shown if any of the following conditions are met: + +- The current directory contains a `_quarto.yml` file +- The current directory contains any `*.qmd` 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 Quarto | +| `style` | `'bold #75AADB'` | The style for the module. | +| `detect_extensions` | `['.qmd']` | Which extensions should trigger this module. | +| `detect_files` | `['_quarto.yml']` | Which filenames should trigger this module. | +| `detect_folders` | `[]` | Which folders should trigger this module. | +| `disabled` | `false` | Disables the `quarto` module. | + +### Variables + +| Variable | Example | Description | +| -------- | --------- | ------------------------------------ | +| version | `1.4.549` | The version of `quarto` | +| 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 + ## R The `rlang` module shows the currently installed version of [R](https://www.r-project.org/). The module will be shown if diff --git a/docs/public/presets/toml/no-empty-icons.toml b/docs/public/presets/toml/no-empty-icons.toml index 8917c0a1..174c9dcb 100644 --- a/docs/public/presets/toml/no-empty-icons.toml +++ b/docs/public/presets/toml/no-empty-icons.toml @@ -87,6 +87,9 @@ format = '(via [$symbol($version )]($style))' [python] format = '(via [${symbol}${pyenv_prefix}(${version} )(\($virtualenv\) )]($style))' +[quarto] +format = '(via [$symbol($version )]($style))' + [raku] format = '(via [$symbol($version-$vm_version )]($style))' diff --git a/docs/public/presets/toml/no-runtime-versions.toml b/docs/public/presets/toml/no-runtime-versions.toml index a3ee88c8..df3a1ff4 100644 --- a/docs/public/presets/toml/no-runtime-versions.toml +++ b/docs/public/presets/toml/no-runtime-versions.toml @@ -91,6 +91,9 @@ format = 'via [$symbol]($style)' [python] format = 'via [$symbol]($style)' +[quarto] +format = 'via [$symbol]($style)' + [raku] format = 'via [$symbol]($style)' diff --git a/docs/public/presets/toml/plain-text-symbols.toml b/docs/public/presets/toml/plain-text-symbols.toml index db0957a1..3574a289 100644 --- a/docs/public/presets/toml/plain-text-symbols.toml +++ b/docs/public/presets/toml/plain-text-symbols.toml @@ -182,6 +182,9 @@ symbol = "purs " [python] symbol = "py " +[quarto] +symbol = "quarto " + [raku] symbol = "raku " diff --git a/src/configs/mod.rs b/src/configs/mod.rs index c2cf0a8d..591b350d 100644 --- a/src/configs/mod.rs +++ b/src/configs/mod.rs @@ -68,6 +68,7 @@ pub mod pijul_channel; pub mod pulumi; pub mod purescript; pub mod python; +pub mod quarto; pub mod raku; pub mod red; pub mod rlang; @@ -241,6 +242,8 @@ pub struct FullConfig<'a> { #[serde(borrow)] python: python::PythonConfig<'a>, #[serde(borrow)] + quarto: quarto::QuartoConfig<'a>, + #[serde(borrow)] raku: raku::RakuConfig<'a>, #[serde(borrow)] red: red::RedConfig<'a>, diff --git a/src/configs/quarto.rs b/src/configs/quarto.rs new file mode 100644 index 00000000..6fb1b92a --- /dev/null +++ b/src/configs/quarto.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 QuartoConfig<'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 QuartoConfig<'a> { + fn default() -> Self { + QuartoConfig { + format: "via [$symbol($version )]($style)", + version_format: "v${raw}", + symbol: "⨁ ", + style: "bold #75AADB", + disabled: false, + detect_extensions: vec!["qmd"], + detect_files: vec!["_quarto.yml"], + detect_folders: vec![], + } + } +} diff --git a/src/configs/starship_root.rs b/src/configs/starship_root.rs index 86fe7e75..7612a550 100644 --- a/src/configs/starship_root.rs +++ b/src/configs/starship_root.rs @@ -82,6 +82,7 @@ pub const PROMPT_ORDER: &[&str] = &[ "pulumi", "purescript", "python", + "quarto", "raku", "rlang", "red", diff --git a/src/module.rs b/src/module.rs index 0dcc0aad..3a8533f3 100644 --- a/src/module.rs +++ b/src/module.rs @@ -75,6 +75,7 @@ pub const ALL_MODULES: &[&str] = &[ "pulumi", "purescript", "python", + "quarto", "raku", "red", "rlang", diff --git a/src/modules/mod.rs b/src/modules/mod.rs index 57983cd1..a219cd0d 100644 --- a/src/modules/mod.rs +++ b/src/modules/mod.rs @@ -65,6 +65,7 @@ mod pijul_channel; mod pulumi; mod purescript; mod python; +mod quarto; mod raku; mod red; mod rlang; @@ -172,6 +173,7 @@ pub fn handle<'a>(module: &str, context: &'a Context) -> Option> { "pulumi" => pulumi::module(context), "purescript" => purescript::module(context), "python" => python::module(context), + "quarto" => quarto::module(context), "raku" => raku::module(context), "rlang" => rlang::module(context), "red" => red::module(context), @@ -292,6 +294,7 @@ pub fn description(module: &str) -> &'static str { "pulumi" => "The current username, stack, and installed version of Pulumi", "purescript" => "The currently installed version of PureScript", "python" => "The currently installed version of Python", + "quarto" => "The current installed version of quarto", "raku" => "The currently installed version of Raku", "red" => "The currently installed version of Red", "rlang" => "The currently installed version of R", diff --git a/src/modules/quarto.rs b/src/modules/quarto.rs new file mode 100644 index 00000000..25c72b4c --- /dev/null +++ b/src/modules/quarto.rs @@ -0,0 +1,93 @@ +use super::{Context, Module, ModuleConfig}; + +use crate::configs::quarto::QuartoConfig; +use crate::formatter::{StringFormatter, VersionFormatter}; + +/// Creates a module with the current Quarto version +pub fn module<'a>(context: &'a Context) -> Option> { + let mut module = context.new_module("quarto"); + let config = QuartoConfig::try_load(module.config); + + let is_quarto_project = context + .try_begin_scan()? + .set_files(&config.detect_files) + .set_extensions(&config.detect_extensions) + .set_folders(&config.detect_folders) + .is_match(); + + if !is_quarto_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 version = context + .exec_cmd("quarto", &["--version"])? + .stdout + .trim_end() + .to_owned(); + VersionFormatter::format_module_version( + module.get_name(), + &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 `quarto`:\n{}", error); + return None; + } + }); + + Some(module) +} + +#[cfg(test)] +mod tests { + use crate::test::ModuleRenderer; + use nu_ansi_term::Color; + use std::fs::File; + use std::io; + #[test] + fn read_quarto_not_present() -> io::Result<()> { + let dir = tempfile::tempdir()?; + + let actual = ModuleRenderer::new("quarto").path(dir.path()).collect(); + + let expected = None; + assert_eq!(expected, actual); + dir.close() + } + + #[test] + fn read_quarto_present() -> io::Result<()> { + let dir = tempfile::tempdir()?; + + File::create(dir.path().join("test.qmd"))?.sync_all()?; + + let actual = ModuleRenderer::new("quarto").path(dir.path()).collect(); + let expected = Some(format!( + "via {}", + Color::Rgb(117, 170, 219).bold().paint("⨁ v1.4.549 ") + )); + assert_eq!(expected, actual); + dir.close() + } +} diff --git a/src/utils.rs b/src/utils.rs index a0d53855..35cee76d 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -393,6 +393,10 @@ WebAssembly: unavailable stdout: String::from("Python 3.8.0\n"), stderr: String::default(), }), + "quarto --version" => Some(CommandOutput { + stdout: String::from("1.4.549\n"), + stderr: String::default(), + }), "R --version" => Some(CommandOutput { stdout: String::default(), stderr: String::from(