Add support for theme family-specific syntax mapping overrides (#3551)
This PR adds support for adding a specific set of mappings from Zed syntax tokens to VS Code scopes for a particular theme family. We can use this as a fallback when we aren't otherwise able to rely on the mappings in the theme importer, as sometimes it isn't possible to make a specific enough matcher that works across all of the themes. Release Notes: - N/A
This commit is contained in:
parent
5b96ffbbd1
commit
7a9f764aa0
6 changed files with 42 additions and 11 deletions
|
@ -17,5 +17,8 @@
|
||||||
"file_name": "rose-pine-dawn.json",
|
"file_name": "rose-pine-dawn.json",
|
||||||
"appearance": "light"
|
"appearance": "light"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"syntax": {
|
||||||
|
"function": ["entity.name"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,7 +106,7 @@ pub fn rose_pine() -> UserThemeFamily {
|
||||||
(
|
(
|
||||||
"function".into(),
|
"function".into(),
|
||||||
UserHighlightStyle {
|
UserHighlightStyle {
|
||||||
color: Some(rgba(0xe0def4ff).into()),
|
color: Some(rgba(0xebbcbaff).into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -283,7 +283,7 @@ pub fn rose_pine() -> UserThemeFamily {
|
||||||
(
|
(
|
||||||
"function".into(),
|
"function".into(),
|
||||||
UserHighlightStyle {
|
UserHighlightStyle {
|
||||||
color: Some(rgba(0xe0def4ff).into()),
|
color: Some(rgba(0xea9a97ff).into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -460,7 +460,7 @@ pub fn rose_pine() -> UserThemeFamily {
|
||||||
(
|
(
|
||||||
"function".into(),
|
"function".into(),
|
||||||
UserHighlightStyle {
|
UserHighlightStyle {
|
||||||
color: Some(rgba(0x575279ff).into()),
|
color: Some(rgba(0xd7827eff).into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
@ -10,7 +10,7 @@ publish = false
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
convert_case = "0.6.0"
|
convert_case = "0.6.0"
|
||||||
gpui = { package = "gpui2", path = "../gpui2" }
|
gpui = { package = "gpui2", path = "../gpui2" }
|
||||||
indexmap = "1.6.2"
|
indexmap = { version = "1.6.2", features = ["serde"] }
|
||||||
json_comments = "0.2.2"
|
json_comments = "0.2.2"
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
palette = { version = "0.7.3", default-features = false, features = ["std"] }
|
palette = { version = "0.7.3", default-features = false, features = ["std"] }
|
||||||
|
|
|
@ -12,6 +12,7 @@ use std::str::FromStr;
|
||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
use convert_case::{Case, Casing};
|
use convert_case::{Case, Casing};
|
||||||
use gpui::serde_json;
|
use gpui::serde_json;
|
||||||
|
use indexmap::IndexMap;
|
||||||
use json_comments::StripComments;
|
use json_comments::StripComments;
|
||||||
use log::LevelFilter;
|
use log::LevelFilter;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
@ -27,6 +28,14 @@ struct FamilyMetadata {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub author: String,
|
pub author: String,
|
||||||
pub themes: Vec<ThemeMetadata>,
|
pub themes: Vec<ThemeMetadata>,
|
||||||
|
|
||||||
|
/// Overrides for specific syntax tokens.
|
||||||
|
///
|
||||||
|
/// Use this to ensure certain Zed syntax tokens are matched
|
||||||
|
/// to an exact set of scopes when it is not otherwise possible
|
||||||
|
/// to rely on the default mappings in the theme importer.
|
||||||
|
#[serde(default)]
|
||||||
|
pub syntax: IndexMap<String, Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Deserialize)]
|
#[derive(Debug, Clone, Copy, Deserialize)]
|
||||||
|
@ -127,7 +136,11 @@ fn main() -> Result<()> {
|
||||||
let vscode_theme: VsCodeTheme = serde_json::from_reader(theme_without_comments)
|
let vscode_theme: VsCodeTheme = serde_json::from_reader(theme_without_comments)
|
||||||
.context(format!("failed to parse theme {theme_file_path:?}"))?;
|
.context(format!("failed to parse theme {theme_file_path:?}"))?;
|
||||||
|
|
||||||
let converter = VsCodeThemeConverter::new(vscode_theme, theme_metadata);
|
let converter = VsCodeThemeConverter::new(
|
||||||
|
vscode_theme,
|
||||||
|
theme_metadata,
|
||||||
|
family_metadata.syntax.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
let theme = converter.convert()?;
|
let theme = converter.convert()?;
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ use theme::{
|
||||||
|
|
||||||
use crate::color::try_parse_color;
|
use crate::color::try_parse_color;
|
||||||
use crate::util::Traverse;
|
use crate::util::Traverse;
|
||||||
use crate::vscode::VsCodeTheme;
|
use crate::vscode::{VsCodeTheme, VsCodeTokenScope};
|
||||||
use crate::ThemeMetadata;
|
use crate::ThemeMetadata;
|
||||||
|
|
||||||
use super::ZedSyntaxToken;
|
use super::ZedSyntaxToken;
|
||||||
|
@ -32,13 +32,19 @@ pub(crate) fn try_parse_font_style(font_style: &str) -> Option<UserFontStyle> {
|
||||||
pub struct VsCodeThemeConverter {
|
pub struct VsCodeThemeConverter {
|
||||||
theme: VsCodeTheme,
|
theme: VsCodeTheme,
|
||||||
theme_metadata: ThemeMetadata,
|
theme_metadata: ThemeMetadata,
|
||||||
|
syntax_overrides: IndexMap<String, Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VsCodeThemeConverter {
|
impl VsCodeThemeConverter {
|
||||||
pub fn new(theme: VsCodeTheme, theme_metadata: ThemeMetadata) -> Self {
|
pub fn new(
|
||||||
|
theme: VsCodeTheme,
|
||||||
|
theme_metadata: ThemeMetadata,
|
||||||
|
syntax_overrides: IndexMap<String, Vec<String>>,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
theme,
|
theme,
|
||||||
theme_metadata,
|
theme_metadata,
|
||||||
|
syntax_overrides,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,8 +297,17 @@ impl VsCodeThemeConverter {
|
||||||
let mut highlight_styles = IndexMap::new();
|
let mut highlight_styles = IndexMap::new();
|
||||||
|
|
||||||
for syntax_token in ZedSyntaxToken::iter() {
|
for syntax_token in ZedSyntaxToken::iter() {
|
||||||
let best_match = syntax_token
|
let override_match = self
|
||||||
.find_best_token_color_match(&self.theme.token_colors)
|
.syntax_overrides
|
||||||
|
.get(&syntax_token.to_string())
|
||||||
|
.and_then(|scope| {
|
||||||
|
self.theme.token_colors.iter().find(|token_color| {
|
||||||
|
token_color.scope == Some(VsCodeTokenScope::Many(scope.clone()))
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
let best_match = override_match
|
||||||
|
.or_else(|| syntax_token.find_best_token_color_match(&self.theme.token_colors))
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
syntax_token.fallbacks().iter().find_map(|fallback| {
|
syntax_token.fallbacks().iter().find_map(|fallback| {
|
||||||
fallback.find_best_token_color_match(&self.theme.token_colors)
|
fallback.find_best_token_color_match(&self.theme.token_colors)
|
||||||
|
|
|
@ -2,7 +2,7 @@ use indexmap::IndexMap;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use strum::EnumIter;
|
use strum::EnumIter;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, PartialEq, Eq, Deserialize)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
pub enum VsCodeTokenScope {
|
pub enum VsCodeTokenScope {
|
||||||
One(String),
|
One(String),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue