Cargo.lock 🔗
@@ -7374,7 +7374,7 @@ name = "storybook"
version = "0.1.0"
dependencies = [
"anyhow",
- "clap 3.2.25",
+ "clap 4.4.4",
"gpui2",
"log",
"rust-embed",
Marshall Bowers created
This PR updates the storybook CLI to support displaying all of the
available stories.
The `--help` flag will now show a list of all the available stories:
<img width="1435" alt="Screenshot 2023-09-22 at 6 11 00 PM"
src="https://github.com/zed-industries/zed/assets/1486634/284e1a24-46ec-462e-9709-0f9b6e94931f">
Inputting an invalid story name will also show the list of available
stories:
<img width="1435" alt="Screenshot 2023-09-22 at 6 10 43 PM"
src="https://github.com/zed-industries/zed/assets/1486634/1ce3ae3f-ab03-4976-a06a-5a2b5f61eae3">
Release Notes:
- N/A
Cargo.lock | 2
crates/storybook/Cargo.toml | 2
crates/storybook/src/story_selector.rs | 76 ++++++++++++++++++++++++++++
crates/storybook/src/storybook.rs | 55 ++------------------
4 files changed, 84 insertions(+), 51 deletions(-)
@@ -7374,7 +7374,7 @@ name = "storybook"
version = "0.1.0"
dependencies = [
"anyhow",
- "clap 3.2.25",
+ "clap 4.4.4",
"gpui2",
"log",
"rust-embed",
@@ -10,7 +10,7 @@ path = "src/storybook.rs"
[dependencies]
anyhow.workspace = true
-clap = { version = "3.1", features = ["derive"] }
+clap = { version = "4.4", features = ["derive", "string"] }
gpui2 = { path = "../gpui2" }
log.workspace = true
rust-embed.workspace = true
@@ -0,0 +1,76 @@
+use std::{str::FromStr, sync::OnceLock};
+
+use anyhow::{anyhow, Context};
+use clap::builder::PossibleValue;
+use clap::ValueEnum;
+use strum::{EnumIter, EnumString, IntoEnumIterator};
+
+#[derive(Debug, Clone, Copy, strum::Display, EnumString, EnumIter)]
+#[strum(serialize_all = "snake_case")]
+pub enum ElementStory {
+ Avatar,
+}
+
+#[derive(Debug, Clone, Copy, strum::Display, EnumString, EnumIter)]
+#[strum(serialize_all = "snake_case")]
+pub enum ComponentStory {
+ Breadcrumb,
+ Facepile,
+ Toolbar,
+ TrafficLights,
+}
+
+#[derive(Debug, Clone, Copy)]
+pub enum StorySelector {
+ Element(ElementStory),
+ Component(ComponentStory),
+}
+
+impl FromStr for StorySelector {
+ type Err = anyhow::Error;
+
+ fn from_str(raw_story_name: &str) -> std::result::Result<Self, Self::Err> {
+ 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}'"))
+ }
+}
+
+/// The list of all stories available in the storybook.
+static ALL_STORIES: OnceLock<Vec<StorySelector>> = OnceLock::new();
+
+impl ValueEnum for StorySelector {
+ fn value_variants<'a>() -> &'a [Self] {
+ let stories = ALL_STORIES.get_or_init(|| {
+ let element_stories = ElementStory::iter().map(Self::Element);
+ let component_stories = ComponentStory::iter().map(Self::Component);
+
+ element_stories.chain(component_stories).collect::<Vec<_>>()
+ });
+
+ stories
+ }
+
+ fn to_possible_value(&self) -> Option<clap::builder::PossibleValue> {
+ let value = match self {
+ Self::Element(story) => format!("elements/{story}"),
+ Self::Component(story) => format!("components/{story}"),
+ };
+
+ Some(PossibleValue::new(value))
+ }
+}
@@ -3,10 +3,9 @@
mod collab_panel;
mod stories;
mod story;
+mod story_selector;
mod workspace;
-use std::str::FromStr;
-
use ::theme as legacy_theme;
use clap::Parser;
use gpui2::{serde_json, vec2f, view, Element, IntoElement, RectF, ViewContext, WindowBounds};
@@ -19,61 +18,19 @@ use stories::components::facepile::FacepileStory;
use stories::components::toolbar::ToolbarStory;
use stories::components::traffic_lights::TrafficLightsStory;
use stories::elements::avatar::AvatarStory;
-use strum::EnumString;
use ui::{ElementExt, Theme};
+use crate::story_selector::{ComponentStory, ElementStory, StorySelector};
+
gpui2::actions! {
storybook,
[ToggleInspector]
}
-#[derive(Debug, Clone, Copy)]
-enum StorySelector {
- Element(ElementStory),
- Component(ComponentStory),
-}
-
-impl FromStr for StorySelector {
- type Err = anyhow::Error;
-
- fn from_str(raw_story_name: &str) -> std::result::Result<Self, Self::Err> {
- 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, EnumString)]
-#[strum(serialize_all = "snake_case")]
-enum ElementStory {
- Avatar,
-}
-
-#[derive(Debug, Clone, Copy, EnumString)]
-#[strum(serialize_all = "snake_case")]
-enum ComponentStory {
- Breadcrumb,
- Facepile,
- Toolbar,
- TrafficLights,
-}
-
#[derive(Parser)]
+#[command(author, version, about, long_about = None)]
struct Args {
+ #[arg(value_enum)]
story: Option<StorySelector>,
}
@@ -146,7 +103,7 @@ fn current_theme<V: 'static>(cx: &mut ViewContext<V>) -> Theme {
.clone()
}
-use anyhow::{anyhow, Context, Result};
+use anyhow::{anyhow, Result};
use gpui2::AssetSource;
use rust_embed::RustEmbed;
use workspace::WorkspaceElement;