Skip to content

Commit

Permalink
refactor: propagate version formatting errors (starship#2566)
Browse files Browse the repository at this point in the history
* refactor: propagate version formatting errors

* refactor: trim version formatting boilerplate

* refactor(node): unwrap version formatting

* docs: fix typo

* docs: remove dots after `version_format`

* feat: lazy version parsing

* refactor(version-formatter): collect segments into string
  • Loading branch information
vladimyr authored and DavidSmith166 committed Apr 24, 2021
1 parent dcd6afa commit 8d4772f
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 158 deletions.
12 changes: 6 additions & 6 deletions docs/config/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1379,7 +1379,7 @@ By default the module will be shown if any of the following conditions are met:
| 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` |
| `version_format` | `v{raw}` | The version format. Available vars are `raw`, `major`, `minor`, & `patch` |
| `detect_extensions` | `["java", "class", "gradle", "jar", "cljs", "cljc"]` | Which extensions should trigger this module. |
| `detect_files` | `["pom.xml", "build.gradle.kts", "build.sbt", ".java-version", ".deps.edn", "project.clj", "build.boot"]` | Which filenames should trigger this module. |
| `detect_folders` | `[]` | Which folders should trigger this modules. |
Expand Down Expand Up @@ -1825,9 +1825,9 @@ By default the module will be shown if any of the following conditions are met:
| 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` |
| `version_format` | `v{raw}` | The version format. Available vars are `raw`, `major`, `minor`, & `patch` |
| `symbol` | `" "` | A format string representing the symbol of NodeJS. |
| `detect_extensions` | `["js", "mjs", "cjs", "ts"]` | Which extensions should trigger this moudle. |
| `detect_extensions` | `["js", "mjs", "cjs", "ts"]` | Which extensions should trigger this module. |
| `detect_files` | `["package.json", ".node-version"]` | Which filenames should trigger this module. |
| `detect_folders` | `["node_modules"]` | Which folders should trigger this module. |
| `style` | `"bold green"` | The style for the module. |
Expand Down Expand Up @@ -2135,7 +2135,7 @@ By default the module will be shown if any of the following conditions are met:
| Option | Default | Description |
| -------------------- | ------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------- |
| `format` | `'via [${symbol}${pyenv_prefix}(${version} )(\($virtualenv\) )]($style)'` | The format for the module. |
| `version_format`. | `v{raw}` | The version format. Available vars are `raw`, `major`, `minor`, & `patch` |
| `version_format` | `v{raw}` | The version format. Available vars are `raw`, `major`, `minor`, & `patch` |
| `symbol` | `"🐍 "` | A format string representing the symbol of Python |
| `style` | `"yellow bold"` | The style for the module. |
| `pyenv_version_name` | `false` | Use pyenv to get Python version |
Expand Down Expand Up @@ -2214,7 +2214,7 @@ The module will be shown if any of the following conditions are met:
| 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` |
| `version_format` | `v{raw}` | The version format. Available vars are `raw`, `major`, `minor`, & `patch` |
| `symbol` | `"💎 "` | A format string representing the symbol of Ruby. |
| `detect_extensions` | `["rb"]` | Which extensions should trigger this module. |
| `detect_files` | `["Gemfile", ".ruby-version"]` | Which filenames should trigger this module. |
Expand Down Expand Up @@ -2254,7 +2254,7 @@ The module will be shown if any of the following conditions are met:
| 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` |
| `version_format` | `v{raw}` | The version format. Available vars are `raw`, `major`, `minor`, & `patch` |
| `symbol` | `"🦀 "` | A format string representing the symbol of Rust |
| `detect_extensions` | `["rs"]` | Which extensions should trigger this module. |
| `detect_files` | `["Cargo.toml"]` | Which filenames should trigger this module. |
Expand Down
2 changes: 1 addition & 1 deletion src/formatter/string_formatter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ type VariableMapType<'a> =
type StyleVariableMapType<'a> =
BTreeMap<String, Option<Result<Cow<'a, str>, StringFormatterError>>>;

#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub enum StringFormatterError {
Custom(String),
Parse(PestError<Rule>),
Expand Down
73 changes: 39 additions & 34 deletions src/formatter/version.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use super::string_formatter::StringFormatterError;
use super::StringFormatter;
use once_cell::sync::Lazy;
use std::ops::Deref;
use versions::Versioning;

pub struct VersionFormatter<'a> {
Expand All @@ -17,81 +19,84 @@ impl<'a> VersionFormatter<'a> {
Ok(Self { formatter })
}

/// Format version string using provided format
pub fn format_version(
version: &'a str,
format: &'a str,
) -> Result<String, StringFormatterError> {
Self::new(format).and_then(|formatter| formatter.format(version))
}

/// Formats a version structure into a readable string
///
/// No matter what comes in, this will return some usable string
pub fn format_version(self, version: &str) -> String {
let parsed = Versioning::new(version);
pub fn format(self, version: &'a str) -> Result<String, StringFormatterError> {
let parsed = Lazy::new(|| Versioning::new(version));
let formatted = self
.formatter
.map(|variable| match variable {
"raw" => Some(Ok(version.to_string())),
"major" => match parsed.as_ref() {
"major" => match parsed.deref().as_ref() {
Some(Versioning::Ideal(v)) => Some(Ok(v.major.to_string())),
Some(Versioning::General(v)) => Some(Ok(v.nth_lenient(0)?.to_string())),
_ => None,
},
"minor" => match parsed.as_ref() {
"minor" => match parsed.deref().as_ref() {
Some(Versioning::Ideal(v)) => Some(Ok(v.minor.to_string())),
Some(Versioning::General(v)) => Some(Ok(v.nth_lenient(1)?.to_string())),
_ => None,
},
"patch" => match parsed.as_ref() {
"patch" => match parsed.deref().as_ref() {
Some(Versioning::Ideal(v)) => Some(Ok(v.patch.to_string())),
Some(Versioning::General(v)) => Some(Ok(v.nth_lenient(2)?.to_string())),
_ => None,
},
_ => None,
})
.parse(None);
match formatted {
Ok(segments) => segments

formatted.map(|segments| {
segments
.iter()
.map(|segment| segment.value.as_str())
.collect::<Vec<&str>>()
.join(""),
Err(_) => version.to_string(),
}
.collect::<String>()
})
}
}

#[cfg(test)]
mod tests {
use super::*;

const VERSION_FORMAT: &str = "major:${major} minor:${minor} patch:${patch} raw:${raw}";

#[test]
fn test_semver_full() {
const FORMAT_STR: &str = "major:${major} minor:${minor} patch:${patch} raw:${raw}";
let result = VersionFormatter::new(FORMAT_STR)
.unwrap()
.format_version("1.2.3");
assert_eq!(result, "major:1 minor:2 patch:3 raw:1.2.3");
assert_eq!(
VersionFormatter::format_version("1.2.3", VERSION_FORMAT),
Ok("major:1 minor:2 patch:3 raw:1.2.3".to_string())
);
}

#[test]
fn test_semver_partial() {
const FORMAT_STR: &str = "major:${major} minor:${minor} patch:${patch} raw:${raw}";
let result = VersionFormatter::new(FORMAT_STR)
.unwrap()
.format_version("1.2");
assert_eq!(result, "major:1 minor:2 patch: raw:1.2");
assert_eq!(
VersionFormatter::format_version("1.2", VERSION_FORMAT),
Ok("major:1 minor:2 patch: raw:1.2".to_string())
);
}

#[test]
fn test_general() {
const FORMAT_STR: &str = "major:${major} minor:${minor} patch:${patch} raw:${raw}";
let result = VersionFormatter::new(FORMAT_STR)
.unwrap()
.format_version("1.2-a.3");
assert_eq!(result, "major:1 minor:2 patch: raw:1.2-a.3");
assert_eq!(
VersionFormatter::format_version("1.2-a.3", VERSION_FORMAT),
Ok("major:1 minor:2 patch: raw:1.2-a.3".to_string())
);
}

#[test]
fn test_mess() {
const FORMAT_STR: &str = "major:${major} minor:${minor} patch:${patch} raw:${raw}";
let result = VersionFormatter::new(FORMAT_STR)
.unwrap()
.format_version("utter junk");
assert_eq!(result, "major: minor: patch: raw:utter junk");
fn test_dummy() {
assert_eq!(
VersionFormatter::format_version("dummy version", VERSION_FORMAT),
Ok("major: minor: patch: raw:dummy version".to_string())
);
}
}
Loading

0 comments on commit 8d4772f

Please sign in to comment.