diff --git a/Cargo.toml b/Cargo.toml index 1d1f1a9ef..8845f6ee6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -110,6 +110,7 @@ nix = { version = "0.24.2", default-features = false, features = ["feature", "fs [build-dependencies] shadow-rs = "0.16.1" +dunce = "1.0.2" [target.'cfg(windows)'.build-dependencies] winres = "0.1.12" diff --git a/build.rs b/build.rs index 38b4e1ac5..7a6753419 100644 --- a/build.rs +++ b/build.rs @@ -1,7 +1,11 @@ -use std::error::Error; +use std::fs::{self, File}; +use std::io::Write; -fn main() -> Result<(), Box> { +use shadow_rs::SdResult; + +fn main() -> SdResult<()> { shadow_rs::new().map_err(|err| err.to_string())?; + shadow_rs::new_hook(gen_presets_hook)?; #[cfg(windows)] { @@ -13,3 +17,55 @@ fn main() -> Result<(), Box> { Ok(()) } + +fn gen_presets_hook(mut file: &File) -> SdResult<()> { + println!("cargo:rerun-if-changed=docs/.vuepress/public/presets/toml"); + let paths = fs::read_dir("docs/.vuepress/public/presets/toml")?; + + let mut presets = String::new(); + let mut match_arms = String::new(); + for path in paths { + let unwrapped = path?; + let file_name = unwrapped.file_name(); + let full_path = dunce::canonicalize(unwrapped.path())?; + let full_path = full_path.to_str().expect("failed to convert to string"); + let name = file_name + .to_str() + .and_then(|v| v.strip_suffix(".toml")) + .expect("Failed to process filename"); + presets.push_str(format!("print::Preset(\"{}\"),\n", name).as_str()); + match_arms.push_str( + format!( + r#" +"{name}" => {{ + let mut stdout = io::stdout().lock(); + let _ = stdout.write_all(include_bytes!(r"{full_path}")); +}} +"# + ) + .as_str(), + ); + } + + writeln!( + file, + r#" +use std::io::{{self, Write}}; +use crate::print; + +pub fn get_preset_list<'a>() -> &'a [print::Preset] {{ + &[ + {presets} + ] +}} + +pub fn print_preset_content(name: &str) {{ + match name {{ + {match_arms} + _ => {{}} + }} +}} +"# + )?; + Ok(()) +} diff --git a/docs/presets/bracketed-segments.md b/docs/presets/bracketed-segments.md index f595e7778..921f58bdb 100644 --- a/docs/presets/bracketed-segments.md +++ b/docs/presets/bracketed-segments.md @@ -9,6 +9,10 @@ in brackets instead of using the default Starship wording ("via", "on", etc.). ### Configuration +```sh +starship preset bracketed-segments > ~/.config/starship.toml +``` + [Click to download TOML](/presets/toml/bracketed-segments.toml) <<< @/.vuepress/public/presets/toml/bracketed-segments.toml diff --git a/docs/presets/nerd-font.md b/docs/presets/nerd-font.md index c5810efff..f523d01c6 100644 --- a/docs/presets/nerd-font.md +++ b/docs/presets/nerd-font.md @@ -12,6 +12,10 @@ This preset changes the symbols for each module to use Nerd Font symbols. ### Configuration +```sh +starship preset nerd-font-symbols > ~/.config/starship.toml +``` + [Click to download TOML](/presets/toml/nerd-font-symbols.toml) <<< @/.vuepress/public/presets/toml/nerd-font-symbols.toml diff --git a/docs/presets/no-runtimes.md b/docs/presets/no-runtimes.md index fd3050513..a8b326cc6 100644 --- a/docs/presets/no-runtimes.md +++ b/docs/presets/no-runtimes.md @@ -8,6 +8,10 @@ This preset hides the version of language runtimes. If you work in containers or ### Configuration +```sh +starship preset no-runtime-versions > ~/.config/starship.toml +``` + [Click to download TOML](/presets/toml/no-runtime-versions.toml) <<< @/.vuepress/public/presets/toml/no-runtime-versions.toml diff --git a/docs/presets/pastel-powerline.md b/docs/presets/pastel-powerline.md index 5488b00a2..72c8d0009 100644 --- a/docs/presets/pastel-powerline.md +++ b/docs/presets/pastel-powerline.md @@ -13,6 +13,10 @@ It also shows how path substitution works in starship. ### Configuration +```sh +starship preset pastel-powerline > ~/.config/starship.toml +``` + [Click to download TOML](/presets/toml/pastel-powerline.toml) <<< @/.vuepress/public/presets/toml/pastel-powerline.toml diff --git a/docs/presets/plain-text.md b/docs/presets/plain-text.md index 6c38c49a7..9f9e45924 100644 --- a/docs/presets/plain-text.md +++ b/docs/presets/plain-text.md @@ -9,6 +9,10 @@ don't have access to Unicode. ### Configuration +```sh +starship preset plain-text-symbols > ~/.config/starship.toml +``` + [Click to download TOML](/presets/toml/plain-text-symbols.toml) <<< @/.vuepress/public/presets/toml/plain-text-symbols.toml diff --git a/docs/presets/pure-preset.md b/docs/presets/pure-preset.md index ad61b4995..ae1e85fc4 100644 --- a/docs/presets/pure-preset.md +++ b/docs/presets/pure-preset.md @@ -8,6 +8,10 @@ This preset emulates the look and behavior of [Pure](https://github.com/sindreso ### Configuration +```sh +starship preset pure-preset > ~/.config/starship.toml +``` + [Click to download TOML](/presets/toml/pure-preset.toml) <<< @/.vuepress/public/presets/toml/pure-preset.toml diff --git a/src/main.rs b/src/main.rs index fba5a094f..0e4ba6538 100644 --- a/src/main.rs +++ b/src/main.rs @@ -63,6 +63,15 @@ enum Commands { #[clap(flatten)] properties: Properties, }, + /// Prints a preset config + Preset { + /// The name of preset to be printed + #[clap(required_unless_present("list"), value_enum)] + name: Option, + /// List out all preset names + #[clap(short, long)] + list: bool, + }, /// Prints the computed starship configuration PrintConfig { /// Print the default instead of the computed config @@ -182,6 +191,7 @@ fn main() { print::module(&module_name, properties); } } + Commands::Preset { name, list } => print::preset_command(name, list), Commands::Config { name, value } => { if let Some(name) = name { if let Some(value) = value { diff --git a/src/print.rs b/src/print.rs index 4c3a3c2f7..67572cd3c 100644 --- a/src/print.rs +++ b/src/print.rs @@ -1,4 +1,5 @@ use ansi_term::ANSIStrings; +use clap::{PossibleValue, ValueEnum}; use rayon::prelude::*; use std::collections::BTreeSet; use std::fmt::{self, Debug, Write as FmtWrite}; @@ -15,6 +16,7 @@ use crate::module::Module; use crate::module::ALL_MODULES; use crate::modules; use crate::segment::Segment; +use crate::shadow; pub struct Grapheme<'a>(pub &'a str); @@ -450,6 +452,35 @@ pub fn print_schema() { println!("{}", serde_json::to_string_pretty(&schema).unwrap()); } +#[derive(Clone, Debug)] +pub struct Preset(pub &'static str); + +impl ValueEnum for Preset { + fn value_variants<'a>() -> &'a [Self] { + shadow::get_preset_list() + } + + fn to_possible_value<'a>(&self) -> Option> { + Some(PossibleValue::new(self.0)) + } +} + +pub fn preset_command(name: Option, list: bool) { + if list { + println!("{}", preset_list()); + return; + } + let variant = name.expect("name argument must be specified"); + shadow::print_preset_content(variant.0); +} + +fn preset_list() -> String { + Preset::value_variants() + .iter() + .map(|v| format!("{}\n", v.0)) + .collect() +} + #[cfg(test)] mod test { use super::*; @@ -490,6 +521,19 @@ mod test { assert_eq!(expected, actual); } + #[test] + fn preset_list_returns_one_or_more_items() { + assert!(preset_list().trim().split('\n').count() > 0); + } + + #[test] + fn preset_command_does_not_panic_on_correct_inputs() { + preset_command(None, true); + Preset::value_variants() + .iter() + .for_each(|v| preset_command(Some(v.clone()), false)); + } + #[test] #[cfg(feature = "config-schema")] fn print_schema_does_not_panic() {