From 7b217056bdb8dcb5b328b51fa3b68fe837f9fb3c Mon Sep 17 00:00:00 2001 From: Charlotte Thomas Date: Thu, 26 Oct 2023 15:31:16 +0200 Subject: [PATCH] feat: add typst module Co-authored-by: David Knaack --- .github/config-schema.json | 72 ++++++++++++++ .../public/presets/toml/no-empty-icons.toml | 3 + .../public/presets/toml/no-nerd-font.toml | 3 + .../presets/toml/no-runtime-versions.toml | 3 + .../presets/toml/plain-text-symbols.toml | 3 + docs/config/README.md | 34 +++++++ src/configs/mod.rs | 3 + src/configs/starship_root.rs | 1 + src/configs/typst.rs | 34 +++++++ src/module.rs | 1 + src/modules/mod.rs | 3 + src/modules/typst.rs | 98 +++++++++++++++++++ src/utils.rs | 5 + 13 files changed, 263 insertions(+) create mode 100644 src/configs/typst.rs create mode 100644 src/modules/typst.rs diff --git a/.github/config-schema.json b/.github/config-schema.json index 1f091efb..9931b848 100644 --- a/.github/config-schema.json +++ b/.github/config-schema.json @@ -1671,6 +1671,27 @@ } ] }, + "typst": { + "default": { + "detect_extensions": [ + "typ" + ], + "detect_files": [ + "template.typ" + ], + "detect_folders": [], + "disabled": false, + "format": "via [$symbol($version )]($style)", + "style": "bold #0093A7", + "symbol": "t ", + "version_format": "v${raw}" + }, + "allOf": [ + { + "$ref": "#/definitions/TypstConfig" + } + ] + }, "username": { "default": { "disabled": false, @@ -5709,6 +5730,57 @@ }, "additionalProperties": false }, + "TypstConfig": { + "type": "object", + "properties": { + "format": { + "default": "via [$symbol($version )]($style)", + "type": "string" + }, + "version_format": { + "default": "v${raw}", + "type": "string" + }, + "symbol": { + "default": "t ", + "type": "string" + }, + "style": { + "default": "bold #0093A7", + "type": "string" + }, + "disabled": { + "default": false, + "type": "boolean" + }, + "detect_extensions": { + "default": [ + "typ" + ], + "type": "array", + "items": { + "type": "string" + } + }, + "detect_files": { + "default": [ + "template.typ" + ], + "type": "array", + "items": { + "type": "string" + } + }, + "detect_folders": { + "default": [], + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, "UsernameConfig": { "type": "object", "properties": { diff --git a/docs/.vuepress/public/presets/toml/no-empty-icons.toml b/docs/.vuepress/public/presets/toml/no-empty-icons.toml index eb94f1a3..8917c0a1 100644 --- a/docs/.vuepress/public/presets/toml/no-empty-icons.toml +++ b/docs/.vuepress/public/presets/toml/no-empty-icons.toml @@ -108,6 +108,9 @@ format = '(via [$symbol($version )]($style))' [swift] format = '(via [$symbol($version )]($style))' +[typst] +format = '(via [$symbol($version )]($style))' + [vagrant] format = '(via [$symbol($version )]($style))' diff --git a/docs/.vuepress/public/presets/toml/no-nerd-font.toml b/docs/.vuepress/public/presets/toml/no-nerd-font.toml index a34b3044..3c4da2af 100644 --- a/docs/.vuepress/public/presets/toml/no-nerd-font.toml +++ b/docs/.vuepress/public/presets/toml/no-nerd-font.toml @@ -13,3 +13,6 @@ symbol = "[⬢](bold green) " [pulumi] symbol = "🧊 " + +[typst] +symbol = "t " diff --git a/docs/.vuepress/public/presets/toml/no-runtime-versions.toml b/docs/.vuepress/public/presets/toml/no-runtime-versions.toml index dc573954..a3ee88c8 100644 --- a/docs/.vuepress/public/presets/toml/no-runtime-versions.toml +++ b/docs/.vuepress/public/presets/toml/no-runtime-versions.toml @@ -109,6 +109,9 @@ format = 'via [$symbol]($style)' [solidity] format = 'via [$symbol]($style)' +[typst] +format = 'via [$symbol]($style)' + [swift] 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 32126a01..db0957a1 100644 --- a/docs/.vuepress/public/presets/toml/plain-text-symbols.toml +++ b/docs/.vuepress/public/presets/toml/plain-text-symbols.toml @@ -209,6 +209,9 @@ symbol = "sudo " [swift] symbol = "swift " +[typst] +symbol = "typst " + [terraform] symbol = "terraform " diff --git a/docs/config/README.md b/docs/config/README.md index 55315d93..e200115b 100644 --- a/docs/config/README.md +++ b/docs/config/README.md @@ -323,6 +323,7 @@ $scala\ $solidity\ $swift\ $terraform\ +$typst\ $vlang\ $vagrant\ $zig\ @@ -4278,6 +4279,39 @@ utc_time_offset = '-5' time_range = '10:00:00-14:00:00' ``` +## Typst + +The `typst` module shows the current installed version of Typst used in a project. + +By default, the module will be shown if any of the following conditions are met: + +- The current directory contains a `template.typ` file +- The current directory contains any `*.typ` 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` | `'t '` | A format string representing the symbol of Daml | +| `style` | `'bold #0093A7'` | The style for the module. | +| `detect_extensions` | `['.typ']` | Which extensions should trigger this module. | +| `detect_files` | `['template.typ']` | Which filenames should trigger this module. | +| `detect_folders` | `[]` | Which folders should trigger this module. | +| `disabled` | `false` | Disables the `daml` module. | + +### Variables + +| Variable | Example | Description | +| ------------- | --------- | ----------------------------------------------- | +| version | `v0.9.0` | The version of `typst`, alias for typst_version | +| typst_version | `default` | The current Typst version | +| 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 + ## Username The `username` module shows active user's username. diff --git a/src/configs/mod.rs b/src/configs/mod.rs index aeb8193f..883055b8 100644 --- a/src/configs/mod.rs +++ b/src/configs/mod.rs @@ -84,6 +84,7 @@ pub mod sudo; pub mod swift; pub mod terraform; pub mod time; +pub mod typst; pub mod username; pub mod v; pub mod vagrant; @@ -269,6 +270,8 @@ pub struct FullConfig<'a> { #[serde(borrow)] time: time::TimeConfig<'a>, #[serde(borrow)] + typst: typst::TypstConfig<'a>, + #[serde(borrow)] username: username::UsernameConfig<'a>, #[serde(borrow)] vagrant: vagrant::VagrantConfig<'a>, diff --git a/src/configs/starship_root.rs b/src/configs/starship_root.rs index 6308d6d9..c93c1543 100644 --- a/src/configs/starship_root.rs +++ b/src/configs/starship_root.rs @@ -91,6 +91,7 @@ pub const PROMPT_ORDER: &[&str] = &[ "solidity", "swift", "terraform", + "typst", "vlang", "vagrant", "zig", diff --git a/src/configs/typst.rs b/src/configs/typst.rs new file mode 100644 index 00000000..28f4fc62 --- /dev/null +++ b/src/configs/typst.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 TypstConfig<'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 TypstConfig<'a> { + fn default() -> Self { + TypstConfig { + format: "via [$symbol($version )]($style)", + version_format: "v${raw}", + symbol: "t ", + style: "bold #0093A7", + disabled: false, + detect_extensions: vec!["typ"], + detect_files: vec!["template.typ"], + detect_folders: vec![], + } + } +} diff --git a/src/module.rs b/src/module.rs index 26d46c97..33f8287b 100644 --- a/src/module.rs +++ b/src/module.rs @@ -90,6 +90,7 @@ pub const ALL_MODULES: &[&str] = &[ "swift", "terraform", "time", + "typst", "username", "vagrant", "vcsh", diff --git a/src/modules/mod.rs b/src/modules/mod.rs index fe4f4230..cc1eec4e 100644 --- a/src/modules/mod.rs +++ b/src/modules/mod.rs @@ -89,6 +89,7 @@ mod zig; #[cfg(feature = "battery")] mod battery; +mod typst; #[cfg(feature = "battery")] pub use self::battery::{BatteryInfoProvider, BatteryInfoProviderImpl}; @@ -185,6 +186,7 @@ pub fn handle<'a>(module: &str, context: &'a Context) -> Option> { "sudo" => sudo::module(context), "terraform" => terraform::module(context), "time" => time::module(context), + "typst" => typst::module(context), "crystal" => crystal::module(context), "username" => username::module(context), "vlang" => vlang::module(context), @@ -303,6 +305,7 @@ pub fn description(module: &str) -> &'static str { "swift" => "The currently installed version of Swift", "terraform" => "The currently selected terraform workspace and version", "time" => "The current local time", + "typst" => "The current installed version of typst", "username" => "The active user's username", "vagrant" => "The currently installed version of Vagrant", "vcsh" => "The currently active VCSH repository", diff --git a/src/modules/typst.rs b/src/modules/typst.rs new file mode 100644 index 00000000..a1c0ba4a --- /dev/null +++ b/src/modules/typst.rs @@ -0,0 +1,98 @@ +use super::{Context, Module, ModuleConfig}; + +use crate::configs::typst::TypstConfig; +use crate::formatter::{StringFormatter, VersionFormatter}; + +/// Creates a module with the current Typst version +pub fn module<'a>(context: &'a Context) -> Option> { + let mut module = context.new_module("typst"); + let config = TypstConfig::try_load(module.config); + + let is_typst_project = context + .try_begin_scan()? + .set_files(&config.detect_files) + .set_extensions(&config.detect_extensions) + .set_folders(&config.detect_folders) + .is_match(); + + if !is_typst_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 = get_typst_config(context)?; + 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 `typst`:\n{}", error); + return None; + } + }); + + Some(module) +} + +fn get_typst_config(context: &Context) -> Option { + context + .exec_cmd("typst", &["--version"])? + .stdout + .trim() + .strip_prefix("typst ") + .and_then(|version| version.split_whitespace().next().map(ToOwned::to_owned)) +} + +#[cfg(test)] +mod tests { + use crate::test::ModuleRenderer; + use nu_ansi_term::Color; + use std::fs::File; + use std::io; + #[test] + fn read_typst_not_present() -> io::Result<()> { + let dir = tempfile::tempdir()?; + + let actual = ModuleRenderer::new("typst").path(dir.path()).collect(); + + let expected = None; + assert_eq!(expected, actual); + dir.close() + } + + #[test] + fn read_typst_present() -> io::Result<()> { + let dir = tempfile::tempdir()?; + + File::create(dir.path().join("test.typ"))?.sync_all()?; + + let actual = ModuleRenderer::new("typst").path(dir.path()).collect(); + let expected = Some(format!( + "via {}", + Color::Rgb(0, 147, 167).bold().paint("t v0.10 ") + )); + assert_eq!(expected, actual); + dir.close() + } +} diff --git a/src/utils.rs b/src/utils.rs index d4d68a81..0459f5f7 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -341,6 +341,11 @@ WebAssembly: unavailable stdout: String::from("default\n"), stderr: String::default(), }), + "typst --version" => Some(CommandOutput { + stdout: String::from("typst 0.10 (360cc9b9)"), + stderr: String::default(), + }), + "esy ocaml -vnum" => Some(CommandOutput { stdout: String::from("4.08.1\n"), stderr: String::default(),