324 lines
12 KiB
Rust
324 lines
12 KiB
Rust
use anyhow::Result;
|
|
use gpui::{rgba, Hsla, Rgba};
|
|
use indexmap::IndexMap;
|
|
use strum::IntoEnumIterator;
|
|
use theme::{
|
|
StatusColorsRefinement, ThemeColorsRefinement, UserFontStyle, UserFontWeight,
|
|
UserHighlightStyle, UserSyntaxTheme, UserTheme, UserThemeStylesRefinement,
|
|
};
|
|
|
|
use crate::util::Traverse;
|
|
use crate::vscode::VsCodeTheme;
|
|
use crate::ThemeMetadata;
|
|
|
|
use super::ZedSyntaxToken;
|
|
|
|
pub(crate) fn try_parse_color(color: &str) -> Result<Hsla> {
|
|
Ok(Rgba::try_from(color)?.into())
|
|
}
|
|
|
|
pub(crate) fn try_parse_font_weight(font_style: &str) -> Option<UserFontWeight> {
|
|
match font_style {
|
|
style if style.contains("bold") => Some(UserFontWeight::BOLD),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub(crate) fn try_parse_font_style(font_style: &str) -> Option<UserFontStyle> {
|
|
match font_style {
|
|
style if style.contains("italic") => Some(UserFontStyle::Italic),
|
|
style if style.contains("oblique") => Some(UserFontStyle::Oblique),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
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<UserTheme> {
|
|
let appearance = self.theme_metadata.appearance.into();
|
|
|
|
let status_color_refinements = self.convert_status_colors()?;
|
|
let theme_colors_refinements = self.convert_theme_colors()?;
|
|
let syntax_theme = self.convert_syntax_theme()?;
|
|
|
|
Ok(UserTheme {
|
|
name: self.theme_metadata.name.into(),
|
|
appearance,
|
|
styles: UserThemeStylesRefinement {
|
|
colors: theme_colors_refinements,
|
|
status: status_color_refinements,
|
|
syntax: Some(syntax_theme),
|
|
},
|
|
})
|
|
}
|
|
|
|
fn convert_status_colors(&self) -> Result<StatusColorsRefinement> {
|
|
let vscode_colors = &self.theme.colors;
|
|
|
|
let vscode_base_status_colors = StatusColorsRefinement {
|
|
hint: Some(rgba(0x969696ff).into()),
|
|
..Default::default()
|
|
};
|
|
|
|
Ok(StatusColorsRefinement {
|
|
// conflict: None,
|
|
// created: None,
|
|
deleted: vscode_colors
|
|
.error_foreground
|
|
.as_ref()
|
|
.traverse(|color| try_parse_color(&color))?,
|
|
error: vscode_colors
|
|
.error_foreground
|
|
.as_ref()
|
|
.traverse(|color| try_parse_color(&color))?,
|
|
hidden: vscode_colors
|
|
.tab_inactive_foreground
|
|
.as_ref()
|
|
.traverse(|color| try_parse_color(&color))?,
|
|
hint: vscode_colors
|
|
.editor_inlay_hint_foreground
|
|
.as_ref()
|
|
.traverse(|color| try_parse_color(&color))?
|
|
.or(vscode_base_status_colors.hint),
|
|
// ignored: None,
|
|
// info: None,
|
|
// modified: None,
|
|
// renamed: None,
|
|
// success: None,
|
|
warning: vscode_colors
|
|
.list_warning_foreground
|
|
.as_ref()
|
|
.traverse(|color| try_parse_color(&color))?,
|
|
..Default::default()
|
|
})
|
|
}
|
|
|
|
fn convert_theme_colors(&self) -> Result<ThemeColorsRefinement> {
|
|
let vscode_colors = &self.theme.colors;
|
|
|
|
Ok(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
|
|
.focus_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))?,
|
|
element_hover: vscode_colors
|
|
.list_hover_background
|
|
.as_ref()
|
|
.traverse(|color| try_parse_color(&color))?,
|
|
element_selected: vscode_colors
|
|
.list_active_selection_background
|
|
.as_ref()
|
|
.traverse(|color| try_parse_color(&color))?,
|
|
ghost_element_hover: vscode_colors
|
|
.list_hover_background
|
|
.as_ref()
|
|
.traverse(|color| try_parse_color(&color))?,
|
|
drop_target_background: vscode_colors
|
|
.list_drop_background
|
|
.as_ref()
|
|
.traverse(|color| try_parse_color(&color))?,
|
|
text: vscode_colors
|
|
.foreground
|
|
.as_ref()
|
|
.traverse(|color| try_parse_color(&color))?
|
|
.or_else(|| {
|
|
self.theme
|
|
.token_colors
|
|
.iter()
|
|
.find(|token_color| token_color.scope.is_none())
|
|
.and_then(|token_color| token_color.settings.foreground.as_ref())
|
|
.traverse(|color| try_parse_color(&color))
|
|
.ok()
|
|
.flatten()
|
|
}),
|
|
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))?,
|
|
editor_background: vscode_colors
|
|
.editor_background
|
|
.as_ref()
|
|
.traverse(|color| try_parse_color(&color))?,
|
|
editor_gutter_background: vscode_colors
|
|
.editor_background
|
|
.as_ref()
|
|
.traverse(|color| try_parse_color(&color))?,
|
|
editor_line_number: vscode_colors
|
|
.editor_line_number_foreground
|
|
.as_ref()
|
|
.traverse(|color| try_parse_color(&color))?,
|
|
editor_active_line_number: vscode_colors
|
|
.editor_foreground
|
|
.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()
|
|
})
|
|
}
|
|
|
|
fn convert_syntax_theme(&self) -> Result<UserSyntaxTheme> {
|
|
let mut highlight_styles = IndexMap::new();
|
|
|
|
for syntax_token in ZedSyntaxToken::iter() {
|
|
let multimatch_scopes = syntax_token.to_vscode();
|
|
|
|
let token_color = self.theme.token_colors.iter().find(|token_color| {
|
|
token_color
|
|
.scope
|
|
.as_ref()
|
|
.map(|scope| scope.multimatch(&multimatch_scopes))
|
|
.unwrap_or(false)
|
|
});
|
|
|
|
let Some(token_color) = token_color else {
|
|
continue;
|
|
};
|
|
|
|
let highlight_style = UserHighlightStyle {
|
|
color: token_color
|
|
.settings
|
|
.foreground
|
|
.as_ref()
|
|
.traverse(|color| try_parse_color(&color))?,
|
|
font_style: token_color
|
|
.settings
|
|
.font_style
|
|
.as_ref()
|
|
.and_then(|style| try_parse_font_style(&style)),
|
|
font_weight: token_color
|
|
.settings
|
|
.font_style
|
|
.as_ref()
|
|
.and_then(|style| try_parse_font_weight(&style)),
|
|
};
|
|
|
|
if highlight_style.is_empty() {
|
|
continue;
|
|
}
|
|
|
|
highlight_styles.insert(syntax_token.to_string(), highlight_style);
|
|
}
|
|
|
|
Ok(UserSyntaxTheme {
|
|
highlights: highlight_styles.into_iter().collect(),
|
|
})
|
|
}
|
|
}
|