Add serialized versions of themes (#6885)

This PR adds serialized versions of each of the themes that currently
ship with Zed.

In a future PR we'll be looking to make these the canonical
representations of the built-in themes.

Note that we're intentionally repurposing the `theme_importer` to do
this, so that crate is a bit rough-and-ready at the moment.

Release Notes:

- N/A
This commit is contained in:
Marshall Bowers 2024-01-27 13:35:43 -05:00 committed by GitHub
parent 9d6414b0cc
commit 0fe0683ef4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 13672 additions and 14 deletions

View file

@ -23,5 +23,5 @@ serde.workspace = true
serde_json.workspace = true
simplelog = "0.9"
strum = { version = "0.25.0", features = ["derive"] }
theme = { path = "../theme", features = ["importing-themes"] }
theme = { path = "../theme", features = [] }
uuid.workspace = true

View file

@ -16,13 +16,17 @@ use any_ascii::any_ascii;
use anyhow::{anyhow, Context, Result};
use clap::Parser;
use convert_case::{Case, Casing};
use gpui::Hsla;
use indexmap::IndexMap;
use indoc::formatdoc;
use json_comments::StripComments;
use log::LevelFilter;
use serde::Deserialize;
use simplelog::{TermLogger, TerminalMode};
use theme::{Appearance, UserTheme, UserThemeFamily};
use theme::{
Appearance, FontWeightContent, HighlightStyleContent, StatusColorsContent, ThemeColorsContent,
ThemeContent, ThemeFamilyContent, ThemeStyleContent, UserTheme, UserThemeFamily,
};
use crate::theme_printer::UserThemeFamilyPrinter;
use crate::vscode::VsCodeTheme;
@ -100,6 +104,38 @@ fn main() -> Result<()> {
TermLogger::init(LevelFilter::Trace, log_config, TerminalMode::Mixed)
.expect("could not initialize logger");
if 1 < 2 {
let themes = Vec::new();
// Uncomment this line when you need to regenerate themes.
// let themes = theme::all_user_themes();
let mut families = Vec::new();
for family in themes {
families.push(convert_family(family));
}
for family in families {
let theme_family_slug = any_ascii(&family.name)
.replace("(", "")
.replace(")", "")
.to_case(Case::Snake);
let output_dir = PathBuf::from("assets/themes/").join(&theme_family_slug);
fs::create_dir_all(&output_dir)?;
let mut output_file =
File::create(output_dir.join(format!("{theme_family_slug}.json")))?;
let theme_json = serde_json::to_string_pretty(&family).unwrap();
output_file.write_all(format!("{theme_json}\n").as_bytes())?;
}
return Ok(());
}
let mut theme_families = Vec::new();
/// Whether VS Code themes should be imported.
@ -420,3 +456,240 @@ fn format_themes_crate() -> std::io::Result<std::process::Output> {
.args(["fmt", "--package", "theme"])
.output()
}
fn convert_family(family: UserThemeFamily) -> ThemeFamilyContent {
ThemeFamilyContent {
name: family.name,
author: family.author,
themes: family.themes.into_iter().map(convert_theme).collect(),
}
}
fn convert_theme(theme: UserTheme) -> ThemeContent {
ThemeContent {
name: theme.name,
appearance: match theme.appearance {
Appearance::Light => theme::AppearanceContent::Light,
Appearance::Dark => theme::AppearanceContent::Dark,
},
style: convert_theme_styles(theme.styles),
}
}
fn serialize_color(color: Hsla) -> String {
let rgba = color.to_rgb();
format!("#{:08x}", u32::from(rgba))
}
fn convert_theme_styles(styles: theme::UserThemeStylesRefinement) -> ThemeStyleContent {
ThemeStyleContent {
colors: ThemeColorsContent {
border: styles.colors.border.map(serialize_color),
border_variant: styles.colors.border_variant.map(serialize_color),
border_focused: styles.colors.border_focused.map(serialize_color),
border_selected: styles.colors.border_selected.map(serialize_color),
border_transparent: styles.colors.border_transparent.map(serialize_color),
border_disabled: styles.colors.border_disabled.map(serialize_color),
elevated_surface_background: styles
.colors
.elevated_surface_background
.map(serialize_color),
surface_background: styles.colors.surface_background.map(serialize_color),
background: styles.colors.background.map(serialize_color),
element_background: styles.colors.element_background.map(serialize_color),
element_hover: styles.colors.element_hover.map(serialize_color),
element_active: styles.colors.element_active.map(serialize_color),
element_selected: styles.colors.element_selected.map(serialize_color),
element_disabled: styles.colors.element_disabled.map(serialize_color),
drop_target_background: styles.colors.drop_target_background.map(serialize_color),
ghost_element_background: styles.colors.ghost_element_background.map(serialize_color),
ghost_element_hover: styles.colors.ghost_element_hover.map(serialize_color),
ghost_element_active: styles.colors.ghost_element_active.map(serialize_color),
ghost_element_selected: styles.colors.ghost_element_selected.map(serialize_color),
ghost_element_disabled: styles.colors.ghost_element_disabled.map(serialize_color),
text: styles.colors.text.map(serialize_color),
text_muted: styles.colors.text_muted.map(serialize_color),
text_placeholder: styles.colors.text_placeholder.map(serialize_color),
text_disabled: styles.colors.text_disabled.map(serialize_color),
text_accent: styles.colors.text_accent.map(serialize_color),
icon: styles.colors.icon.map(serialize_color),
icon_muted: styles.colors.icon_muted.map(serialize_color),
icon_disabled: styles.colors.icon_disabled.map(serialize_color),
icon_placeholder: styles.colors.icon_placeholder.map(serialize_color),
icon_accent: styles.colors.icon_accent.map(serialize_color),
status_bar_background: styles.colors.status_bar_background.map(serialize_color),
title_bar_background: styles.colors.title_bar_background.map(serialize_color),
toolbar_background: styles.colors.toolbar_background.map(serialize_color),
tab_bar_background: styles.colors.tab_bar_background.map(serialize_color),
tab_inactive_background: styles.colors.tab_inactive_background.map(serialize_color),
tab_active_background: styles.colors.tab_active_background.map(serialize_color),
search_match_background: styles.colors.search_match_background.map(serialize_color),
panel_background: styles.colors.panel_background.map(serialize_color),
panel_focused_border: styles.colors.panel_focused_border.map(serialize_color),
pane_focused_border: styles.colors.pane_focused_border.map(serialize_color),
scrollbar_thumb_background: styles
.colors
.scrollbar_thumb_background
.map(serialize_color),
scrollbar_thumb_hover_background: styles
.colors
.scrollbar_thumb_hover_background
.map(serialize_color),
scrollbar_thumb_border: styles.colors.scrollbar_thumb_border.map(serialize_color),
scrollbar_track_background: styles
.colors
.scrollbar_track_background
.map(serialize_color),
scrollbar_track_border: styles.colors.scrollbar_track_border.map(serialize_color),
editor_foreground: styles.colors.editor_foreground.map(serialize_color),
editor_background: styles.colors.editor_background.map(serialize_color),
editor_gutter_background: styles.colors.editor_gutter_background.map(serialize_color),
editor_subheader_background: styles
.colors
.editor_subheader_background
.map(serialize_color),
editor_active_line_background: styles
.colors
.editor_active_line_background
.map(serialize_color),
editor_highlighted_line_background: styles
.colors
.editor_highlighted_line_background
.map(serialize_color),
editor_line_number: styles.colors.editor_line_number.map(serialize_color),
editor_active_line_number: styles.colors.editor_active_line_number.map(serialize_color),
editor_invisible: styles.colors.editor_invisible.map(serialize_color),
editor_wrap_guide: styles.colors.editor_wrap_guide.map(serialize_color),
editor_active_wrap_guide: styles.colors.editor_active_wrap_guide.map(serialize_color),
editor_document_highlight_read_background: styles
.colors
.editor_document_highlight_read_background
.map(serialize_color),
editor_document_highlight_write_background: styles
.colors
.editor_document_highlight_write_background
.map(serialize_color),
terminal_background: styles.colors.terminal_background.map(serialize_color),
terminal_foreground: styles.colors.terminal_foreground.map(serialize_color),
terminal_bright_foreground: styles
.colors
.terminal_bright_foreground
.map(serialize_color),
terminal_dim_foreground: styles.colors.terminal_dim_foreground.map(serialize_color),
terminal_ansi_black: styles.colors.terminal_ansi_black.map(serialize_color),
terminal_ansi_bright_black: styles
.colors
.terminal_ansi_bright_black
.map(serialize_color),
terminal_ansi_dim_black: styles.colors.terminal_ansi_dim_black.map(serialize_color),
terminal_ansi_red: styles.colors.terminal_ansi_red.map(serialize_color),
terminal_ansi_bright_red: styles.colors.terminal_ansi_bright_red.map(serialize_color),
terminal_ansi_dim_red: styles.colors.terminal_ansi_dim_red.map(serialize_color),
terminal_ansi_green: styles.colors.terminal_ansi_green.map(serialize_color),
terminal_ansi_bright_green: styles
.colors
.terminal_ansi_bright_green
.map(serialize_color),
terminal_ansi_dim_green: styles.colors.terminal_ansi_dim_green.map(serialize_color),
terminal_ansi_yellow: styles.colors.terminal_ansi_yellow.map(serialize_color),
terminal_ansi_bright_yellow: styles
.colors
.terminal_ansi_bright_yellow
.map(serialize_color),
terminal_ansi_dim_yellow: styles.colors.terminal_ansi_dim_yellow.map(serialize_color),
terminal_ansi_blue: styles.colors.terminal_ansi_blue.map(serialize_color),
terminal_ansi_bright_blue: styles.colors.terminal_ansi_bright_blue.map(serialize_color),
terminal_ansi_dim_blue: styles.colors.terminal_ansi_dim_blue.map(serialize_color),
terminal_ansi_magenta: styles.colors.terminal_ansi_magenta.map(serialize_color),
terminal_ansi_bright_magenta: styles
.colors
.terminal_ansi_bright_magenta
.map(serialize_color),
terminal_ansi_dim_magenta: styles.colors.terminal_ansi_dim_magenta.map(serialize_color),
terminal_ansi_cyan: styles.colors.terminal_ansi_cyan.map(serialize_color),
terminal_ansi_bright_cyan: styles.colors.terminal_ansi_bright_cyan.map(serialize_color),
terminal_ansi_dim_cyan: styles.colors.terminal_ansi_dim_cyan.map(serialize_color),
terminal_ansi_white: styles.colors.terminal_ansi_white.map(serialize_color),
terminal_ansi_bright_white: styles
.colors
.terminal_ansi_bright_white
.map(serialize_color),
terminal_ansi_dim_white: styles.colors.terminal_ansi_dim_white.map(serialize_color),
link_text_hover: styles.colors.link_text_hover.map(serialize_color),
},
status: StatusColorsContent {
conflict: styles.status.conflict.map(serialize_color),
conflict_background: styles.status.conflict_background.map(serialize_color),
conflict_border: styles.status.conflict_border.map(serialize_color),
created: styles.status.created.map(serialize_color),
created_background: styles.status.created_background.map(serialize_color),
created_border: styles.status.created_border.map(serialize_color),
deleted: styles.status.deleted.map(serialize_color),
deleted_background: styles.status.deleted_background.map(serialize_color),
deleted_border: styles.status.deleted_border.map(serialize_color),
error: styles.status.error.map(serialize_color),
error_background: styles.status.error_background.map(serialize_color),
error_border: styles.status.error_border.map(serialize_color),
hidden: styles.status.hidden.map(serialize_color),
hidden_background: styles.status.hidden_background.map(serialize_color),
hidden_border: styles.status.hidden_border.map(serialize_color),
hint: styles.status.hint.map(serialize_color),
hint_background: styles.status.hint_background.map(serialize_color),
hint_border: styles.status.hint_border.map(serialize_color),
ignored: styles.status.ignored.map(serialize_color),
ignored_background: styles.status.ignored_background.map(serialize_color),
ignored_border: styles.status.ignored_border.map(serialize_color),
info: styles.status.info.map(serialize_color),
info_background: styles.status.info_background.map(serialize_color),
info_border: styles.status.info_border.map(serialize_color),
modified: styles.status.modified.map(serialize_color),
modified_background: styles.status.modified_background.map(serialize_color),
modified_border: styles.status.modified_border.map(serialize_color),
predictive: styles.status.predictive.map(serialize_color),
predictive_background: styles.status.predictive_background.map(serialize_color),
predictive_border: styles.status.predictive_border.map(serialize_color),
renamed: styles.status.renamed.map(serialize_color),
renamed_background: styles.status.renamed_background.map(serialize_color),
renamed_border: styles.status.renamed_border.map(serialize_color),
success: styles.status.success.map(serialize_color),
success_background: styles.status.success_background.map(serialize_color),
success_border: styles.status.success_border.map(serialize_color),
unreachable: styles.status.unreachable.map(serialize_color),
unreachable_background: styles.status.unreachable_background.map(serialize_color),
unreachable_border: styles.status.unreachable_border.map(serialize_color),
warning: styles.status.warning.map(serialize_color),
warning_background: styles.status.warning_background.map(serialize_color),
warning_border: styles.status.warning_border.map(serialize_color),
},
syntax: styles
.syntax
.map(|syntax| {
IndexMap::from_iter(syntax.highlights.into_iter().map(|(name, style)| {
(
name,
HighlightStyleContent {
color: style.color.map(serialize_color),
font_style: style.font_style.map(|font_style| match font_style {
theme::UserFontStyle::Normal => theme::FontStyleContent::Normal,
theme::UserFontStyle::Italic => theme::FontStyleContent::Italic,
theme::UserFontStyle::Oblique => theme::FontStyleContent::Oblique,
}),
font_weight: style.font_weight.map(|font_weight| match font_weight.0 {
_ if font_weight.0 == 100.0 => FontWeightContent::Thin,
_ if font_weight.0 == 200.0 => FontWeightContent::ExtraLight,
_ if font_weight.0 == 300.0 => FontWeightContent::Light,
_ if font_weight.0 == 400.0 => FontWeightContent::Normal,
_ if font_weight.0 == 500.0 => FontWeightContent::Medium,
_ if font_weight.0 == 600.0 => FontWeightContent::Semibold,
_ if font_weight.0 == 700.0 => FontWeightContent::Bold,
_ if font_weight.0 == 800.0 => FontWeightContent::ExtraBold,
_ if font_weight.0 == 900.0 => FontWeightContent::Black,
_ => unreachable!(),
}),
},
)
}))
})
.unwrap_or_default(),
}
}