Publish theme json schema v0.2.0 (#21428)

Peter Tripp created

Fix theme json schema so `./script/import-themes print-schema` works again
Update schema to reflect current structs
([diff](https://gist.github.com/notpeter/26e6d0939985f542e8492458442ac62a/revisions?diff=unified&w=))

https://zed.dev/schema/themes/v0.2.0.json

Change summary

assets/themes/andromeda/andromeda.json   |  2 
assets/themes/atelier/atelier.json       |  2 
assets/themes/ayu/ayu.json               |  2 
assets/themes/gruvbox/gruvbox.json       |  2 
assets/themes/one/one.json               |  2 
assets/themes/rose_pine/rose_pine.json   |  2 
assets/themes/sandcastle/sandcastle.json |  2 
assets/themes/solarized/solarized.json   |  2 
assets/themes/summercamp/summercamp.json |  2 
crates/theme_importer/src/main.rs        | 78 ++++++++++++++-----------
docs/src/extensions/themes.md            |  4 
script/import-themes                     |  2 
12 files changed, 55 insertions(+), 47 deletions(-)

Detailed changes

assets/themes/andromeda/andromeda.json πŸ”—

@@ -1,5 +1,5 @@
 {
-  "$schema": "https://zed.dev/schema/themes/v0.1.0.json",
+  "$schema": "https://zed.dev/schema/themes/v0.2.0.json",
   "name": "Andromeda",
   "author": "Zed Industries",
   "themes": [

assets/themes/atelier/atelier.json πŸ”—

@@ -1,5 +1,5 @@
 {
-  "$schema": "https://zed.dev/schema/themes/v0.1.0.json",
+  "$schema": "https://zed.dev/schema/themes/v0.2.0.json",
   "name": "Atelier",
   "author": "Zed Industries",
   "themes": [

assets/themes/ayu/ayu.json πŸ”—

@@ -1,5 +1,5 @@
 {
-  "$schema": "https://zed.dev/schema/themes/v0.1.0.json",
+  "$schema": "https://zed.dev/schema/themes/v0.2.0.json",
   "name": "Ayu",
   "author": "Zed Industries",
   "themes": [

assets/themes/gruvbox/gruvbox.json πŸ”—

@@ -1,5 +1,5 @@
 {
-  "$schema": "https://zed.dev/schema/themes/v0.1.0.json",
+  "$schema": "https://zed.dev/schema/themes/v0.2.0.json",
   "name": "Gruvbox",
   "author": "Zed Industries",
   "themes": [

assets/themes/one/one.json πŸ”—

@@ -1,5 +1,5 @@
 {
-  "$schema": "https://zed.dev/schema/themes/v0.1.0.json",
+  "$schema": "https://zed.dev/schema/themes/v0.2.0.json",
   "name": "One",
   "author": "Zed Industries",
   "themes": [

assets/themes/rose_pine/rose_pine.json πŸ”—

@@ -1,5 +1,5 @@
 {
-  "$schema": "https://zed.dev/schema/themes/v0.1.0.json",
+  "$schema": "https://zed.dev/schema/themes/v0.2.0.json",
   "name": "RosΓ© Pine",
   "author": "Zed Industries",
   "themes": [

assets/themes/sandcastle/sandcastle.json πŸ”—

@@ -1,5 +1,5 @@
 {
-  "$schema": "https://zed.dev/schema/themes/v0.1.0.json",
+  "$schema": "https://zed.dev/schema/themes/v0.2.0.json",
   "name": "Sandcastle",
   "author": "Zed Industries",
   "themes": [

assets/themes/solarized/solarized.json πŸ”—

@@ -1,5 +1,5 @@
 {
-  "$schema": "https://zed.dev/schema/themes/v0.1.0.json",
+  "$schema": "https://zed.dev/schema/themes/v0.2.0.json",
   "name": "Solarized",
   "author": "Zed Industries",
   "themes": [

assets/themes/summercamp/summercamp.json πŸ”—

@@ -1,5 +1,5 @@
 {
-  "$schema": "https://zed.dev/schema/themes/v0.1.0.json",
+  "$schema": "https://zed.dev/schema/themes/v0.2.0.json",
   "name": "Summercamp",
   "author": "Zed Industries",
   "themes": [

crates/theme_importer/src/main.rs πŸ”—

@@ -19,6 +19,8 @@ use theme::{Appearance, AppearanceContent, ThemeFamilyContent};
 use crate::vscode::VsCodeTheme;
 use crate::vscode::VsCodeThemeConverter;
 
+const ZED_THEME_SCHEMA_URL: &str = "https://zed.dev/public/schema/themes/v0.2.0.json";
+
 #[derive(Debug, Deserialize)]
 struct FamilyMetadata {
     pub name: String,
@@ -69,34 +71,53 @@ pub struct ThemeMetadata {
 #[derive(Parser)]
 #[command(author, version, about, long_about = None)]
 struct Args {
-    /// The path to the theme to import.
-    theme_path: PathBuf,
-
-    /// Whether to warn when values are missing from the theme.
-    #[arg(long)]
-    warn_on_missing: bool,
-
-    /// The path to write the output to.
-    #[arg(long, short)]
-    output: Option<PathBuf>,
-
     #[command(subcommand)]
-    command: Option<Command>,
+    command: Command,
 }
 
-#[derive(Subcommand)]
+#[derive(PartialEq, Subcommand)]
 enum Command {
     /// Prints the JSON schema for a theme.
     PrintSchema,
+    /// Converts a VSCode theme to Zed format [default]
+    Convert {
+        /// The path to the theme to import.
+        theme_path: PathBuf,
+
+        /// Whether to warn when values are missing from the theme.
+        #[arg(long)]
+        warn_on_missing: bool,
+
+        /// The path to write the output to.
+        #[arg(long, short)]
+        output: Option<PathBuf>,
+    },
 }
 
 fn main() -> Result<()> {
     let args = Args::parse();
 
+    match args.command {
+        Command::PrintSchema => {
+            let theme_family_schema = schema_for!(ThemeFamilyContent);
+            println!(
+                "{}",
+                serde_json::to_string_pretty(&theme_family_schema).unwrap()
+            );
+            Ok(())
+        }
+        Command::Convert {
+            theme_path,
+            warn_on_missing,
+            output,
+        } => convert(theme_path, output, warn_on_missing),
+    }
+}
+
+fn convert(theme_file_path: PathBuf, output: Option<PathBuf>, warn_on_missing: bool) -> Result<()> {
     let log_config = {
         let mut config = simplelog::ConfigBuilder::new();
-
-        if !args.warn_on_missing {
+        if !warn_on_missing {
             config.add_filter_ignore_str("theme_printer");
         }
 
@@ -111,28 +132,11 @@ fn main() -> Result<()> {
     )
     .expect("could not initialize logger");
 
-    if let Some(command) = args.command {
-        match command {
-            Command::PrintSchema => {
-                let theme_family_schema = schema_for!(ThemeFamilyContent);
-
-                println!(
-                    "{}",
-                    serde_json::to_string_pretty(&theme_family_schema).unwrap()
-                );
-
-                return Ok(());
-            }
-        }
-    }
-
-    let theme_file_path = args.theme_path;
-
     let theme_file = match File::open(&theme_file_path) {
         Ok(file) => file,
         Err(err) => {
             log::info!("Failed to open file at path: {:?}", theme_file_path);
-            return Err(err)?;
+            return Err(err.into());
         }
     };
 
@@ -148,10 +152,14 @@ fn main() -> Result<()> {
     let converter = VsCodeThemeConverter::new(vscode_theme, theme_metadata, IndexMap::new());
 
     let theme = converter.convert()?;
-
+    let mut theme = serde_json::to_value(theme).unwrap();
+    theme.as_object_mut().unwrap().insert(
+        "$schema".to_string(),
+        serde_json::Value::String(ZED_THEME_SCHEMA_URL.to_string()),
+    );
     let theme_json = serde_json::to_string_pretty(&theme).unwrap();
 
-    if let Some(output) = args.output {
+    if let Some(output) = output {
         let mut file = File::create(output)?;
         file.write_all(theme_json.as_bytes())?;
     } else {

docs/src/extensions/themes.md πŸ”—

@@ -2,13 +2,13 @@
 
 The `themes` directory in an extension should contain one or more theme files.
 
-Each theme file should adhere to the JSON schema specified at [`https://zed.dev/schema/themes/v0.1.0.json`](https://zed.dev/schema/themes/v0.1.0.json).
+Each theme file should adhere to the JSON schema specified at [`https://zed.dev/schema/themes/v0.2.0.json`](https://zed.dev/schema/themes/v0.2.0.json).
 
 See [this blog post](https://zed.dev/blog/user-themes-now-in-preview) for more details about creating themes.
 
 ## Theme JSON Structure
 
-The structure of a Zed theme is defined in the [Zed Theme JSON Schema](https://zed.dev/schema/themes/v0.1.0.json).
+The structure of a Zed theme is defined in the [Zed Theme JSON Schema](https://zed.dev/schema/themes/v0.2.0.json).
 
 A Zed theme consists of a Theme Family object including: