Begin porting Zed1 themes to Zed2 (#3793)
This PR is a first pass at porting the Zed1 themes to Zed2. For the initial release of Zed2 we'll be shipping just the themes that existed in Zed1, ported to Zed2. The new themes that were previously added just in Zed2 have been removed. Release Notes: - N/A
This commit is contained in:
parent
a1bd636c18
commit
b501f4eafc
21 changed files with 11599 additions and 7614 deletions
|
@ -73,10 +73,6 @@ pub struct ThemeMetadata {
|
|||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
struct Args {
|
||||
/// Whether to import Zed1 themes.
|
||||
#[arg(long)]
|
||||
zed1: bool,
|
||||
|
||||
/// Whether to warn when values are missing from the theme.
|
||||
#[arg(long)]
|
||||
warn_on_missing: bool,
|
||||
|
@ -106,176 +102,87 @@ fn main() -> Result<()> {
|
|||
TermLogger::init(LevelFilter::Trace, log_config, TerminalMode::Mixed)
|
||||
.expect("could not initialize logger");
|
||||
|
||||
log::info!("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?;
|
||||
/// Whether VS Code themes should be imported.
|
||||
///
|
||||
/// For the initial release of Zed2, we will just be using the Zed1 themes ported to Zed2.
|
||||
const IMPORT_VS_CODE_THEMES: bool = false;
|
||||
|
||||
if !theme_family_dir.file_type()?.is_dir() {
|
||||
continue;
|
||||
if IMPORT_VS_CODE_THEMES {
|
||||
log::info!("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 theme_family_slug = theme_family_dir
|
||||
.path()
|
||||
.file_stem()
|
||||
.ok_or(anyhow!("no file stem"))
|
||||
.map(|stem| stem.to_string_lossy().to_string())?;
|
||||
for theme_family_dir in fs::read_dir(&vscode_themes_path)? {
|
||||
let theme_family_dir = theme_family_dir?;
|
||||
|
||||
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() {
|
||||
log::info!("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 {
|
||||
log::info!("Converting '{}' theme", &theme_metadata.name);
|
||||
|
||||
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(_) => {
|
||||
log::info!("Failed to open file at path: {:?}", theme_file_path);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let theme_without_comments = StripComments::new(theme_file);
|
||||
let vscode_theme: VsCodeTheme = serde_json::from_reader(theme_without_comments)
|
||||
.context(format!("failed to parse theme {theme_file_path:?}"))?;
|
||||
|
||||
let converter = VsCodeThemeConverter::new(
|
||||
vscode_theme,
|
||||
theme_metadata,
|
||||
family_metadata.syntax.clone(),
|
||||
);
|
||||
|
||||
let theme = converter.convert()?;
|
||||
|
||||
themes.push(theme);
|
||||
}
|
||||
|
||||
let theme_family = UserThemeFamily {
|
||||
name: family_metadata.name.into(),
|
||||
author: family_metadata.author.into(),
|
||||
themes,
|
||||
};
|
||||
|
||||
theme_families.push(theme_family);
|
||||
}
|
||||
|
||||
if args.zed1 {
|
||||
let zed1_themes_path = PathBuf::from_str("assets/themes")?;
|
||||
|
||||
let zed1_theme_familes = [
|
||||
"Andromeda",
|
||||
"Atelier",
|
||||
"Ayu",
|
||||
"Gruvbox",
|
||||
"One",
|
||||
"Rosé Pine",
|
||||
"Sandcastle",
|
||||
"Solarized",
|
||||
"Summercamp",
|
||||
];
|
||||
|
||||
let mut zed1_themes_by_family: HashMap<String, Vec<UserTheme>> = HashMap::from_iter(
|
||||
zed1_theme_familes
|
||||
.into_iter()
|
||||
.map(|family| (family.to_string(), Vec::new())),
|
||||
);
|
||||
|
||||
let platform = gpui1::platform::current::platform();
|
||||
let zed1_font_cache = Arc::new(gpui1::FontCache::new(platform.fonts()));
|
||||
|
||||
let mut embedded_fonts = Vec::new();
|
||||
for font_path in Assets.list("fonts")? {
|
||||
if font_path.ends_with(".ttf") {
|
||||
let font_bytes = Assets.load(&font_path)?.to_vec();
|
||||
embedded_fonts.push(Arc::from(font_bytes));
|
||||
}
|
||||
}
|
||||
|
||||
platform.fonts().add_fonts(&embedded_fonts)?;
|
||||
|
||||
for entry in fs::read_dir(&zed1_themes_path)? {
|
||||
let entry = entry?;
|
||||
|
||||
if entry.file_type()?.is_dir() {
|
||||
if !theme_family_dir.file_type()?.is_dir() {
|
||||
continue;
|
||||
}
|
||||
|
||||
match entry.path().extension() {
|
||||
None => continue,
|
||||
Some(extension) => {
|
||||
if extension != "json" {
|
||||
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() {
|
||||
log::info!("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 {
|
||||
log::info!("Converting '{}' theme", &theme_metadata.name);
|
||||
|
||||
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(_) => {
|
||||
log::info!("Failed to open file at path: {:?}", theme_file_path);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let theme_without_comments = StripComments::new(theme_file);
|
||||
let vscode_theme: VsCodeTheme = serde_json::from_reader(theme_without_comments)
|
||||
.context(format!("failed to parse theme {theme_file_path:?}"))?;
|
||||
|
||||
let converter = VsCodeThemeConverter::new(
|
||||
vscode_theme,
|
||||
theme_metadata,
|
||||
family_metadata.syntax.clone(),
|
||||
);
|
||||
|
||||
let theme = converter.convert()?;
|
||||
|
||||
themes.push(theme);
|
||||
}
|
||||
|
||||
let theme_file_path = entry.path();
|
||||
|
||||
let theme_file = match File::open(&theme_file_path) {
|
||||
Ok(file) => file,
|
||||
Err(_) => {
|
||||
log::info!("Failed to open file at path: {:?}", theme_file_path);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let theme_without_comments = StripComments::new(theme_file);
|
||||
|
||||
let zed1_theme: Zed1Theme =
|
||||
gpui1::fonts::with_font_cache(zed1_font_cache.clone(), || {
|
||||
serde_json::from_reader(theme_without_comments)
|
||||
.context(format!("failed to parse theme {theme_file_path:?}"))
|
||||
})?;
|
||||
|
||||
let theme_name = zed1_theme.meta.name.clone();
|
||||
|
||||
let converter = Zed1ThemeConverter::new(zed1_theme);
|
||||
|
||||
let theme = converter.convert()?;
|
||||
|
||||
let Some((_, themes_for_family)) = zed1_themes_by_family
|
||||
.iter_mut()
|
||||
.find(|(family, _)| theme_name.starts_with(*family))
|
||||
else {
|
||||
log::warn!("No theme family found for '{}'.", theme_name);
|
||||
continue;
|
||||
};
|
||||
|
||||
themes_for_family.push(theme);
|
||||
}
|
||||
|
||||
for (family, themes) in zed1_themes_by_family {
|
||||
let theme_family = UserThemeFamily {
|
||||
name: format!("{family} (Zed1)"),
|
||||
author: "Zed Industries".to_string(),
|
||||
name: family_metadata.name.into(),
|
||||
author: family_metadata.author.into(),
|
||||
themes,
|
||||
};
|
||||
|
||||
|
@ -283,6 +190,99 @@ fn main() -> Result<()> {
|
|||
}
|
||||
}
|
||||
|
||||
let zed1_themes_path = PathBuf::from_str("assets/themes")?;
|
||||
|
||||
let zed1_theme_familes = [
|
||||
"Andromeda",
|
||||
"Atelier",
|
||||
"Ayu",
|
||||
"Gruvbox",
|
||||
"One",
|
||||
"Rosé Pine",
|
||||
"Sandcastle",
|
||||
"Solarized",
|
||||
"Summercamp",
|
||||
];
|
||||
|
||||
let mut zed1_themes_by_family: HashMap<String, Vec<UserTheme>> = HashMap::from_iter(
|
||||
zed1_theme_familes
|
||||
.into_iter()
|
||||
.map(|family| (family.to_string(), Vec::new())),
|
||||
);
|
||||
|
||||
let platform = gpui1::platform::current::platform();
|
||||
let zed1_font_cache = Arc::new(gpui1::FontCache::new(platform.fonts()));
|
||||
|
||||
let mut embedded_fonts = Vec::new();
|
||||
for font_path in Assets.list("fonts")? {
|
||||
if font_path.ends_with(".ttf") {
|
||||
let font_bytes = Assets.load(&font_path)?.to_vec();
|
||||
embedded_fonts.push(Arc::from(font_bytes));
|
||||
}
|
||||
}
|
||||
|
||||
platform.fonts().add_fonts(&embedded_fonts)?;
|
||||
|
||||
for entry in fs::read_dir(&zed1_themes_path)? {
|
||||
let entry = entry?;
|
||||
|
||||
if entry.file_type()?.is_dir() {
|
||||
continue;
|
||||
}
|
||||
|
||||
match entry.path().extension() {
|
||||
None => continue,
|
||||
Some(extension) => {
|
||||
if extension != "json" {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let theme_file_path = entry.path();
|
||||
|
||||
let theme_file = match File::open(&theme_file_path) {
|
||||
Ok(file) => file,
|
||||
Err(_) => {
|
||||
log::info!("Failed to open file at path: {:?}", theme_file_path);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let theme_without_comments = StripComments::new(theme_file);
|
||||
|
||||
let zed1_theme: Zed1Theme = gpui1::fonts::with_font_cache(zed1_font_cache.clone(), || {
|
||||
serde_json::from_reader(theme_without_comments)
|
||||
.context(format!("failed to parse theme {theme_file_path:?}"))
|
||||
})?;
|
||||
|
||||
let theme_name = zed1_theme.meta.name.clone();
|
||||
|
||||
let converter = Zed1ThemeConverter::new(zed1_theme);
|
||||
|
||||
let theme = converter.convert()?;
|
||||
|
||||
let Some((_, themes_for_family)) = zed1_themes_by_family
|
||||
.iter_mut()
|
||||
.find(|(family, _)| theme_name.starts_with(*family))
|
||||
else {
|
||||
log::warn!("No theme family found for '{}'.", theme_name);
|
||||
continue;
|
||||
};
|
||||
|
||||
themes_for_family.push(theme);
|
||||
}
|
||||
|
||||
for (family, themes) in zed1_themes_by_family {
|
||||
let theme_family = UserThemeFamily {
|
||||
name: family,
|
||||
author: "Zed Industries".to_string(),
|
||||
themes,
|
||||
};
|
||||
|
||||
theme_families.push(theme_family);
|
||||
}
|
||||
|
||||
let themes_output_path = PathBuf::from_str(OUT_PATH)?;
|
||||
|
||||
if !themes_output_path.exists() {
|
||||
|
|
|
@ -160,6 +160,7 @@ impl<'a> Debug for ThemeColorsRefinementPrinter<'a> {
|
|||
),
|
||||
("surface_background", self.0.surface_background),
|
||||
("background", self.0.background),
|
||||
("panel_background", self.0.panel_background),
|
||||
("element_background", self.0.element_background),
|
||||
("element_hover", self.0.element_hover),
|
||||
("element_active", self.0.element_active),
|
||||
|
|
|
@ -53,7 +53,7 @@ impl Zed1ThemeConverter {
|
|||
let syntax_theme = self.convert_syntax_theme()?;
|
||||
|
||||
Ok(UserTheme {
|
||||
name: format!("{} (Zed1)", self.theme.meta.name),
|
||||
name: self.theme.meta.name,
|
||||
appearance,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: theme_colors_refinement,
|
||||
|
@ -68,12 +68,16 @@ impl Zed1ThemeConverter {
|
|||
Some(zed1_color_to_hsla(color))
|
||||
}
|
||||
|
||||
let diff_style = self.theme.editor.diff.clone();
|
||||
let diff_style = &self.theme.editor.diff;
|
||||
let diagnostic_summary = &self.theme.workspace.status_bar.diagnostic_summary;
|
||||
|
||||
Ok(StatusColorsRefinement {
|
||||
created: convert(diff_style.inserted),
|
||||
modified: convert(diff_style.modified),
|
||||
deleted: convert(diff_style.deleted),
|
||||
success: convert(diagnostic_summary.icon_color_ok),
|
||||
warning: convert(diagnostic_summary.icon_color_warning),
|
||||
error: convert(diagnostic_summary.icon_color_error),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
@ -83,11 +87,11 @@ impl Zed1ThemeConverter {
|
|||
Some(zed1_color_to_hsla(color))
|
||||
}
|
||||
|
||||
let tab_bar = self.theme.workspace.tab_bar.clone();
|
||||
let active_tab = self.theme.workspace.tab_bar.tab_style(true, true).clone();
|
||||
let inactive_tab = self.theme.workspace.tab_bar.tab_style(true, false).clone();
|
||||
let toolbar = self.theme.workspace.toolbar.clone();
|
||||
let scrollbar = self.theme.editor.scrollbar.clone();
|
||||
let tab_bar = &self.theme.workspace.tab_bar;
|
||||
let active_tab = &self.theme.workspace.tab_bar.tab_style(true, true);
|
||||
let inactive_tab = &self.theme.workspace.tab_bar.tab_style(true, false);
|
||||
let toolbar = &self.theme.workspace.toolbar;
|
||||
let scrollbar = &self.theme.editor.scrollbar;
|
||||
|
||||
let zed1_titlebar_border = convert(self.theme.titlebar.container.border.color);
|
||||
|
||||
|
@ -95,6 +99,12 @@ impl Zed1ThemeConverter {
|
|||
border: zed1_titlebar_border,
|
||||
border_variant: zed1_titlebar_border,
|
||||
background: convert(self.theme.workspace.background),
|
||||
elevated_surface_background: self
|
||||
.theme
|
||||
.picker
|
||||
.container
|
||||
.background_color
|
||||
.map(zed1_color_to_hsla),
|
||||
title_bar_background: self
|
||||
.theme
|
||||
.titlebar
|
||||
|
@ -107,8 +117,38 @@ impl Zed1ThemeConverter {
|
|||
.status_bar
|
||||
.container
|
||||
.background_color
|
||||
.map(zed1_color_to_hsla)
|
||||
.or_else(|| {
|
||||
self.theme
|
||||
.titlebar
|
||||
.container
|
||||
.background_color
|
||||
.map(zed1_color_to_hsla)
|
||||
}),
|
||||
panel_background: self
|
||||
.theme
|
||||
.project_panel
|
||||
.container
|
||||
.background_color
|
||||
.map(zed1_color_to_hsla),
|
||||
text: convert(self.theme.project_panel.entry.default_style().text.color),
|
||||
text_muted: convert(active_tab.description.text.color),
|
||||
element_hover: self
|
||||
.theme
|
||||
.picker
|
||||
.item
|
||||
.hovered
|
||||
.as_ref()
|
||||
.and_then(|hovered| hovered.container.background_color)
|
||||
.map(zed1_color_to_hsla),
|
||||
element_selected: self
|
||||
.theme
|
||||
.picker
|
||||
.item
|
||||
.active_state()
|
||||
.container
|
||||
.background_color
|
||||
.map(zed1_color_to_hsla),
|
||||
text: convert(self.theme.editor.text_color),
|
||||
tab_bar_background: tab_bar.container.background_color.map(zed1_color_to_hsla),
|
||||
tab_active_background: active_tab
|
||||
.container
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue