Merge remote-tracking branch 'origin/main' into editor2-paint

This commit is contained in:
Antonio Scandurra 2023-11-07 13:09:48 +01:00
commit bdf6e8bcc7
204 changed files with 48828 additions and 1648 deletions

View file

@ -0,0 +1,18 @@
[package]
name = "theme_importer"
version = "0.1.0"
edition = "2021"
publish = false
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
anyhow.workspace = true
convert_case = "0.6.0"
gpui = { package = "gpui2", path = "../gpui2" }
log.workspace = true
rust-embed.workspace = true
serde.workspace = true
simplelog = "0.9"
theme = { package = "theme2", path = "../theme2" }
uuid.workspace = true

View file

@ -0,0 +1,124 @@
# Zed Theme Importer
---
## Usage
- `cargo run -p theme_importer` - Import the context of `assets/themes/src`
---
## Troubleshooting
As the importer generates rust files, you may need to manually do some cleanup in `registry.rs` and `themes/mod.rs` if you remove themes or delete the `themes` folder in the theme crate.
---
## Required Structure
To import a theme or series of themes 3 things are required:
- `family.json`: A JSON file containing the theme family metadata and list of theme variants
- `{theme_name}.json`: One theme json for each theme variant
- `LICENSE`: A license file for the theme family
### `family.json`
#### `name`
The name of the theme family. Avoid special characters.
This will be used for the theme family directory name (lowercased) and the theme family name in the Zed UI.
Good:
- `Rose Pine`
- `Synthwave 84`
- `Monokai Solarized`
Bad:
- `Rosé Pine`
- `Synthwave '84`
- `Monokai (Solarized)`
#### `author`
The author of the theme family. This can be a name or a username.
This will be used for the theme family author in the Zed UI.
#### `themes`
A list of theme variants.
`appearance` can be either `light` or `dark`. This will impact which default fallback colors are used, and where the theme shows up in the Zed UI.
### `{theme_name}.json`
Each theme added to the family must have a corresponding JSON file. This JSON file can be obtained from the VSCode extensions folder (once you have installed it.) This is usually located at `~/.vscode/extensions` (on macOS).
You can use `open ~/.vscode/extensions` to open the folder in Finder directly.
Copy that json file into the theme family directory and tidy up the filenames as needed.
### `LICENSE`
A LICENSE file is required to import a theme family. Failing to provide a complete text license will cause it to be skipped when the import is run.
If the theme only provices a license code (e.g. MIT, Apache 2.0, etc.) then put that code into the LICENSE file.
If no license is provided, either contact the theme creator or don't add the theme.
---
### Complete Example:
An example family with multiple variants:
```json
{
"name": "Ayu",
// When both name and username are available
// prefer the `username (name)` format
"author": "dempfi (Ike Ku)",
"themes": [
{
"name": "Ayu Light",
"file_name": "ayu-light.json",
"appearance": "light"
},
{
"name": "Ayu Mirage",
"file_name": "ayu-mirage.json",
"appearance": "dark"
},
{
"name": "Ayu Dark",
"file_name": "ayu-dark.json",
"appearance": "dark"
}
]
}
```
An example single variant family:
```json
{
"name": "Andromeda",
"author": "Eliver Lara (EliverLara)",
"themes": [
{
"name": "Andromeda",
"file_name": "andromeda.json",
"appearance": "dark"
},
{
"name": "Andromeda Bordered",
"file_name": "andromeda-bordered.json",
"appearance": "dark"
}
]
}
```

View file

@ -0,0 +1,215 @@
mod theme_printer;
mod util;
mod vscode;
use std::fs::{self, File};
use std::io::Write;
use std::path::PathBuf;
use std::str::FromStr;
use anyhow::{anyhow, Context, Result};
use convert_case::{Case, Casing};
use gpui::serde_json;
use log::LevelFilter;
use serde::Deserialize;
use simplelog::SimpleLogger;
use theme::{default_color_scales, Appearance, ThemeFamily};
use vscode::VsCodeThemeConverter;
use crate::theme_printer::ThemeFamilyPrinter;
use crate::vscode::VsCodeTheme;
#[derive(Debug, Deserialize)]
struct FamilyMetadata {
pub name: String,
pub author: String,
pub themes: Vec<ThemeMetadata>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ThemeAppearanceJson {
Light,
Dark,
}
impl From<ThemeAppearanceJson> for Appearance {
fn from(value: ThemeAppearanceJson) -> Self {
match value {
ThemeAppearanceJson::Light => Self::Light,
ThemeAppearanceJson::Dark => Self::Dark,
}
}
}
#[derive(Debug, Deserialize)]
pub struct ThemeMetadata {
pub name: String,
pub file_name: String,
pub appearance: ThemeAppearanceJson,
}
fn main() -> Result<()> {
const SOURCE_PATH: &str = "assets/themes/src/vscode";
const OUT_PATH: &str = "crates/theme2/src/themes";
SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger");
println!("Loading themes source...");
let vscode_themes_path = PathBuf::from_str(SOURCE_PATH)?;
if !vscode_themes_path.exists() {
return Err(anyhow!(format!(
"Couldn't find {}, make sure it exists",
SOURCE_PATH
)));
}
let mut theme_families = Vec::new();
for theme_family_dir in fs::read_dir(&vscode_themes_path)? {
let theme_family_dir = theme_family_dir?;
if !theme_family_dir.file_type()?.is_dir() {
continue;
}
let theme_family_slug = theme_family_dir
.path()
.file_stem()
.ok_or(anyhow!("no file stem"))
.map(|stem| stem.to_string_lossy().to_string())?;
let family_metadata_file = File::open(theme_family_dir.path().join("family.json"))
.context(format!(
"no `family.json` found for '{}'",
theme_family_slug
))?;
let license_file_path = theme_family_dir.path().join("LICENSE");
if !license_file_path.exists() {
println!("Skipping theme family '{}' because it does not have a LICENSE file. This theme will only be imported once a LICENSE file is provided.", theme_family_slug);
continue;
}
let family_metadata: FamilyMetadata = serde_json::from_reader(family_metadata_file)
.context(format!(
"failed to parse `family.json` for '{theme_family_slug}'"
))?;
let mut themes = Vec::new();
for theme_metadata in family_metadata.themes {
let theme_file_path = theme_family_dir.path().join(&theme_metadata.file_name);
let theme_file = match File::open(&theme_file_path) {
Ok(file) => file,
Err(_) => {
println!("Failed to open file at path: {:?}", theme_file_path);
continue;
}
};
let vscode_theme: VsCodeTheme = serde_json::from_reader(theme_file)
.context(format!("failed to parse theme {theme_file_path:?}"))?;
let converter = VsCodeThemeConverter::new(vscode_theme, theme_metadata);
let theme = converter.convert()?;
themes.push(theme);
}
let theme_family = ThemeFamily {
id: uuid::Uuid::new_v4().to_string(),
name: family_metadata.name.into(),
author: family_metadata.author.into(),
themes,
scales: default_color_scales(),
};
theme_families.push(theme_family);
}
let themes_output_path = PathBuf::from_str(OUT_PATH)?;
if !themes_output_path.exists() {
println!("Creating directory: {:?}", themes_output_path);
fs::create_dir_all(&themes_output_path)?;
}
let mut mod_rs_file = File::create(themes_output_path.join(format!("mod.rs")))?;
let mut theme_modules = Vec::new();
for theme_family in theme_families {
let theme_family_slug = theme_family.name.to_string().to_case(Case::Snake);
let mut output_file =
File::create(themes_output_path.join(format!("{theme_family_slug}.rs")))?;
println!(
"Creating file: {:?}",
themes_output_path.join(format!("{theme_family_slug}.rs"))
);
let theme_module = format!(
r#"
use gpui::rgba;
use crate::{{
default_color_scales, Appearance, GitStatusColors, PlayerColor, PlayerColors, StatusColors,
SyntaxTheme, SystemColors, ThemeColors, ThemeFamily, ThemeStyles, ThemeVariant,
}};
pub fn {theme_family_slug}() -> ThemeFamily {{
{theme_family_definition}
}}
"#,
theme_family_definition = format!("{:#?}", ThemeFamilyPrinter::new(theme_family))
);
output_file.write_all(theme_module.as_bytes())?;
theme_modules.push(theme_family_slug);
}
let themes_vector_contents = format!(
r#"
use crate::ThemeFamily;
pub(crate) fn all_imported_themes() -> Vec<ThemeFamily> {{
vec![{all_themes}]
}}
"#,
all_themes = theme_modules
.iter()
.map(|module| format!("{}()", module))
.collect::<Vec<_>>()
.join(", ")
);
let mod_rs_contents = format!(
r#"
{mod_statements}
{use_statements}
{themes_vector_contents}
"#,
mod_statements = theme_modules
.iter()
.map(|module| format!("mod {module};"))
.collect::<Vec<_>>()
.join("\n"),
use_statements = theme_modules
.iter()
.map(|module| format!("pub use {module}::*;"))
.collect::<Vec<_>>()
.join("\n"),
themes_vector_contents = themes_vector_contents
);
mod_rs_file.write_all(mod_rs_contents.as_bytes())?;
Ok(())
}

View file

@ -0,0 +1,384 @@
use std::fmt::{self, Debug};
use gpui::{Hsla, Rgba};
use theme::{
Appearance, GitStatusColors, PlayerColor, PlayerColors, StatusColors, SyntaxTheme,
SystemColors, ThemeColors, ThemeFamily, ThemeStyles, ThemeVariant,
};
struct RawSyntaxPrinter<'a>(&'a str);
impl<'a> Debug for RawSyntaxPrinter<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
struct HslaPrinter(Hsla);
impl Debug for HslaPrinter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", IntoPrinter(&Rgba::from(self.0)))
}
}
struct IntoPrinter<'a, D: Debug>(&'a D);
impl<'a, D: Debug> Debug for IntoPrinter<'a, D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}.into()", self.0)
}
}
pub struct VecPrinter<'a, T>(&'a Vec<T>);
impl<'a, T: Debug> Debug for VecPrinter<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "vec!{:?}", &self.0)
}
}
pub struct ThemeFamilyPrinter(ThemeFamily);
impl ThemeFamilyPrinter {
pub fn new(theme_family: ThemeFamily) -> Self {
Self(theme_family)
}
}
impl Debug for ThemeFamilyPrinter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ThemeFamily")
.field("id", &IntoPrinter(&self.0.id))
.field("name", &IntoPrinter(&self.0.name))
.field("author", &IntoPrinter(&self.0.author))
.field(
"themes",
&VecPrinter(
&self
.0
.themes
.iter()
.map(|theme| ThemeVariantPrinter(theme))
.collect(),
),
)
.field("scales", &RawSyntaxPrinter("default_color_scales()"))
.finish()
}
}
pub struct ThemeVariantPrinter<'a>(&'a ThemeVariant);
impl<'a> Debug for ThemeVariantPrinter<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ThemeVariant")
.field("id", &IntoPrinter(&self.0.id))
.field("name", &IntoPrinter(&self.0.name))
.field("appearance", &AppearancePrinter(self.0.appearance))
.field("styles", &ThemeStylesPrinter(&self.0.styles))
.finish()
}
}
pub struct AppearancePrinter(Appearance);
impl Debug for AppearancePrinter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Appearance::{:?}", self.0)
}
}
pub struct ThemeStylesPrinter<'a>(&'a ThemeStyles);
impl<'a> Debug for ThemeStylesPrinter<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ThemeStyles")
.field("system", &SystemColorsPrinter(&self.0.system))
.field("colors", &ThemeColorsPrinter(&self.0.colors))
.field("status", &StatusColorsPrinter(&self.0.status))
.field("git", &GitStatusColorsPrinter(&self.0.git))
.field("player", &PlayerColorsPrinter(&self.0.player))
.field("syntax", &SyntaxThemePrinter(&self.0.syntax))
.finish()
}
}
pub struct SystemColorsPrinter<'a>(&'a SystemColors);
impl<'a> Debug for SystemColorsPrinter<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SystemColors")
.field("transparent", &HslaPrinter(self.0.transparent))
.field(
"mac_os_traffic_light_red",
&HslaPrinter(self.0.mac_os_traffic_light_red),
)
.field(
"mac_os_traffic_light_yellow",
&HslaPrinter(self.0.mac_os_traffic_light_yellow),
)
.field(
"mac_os_traffic_light_green",
&HslaPrinter(self.0.mac_os_traffic_light_green),
)
.finish()
}
}
pub struct ThemeColorsPrinter<'a>(&'a ThemeColors);
impl<'a> Debug for ThemeColorsPrinter<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ThemeColors")
.field("border", &HslaPrinter(self.0.border))
.field("border_variant", &HslaPrinter(self.0.border_variant))
.field("border_focused", &HslaPrinter(self.0.border_focused))
.field("border_disabled", &HslaPrinter(self.0.border_disabled))
.field("border_selected", &HslaPrinter(self.0.border_selected))
.field(
"border_transparent",
&HslaPrinter(self.0.border_transparent),
)
.field(
"elevated_surface_background",
&HslaPrinter(self.0.elevated_surface_background),
)
.field(
"surface_background",
&HslaPrinter(self.0.surface_background),
)
.field("background", &HslaPrinter(self.0.background))
.field(
"element_background",
&HslaPrinter(self.0.element_background),
)
.field("element_hover", &HslaPrinter(self.0.element_hover))
.field("element_active", &HslaPrinter(self.0.element_active))
.field("element_selected", &HslaPrinter(self.0.element_selected))
.field("element_disabled", &HslaPrinter(self.0.element_disabled))
.field(
"element_placeholder",
&HslaPrinter(self.0.element_placeholder),
)
.field(
"element_drop_target",
&HslaPrinter(self.0.element_drop_target),
)
.field(
"ghost_element_background",
&HslaPrinter(self.0.ghost_element_background),
)
.field(
"ghost_element_hover",
&HslaPrinter(self.0.ghost_element_hover),
)
.field(
"ghost_element_active",
&HslaPrinter(self.0.ghost_element_active),
)
.field(
"ghost_element_selected",
&HslaPrinter(self.0.ghost_element_selected),
)
.field(
"ghost_element_disabled",
&HslaPrinter(self.0.ghost_element_disabled),
)
.field("text", &HslaPrinter(self.0.text))
.field("text_muted", &HslaPrinter(self.0.text_muted))
.field("text_placeholder", &HslaPrinter(self.0.text_placeholder))
.field("text_disabled", &HslaPrinter(self.0.text_disabled))
.field("text_accent", &HslaPrinter(self.0.text_accent))
.field("icon", &HslaPrinter(self.0.icon))
.field("icon_muted", &HslaPrinter(self.0.icon_muted))
.field("icon_disabled", &HslaPrinter(self.0.icon_disabled))
.field("icon_placeholder", &HslaPrinter(self.0.icon_placeholder))
.field("icon_accent", &HslaPrinter(self.0.icon_accent))
.field(
"status_bar_background",
&HslaPrinter(self.0.status_bar_background),
)
.field(
"title_bar_background",
&HslaPrinter(self.0.title_bar_background),
)
.field(
"toolbar_background",
&HslaPrinter(self.0.toolbar_background),
)
.field(
"tab_bar_background",
&HslaPrinter(self.0.tab_bar_background),
)
.field(
"tab_inactive_background",
&HslaPrinter(self.0.tab_inactive_background),
)
.field(
"tab_active_background",
&HslaPrinter(self.0.tab_active_background),
)
.field("editor_background", &HslaPrinter(self.0.editor_background))
.field(
"editor_subheader_background",
&HslaPrinter(self.0.editor_subheader_background),
)
.field(
"editor_active_line",
&HslaPrinter(self.0.editor_active_line_background),
)
.field(
"terminal_background",
&HslaPrinter(self.0.terminal_background),
)
.field(
"terminal_ansi_bright_black",
&HslaPrinter(self.0.terminal_ansi_bright_black),
)
.field(
"terminal_ansi_bright_red",
&HslaPrinter(self.0.terminal_ansi_bright_red),
)
.field(
"terminal_ansi_bright_green",
&HslaPrinter(self.0.terminal_ansi_bright_green),
)
.field(
"terminal_ansi_bright_yellow",
&HslaPrinter(self.0.terminal_ansi_bright_yellow),
)
.field(
"terminal_ansi_bright_blue",
&HslaPrinter(self.0.terminal_ansi_bright_blue),
)
.field(
"terminal_ansi_bright_magenta",
&HslaPrinter(self.0.terminal_ansi_bright_magenta),
)
.field(
"terminal_ansi_bright_cyan",
&HslaPrinter(self.0.terminal_ansi_bright_cyan),
)
.field(
"terminal_ansi_bright_white",
&HslaPrinter(self.0.terminal_ansi_bright_white),
)
.field(
"terminal_ansi_black",
&HslaPrinter(self.0.terminal_ansi_black),
)
.field("terminal_ansi_red", &HslaPrinter(self.0.terminal_ansi_red))
.field(
"terminal_ansi_green",
&HslaPrinter(self.0.terminal_ansi_green),
)
.field(
"terminal_ansi_yellow",
&HslaPrinter(self.0.terminal_ansi_yellow),
)
.field(
"terminal_ansi_blue",
&HslaPrinter(self.0.terminal_ansi_blue),
)
.field(
"terminal_ansi_magenta",
&HslaPrinter(self.0.terminal_ansi_magenta),
)
.field(
"terminal_ansi_cyan",
&HslaPrinter(self.0.terminal_ansi_cyan),
)
.field(
"terminal_ansi_white",
&HslaPrinter(self.0.terminal_ansi_white),
)
.finish()
}
}
pub struct StatusColorsPrinter<'a>(&'a StatusColors);
impl<'a> Debug for StatusColorsPrinter<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("StatusColors")
.field("conflict", &HslaPrinter(self.0.conflict))
.field("created", &HslaPrinter(self.0.created))
.field("deleted", &HslaPrinter(self.0.deleted))
.field("error", &HslaPrinter(self.0.error))
.field("hidden", &HslaPrinter(self.0.hidden))
.field("ignored", &HslaPrinter(self.0.ignored))
.field("info", &HslaPrinter(self.0.info))
.field("modified", &HslaPrinter(self.0.modified))
.field("renamed", &HslaPrinter(self.0.renamed))
.field("success", &HslaPrinter(self.0.success))
.field("warning", &HslaPrinter(self.0.warning))
.finish()
}
}
pub struct GitStatusColorsPrinter<'a>(&'a GitStatusColors);
impl<'a> Debug for GitStatusColorsPrinter<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("GitStatusColors")
.field("conflict", &HslaPrinter(self.0.conflict))
.field("created", &HslaPrinter(self.0.created))
.field("deleted", &HslaPrinter(self.0.deleted))
.field("ignored", &HslaPrinter(self.0.ignored))
.field("modified", &HslaPrinter(self.0.modified))
.field("renamed", &HslaPrinter(self.0.renamed))
.finish()
}
}
pub struct PlayerColorsPrinter<'a>(&'a PlayerColors);
impl<'a> Debug for PlayerColorsPrinter<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("PlayerColors")
.field(&VecPrinter(
&self
.0
.0
.iter()
.map(|player_color| PlayerColorPrinter(player_color))
.collect(),
))
.finish()
}
}
pub struct PlayerColorPrinter<'a>(&'a PlayerColor);
impl<'a> Debug for PlayerColorPrinter<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PlayerColor")
.field("cursor", &HslaPrinter(self.0.cursor))
.field("background", &HslaPrinter(self.0.background))
.field("selection", &HslaPrinter(self.0.selection))
.finish()
}
}
pub struct SyntaxThemePrinter<'a>(&'a SyntaxTheme);
impl<'a> Debug for SyntaxThemePrinter<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SyntaxTheme")
.field(
"highlights",
&VecPrinter(
&self
.0
.highlights
.iter()
.map(|(token, highlight)| {
(IntoPrinter(token), HslaPrinter(highlight.color.unwrap()))
})
.collect(),
),
)
.finish()
}
}

View file

@ -0,0 +1,11 @@
use anyhow::Result;
pub trait Traverse<T, U> {
fn traverse(self, f: impl FnOnce(T) -> Result<U>) -> Result<Option<U>>;
}
impl<T, U> Traverse<T, U> for Option<T> {
fn traverse(self, f: impl FnOnce(T) -> Result<U>) -> Result<Option<U>> {
self.map_or(Ok(None), |value| f(value).map(Some))
}
}

View file

@ -0,0 +1,606 @@
use anyhow::Result;
use gpui::{Hsla, Refineable, Rgba};
use serde::Deserialize;
use theme::{
Appearance, GitStatusColors, PlayerColors, StatusColors, SyntaxTheme, SystemColors,
ThemeColors, ThemeColorsRefinement, ThemeStyles, ThemeVariant,
};
use crate::util::Traverse;
use crate::ThemeMetadata;
#[derive(Deserialize, Debug)]
pub struct VsCodeTheme {
#[serde(rename = "$schema")]
pub schema: Option<String>,
pub name: Option<String>,
pub author: Option<String>,
pub maintainers: Option<Vec<String>>,
#[serde(rename = "semanticClass")]
pub semantic_class: Option<String>,
#[serde(rename = "semanticHighlighting")]
pub semantic_highlighting: Option<bool>,
pub colors: VsCodeColors,
}
#[derive(Debug, Deserialize)]
pub struct VsCodeColors {
#[serde(rename = "terminal.background")]
pub terminal_background: Option<String>,
#[serde(rename = "terminal.foreground")]
pub terminal_foreground: Option<String>,
#[serde(rename = "terminal.ansiBrightBlack")]
pub terminal_ansi_bright_black: Option<String>,
#[serde(rename = "terminal.ansiBrightRed")]
pub terminal_ansi_bright_red: Option<String>,
#[serde(rename = "terminal.ansiBrightGreen")]
pub terminal_ansi_bright_green: Option<String>,
#[serde(rename = "terminal.ansiBrightYellow")]
pub terminal_ansi_bright_yellow: Option<String>,
#[serde(rename = "terminal.ansiBrightBlue")]
pub terminal_ansi_bright_blue: Option<String>,
#[serde(rename = "terminal.ansiBrightMagenta")]
pub terminal_ansi_bright_magenta: Option<String>,
#[serde(rename = "terminal.ansiBrightCyan")]
pub terminal_ansi_bright_cyan: Option<String>,
#[serde(rename = "terminal.ansiBrightWhite")]
pub terminal_ansi_bright_white: Option<String>,
#[serde(rename = "terminal.ansiBlack")]
pub terminal_ansi_black: Option<String>,
#[serde(rename = "terminal.ansiRed")]
pub terminal_ansi_red: Option<String>,
#[serde(rename = "terminal.ansiGreen")]
pub terminal_ansi_green: Option<String>,
#[serde(rename = "terminal.ansiYellow")]
pub terminal_ansi_yellow: Option<String>,
#[serde(rename = "terminal.ansiBlue")]
pub terminal_ansi_blue: Option<String>,
#[serde(rename = "terminal.ansiMagenta")]
pub terminal_ansi_magenta: Option<String>,
#[serde(rename = "terminal.ansiCyan")]
pub terminal_ansi_cyan: Option<String>,
#[serde(rename = "terminal.ansiWhite")]
pub terminal_ansi_white: Option<String>,
#[serde(rename = "focusBorder")]
pub focus_border: Option<String>,
pub foreground: Option<String>,
#[serde(rename = "selection.background")]
pub selection_background: Option<String>,
#[serde(rename = "errorForeground")]
pub error_foreground: Option<String>,
#[serde(rename = "button.background")]
pub button_background: Option<String>,
#[serde(rename = "button.foreground")]
pub button_foreground: Option<String>,
#[serde(rename = "button.secondaryBackground")]
pub button_secondary_background: Option<String>,
#[serde(rename = "button.secondaryForeground")]
pub button_secondary_foreground: Option<String>,
#[serde(rename = "button.secondaryHoverBackground")]
pub button_secondary_hover_background: Option<String>,
#[serde(rename = "dropdown.background")]
pub dropdown_background: Option<String>,
#[serde(rename = "dropdown.border")]
pub dropdown_border: Option<String>,
#[serde(rename = "dropdown.foreground")]
pub dropdown_foreground: Option<String>,
#[serde(rename = "input.background")]
pub input_background: Option<String>,
#[serde(rename = "input.foreground")]
pub input_foreground: Option<String>,
#[serde(rename = "input.border")]
pub input_border: Option<String>,
#[serde(rename = "input.placeholderForeground")]
pub input_placeholder_foreground: Option<String>,
#[serde(rename = "inputOption.activeBorder")]
pub input_option_active_border: Option<String>,
#[serde(rename = "inputValidation.infoBorder")]
pub input_validation_info_border: Option<String>,
#[serde(rename = "inputValidation.warningBorder")]
pub input_validation_warning_border: Option<String>,
#[serde(rename = "inputValidation.errorBorder")]
pub input_validation_error_border: Option<String>,
#[serde(rename = "badge.foreground")]
pub badge_foreground: Option<String>,
#[serde(rename = "badge.background")]
pub badge_background: Option<String>,
#[serde(rename = "progressBar.background")]
pub progress_bar_background: Option<String>,
#[serde(rename = "list.activeSelectionBackground")]
pub list_active_selection_background: Option<String>,
#[serde(rename = "list.activeSelectionForeground")]
pub list_active_selection_foreground: Option<String>,
#[serde(rename = "list.dropBackground")]
pub list_drop_background: Option<String>,
#[serde(rename = "list.focusBackground")]
pub list_focus_background: Option<String>,
#[serde(rename = "list.highlightForeground")]
pub list_highlight_foreground: Option<String>,
#[serde(rename = "list.hoverBackground")]
pub list_hover_background: Option<String>,
#[serde(rename = "list.inactiveSelectionBackground")]
pub list_inactive_selection_background: Option<String>,
#[serde(rename = "list.warningForeground")]
pub list_warning_foreground: Option<String>,
#[serde(rename = "list.errorForeground")]
pub list_error_foreground: Option<String>,
#[serde(rename = "activityBar.background")]
pub activity_bar_background: Option<String>,
#[serde(rename = "activityBar.inactiveForeground")]
pub activity_bar_inactive_foreground: Option<String>,
#[serde(rename = "activityBar.foreground")]
pub activity_bar_foreground: Option<String>,
#[serde(rename = "activityBar.activeBorder")]
pub activity_bar_active_border: Option<String>,
#[serde(rename = "activityBar.activeBackground")]
pub activity_bar_active_background: Option<String>,
#[serde(rename = "activityBarBadge.background")]
pub activity_bar_badge_background: Option<String>,
#[serde(rename = "activityBarBadge.foreground")]
pub activity_bar_badge_foreground: Option<String>,
#[serde(rename = "sideBar.background")]
pub side_bar_background: Option<String>,
#[serde(rename = "sideBarTitle.foreground")]
pub side_bar_title_foreground: Option<String>,
#[serde(rename = "sideBarSectionHeader.background")]
pub side_bar_section_header_background: Option<String>,
#[serde(rename = "sideBarSectionHeader.border")]
pub side_bar_section_header_border: Option<String>,
#[serde(rename = "editorGroup.border")]
pub editor_group_border: Option<String>,
#[serde(rename = "editorGroup.dropBackground")]
pub editor_group_drop_background: Option<String>,
#[serde(rename = "editorGroupHeader.tabsBackground")]
pub editor_group_header_tabs_background: Option<String>,
#[serde(rename = "tab.activeBackground")]
pub tab_active_background: Option<String>,
#[serde(rename = "tab.activeForeground")]
pub tab_active_foreground: Option<String>,
#[serde(rename = "tab.border")]
pub tab_border: Option<String>,
#[serde(rename = "tab.activeBorderTop")]
pub tab_active_border_top: Option<String>,
#[serde(rename = "tab.inactiveBackground")]
pub tab_inactive_background: Option<String>,
#[serde(rename = "tab.inactiveForeground")]
pub tab_inactive_foreground: Option<String>,
#[serde(rename = "editor.foreground")]
pub editor_foreground: Option<String>,
#[serde(rename = "editor.background")]
pub editor_background: Option<String>,
#[serde(rename = "editorLineNumber.foreground")]
pub editor_line_number_foreground: Option<String>,
#[serde(rename = "editor.selectionBackground")]
pub editor_selection_background: Option<String>,
#[serde(rename = "editor.selectionHighlightBackground")]
pub editor_selection_highlight_background: Option<String>,
#[serde(rename = "editor.foldBackground")]
pub editor_fold_background: Option<String>,
#[serde(rename = "editor.wordHighlightBackground")]
pub editor_word_highlight_background: Option<String>,
#[serde(rename = "editor.wordHighlightStrongBackground")]
pub editor_word_highlight_strong_background: Option<String>,
#[serde(rename = "editor.findMatchBackground")]
pub editor_find_match_background: Option<String>,
#[serde(rename = "editor.findMatchHighlightBackground")]
pub editor_find_match_highlight_background: Option<String>,
#[serde(rename = "editor.findRangeHighlightBackground")]
pub editor_find_range_highlight_background: Option<String>,
#[serde(rename = "editor.hoverHighlightBackground")]
pub editor_hover_highlight_background: Option<String>,
#[serde(rename = "editor.lineHighlightBorder")]
pub editor_line_highlight_border: Option<String>,
#[serde(rename = "editorLink.activeForeground")]
pub editor_link_active_foreground: Option<String>,
#[serde(rename = "editor.rangeHighlightBackground")]
pub editor_range_highlight_background: Option<String>,
#[serde(rename = "editor.snippetTabstopHighlightBackground")]
pub editor_snippet_tabstop_highlight_background: Option<String>,
#[serde(rename = "editor.snippetTabstopHighlightBorder")]
pub editor_snippet_tabstop_highlight_border: Option<String>,
#[serde(rename = "editor.snippetFinalTabstopHighlightBackground")]
pub editor_snippet_final_tabstop_highlight_background: Option<String>,
#[serde(rename = "editor.snippetFinalTabstopHighlightBorder")]
pub editor_snippet_final_tabstop_highlight_border: Option<String>,
#[serde(rename = "editorWhitespace.foreground")]
pub editor_whitespace_foreground: Option<String>,
#[serde(rename = "editorIndentGuide.background")]
pub editor_indent_guide_background: Option<String>,
#[serde(rename = "editorIndentGuide.activeBackground")]
pub editor_indent_guide_active_background: Option<String>,
#[serde(rename = "editorRuler.foreground")]
pub editor_ruler_foreground: Option<String>,
#[serde(rename = "editorCodeLens.foreground")]
pub editor_code_lens_foreground: Option<String>,
#[serde(rename = "editorBracketHighlight.foreground1")]
pub editor_bracket_highlight_foreground1: Option<String>,
#[serde(rename = "editorBracketHighlight.foreground2")]
pub editor_bracket_highlight_foreground2: Option<String>,
#[serde(rename = "editorBracketHighlight.foreground3")]
pub editor_bracket_highlight_foreground3: Option<String>,
#[serde(rename = "editorBracketHighlight.foreground4")]
pub editor_bracket_highlight_foreground4: Option<String>,
#[serde(rename = "editorBracketHighlight.foreground5")]
pub editor_bracket_highlight_foreground5: Option<String>,
#[serde(rename = "editorBracketHighlight.foreground6")]
pub editor_bracket_highlight_foreground6: Option<String>,
#[serde(rename = "editorBracketHighlight.unexpectedBracket.foreground")]
pub editor_bracket_highlight_unexpected_bracket_foreground: Option<String>,
#[serde(rename = "editorOverviewRuler.border")]
pub editor_overview_ruler_border: Option<String>,
#[serde(rename = "editorOverviewRuler.selectionHighlightForeground")]
pub editor_overview_ruler_selection_highlight_foreground: Option<String>,
#[serde(rename = "editorOverviewRuler.wordHighlightForeground")]
pub editor_overview_ruler_word_highlight_foreground: Option<String>,
#[serde(rename = "editorOverviewRuler.wordHighlightStrongForeground")]
pub editor_overview_ruler_word_highlight_strong_foreground: Option<String>,
#[serde(rename = "editorOverviewRuler.modifiedForeground")]
pub editor_overview_ruler_modified_foreground: Option<String>,
#[serde(rename = "editorOverviewRuler.addedForeground")]
pub editor_overview_ruler_added_foreground: Option<String>,
#[serde(rename = "editorOverviewRuler.deletedForeground")]
pub editor_overview_ruler_deleted_foreground: Option<String>,
#[serde(rename = "editorOverviewRuler.errorForeground")]
pub editor_overview_ruler_error_foreground: Option<String>,
#[serde(rename = "editorOverviewRuler.warningForeground")]
pub editor_overview_ruler_warning_foreground: Option<String>,
#[serde(rename = "editorOverviewRuler.infoForeground")]
pub editor_overview_ruler_info_foreground: Option<String>,
#[serde(rename = "editorError.foreground")]
pub editor_error_foreground: Option<String>,
#[serde(rename = "editorWarning.foreground")]
pub editor_warning_foreground: Option<String>,
#[serde(rename = "editorGutter.modifiedBackground")]
pub editor_gutter_modified_background: Option<String>,
#[serde(rename = "editorGutter.addedBackground")]
pub editor_gutter_added_background: Option<String>,
#[serde(rename = "editorGutter.deletedBackground")]
pub editor_gutter_deleted_background: Option<String>,
#[serde(rename = "gitDecoration.modifiedResourceForeground")]
pub git_decoration_modified_resource_foreground: Option<String>,
#[serde(rename = "gitDecoration.deletedResourceForeground")]
pub git_decoration_deleted_resource_foreground: Option<String>,
#[serde(rename = "gitDecoration.untrackedResourceForeground")]
pub git_decoration_untracked_resource_foreground: Option<String>,
#[serde(rename = "gitDecoration.ignoredResourceForeground")]
pub git_decoration_ignored_resource_foreground: Option<String>,
#[serde(rename = "gitDecoration.conflictingResourceForeground")]
pub git_decoration_conflicting_resource_foreground: Option<String>,
#[serde(rename = "diffEditor.insertedTextBackground")]
pub diff_editor_inserted_text_background: Option<String>,
#[serde(rename = "diffEditor.removedTextBackground")]
pub diff_editor_removed_text_background: Option<String>,
#[serde(rename = "inlineChat.regionHighlight")]
pub inline_chat_region_highlight: Option<String>,
#[serde(rename = "editorWidget.background")]
pub editor_widget_background: Option<String>,
#[serde(rename = "editorSuggestWidget.background")]
pub editor_suggest_widget_background: Option<String>,
#[serde(rename = "editorSuggestWidget.foreground")]
pub editor_suggest_widget_foreground: Option<String>,
#[serde(rename = "editorSuggestWidget.selectedBackground")]
pub editor_suggest_widget_selected_background: Option<String>,
#[serde(rename = "editorHoverWidget.background")]
pub editor_hover_widget_background: Option<String>,
#[serde(rename = "editorHoverWidget.border")]
pub editor_hover_widget_border: Option<String>,
#[serde(rename = "editorMarkerNavigation.background")]
pub editor_marker_navigation_background: Option<String>,
#[serde(rename = "peekView.border")]
pub peek_view_border: Option<String>,
#[serde(rename = "peekViewEditor.background")]
pub peek_view_editor_background: Option<String>,
#[serde(rename = "peekViewEditor.matchHighlightBackground")]
pub peek_view_editor_match_highlight_background: Option<String>,
#[serde(rename = "peekViewResult.background")]
pub peek_view_result_background: Option<String>,
#[serde(rename = "peekViewResult.fileForeground")]
pub peek_view_result_file_foreground: Option<String>,
#[serde(rename = "peekViewResult.lineForeground")]
pub peek_view_result_line_foreground: Option<String>,
#[serde(rename = "peekViewResult.matchHighlightBackground")]
pub peek_view_result_match_highlight_background: Option<String>,
#[serde(rename = "peekViewResult.selectionBackground")]
pub peek_view_result_selection_background: Option<String>,
#[serde(rename = "peekViewResult.selectionForeground")]
pub peek_view_result_selection_foreground: Option<String>,
#[serde(rename = "peekViewTitle.background")]
pub peek_view_title_background: Option<String>,
#[serde(rename = "peekViewTitleDescription.foreground")]
pub peek_view_title_description_foreground: Option<String>,
#[serde(rename = "peekViewTitleLabel.foreground")]
pub peek_view_title_label_foreground: Option<String>,
#[serde(rename = "merge.currentHeaderBackground")]
pub merge_current_header_background: Option<String>,
#[serde(rename = "merge.incomingHeaderBackground")]
pub merge_incoming_header_background: Option<String>,
#[serde(rename = "editorOverviewRuler.currentContentForeground")]
pub editor_overview_ruler_current_content_foreground: Option<String>,
#[serde(rename = "editorOverviewRuler.incomingContentForeground")]
pub editor_overview_ruler_incoming_content_foreground: Option<String>,
#[serde(rename = "panel.background")]
pub panel_background: Option<String>,
#[serde(rename = "panel.border")]
pub panel_border: Option<String>,
#[serde(rename = "panelTitle.activeBorder")]
pub panel_title_active_border: Option<String>,
#[serde(rename = "panelTitle.activeForeground")]
pub panel_title_active_foreground: Option<String>,
#[serde(rename = "panelTitle.inactiveForeground")]
pub panel_title_inactive_foreground: Option<String>,
#[serde(rename = "statusBar.background")]
pub status_bar_background: Option<String>,
#[serde(rename = "statusBar.foreground")]
pub status_bar_foreground: Option<String>,
#[serde(rename = "statusBar.debuggingBackground")]
pub status_bar_debugging_background: Option<String>,
#[serde(rename = "statusBar.debuggingForeground")]
pub status_bar_debugging_foreground: Option<String>,
#[serde(rename = "statusBar.noFolderBackground")]
pub status_bar_no_folder_background: Option<String>,
#[serde(rename = "statusBar.noFolderForeground")]
pub status_bar_no_folder_foreground: Option<String>,
#[serde(rename = "statusBarItem.prominentBackground")]
pub status_bar_item_prominent_background: Option<String>,
#[serde(rename = "statusBarItem.prominentHoverBackground")]
pub status_bar_item_prominent_hover_background: Option<String>,
#[serde(rename = "statusBarItem.remoteForeground")]
pub status_bar_item_remote_foreground: Option<String>,
#[serde(rename = "statusBarItem.remoteBackground")]
pub status_bar_item_remote_background: Option<String>,
#[serde(rename = "titleBar.activeBackground")]
pub title_bar_active_background: Option<String>,
#[serde(rename = "titleBar.activeForeground")]
pub title_bar_active_foreground: Option<String>,
#[serde(rename = "titleBar.inactiveBackground")]
pub title_bar_inactive_background: Option<String>,
#[serde(rename = "titleBar.inactiveForeground")]
pub title_bar_inactive_foreground: Option<String>,
#[serde(rename = "extensionButton.prominentForeground")]
pub extension_button_prominent_foreground: Option<String>,
#[serde(rename = "extensionButton.prominentBackground")]
pub extension_button_prominent_background: Option<String>,
#[serde(rename = "extensionButton.prominentHoverBackground")]
pub extension_button_prominent_hover_background: Option<String>,
#[serde(rename = "pickerGroup.border")]
pub picker_group_border: Option<String>,
#[serde(rename = "pickerGroup.foreground")]
pub picker_group_foreground: Option<String>,
#[serde(rename = "debugToolBar.background")]
pub debug_tool_bar_background: Option<String>,
#[serde(rename = "walkThrough.embeddedEditorBackground")]
pub walk_through_embedded_editor_background: Option<String>,
#[serde(rename = "settings.headerForeground")]
pub settings_header_foreground: Option<String>,
#[serde(rename = "settings.modifiedItemIndicator")]
pub settings_modified_item_indicator: Option<String>,
#[serde(rename = "settings.dropdownBackground")]
pub settings_dropdown_background: Option<String>,
#[serde(rename = "settings.dropdownForeground")]
pub settings_dropdown_foreground: Option<String>,
#[serde(rename = "settings.dropdownBorder")]
pub settings_dropdown_border: Option<String>,
#[serde(rename = "settings.checkboxBackground")]
pub settings_checkbox_background: Option<String>,
#[serde(rename = "settings.checkboxForeground")]
pub settings_checkbox_foreground: Option<String>,
#[serde(rename = "settings.checkboxBorder")]
pub settings_checkbox_border: Option<String>,
#[serde(rename = "settings.textInputBackground")]
pub settings_text_input_background: Option<String>,
#[serde(rename = "settings.textInputForeground")]
pub settings_text_input_foreground: Option<String>,
#[serde(rename = "settings.textInputBorder")]
pub settings_text_input_border: Option<String>,
#[serde(rename = "settings.numberInputBackground")]
pub settings_number_input_background: Option<String>,
#[serde(rename = "settings.numberInputForeground")]
pub settings_number_input_foreground: Option<String>,
#[serde(rename = "settings.numberInputBorder")]
pub settings_number_input_border: Option<String>,
#[serde(rename = "breadcrumb.foreground")]
pub breadcrumb_foreground: Option<String>,
#[serde(rename = "breadcrumb.background")]
pub breadcrumb_background: Option<String>,
#[serde(rename = "breadcrumb.focusForeground")]
pub breadcrumb_focus_foreground: Option<String>,
#[serde(rename = "breadcrumb.activeSelectionForeground")]
pub breadcrumb_active_selection_foreground: Option<String>,
#[serde(rename = "breadcrumbPicker.background")]
pub breadcrumb_picker_background: Option<String>,
#[serde(rename = "listFilterWidget.background")]
pub list_filter_widget_background: Option<String>,
#[serde(rename = "listFilterWidget.outline")]
pub list_filter_widget_outline: Option<String>,
#[serde(rename = "listFilterWidget.noMatchesOutline")]
pub list_filter_widget_no_matches_outline: Option<String>,
}
fn try_parse_color(color: &str) -> Result<Hsla> {
Ok(Rgba::try_from(color)?.into())
}
pub struct VsCodeThemeConverter {
theme: VsCodeTheme,
theme_metadata: ThemeMetadata,
}
impl VsCodeThemeConverter {
pub fn new(theme: VsCodeTheme, theme_metadata: ThemeMetadata) -> Self {
Self {
theme,
theme_metadata,
}
}
pub fn convert(self) -> Result<ThemeVariant> {
let appearance = self.theme_metadata.appearance.into();
let mut theme_colors = match appearance {
Appearance::Light => ThemeColors::default_light(),
Appearance::Dark => ThemeColors::default_dark(),
};
let vscode_colors = &self.theme.colors;
let theme_colors_refinements = ThemeColorsRefinement {
border: vscode_colors
.panel_border
.as_ref()
.traverse(|color| try_parse_color(&color))?,
border_variant: vscode_colors
.panel_border
.as_ref()
.traverse(|color| try_parse_color(&color))?,
border_focused: vscode_colors
.panel_border
.as_ref()
.traverse(|color| try_parse_color(&color))?,
border_disabled: vscode_colors
.panel_border
.as_ref()
.traverse(|color| try_parse_color(&color))?,
border_selected: vscode_colors
.panel_border
.as_ref()
.traverse(|color| try_parse_color(&color))?,
border_transparent: vscode_colors
.panel_border
.as_ref()
.traverse(|color| try_parse_color(&color))?,
elevated_surface_background: vscode_colors
.panel_background
.as_ref()
.traverse(|color| try_parse_color(&color))?,
surface_background: vscode_colors
.panel_background
.as_ref()
.traverse(|color| try_parse_color(&color))?,
background: vscode_colors
.editor_background
.as_ref()
.traverse(|color| try_parse_color(&color))?,
element_background: vscode_colors
.button_background
.as_ref()
.traverse(|color| try_parse_color(&color))?,
text: vscode_colors
.foreground
.as_ref()
.traverse(|color| try_parse_color(&color))?,
tab_active_background: vscode_colors
.tab_active_background
.as_ref()
.traverse(|color| try_parse_color(&color))?,
tab_inactive_background: vscode_colors
.tab_inactive_background
.as_ref()
.traverse(|color| try_parse_color(&color))?,
terminal_background: vscode_colors
.terminal_background
.as_ref()
.traverse(|color| try_parse_color(&color))?,
terminal_ansi_bright_black: vscode_colors
.terminal_ansi_bright_black
.as_ref()
.traverse(|color| try_parse_color(&color))?,
terminal_ansi_bright_red: vscode_colors
.terminal_ansi_bright_red
.as_ref()
.traverse(|color| try_parse_color(&color))?,
terminal_ansi_bright_green: vscode_colors
.terminal_ansi_bright_green
.as_ref()
.traverse(|color| try_parse_color(&color))?,
terminal_ansi_bright_yellow: vscode_colors
.terminal_ansi_bright_yellow
.as_ref()
.traverse(|color| try_parse_color(&color))?,
terminal_ansi_bright_blue: vscode_colors
.terminal_ansi_bright_blue
.as_ref()
.traverse(|color| try_parse_color(&color))?,
terminal_ansi_bright_magenta: vscode_colors
.terminal_ansi_bright_magenta
.as_ref()
.traverse(|color| try_parse_color(&color))?,
terminal_ansi_bright_cyan: vscode_colors
.terminal_ansi_bright_cyan
.as_ref()
.traverse(|color| try_parse_color(&color))?,
terminal_ansi_bright_white: vscode_colors
.terminal_ansi_bright_white
.as_ref()
.traverse(|color| try_parse_color(&color))?,
terminal_ansi_black: vscode_colors
.terminal_ansi_black
.as_ref()
.traverse(|color| try_parse_color(&color))?,
terminal_ansi_red: vscode_colors
.terminal_ansi_red
.as_ref()
.traverse(|color| try_parse_color(&color))?,
terminal_ansi_green: vscode_colors
.terminal_ansi_green
.as_ref()
.traverse(|color| try_parse_color(&color))?,
terminal_ansi_yellow: vscode_colors
.terminal_ansi_yellow
.as_ref()
.traverse(|color| try_parse_color(&color))?,
terminal_ansi_blue: vscode_colors
.terminal_ansi_blue
.as_ref()
.traverse(|color| try_parse_color(&color))?,
terminal_ansi_magenta: vscode_colors
.terminal_ansi_magenta
.as_ref()
.traverse(|color| try_parse_color(&color))?,
terminal_ansi_cyan: vscode_colors
.terminal_ansi_cyan
.as_ref()
.traverse(|color| try_parse_color(&color))?,
terminal_ansi_white: vscode_colors
.terminal_ansi_white
.as_ref()
.traverse(|color| try_parse_color(&color))?,
..Default::default()
};
theme_colors.refine(&theme_colors_refinements);
Ok(ThemeVariant {
id: uuid::Uuid::new_v4().to_string(),
name: self.theme_metadata.name.into(),
appearance,
styles: ThemeStyles {
system: SystemColors::default(),
colors: theme_colors,
status: StatusColors::default(),
git: GitStatusColors::default(),
player: PlayerColors::default(),
syntax: SyntaxTheme::default_dark(),
},
})
}
}
// #[cfg(test)]
// mod tests {
// use super::*;
// use std::path::PathBuf;
// #[test]
// fn test_deserialize_theme() {
// let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
// let root_dir = manifest_dir.parent().unwrap().parent().unwrap();
// let mut d = root_dir.to_path_buf();
// d.push("assets/themes/src/vsc/dracula/dracula.json");
// let data = std::fs::read_to_string(d).expect("Unable to read file");
// let result: Theme = serde_json::from_str(&data).unwrap();
// println!("{:#?}", result);
// }
// }