From 8b6e982495aabf8396cae6fd93ff312d6c525fab Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Fri, 22 Sep 2023 14:06:09 -0400 Subject: [PATCH] Remove manual mapping in `FromStr` implementation for `StorySelector` (#3018) This PR removes the need for writing manual mappings in the `FromStr` implementation for the `StorySelector` enum used in the storybook CLI. We are now using the [`EnumString`](https://docs.rs/strum/0.25.0/strum/derive.EnumString.html) trait from `strum` to automatically derive snake_cased names for the enums. This will cut down on some of the manual work needed to wire up more stories to the storybook. Release Notes: - N/A --- Cargo.lock | 23 ++++++++++++++++++++++ crates/storybook/Cargo.toml | 1 + crates/storybook/src/storybook.rs | 32 ++++++++++++++++++++++--------- 3 files changed, 47 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5c01bbc4a9..186427e863 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7381,6 +7381,7 @@ dependencies = [ "serde", "settings", "simplelog", + "strum", "theme", "ui", "util", @@ -7403,6 +7404,28 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8d03b598d3d0fff69bf533ee3ef19b8eeb342729596df84bcc7e1f96ec4059" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.37", +] + [[package]] name = "subtle" version = "2.4.1" diff --git a/crates/storybook/Cargo.toml b/crates/storybook/Cargo.toml index 882a1a1bdb..49dd05ba30 100644 --- a/crates/storybook/Cargo.toml +++ b/crates/storybook/Cargo.toml @@ -17,6 +17,7 @@ rust-embed.workspace = true serde.workspace = true settings = { path = "../settings" } simplelog = "0.9" +strum = { version = "0.25.0", features = ["derive"] } theme = { path = "../theme" } ui = { path = "../ui" } util = { path = "../util" } diff --git a/crates/storybook/src/storybook.rs b/crates/storybook/src/storybook.rs index 3974bbce40..a57be4fd89 100644 --- a/crates/storybook/src/storybook.rs +++ b/crates/storybook/src/storybook.rs @@ -17,6 +17,7 @@ use simplelog::SimpleLogger; use stories::components::facepile::FacepileStory; use stories::components::traffic_lights::TrafficLightsStory; use stories::elements::avatar::AvatarStory; +use strum::EnumString; use ui::{ElementExt, Theme}; gpui2::actions! { @@ -33,22 +34,35 @@ enum StorySelector { impl FromStr for StorySelector { type Err = anyhow::Error; - fn from_str(s: &str) -> std::result::Result { - match s.to_ascii_lowercase().as_str() { - "elements/avatar" => Ok(Self::Element(ElementStory::Avatar)), - "components/facepile" => Ok(Self::Component(ComponentStory::Facepile)), - "components/traffic_lights" => Ok(Self::Component(ComponentStory::TrafficLights)), - _ => Err(anyhow!("story not found for '{s}'")), + fn from_str(raw_story_name: &str) -> std::result::Result { + let story = raw_story_name.to_ascii_lowercase(); + + if let Some((_, story)) = story.split_once("elements/") { + let element_story = ElementStory::from_str(story) + .with_context(|| format!("story not found for element '{story}'"))?; + + return Ok(Self::Element(element_story)); } + + if let Some((_, story)) = story.split_once("components/") { + let component_story = ComponentStory::from_str(story) + .with_context(|| format!("story not found for component '{story}'"))?; + + return Ok(Self::Component(component_story)); + } + + Err(anyhow!("story not found for '{raw_story_name}'")) } } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, EnumString)] +#[strum(serialize_all = "snake_case")] enum ElementStory { Avatar, } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, EnumString)] +#[strum(serialize_all = "snake_case")] enum ComponentStory { Facepile, TrafficLights, @@ -122,7 +136,7 @@ fn current_theme(cx: &mut ViewContext) -> Theme { .clone() } -use anyhow::{anyhow, Result}; +use anyhow::{anyhow, Context, Result}; use gpui2::AssetSource; use rust_embed::RustEmbed; use workspace::WorkspaceElement;