From b2c733baab2de1abd2dffa478069b878cfb4a32a Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 17 Mar 2023 09:51:07 +0100 Subject: [PATCH 1/9] WIP: Allow specifying font features in the editor This just lays the foundation for threading through a `fonts::Features` struct, but it's not used yet. --- Cargo.lock | 1 + assets/settings/default.json | 4 ++ crates/editor/src/display_map.rs | 33 +++++++++++---- crates/editor/src/display_map/block_map.rs | 15 +++++-- crates/editor/src/display_map/wrap_map.rs | 4 +- crates/editor/src/movement.rs | 5 ++- crates/editor/src/test.rs | 5 ++- crates/gpui/Cargo.toml | 1 + crates/gpui/examples/text.rs | 5 ++- crates/gpui/src/elements/label.rs | 2 + crates/gpui/src/font_cache.rs | 35 +++++++++++++--- crates/gpui/src/fonts.rs | 16 ++++++-- crates/gpui/src/platform.rs | 7 +++- crates/gpui/src/platform/mac/fonts.rs | 20 ++++----- crates/gpui/src/text_layout.rs | 8 +++- crates/settings/src/settings.rs | 43 +++++++++++++++++--- crates/terminal_view/src/terminal_element.rs | 7 +++- 17 files changed, 167 insertions(+), 44 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b111ab7190bb6d8a91ef42da5ee9755fd778dbac..a9c572ba6c763879cfc08d77321fe839deaeba25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2664,6 +2664,7 @@ dependencies = [ "postage", "rand 0.8.5", "resvg", + "schemars", "seahash", "serde", "serde_json", diff --git a/assets/settings/default.json b/assets/settings/default.json index add664f956a221529e52c30e969126ceb59db0de..2f7ced922d28627c439b9696d7df5422aed02941 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -3,6 +3,10 @@ "theme": "One Dark", // The name of a font to use for rendering text in the editor "buffer_font_family": "Zed Mono", + // The OpenType features to enable for text in the editor. + "buffer_font_features": { + "calt": true + }, // The default font size for text in the editor "buffer_font_size": 15, // The factor to grow the active pane by. Defaults to 1.0 diff --git a/crates/editor/src/display_map.rs b/crates/editor/src/display_map.rs index 500f3626e348aeaf94cfa0efeff71ce5454ad01d..6684d0ae56a94cf1d33149e1d088320ac7ec22d7 100644 --- a/crates/editor/src/display_map.rs +++ b/crates/editor/src/display_map.rs @@ -785,7 +785,9 @@ pub mod tests { let mut tab_size = rng.gen_range(1..=4); let buffer_start_excerpt_header_height = rng.gen_range(1..=5); let excerpt_header_height = rng.gen_range(1..=5); - let family_id = font_cache.load_family(&["Helvetica"]).unwrap(); + let family_id = font_cache + .load_family(&["Helvetica"], Default::default()) + .unwrap(); let font_id = font_cache .select_font(family_id, &Default::default()) .unwrap(); @@ -1042,7 +1044,9 @@ pub mod tests { let font_cache = cx.font_cache(); - let family_id = font_cache.load_family(&["Helvetica"]).unwrap(); + let family_id = font_cache + .load_family(&["Helvetica"], Default::default()) + .unwrap(); let font_id = font_cache .select_font(family_id, &Default::default()) .unwrap(); @@ -1131,7 +1135,10 @@ pub mod tests { cx.set_global(Settings::test(cx)); let text = sample_text(6, 6, 'a'); let buffer = MultiBuffer::build_simple(&text, cx); - let family_id = cx.font_cache().load_family(&["Helvetica"]).unwrap(); + let family_id = cx + .font_cache() + .load_family(&["Helvetica"], Default::default()) + .unwrap(); let font_id = cx .font_cache() .select_font(family_id, &Default::default()) @@ -1214,7 +1221,9 @@ pub mod tests { let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); let font_cache = cx.font_cache(); - let family_id = font_cache.load_family(&["Helvetica"]).unwrap(); + let family_id = font_cache + .load_family(&["Helvetica"], Default::default()) + .unwrap(); let font_id = font_cache .select_font(family_id, &Default::default()) .unwrap(); @@ -1302,7 +1311,9 @@ pub mod tests { let font_cache = cx.font_cache(); - let family_id = font_cache.load_family(&["Courier"]).unwrap(); + let family_id = font_cache + .load_family(&["Courier"], Default::default()) + .unwrap(); let font_id = font_cache .select_font(family_id, &Default::default()) .unwrap(); @@ -1374,7 +1385,9 @@ pub mod tests { let buffer_snapshot = buffer.read_with(cx, |buffer, cx| buffer.snapshot(cx)); let font_cache = cx.font_cache(); - let family_id = font_cache.load_family(&["Courier"]).unwrap(); + let family_id = font_cache + .load_family(&["Courier"], Default::default()) + .unwrap(); let font_id = font_cache .select_font(family_id, &Default::default()) .unwrap(); @@ -1490,7 +1503,9 @@ pub mod tests { let text = "✅\t\tα\nβ\t\n🏀β\t\tγ"; let buffer = MultiBuffer::build_simple(text, cx); let font_cache = cx.font_cache(); - let family_id = font_cache.load_family(&["Helvetica"]).unwrap(); + let family_id = font_cache + .load_family(&["Helvetica"], Default::default()) + .unwrap(); let font_id = font_cache .select_font(family_id, &Default::default()) .unwrap(); @@ -1548,7 +1563,9 @@ pub mod tests { cx.set_global(Settings::test(cx)); let buffer = MultiBuffer::build_simple("aaa\n\t\tbbb", cx); let font_cache = cx.font_cache(); - let family_id = font_cache.load_family(&["Helvetica"]).unwrap(); + let family_id = font_cache + .load_family(&["Helvetica"], Default::default()) + .unwrap(); let font_id = font_cache .select_font(family_id, &Default::default()) .unwrap(); diff --git a/crates/editor/src/display_map/block_map.rs b/crates/editor/src/display_map/block_map.rs index 797f41c52ac829e96a4230d036e6a80ff9d75c30..aeeb7bcc441c86bc2a62a4d039382fd29bbe2676 100644 --- a/crates/editor/src/display_map/block_map.rs +++ b/crates/editor/src/display_map/block_map.rs @@ -1015,7 +1015,10 @@ mod tests { fn test_basic_blocks(cx: &mut gpui::MutableAppContext) { cx.set_global(Settings::test(cx)); - let family_id = cx.font_cache().load_family(&["Helvetica"]).unwrap(); + let family_id = cx + .font_cache() + .load_family(&["Helvetica"], Default::default()) + .unwrap(); let font_id = cx .font_cache() .select_font(family_id, &Default::default()) @@ -1185,7 +1188,10 @@ mod tests { fn test_blocks_on_wrapped_lines(cx: &mut gpui::MutableAppContext) { cx.set_global(Settings::test(cx)); - let family_id = cx.font_cache().load_family(&["Helvetica"]).unwrap(); + let family_id = cx + .font_cache() + .load_family(&["Helvetica"], Default::default()) + .unwrap(); let font_id = cx .font_cache() .select_font(family_id, &Default::default()) @@ -1241,7 +1247,10 @@ mod tests { Some(rng.gen_range(0.0..=100.0)) }; let tab_size = 1.try_into().unwrap(); - let family_id = cx.font_cache().load_family(&["Helvetica"]).unwrap(); + let family_id = cx + .font_cache() + .load_family(&["Helvetica"], Default::default()) + .unwrap(); let font_id = cx .font_cache() .select_font(family_id, &Default::default()) diff --git a/crates/editor/src/display_map/wrap_map.rs b/crates/editor/src/display_map/wrap_map.rs index 6c34fa4797f79b5f3728aa6ccf166d66a86375e4..deb7be3e6860f7964bfa96f387f713def56eac5c 100644 --- a/crates/editor/src/display_map/wrap_map.rs +++ b/crates/editor/src/display_map/wrap_map.rs @@ -1053,7 +1053,9 @@ mod tests { Some(rng.gen_range(0.0..=1000.0)) }; let tab_size = NonZeroU32::new(rng.gen_range(1..=4)).unwrap(); - let family_id = font_cache.load_family(&["Helvetica"]).unwrap(); + let family_id = font_cache + .load_family(&["Helvetica"], Default::default()) + .unwrap(); let font_id = font_cache .select_font(family_id, &Default::default()) .unwrap(); diff --git a/crates/editor/src/movement.rs b/crates/editor/src/movement.rs index 0ede6186da4a668dd80ac3368c7f78ad1ea35e22..f554c88a4792e481ffb50af2550c74dbe3cf9fb3 100644 --- a/crates/editor/src/movement.rs +++ b/crates/editor/src/movement.rs @@ -587,7 +587,10 @@ mod tests { #[gpui::test] fn test_move_up_and_down_with_excerpts(cx: &mut gpui::MutableAppContext) { cx.set_global(Settings::test(cx)); - let family_id = cx.font_cache().load_family(&["Helvetica"]).unwrap(); + let family_id = cx + .font_cache() + .load_family(&["Helvetica"], Default::default()) + .unwrap(); let font_id = cx .font_cache() .select_font(family_id, &Default::default()) diff --git a/crates/editor/src/test.rs b/crates/editor/src/test.rs index 48652c44b7e212081e65af087cc0e200b7d8388f..8024986ec5472804fd7cecbc0862507f7f85b4de 100644 --- a/crates/editor/src/test.rs +++ b/crates/editor/src/test.rs @@ -25,7 +25,10 @@ pub fn marked_display_snapshot( ) -> (DisplaySnapshot, Vec) { let (unmarked_text, markers) = marked_text_offsets(text); - let family_id = cx.font_cache().load_family(&["Helvetica"]).unwrap(); + let family_id = cx + .font_cache() + .load_family(&["Helvetica"], Default::default()) + .unwrap(); let font_id = cx .font_cache() .select_font(family_id, &Default::default()) diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index 7be254be4da2b0c0f47b9f03f4ae437df1407261..b3e9bda4ec27308ce884573d8b42bd665ea40b2d 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -39,6 +39,7 @@ pathfinder_geometry = "0.5" postage = { version = "0.4.1", features = ["futures-traits"] } rand = "0.8.3" resvg = "0.14" +schemars = "0.8" seahash = "4.1" serde = { version = "1.0", features = ["derive", "rc"] } serde_json = "1.0" diff --git a/crates/gpui/examples/text.rs b/crates/gpui/examples/text.rs index 4d84fefab62e30e86f25d72f06c7638bf72894f7..82413787c68aaee8f9e3588507992ba5c8ee5381 100644 --- a/crates/gpui/examples/text.rs +++ b/crates/gpui/examples/text.rs @@ -56,7 +56,10 @@ impl gpui::Element for TextElement { cx: &mut gpui::PaintContext, ) -> Self::PaintState { let font_size = 12.; - let family = cx.font_cache.load_family(&["SF Pro Display"]).unwrap(); + let family = cx + .font_cache + .load_family(&["SF Pro Display"], Default::default()) + .unwrap(); let normal = RunStyle { font_id: cx .font_cache diff --git a/crates/gpui/src/elements/label.rs b/crates/gpui/src/elements/label.rs index b7ac1938e327b713fee945e8f60c9bce2bd12a16..aae00b07a85af4ce30834711e751e59fc9d16e2b 100644 --- a/crates/gpui/src/elements/label.rs +++ b/crates/gpui/src/elements/label.rs @@ -216,6 +216,7 @@ mod tests { 12., Default::default(), Default::default(), + Default::default(), Color::black(), cx.font_cache(), ) @@ -225,6 +226,7 @@ mod tests { 12., *FontProperties::new().weight(Weight::BOLD), Default::default(), + Default::default(), Color::new(255, 0, 0, 255), cx.font_cache(), ) diff --git a/crates/gpui/src/font_cache.rs b/crates/gpui/src/font_cache.rs index 3631cbe7243b9b69b86a348bb71ea6dc86a52abc..e2884f038feeb04c74b8d50cb996e898b14b871c 100644 --- a/crates/gpui/src/font_cache.rs +++ b/crates/gpui/src/font_cache.rs @@ -1,5 +1,5 @@ use crate::{ - fonts::{FontId, Metrics, Properties}, + fonts::{Features, FontId, Metrics, Properties}, geometry::vector::{vec2f, Vector2F}, platform, text_layout::LineWrapper, @@ -18,6 +18,7 @@ pub struct FamilyId(usize); struct Family { name: Arc, + font_features: Features, font_ids: Vec, } @@ -58,17 +59,21 @@ impl FontCache { .map(|family| family.name.clone()) } - pub fn load_family(&self, names: &[&str]) -> Result { + pub fn load_family(&self, names: &[&str], features: Features) -> Result { for name in names { let state = self.0.upgradable_read(); - if let Some(ix) = state.families.iter().position(|f| f.name.as_ref() == *name) { + if let Some(ix) = state + .families + .iter() + .position(|f| f.name.as_ref() == *name && f.font_features == features) + { return Ok(FamilyId(ix)); } let mut state = RwLockUpgradableReadGuard::upgrade(state); - if let Ok(font_ids) = state.fonts.load_family(name) { + if let Ok(font_ids) = state.fonts.load_family(name, &features) { if font_ids.is_empty() { continue; } @@ -82,6 +87,7 @@ impl FontCache { state.families.push(Family { name: Arc::from(*name), + font_features: features, font_ids, }); return Ok(family_id); @@ -254,7 +260,15 @@ mod tests { fn test_select_font() { let platform = test::platform(); let fonts = FontCache::new(platform.fonts()); - let arial = fonts.load_family(&["Arial"]).unwrap(); + let arial = fonts + .load_family( + &["Arial"], + Features { + calt: Some(false), + ..Default::default() + }, + ) + .unwrap(); let arial_regular = fonts.select_font(arial, &Properties::new()).unwrap(); let arial_italic = fonts .select_font(arial, Properties::new().style(Style::Italic)) @@ -265,5 +279,16 @@ mod tests { assert_ne!(arial_regular, arial_italic); assert_ne!(arial_regular, arial_bold); assert_ne!(arial_italic, arial_bold); + + let arial_with_calt = fonts + .load_family( + &["Arial"], + Features { + calt: Some(true), + ..Default::default() + }, + ) + .unwrap(); + assert_ne!(arial_with_calt, arial); } } diff --git a/crates/gpui/src/fonts.rs b/crates/gpui/src/fonts.rs index 5c49ddcf6119459c3c2ecad4510f6db34cf44181..86ed46bc46b62d2a6993672bf7eb7d4705dd4ac9 100644 --- a/crates/gpui/src/fonts.rs +++ b/crates/gpui/src/fonts.rs @@ -11,7 +11,8 @@ pub use font_kit::{ properties::{Properties, Stretch, Style, Weight}, }; use ordered_float::OrderedFloat; -use serde::{de, Deserialize}; +use schemars::JsonSchema; +use serde::{de, Deserialize, Serialize}; use serde_json::Value; use std::{cell::RefCell, sync::Arc}; @@ -20,6 +21,11 @@ pub struct FontId(pub usize); pub type GlyphId = u32; +#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, JsonSchema)] +pub struct Features { + pub calt: Option, +} + #[derive(Clone, Debug)] pub struct TextStyle { pub color: Color, @@ -107,12 +113,13 @@ impl TextStyle { font_family_name: impl Into>, font_size: f32, font_properties: Properties, + font_features: Features, underline: Underline, color: Color, font_cache: &FontCache, ) -> Result { let font_family_name = font_family_name.into(); - let font_family_id = font_cache.load_family(&[&font_family_name])?; + let font_family_id = font_cache.load_family(&[&font_family_name], font_features)?; let font_id = font_cache.select_font(font_family_id, &font_properties)?; Ok(Self { color, @@ -175,6 +182,7 @@ impl TextStyle { json.family, json.size, font_properties, + Default::default(), underline_from_json(json.underline), json.color, font_cache, @@ -253,7 +261,9 @@ impl Default for TextStyle { .expect("TextStyle::default can only be called within a call to with_font_cache"); let font_family_name = Arc::from("Courier"); - let font_family_id = font_cache.load_family(&[&font_family_name]).unwrap(); + let font_family_id = font_cache + .load_family(&[&font_family_name], Default::default()) + .unwrap(); let font_id = font_cache .select_font(font_family_id, &Default::default()) .unwrap(); diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index 4c1ba49690c43d6b0e0f033b2d2177311a9e8873..538b46ee7779a9f2bb3331230483fadfa20398f5 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -9,7 +9,10 @@ pub mod current { use crate::{ executor, - fonts::{FontId, GlyphId, Metrics as FontMetrics, Properties as FontProperties}, + fonts::{ + Features as FontFeatures, FontId, GlyphId, Metrics as FontMetrics, + Properties as FontProperties, + }, geometry::{ rect::{RectF, RectI}, vector::Vector2F, @@ -335,7 +338,7 @@ pub enum RasterizationOptions { pub trait FontSystem: Send + Sync { fn add_fonts(&self, fonts: &[Arc>]) -> anyhow::Result<()>; - fn load_family(&self, name: &str) -> anyhow::Result>; + fn load_family(&self, name: &str, features: &FontFeatures) -> anyhow::Result>; fn select_font( &self, font_ids: &[FontId], diff --git a/crates/gpui/src/platform/mac/fonts.rs b/crates/gpui/src/platform/mac/fonts.rs index f39d548049ab5669ca9f754a5c7f2c0e9ed4b0d4..98ed541e3543dfdf446f2feba43ac3b0c8c52a73 100644 --- a/crates/gpui/src/platform/mac/fonts.rs +++ b/crates/gpui/src/platform/mac/fonts.rs @@ -1,5 +1,5 @@ use crate::{ - fonts::{FontId, GlyphId, Metrics, Properties}, + fonts::{Features, FontId, GlyphId, Metrics, Properties}, geometry::{ rect::{RectF, RectI}, transform2d::Transform2F, @@ -64,8 +64,8 @@ impl platform::FontSystem for FontSystem { self.0.write().add_fonts(fonts) } - fn load_family(&self, name: &str) -> anyhow::Result> { - self.0.write().load_family(name) + fn load_family(&self, name: &str, features: &Features) -> anyhow::Result> { + self.0.write().load_family(name, features) } fn select_font(&self, font_ids: &[FontId], properties: &Properties) -> anyhow::Result { @@ -126,7 +126,7 @@ impl FontSystemState { Ok(()) } - fn load_family(&mut self, name: &str) -> anyhow::Result> { + fn load_family(&mut self, name: &str, features: &Features) -> anyhow::Result> { let mut font_ids = Vec::new(); let family = self @@ -503,7 +503,7 @@ mod tests { fn test_layout_str(_: &mut MutableAppContext) { // This is failing intermittently on CI and we don't have time to figure it out let fonts = FontSystem::new(); - let menlo = fonts.load_family("Menlo").unwrap(); + let menlo = fonts.load_family("Menlo", &Default::default()).unwrap(); let menlo_regular = RunStyle { font_id: fonts.select_font(&menlo, &Properties::new()).unwrap(), color: Default::default(), @@ -544,13 +544,13 @@ mod tests { #[test] fn test_glyph_offsets() -> anyhow::Result<()> { let fonts = FontSystem::new(); - let zapfino = fonts.load_family("Zapfino")?; + let zapfino = fonts.load_family("Zapfino", &Default::default())?; let zapfino_regular = RunStyle { font_id: fonts.select_font(&zapfino, &Properties::new())?, color: Default::default(), underline: Default::default(), }; - let menlo = fonts.load_family("Menlo")?; + let menlo = fonts.load_family("Menlo", &Default::default())?; let menlo_regular = RunStyle { font_id: fonts.select_font(&menlo, &Properties::new())?, color: Default::default(), @@ -584,7 +584,7 @@ mod tests { use std::{fs::File, io::BufWriter, path::Path}; let fonts = FontSystem::new(); - let font_ids = fonts.load_family("Fira Code").unwrap(); + let font_ids = fonts.load_family("Fira Code", &Default::default()).unwrap(); let font_id = fonts.select_font(&font_ids, &Default::default()).unwrap(); let glyph_id = fonts.glyph_for_char(font_id, 'G').unwrap(); @@ -618,7 +618,7 @@ mod tests { #[test] fn test_wrap_line() { let fonts = FontSystem::new(); - let font_ids = fonts.load_family("Helvetica").unwrap(); + let font_ids = fonts.load_family("Helvetica", &Default::default()).unwrap(); let font_id = fonts.select_font(&font_ids, &Default::default()).unwrap(); let line = "one two three four five\n"; @@ -636,7 +636,7 @@ mod tests { #[test] fn test_layout_line_bom_char() { let fonts = FontSystem::new(); - let font_ids = fonts.load_family("Helvetica").unwrap(); + let font_ids = fonts.load_family("Helvetica", &Default::default()).unwrap(); let style = RunStyle { font_id: fonts.select_font(&font_ids, &Default::default()).unwrap(), color: Default::default(), diff --git a/crates/gpui/src/text_layout.rs b/crates/gpui/src/text_layout.rs index 8fd10a6018e3149a6cabf0f59626f22a6020314e..654922ea2defb2b6eae78d2afb5306e807f8da15 100644 --- a/crates/gpui/src/text_layout.rs +++ b/crates/gpui/src/text_layout.rs @@ -663,7 +663,9 @@ mod tests { fn test_wrap_line(cx: &mut crate::MutableAppContext) { let font_cache = cx.font_cache().clone(); let font_system = cx.platform().fonts(); - let family = font_cache.load_family(&["Courier"]).unwrap(); + let family = font_cache + .load_family(&["Courier"], Default::default()) + .unwrap(); let font_id = font_cache.select_font(family, &Default::default()).unwrap(); let mut wrapper = LineWrapper::new(font_id, 16., font_system); @@ -725,7 +727,9 @@ mod tests { let font_system = cx.platform().fonts(); let text_layout_cache = TextLayoutCache::new(font_system.clone()); - let family = font_cache.load_family(&["Helvetica"]).unwrap(); + let family = font_cache + .load_family(&["Helvetica"], Default::default()) + .unwrap(); let font_id = font_cache.select_font(family, &Default::default()).unwrap(); let normal = RunStyle { font_id, diff --git a/crates/settings/src/settings.rs b/crates/settings/src/settings.rs index 3dc0769a4b4e7a1eed1c45b8f12a13ee1c6e1075..33977a42e616123d4294cd40888d918ed836aeab 100644 --- a/crates/settings/src/settings.rs +++ b/crates/settings/src/settings.rs @@ -5,7 +5,7 @@ pub mod watched_json; use anyhow::{bail, Result}; use gpui::{ font_cache::{FamilyId, FontCache}, - AssetSource, + fonts, AssetSource, }; use schemars::{ gen::{SchemaGenerator, SchemaSettings}, @@ -28,6 +28,8 @@ pub use watched_json::watch_files; #[derive(Clone)] pub struct Settings { + pub buffer_font_family_name: String, + pub buffer_font_features: fonts::Features, pub buffer_font_family: FamilyId, pub default_buffer_font_size: f32, pub buffer_font_size: f32, @@ -332,6 +334,8 @@ pub struct SettingsFileContent { #[serde(default)] pub buffer_font_size: Option, #[serde(default)] + pub buffer_font_features: Option, + #[serde(default)] pub active_pane_magnification: Option, #[serde(default)] pub cursor_blink: Option, @@ -396,10 +400,16 @@ impl Settings { ) .unwrap(); + let buffer_font_features = defaults.buffer_font_features.unwrap(); Self { buffer_font_family: font_cache - .load_family(&[defaults.buffer_font_family.as_ref().unwrap()]) + .load_family( + &[defaults.buffer_font_family.as_ref().unwrap()], + buffer_font_features, + ) .unwrap(), + buffer_font_family_name: defaults.buffer_font_family.unwrap(), + buffer_font_features, buffer_font_size: defaults.buffer_font_size.unwrap(), active_pane_magnification: defaults.active_pane_magnification.unwrap(), default_buffer_font_size: defaults.buffer_font_size.unwrap(), @@ -451,11 +461,24 @@ impl Settings { theme_registry: &ThemeRegistry, font_cache: &FontCache, ) { - if let Some(value) = &data.buffer_font_family { - if let Some(id) = font_cache.load_family(&[value]).log_err() { + let mut family_changed = false; + if let Some(value) = data.buffer_font_family { + self.buffer_font_family_name = value; + family_changed = true; + } + if let Some(value) = data.buffer_font_features { + self.buffer_font_features = value; + family_changed = true; + } + if family_changed { + if let Some(id) = font_cache + .load_family(&[&self.buffer_font_family_name], self.buffer_font_features) + .log_err() + { self.buffer_font_family = id; } } + if let Some(value) = &data.theme { if let Some(theme) = theme_registry.get(value).log_err() { self.theme = theme; @@ -482,7 +505,10 @@ impl Settings { // Ensure terminal font is loaded, so we can request it in terminal_element layout if let Some(terminal_font) = &data.terminal.font_family { - font_cache.load_family(&[terminal_font]).log_err(); + // TODO: enable font features for the terminal as well. + font_cache + .load_family(&[terminal_font], Default::default()) + .log_err(); } self.editor_overrides = data.editor; @@ -616,7 +642,12 @@ impl Settings { #[cfg(any(test, feature = "test-support"))] pub fn test(cx: &gpui::AppContext) -> Settings { Settings { - buffer_font_family: cx.font_cache().load_family(&["Monaco"]).unwrap(), + buffer_font_family_name: "Monaco".to_string(), + buffer_font_features: Default::default(), + buffer_font_family: cx + .font_cache() + .load_family(&["Monaco"], Default::default()) + .unwrap(), buffer_font_size: 14., active_pane_magnification: 1., default_buffer_font_size: 14., diff --git a/crates/terminal_view/src/terminal_element.rs b/crates/terminal_view/src/terminal_element.rs index 5d03d6304e28ed93d334c308bd5c7d11dc526b07..fc72016d9b448a0f1981b706968b2a6ab68d10d9 100644 --- a/crates/terminal_view/src/terminal_element.rs +++ b/crates/terminal_view/src/terminal_element.rs @@ -505,13 +505,18 @@ impl TerminalElement { ///Configures a text style from the current settings. pub fn make_text_style(font_cache: &FontCache, settings: &Settings) -> TextStyle { + // TODO allow font features // Pull the font family from settings properly overriding let family_id = settings .terminal_overrides .font_family .as_ref() .or(settings.terminal_defaults.font_family.as_ref()) - .and_then(|family_name| font_cache.load_family(&[family_name]).log_err()) + .and_then(|family_name| { + font_cache + .load_family(&[family_name], Default::default()) + .log_err() + }) .unwrap_or(settings.buffer_font_family); let font_size = settings From 7d13b0091417c8213877307ff4b1b14a4e7cab11 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 17 Mar 2023 11:42:24 +0100 Subject: [PATCH 2/9] Allow setting font features on the terminal as well --- crates/editor/src/editor.rs | 2 ++ crates/gpui/src/fonts.rs | 4 ++++ crates/settings/src/settings.rs | 1 + crates/terminal_view/src/terminal_element.rs | 20 +++++++++++-------- crates/theme_testbench/src/theme_testbench.rs | 1 + 5 files changed, 20 insertions(+), 8 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 66169be652ee1402c2a6359095e709a7c89f1911..8eedda7c58b0d728f9f85ff9a46dce3d15f6047e 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -6769,6 +6769,7 @@ fn build_style( } } else { let font_family_id = settings.buffer_font_family; + let font_features = settings.buffer_font_features; let font_family_name = cx.font_cache().family_name(font_family_id).unwrap(); let font_properties = Default::default(); let font_id = font_cache @@ -6779,6 +6780,7 @@ fn build_style( text: TextStyle { color: settings.theme.editor.text_color, font_family_name, + font_features, font_family_id, font_id, font_size, diff --git a/crates/gpui/src/fonts.rs b/crates/gpui/src/fonts.rs index 86ed46bc46b62d2a6993672bf7eb7d4705dd4ac9..298bc27d21a2c18188bb35198a65ec24aa54aa43 100644 --- a/crates/gpui/src/fonts.rs +++ b/crates/gpui/src/fonts.rs @@ -30,6 +30,7 @@ pub struct Features { pub struct TextStyle { pub color: Color, pub font_family_name: Arc, + pub font_features: Features, pub font_family_id: FamilyId, pub font_id: FontId, pub font_size: f32, @@ -124,6 +125,7 @@ impl TextStyle { Ok(Self { color, font_family_name, + font_features, font_family_id, font_id, font_size, @@ -270,6 +272,7 @@ impl Default for TextStyle { Self { color: Default::default(), font_family_name, + font_features: Default::default(), font_family_id, font_id, font_size: 14., @@ -351,6 +354,7 @@ impl ToJson for TextStyle { json!({ "color": self.color.to_json(), "font_family": self.font_family_name.as_ref(), + "font_features": serde_json::to_value(&self.font_features).unwrap(), "font_properties": self.font_properties.to_json(), }) } diff --git a/crates/settings/src/settings.rs b/crates/settings/src/settings.rs index 33977a42e616123d4294cd40888d918ed836aeab..630cacf805b224aeecac1f254ab93c6a81baf7a7 100644 --- a/crates/settings/src/settings.rs +++ b/crates/settings/src/settings.rs @@ -227,6 +227,7 @@ pub struct TerminalSettings { pub working_directory: Option, pub font_size: Option, pub font_family: Option, + pub font_features: Option, pub env: Option>, pub blinking: Option, pub alternate_scroll: Option, diff --git a/crates/terminal_view/src/terminal_element.rs b/crates/terminal_view/src/terminal_element.rs index fc72016d9b448a0f1981b706968b2a6ab68d10d9..be210d490556e977a7fee52a88eea051cd0feb1f 100644 --- a/crates/terminal_view/src/terminal_element.rs +++ b/crates/terminal_view/src/terminal_element.rs @@ -505,18 +505,21 @@ impl TerminalElement { ///Configures a text style from the current settings. pub fn make_text_style(font_cache: &FontCache, settings: &Settings) -> TextStyle { - // TODO allow font features - // Pull the font family from settings properly overriding - let family_id = settings + let font_family_name = settings .terminal_overrides .font_family .as_ref() .or(settings.terminal_defaults.font_family.as_ref()) - .and_then(|family_name| { - font_cache - .load_family(&[family_name], Default::default()) - .log_err() - }) + .unwrap_or(&settings.buffer_font_family_name); + let font_features = settings + .terminal_overrides + .font_features + .or(settings.terminal_defaults.font_features) + .unwrap_or(settings.buffer_font_features); + + let family_id = font_cache + .load_family(&[font_family_name], font_features) + .log_err() .unwrap_or(settings.buffer_font_family); let font_size = settings @@ -533,6 +536,7 @@ impl TerminalElement { color: settings.theme.editor.text_color, font_family_id: family_id, font_family_name: font_cache.family_name(family_id).unwrap(), + font_features, font_id, font_size, font_properties: Default::default(), diff --git a/crates/theme_testbench/src/theme_testbench.rs b/crates/theme_testbench/src/theme_testbench.rs index ad01f51a1535f8d49928f272f42c49624c858ab7..f21c631767a948e0ca665778a4c582551eb883a5 100644 --- a/crates/theme_testbench/src/theme_testbench.rs +++ b/crates/theme_testbench/src/theme_testbench.rs @@ -243,6 +243,7 @@ impl ThemeTestbench { color: style.foreground, font_family_id: family_id, font_family_name: font_cache.family_name(family_id).unwrap(), + font_features: settings.buffer_font_features, font_id, font_size, font_properties: Default::default(), From 76167ca65c03d5af2c9e94cc3f1f0a86d14555d8 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 17 Mar 2023 11:44:29 +0100 Subject: [PATCH 3/9] Allow setting font features on `TextStyle` --- crates/gpui/src/fonts.rs | 4 +++- styles/src/styleTree/components.ts | 7 ++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/crates/gpui/src/fonts.rs b/crates/gpui/src/fonts.rs index 298bc27d21a2c18188bb35198a65ec24aa54aa43..cd7d4e0444b33f71429ba3d0bbea2b39b09bfc77 100644 --- a/crates/gpui/src/fonts.rs +++ b/crates/gpui/src/fonts.rs @@ -78,6 +78,8 @@ thread_local! { struct TextStyleJson { color: Color, family: String, + #[serde(default)] + features: Features, weight: Option, size: f32, #[serde(default)] @@ -184,7 +186,7 @@ impl TextStyle { json.family, json.size, font_properties, - Default::default(), + json.features, underline_from_json(json.underline), json.color, font_cache, diff --git a/styles/src/styleTree/components.ts b/styles/src/styleTree/components.ts index 3f69df981e8124a343c3b534aced6261b72bf309..033c0c87254f81dad1d8c920db0ff9a9cff85b39 100644 --- a/styles/src/styleTree/components.ts +++ b/styles/src/styleTree/components.ts @@ -97,7 +97,12 @@ export interface TextProperties { size?: keyof typeof fontSizes weight?: FontWeight underline?: boolean - color?: string + color?: string, + features?: TextFeatures, +} + +interface TextFeatures { + calt?: boolean } export function text( From 9181ac9872082127b5fab62cfe8ee10cbea85ecb Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 17 Mar 2023 12:01:27 +0100 Subject: [PATCH 4/9] Honor the `calt` font feature --- crates/gpui/src/platform/mac/fonts.rs | 57 ++++++++++++- .../gpui/src/platform/mac/fonts/open_type.rs | 83 +++++++++++++++++++ 2 files changed, 136 insertions(+), 4 deletions(-) create mode 100644 crates/gpui/src/platform/mac/fonts/open_type.rs diff --git a/crates/gpui/src/platform/mac/fonts.rs b/crates/gpui/src/platform/mac/fonts.rs index 98ed541e3543dfdf446f2feba43ac3b0c8c52a73..b6fe297629871f509b93160a2fd298eb0bae751f 100644 --- a/crates/gpui/src/platform/mac/fonts.rs +++ b/crates/gpui/src/platform/mac/fonts.rs @@ -1,3 +1,5 @@ +mod open_type; + use crate::{ fonts::{Features, FontId, GlyphId, Metrics, Properties}, geometry::{ @@ -14,19 +16,29 @@ use core_foundation::{ array::CFIndex, attributed_string::{CFAttributedStringRef, CFMutableAttributedString}, base::{CFRange, TCFType}, + number::CFNumber, string::CFString, }; use core_graphics::{ base::{kCGImageAlphaPremultipliedLast, CGGlyph}, color_space::CGColorSpace, context::CGContext, + geometry::CGAffineTransform, +}; +use core_text::{ + font::{CTFont, CTFontRef}, + font_descriptor::{ + CTFontDescriptor, CTFontDescriptorCreateCopyWithFeature, CTFontDescriptorRef, + }, + line::CTLine, + string_attributes::kCTFontAttributeName, }; -use core_text::{font::CTFont, line::CTLine, string_attributes::kCTFontAttributeName}; use font_kit::{ - handle::Handle, hinting::HintingOptions, source::SystemSource, sources::mem::MemSource, + font::Font, handle::Handle, hinting::HintingOptions, source::SystemSource, + sources::mem::MemSource, }; use parking_lot::RwLock; -use std::{cell::RefCell, char, cmp, convert::TryFrom, ffi::c_void, sync::Arc}; +use std::{cell::RefCell, char, cmp, convert::TryFrom, ffi::c_void, ptr, sync::Arc}; #[allow(non_upper_case_globals)] const kCGImageAlphaOnly: u32 = 7; @@ -134,7 +146,17 @@ impl FontSystemState { .select_family_by_name(name) .or_else(|_| self.system_source.select_family_by_name(name))?; for font in family.fonts() { - let font = font.load()?; + let mut font = font.load()?; + + if let Some(calt) = features.calt { + let value = if calt { + open_type::kContextualAlternatesOnSelector + } else { + open_type::kContextualAlternatesOffSelector + }; + font = toggle_open_type_feature(&font, open_type::kContextualAlternatesType, value); + } + let font_id = FontId(self.fonts.len()); font_ids.push(font_id); let postscript_name = font.postscript_name().unwrap(); @@ -490,6 +512,33 @@ extern "C" { start_index: CFIndex, width: f64, ) -> CFIndex; + + fn CTFontCreateCopyWithAttributes( + font: CTFontRef, + size: CGFloat, + matrix: *const CGAffineTransform, + attributes: CTFontDescriptorRef, + ) -> CTFontRef; +} + +fn toggle_open_type_feature(font: &Font, type_identifier: i32, selector_identifier: i32) -> Font { + let native_font = font.native_font(); + unsafe { + let new_descriptor = CTFontDescriptorCreateCopyWithFeature( + native_font.copy_descriptor().as_concrete_TypeRef(), + CFNumber::from(type_identifier).as_concrete_TypeRef(), + CFNumber::from(selector_identifier).as_concrete_TypeRef(), + ); + let new_descriptor = CTFontDescriptor::wrap_under_create_rule(new_descriptor); + let new_font = CTFontCreateCopyWithAttributes( + font.native_font().as_concrete_TypeRef(), + 0.0, + ptr::null(), + new_descriptor.as_concrete_TypeRef(), + ); + let new_font = CTFont::wrap_under_create_rule(new_font); + Font::from_native_font(new_font) + } } #[cfg(test)] diff --git a/crates/gpui/src/platform/mac/fonts/open_type.rs b/crates/gpui/src/platform/mac/fonts/open_type.rs new file mode 100644 index 0000000000000000000000000000000000000000..b2e17e6d6d08a45ca72569223f823f2e00007675 --- /dev/null +++ b/crates/gpui/src/platform/mac/fonts/open_type.rs @@ -0,0 +1,83 @@ +#![allow(unused, non_upper_case_globals)] + +pub const kAltHalfWidthTextSelector: i32 = 6; +pub const kAltProportionalTextSelector: i32 = 5; +pub const kAlternateHorizKanaOffSelector: i32 = 1; +pub const kAlternateHorizKanaOnSelector: i32 = 0; +pub const kAlternateKanaType: i32 = 34; +pub const kAlternateVertKanaOffSelector: i32 = 3; +pub const kAlternateVertKanaOnSelector: i32 = 2; +pub const kCaseSensitiveLayoutOffSelector: i32 = 1; +pub const kCaseSensitiveLayoutOnSelector: i32 = 0; +pub const kCaseSensitiveLayoutType: i32 = 33; +pub const kCaseSensitiveSpacingOffSelector: i32 = 3; +pub const kCaseSensitiveSpacingOnSelector: i32 = 2; +pub const kContextualAlternatesOffSelector: i32 = 1; +pub const kContextualAlternatesOnSelector: i32 = 0; +pub const kContextualAlternatesType: i32 = 36; +pub const kContextualLigaturesOffSelector: i32 = 19; +pub const kContextualLigaturesOnSelector: i32 = 18; +pub const kContextualSwashAlternatesOffSelector: i32 = 5; +pub const kContextualSwashAlternatesOnSelector: i32 = 4; +pub const kDefaultLowerCaseSelector: i32 = 0; +pub const kDefaultUpperCaseSelector: i32 = 0; +pub const kHistoricalLigaturesOffSelector: i32 = 21; +pub const kHistoricalLigaturesOnSelector: i32 = 20; +pub const kHojoCharactersSelector: i32 = 12; +pub const kJIS2004CharactersSelector: i32 = 11; +pub const kLowerCasePetiteCapsSelector: i32 = 2; +pub const kLowerCaseSmallCapsSelector: i32 = 1; +pub const kLowerCaseType: i32 = 37; +pub const kMathematicalGreekOffSelector: i32 = 11; +pub const kMathematicalGreekOnSelector: i32 = 10; +pub const kNLCCharactersSelector: i32 = 13; +pub const kQuarterWidthTextSelector: i32 = 4; +pub const kScientificInferiorsSelector: i32 = 4; +pub const kStylisticAltEightOffSelector: i32 = 17; +pub const kStylisticAltEightOnSelector: i32 = 16; +pub const kStylisticAltEighteenOffSelector: i32 = 37; +pub const kStylisticAltEighteenOnSelector: i32 = 36; +pub const kStylisticAltElevenOffSelector: i32 = 23; +pub const kStylisticAltElevenOnSelector: i32 = 22; +pub const kStylisticAltFifteenOffSelector: i32 = 31; +pub const kStylisticAltFifteenOnSelector: i32 = 30; +pub const kStylisticAltFiveOffSelector: i32 = 11; +pub const kStylisticAltFiveOnSelector: i32 = 10; +pub const kStylisticAltFourOffSelector: i32 = 9; +pub const kStylisticAltFourOnSelector: i32 = 8; +pub const kStylisticAltFourteenOffSelector: i32 = 29; +pub const kStylisticAltFourteenOnSelector: i32 = 28; +pub const kStylisticAltNineOffSelector: i32 = 19; +pub const kStylisticAltNineOnSelector: i32 = 18; +pub const kStylisticAltNineteenOffSelector: i32 = 39; +pub const kStylisticAltNineteenOnSelector: i32 = 38; +pub const kStylisticAltOneOffSelector: i32 = 3; +pub const kStylisticAltOneOnSelector: i32 = 2; +pub const kStylisticAltSevenOffSelector: i32 = 15; +pub const kStylisticAltSevenOnSelector: i32 = 14; +pub const kStylisticAltSeventeenOffSelector: i32 = 35; +pub const kStylisticAltSeventeenOnSelector: i32 = 34; +pub const kStylisticAltSixOffSelector: i32 = 13; +pub const kStylisticAltSixOnSelector: i32 = 12; +pub const kStylisticAltSixteenOffSelector: i32 = 33; +pub const kStylisticAltSixteenOnSelector: i32 = 32; +pub const kStylisticAltTenOffSelector: i32 = 21; +pub const kStylisticAltTenOnSelector: i32 = 20; +pub const kStylisticAltThirteenOffSelector: i32 = 27; +pub const kStylisticAltThirteenOnSelector: i32 = 26; +pub const kStylisticAltThreeOffSelector: i32 = 7; +pub const kStylisticAltThreeOnSelector: i32 = 6; +pub const kStylisticAltTwelveOffSelector: i32 = 25; +pub const kStylisticAltTwelveOnSelector: i32 = 24; +pub const kStylisticAltTwentyOffSelector: i32 = 41; +pub const kStylisticAltTwentyOnSelector: i32 = 40; +pub const kStylisticAltTwoOffSelector: i32 = 5; +pub const kStylisticAltTwoOnSelector: i32 = 4; +pub const kStylisticAlternativesType: i32 = 35; +pub const kSwashAlternatesOffSelector: i32 = 3; +pub const kSwashAlternatesOnSelector: i32 = 2; +pub const kThirdWidthTextSelector: i32 = 3; +pub const kTraditionalNamesCharactersSelector: i32 = 14; +pub const kUpperCasePetiteCapsSelector: i32 = 2; +pub const kUpperCaseSmallCapsSelector: i32 = 1; +pub const kUpperCaseType: i32 = 38; From f9d793cb4a71b777c8e8177611c68ae69d79da34 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 17 Mar 2023 13:29:58 +0100 Subject: [PATCH 5/9] Honor more OpenType features --- crates/gpui/src/fonts.rs | 33 ++ crates/gpui/src/platform/mac/fonts.rs | 54 +- .../gpui/src/platform/mac/fonts/open_type.rs | 474 +++++++++++++++--- styles/src/styleTree/components.ts | 73 ++- 4 files changed, 500 insertions(+), 134 deletions(-) diff --git a/crates/gpui/src/fonts.rs b/crates/gpui/src/fonts.rs index cd7d4e0444b33f71429ba3d0bbea2b39b09bfc77..b474d8d00f8f9b9d8e714290b07dc1544b24baee 100644 --- a/crates/gpui/src/fonts.rs +++ b/crates/gpui/src/fonts.rs @@ -24,6 +24,39 @@ pub type GlyphId = u32; #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, JsonSchema)] pub struct Features { pub calt: Option, + pub case: Option, + pub cpsp: Option, + pub frac: Option, + pub liga: Option, + pub onum: Option, + pub ordn: Option, + pub pnum: Option, + pub ss01: Option, + pub ss02: Option, + pub ss03: Option, + pub ss04: Option, + pub ss05: Option, + pub ss06: Option, + pub ss07: Option, + pub ss08: Option, + pub ss09: Option, + pub ss10: Option, + pub ss11: Option, + pub ss12: Option, + pub ss13: Option, + pub ss14: Option, + pub ss15: Option, + pub ss16: Option, + pub ss17: Option, + pub ss18: Option, + pub ss19: Option, + pub ss20: Option, + pub subs: Option, + pub sups: Option, + pub swsh: Option, + pub titl: Option, + pub tnum: Option, + pub zero: Option, } #[derive(Clone, Debug)] diff --git a/crates/gpui/src/platform/mac/fonts.rs b/crates/gpui/src/platform/mac/fonts.rs index b6fe297629871f509b93160a2fd298eb0bae751f..de1661b3394305f709e252b00a76087a5fc06f2c 100644 --- a/crates/gpui/src/platform/mac/fonts.rs +++ b/crates/gpui/src/platform/mac/fonts.rs @@ -16,29 +16,19 @@ use core_foundation::{ array::CFIndex, attributed_string::{CFAttributedStringRef, CFMutableAttributedString}, base::{CFRange, TCFType}, - number::CFNumber, string::CFString, }; use core_graphics::{ base::{kCGImageAlphaPremultipliedLast, CGGlyph}, color_space::CGColorSpace, context::CGContext, - geometry::CGAffineTransform, -}; -use core_text::{ - font::{CTFont, CTFontRef}, - font_descriptor::{ - CTFontDescriptor, CTFontDescriptorCreateCopyWithFeature, CTFontDescriptorRef, - }, - line::CTLine, - string_attributes::kCTFontAttributeName, }; +use core_text::{font::CTFont, line::CTLine, string_attributes::kCTFontAttributeName}; use font_kit::{ - font::Font, handle::Handle, hinting::HintingOptions, source::SystemSource, - sources::mem::MemSource, + handle::Handle, hinting::HintingOptions, source::SystemSource, sources::mem::MemSource, }; use parking_lot::RwLock; -use std::{cell::RefCell, char, cmp, convert::TryFrom, ffi::c_void, ptr, sync::Arc}; +use std::{cell::RefCell, char, cmp, convert::TryFrom, ffi::c_void, sync::Arc}; #[allow(non_upper_case_globals)] const kCGImageAlphaOnly: u32 = 7; @@ -147,16 +137,7 @@ impl FontSystemState { .or_else(|_| self.system_source.select_family_by_name(name))?; for font in family.fonts() { let mut font = font.load()?; - - if let Some(calt) = features.calt { - let value = if calt { - open_type::kContextualAlternatesOnSelector - } else { - open_type::kContextualAlternatesOffSelector - }; - font = toggle_open_type_feature(&font, open_type::kContextualAlternatesType, value); - } - + open_type::apply_features(&mut font, features); let font_id = FontId(self.fonts.len()); font_ids.push(font_id); let postscript_name = font.postscript_name().unwrap(); @@ -512,33 +493,6 @@ extern "C" { start_index: CFIndex, width: f64, ) -> CFIndex; - - fn CTFontCreateCopyWithAttributes( - font: CTFontRef, - size: CGFloat, - matrix: *const CGAffineTransform, - attributes: CTFontDescriptorRef, - ) -> CTFontRef; -} - -fn toggle_open_type_feature(font: &Font, type_identifier: i32, selector_identifier: i32) -> Font { - let native_font = font.native_font(); - unsafe { - let new_descriptor = CTFontDescriptorCreateCopyWithFeature( - native_font.copy_descriptor().as_concrete_TypeRef(), - CFNumber::from(type_identifier).as_concrete_TypeRef(), - CFNumber::from(selector_identifier).as_concrete_TypeRef(), - ); - let new_descriptor = CTFontDescriptor::wrap_under_create_rule(new_descriptor); - let new_font = CTFontCreateCopyWithAttributes( - font.native_font().as_concrete_TypeRef(), - 0.0, - ptr::null(), - new_descriptor.as_concrete_TypeRef(), - ); - let new_font = CTFont::wrap_under_create_rule(new_font); - Font::from_native_font(new_font) - } } #[cfg(test)] diff --git a/crates/gpui/src/platform/mac/fonts/open_type.rs b/crates/gpui/src/platform/mac/fonts/open_type.rs index b2e17e6d6d08a45ca72569223f823f2e00007675..8ee10fdb41e4150070dce569633aad3b6d63d67a 100644 --- a/crates/gpui/src/platform/mac/fonts/open_type.rs +++ b/crates/gpui/src/platform/mac/fonts/open_type.rs @@ -1,83 +1,395 @@ #![allow(unused, non_upper_case_globals)] -pub const kAltHalfWidthTextSelector: i32 = 6; -pub const kAltProportionalTextSelector: i32 = 5; -pub const kAlternateHorizKanaOffSelector: i32 = 1; -pub const kAlternateHorizKanaOnSelector: i32 = 0; -pub const kAlternateKanaType: i32 = 34; -pub const kAlternateVertKanaOffSelector: i32 = 3; -pub const kAlternateVertKanaOnSelector: i32 = 2; -pub const kCaseSensitiveLayoutOffSelector: i32 = 1; -pub const kCaseSensitiveLayoutOnSelector: i32 = 0; -pub const kCaseSensitiveLayoutType: i32 = 33; -pub const kCaseSensitiveSpacingOffSelector: i32 = 3; -pub const kCaseSensitiveSpacingOnSelector: i32 = 2; -pub const kContextualAlternatesOffSelector: i32 = 1; -pub const kContextualAlternatesOnSelector: i32 = 0; -pub const kContextualAlternatesType: i32 = 36; -pub const kContextualLigaturesOffSelector: i32 = 19; -pub const kContextualLigaturesOnSelector: i32 = 18; -pub const kContextualSwashAlternatesOffSelector: i32 = 5; -pub const kContextualSwashAlternatesOnSelector: i32 = 4; -pub const kDefaultLowerCaseSelector: i32 = 0; -pub const kDefaultUpperCaseSelector: i32 = 0; -pub const kHistoricalLigaturesOffSelector: i32 = 21; -pub const kHistoricalLigaturesOnSelector: i32 = 20; -pub const kHojoCharactersSelector: i32 = 12; -pub const kJIS2004CharactersSelector: i32 = 11; -pub const kLowerCasePetiteCapsSelector: i32 = 2; -pub const kLowerCaseSmallCapsSelector: i32 = 1; -pub const kLowerCaseType: i32 = 37; -pub const kMathematicalGreekOffSelector: i32 = 11; -pub const kMathematicalGreekOnSelector: i32 = 10; -pub const kNLCCharactersSelector: i32 = 13; -pub const kQuarterWidthTextSelector: i32 = 4; -pub const kScientificInferiorsSelector: i32 = 4; -pub const kStylisticAltEightOffSelector: i32 = 17; -pub const kStylisticAltEightOnSelector: i32 = 16; -pub const kStylisticAltEighteenOffSelector: i32 = 37; -pub const kStylisticAltEighteenOnSelector: i32 = 36; -pub const kStylisticAltElevenOffSelector: i32 = 23; -pub const kStylisticAltElevenOnSelector: i32 = 22; -pub const kStylisticAltFifteenOffSelector: i32 = 31; -pub const kStylisticAltFifteenOnSelector: i32 = 30; -pub const kStylisticAltFiveOffSelector: i32 = 11; -pub const kStylisticAltFiveOnSelector: i32 = 10; -pub const kStylisticAltFourOffSelector: i32 = 9; -pub const kStylisticAltFourOnSelector: i32 = 8; -pub const kStylisticAltFourteenOffSelector: i32 = 29; -pub const kStylisticAltFourteenOnSelector: i32 = 28; -pub const kStylisticAltNineOffSelector: i32 = 19; -pub const kStylisticAltNineOnSelector: i32 = 18; -pub const kStylisticAltNineteenOffSelector: i32 = 39; -pub const kStylisticAltNineteenOnSelector: i32 = 38; -pub const kStylisticAltOneOffSelector: i32 = 3; -pub const kStylisticAltOneOnSelector: i32 = 2; -pub const kStylisticAltSevenOffSelector: i32 = 15; -pub const kStylisticAltSevenOnSelector: i32 = 14; -pub const kStylisticAltSeventeenOffSelector: i32 = 35; -pub const kStylisticAltSeventeenOnSelector: i32 = 34; -pub const kStylisticAltSixOffSelector: i32 = 13; -pub const kStylisticAltSixOnSelector: i32 = 12; -pub const kStylisticAltSixteenOffSelector: i32 = 33; -pub const kStylisticAltSixteenOnSelector: i32 = 32; -pub const kStylisticAltTenOffSelector: i32 = 21; -pub const kStylisticAltTenOnSelector: i32 = 20; -pub const kStylisticAltThirteenOffSelector: i32 = 27; -pub const kStylisticAltThirteenOnSelector: i32 = 26; -pub const kStylisticAltThreeOffSelector: i32 = 7; -pub const kStylisticAltThreeOnSelector: i32 = 6; -pub const kStylisticAltTwelveOffSelector: i32 = 25; -pub const kStylisticAltTwelveOnSelector: i32 = 24; -pub const kStylisticAltTwentyOffSelector: i32 = 41; -pub const kStylisticAltTwentyOnSelector: i32 = 40; -pub const kStylisticAltTwoOffSelector: i32 = 5; -pub const kStylisticAltTwoOnSelector: i32 = 4; -pub const kStylisticAlternativesType: i32 = 35; -pub const kSwashAlternatesOffSelector: i32 = 3; -pub const kSwashAlternatesOnSelector: i32 = 2; -pub const kThirdWidthTextSelector: i32 = 3; -pub const kTraditionalNamesCharactersSelector: i32 = 14; -pub const kUpperCasePetiteCapsSelector: i32 = 2; -pub const kUpperCaseSmallCapsSelector: i32 = 1; -pub const kUpperCaseType: i32 = 38; +use std::ptr; + +use crate::fonts::Features; +use cocoa::appkit::CGFloat; +use core_foundation::{base::TCFType, number::CFNumber}; +use core_graphics::geometry::CGAffineTransform; +use core_text::{ + font::{CTFont, CTFontRef}, + font_descriptor::{ + CTFontDescriptor, CTFontDescriptorCreateCopyWithFeature, CTFontDescriptorRef, + }, +}; +use font_kit::font::Font; + +const kCaseSensitiveLayoutOffSelector: i32 = 1; +const kCaseSensitiveLayoutOnSelector: i32 = 0; +const kCaseSensitiveLayoutType: i32 = 33; +const kCaseSensitiveSpacingOffSelector: i32 = 3; +const kCaseSensitiveSpacingOnSelector: i32 = 2; +const kCharacterAlternativesType: i32 = 17; +const kCommonLigaturesOffSelector: i32 = 3; +const kCommonLigaturesOnSelector: i32 = 2; +const kContextualAlternatesOffSelector: i32 = 1; +const kContextualAlternatesOnSelector: i32 = 0; +const kContextualAlternatesType: i32 = 36; +const kContextualLigaturesOffSelector: i32 = 19; +const kContextualLigaturesOnSelector: i32 = 18; +const kContextualSwashAlternatesOffSelector: i32 = 5; +const kContextualSwashAlternatesOnSelector: i32 = 4; +const kDefaultLowerCaseSelector: i32 = 0; +const kDefaultUpperCaseSelector: i32 = 0; +const kDiagonalFractionsSelector: i32 = 2; +const kFractionsType: i32 = 11; +const kHistoricalLigaturesOffSelector: i32 = 21; +const kHistoricalLigaturesOnSelector: i32 = 20; +const kHojoCharactersSelector: i32 = 12; +const kInferiorsSelector: i32 = 2; +const kJIS2004CharactersSelector: i32 = 11; +const kLigaturesType: i32 = 1; +const kLowerCasePetiteCapsSelector: i32 = 2; +const kLowerCaseSmallCapsSelector: i32 = 1; +const kLowerCaseType: i32 = 37; +const kLowerCaseNumbersSelector: i32 = 0; +const kMathematicalGreekOffSelector: i32 = 11; +const kMathematicalGreekOnSelector: i32 = 10; +const kMonospacedNumbersSelector: i32 = 0; +const kNLCCharactersSelector: i32 = 13; +const kNoFractionsSelector: i32 = 0; +const kNormalPositionSelector: i32 = 0; +const kNoStyleOptionsSelector: i32 = 0; +const kNumberCaseType: i32 = 21; +const kNumberSpacingType: i32 = 6; +const kOrdinalsSelector: i32 = 3; +const kProportionalNumbersSelector: i32 = 1; +const kQuarterWidthTextSelector: i32 = 4; +const kScientificInferiorsSelector: i32 = 4; +const kSlashedZeroOffSelector: i32 = 5; +const kSlashedZeroOnSelector: i32 = 4; +const kStyleOptionsType: i32 = 19; +const kStylisticAltEighteenOffSelector: i32 = 37; +const kStylisticAltEighteenOnSelector: i32 = 36; +const kStylisticAltEightOffSelector: i32 = 17; +const kStylisticAltEightOnSelector: i32 = 16; +const kStylisticAltElevenOffSelector: i32 = 23; +const kStylisticAltElevenOnSelector: i32 = 22; +const kStylisticAlternativesType: i32 = 35; +const kStylisticAltFifteenOffSelector: i32 = 31; +const kStylisticAltFifteenOnSelector: i32 = 30; +const kStylisticAltFiveOffSelector: i32 = 11; +const kStylisticAltFiveOnSelector: i32 = 10; +const kStylisticAltFourOffSelector: i32 = 9; +const kStylisticAltFourOnSelector: i32 = 8; +const kStylisticAltFourteenOffSelector: i32 = 29; +const kStylisticAltFourteenOnSelector: i32 = 28; +const kStylisticAltNineOffSelector: i32 = 19; +const kStylisticAltNineOnSelector: i32 = 18; +const kStylisticAltNineteenOffSelector: i32 = 39; +const kStylisticAltNineteenOnSelector: i32 = 38; +const kStylisticAltOneOffSelector: i32 = 3; +const kStylisticAltOneOnSelector: i32 = 2; +const kStylisticAltSevenOffSelector: i32 = 15; +const kStylisticAltSevenOnSelector: i32 = 14; +const kStylisticAltSeventeenOffSelector: i32 = 35; +const kStylisticAltSeventeenOnSelector: i32 = 34; +const kStylisticAltSixOffSelector: i32 = 13; +const kStylisticAltSixOnSelector: i32 = 12; +const kStylisticAltSixteenOffSelector: i32 = 33; +const kStylisticAltSixteenOnSelector: i32 = 32; +const kStylisticAltTenOffSelector: i32 = 21; +const kStylisticAltTenOnSelector: i32 = 20; +const kStylisticAltThirteenOffSelector: i32 = 27; +const kStylisticAltThirteenOnSelector: i32 = 26; +const kStylisticAltThreeOffSelector: i32 = 7; +const kStylisticAltThreeOnSelector: i32 = 6; +const kStylisticAltTwelveOffSelector: i32 = 25; +const kStylisticAltTwelveOnSelector: i32 = 24; +const kStylisticAltTwentyOffSelector: i32 = 41; +const kStylisticAltTwentyOnSelector: i32 = 40; +const kStylisticAltTwoOffSelector: i32 = 5; +const kStylisticAltTwoOnSelector: i32 = 4; +const kSuperiorsSelector: i32 = 1; +const kSwashAlternatesOffSelector: i32 = 3; +const kSwashAlternatesOnSelector: i32 = 2; +const kTitlingCapsSelector: i32 = 4; +const kTypographicExtrasType: i32 = 14; +const kVerticalFractionsSelector: i32 = 1; +const kVerticalPositionType: i32 = 10; + +pub fn apply_features(font: &mut Font, features: &Features) { + // See https://chromium.googlesource.com/chromium/src/+/66.0.3359.158/third_party/harfbuzz-ng/src/hb-coretext.cc + // for a reference implementation. + toggle_open_type_feature( + font, + features.calt, + kContextualAlternatesType, + kContextualAlternatesOnSelector, + kContextualAlternatesOffSelector, + ); + toggle_open_type_feature( + font, + features.case, + kCaseSensitiveLayoutType, + kCaseSensitiveLayoutOnSelector, + kCaseSensitiveLayoutOffSelector, + ); + toggle_open_type_feature( + font, + features.cpsp, + kCaseSensitiveLayoutType, + kCaseSensitiveSpacingOnSelector, + kCaseSensitiveSpacingOffSelector, + ); + toggle_open_type_feature( + font, + features.frac, + kFractionsType, + kDiagonalFractionsSelector, + kNoFractionsSelector, + ); + toggle_open_type_feature( + font, + features.liga, + kLigaturesType, + kCommonLigaturesOnSelector, + kCommonLigaturesOffSelector, + ); + toggle_open_type_feature( + font, + features.onum, + kNumberCaseType, + kLowerCaseNumbersSelector, + 2, + ); + toggle_open_type_feature( + font, + features.ordn, + kVerticalPositionType, + kOrdinalsSelector, + kNormalPositionSelector, + ); + toggle_open_type_feature( + font, + features.pnum, + kNumberSpacingType, + kProportionalNumbersSelector, + 4, + ); + toggle_open_type_feature( + font, + features.ss01, + kStylisticAlternativesType, + kStylisticAltOneOnSelector, + kStylisticAltOneOffSelector, + ); + toggle_open_type_feature( + font, + features.ss02, + kStylisticAlternativesType, + kStylisticAltTwoOnSelector, + kStylisticAltTwoOffSelector, + ); + toggle_open_type_feature( + font, + features.ss03, + kStylisticAlternativesType, + kStylisticAltThreeOnSelector, + kStylisticAltThreeOffSelector, + ); + toggle_open_type_feature( + font, + features.ss04, + kStylisticAlternativesType, + kStylisticAltFourOnSelector, + kStylisticAltFourOffSelector, + ); + toggle_open_type_feature( + font, + features.ss05, + kStylisticAlternativesType, + kStylisticAltFiveOnSelector, + kStylisticAltFiveOffSelector, + ); + toggle_open_type_feature( + font, + features.ss06, + kStylisticAlternativesType, + kStylisticAltSixOnSelector, + kStylisticAltSixOffSelector, + ); + toggle_open_type_feature( + font, + features.ss07, + kStylisticAlternativesType, + kStylisticAltSevenOnSelector, + kStylisticAltSevenOffSelector, + ); + toggle_open_type_feature( + font, + features.ss08, + kStylisticAlternativesType, + kStylisticAltEightOnSelector, + kStylisticAltEightOffSelector, + ); + toggle_open_type_feature( + font, + features.ss09, + kStylisticAlternativesType, + kStylisticAltNineOnSelector, + kStylisticAltNineOffSelector, + ); + toggle_open_type_feature( + font, + features.ss10, + kStylisticAlternativesType, + kStylisticAltTenOnSelector, + kStylisticAltTenOffSelector, + ); + toggle_open_type_feature( + font, + features.ss11, + kStylisticAlternativesType, + kStylisticAltElevenOnSelector, + kStylisticAltElevenOffSelector, + ); + toggle_open_type_feature( + font, + features.ss12, + kStylisticAlternativesType, + kStylisticAltTwelveOnSelector, + kStylisticAltTwelveOffSelector, + ); + toggle_open_type_feature( + font, + features.ss13, + kStylisticAlternativesType, + kStylisticAltThirteenOnSelector, + kStylisticAltThirteenOffSelector, + ); + toggle_open_type_feature( + font, + features.ss14, + kStylisticAlternativesType, + kStylisticAltFourteenOnSelector, + kStylisticAltFourteenOffSelector, + ); + toggle_open_type_feature( + font, + features.ss15, + kStylisticAlternativesType, + kStylisticAltFifteenOnSelector, + kStylisticAltFifteenOffSelector, + ); + toggle_open_type_feature( + font, + features.ss16, + kStylisticAlternativesType, + kStylisticAltSixteenOnSelector, + kStylisticAltSixteenOffSelector, + ); + toggle_open_type_feature( + font, + features.ss17, + kStylisticAlternativesType, + kStylisticAltSeventeenOnSelector, + kStylisticAltSeventeenOffSelector, + ); + toggle_open_type_feature( + font, + features.ss18, + kStylisticAlternativesType, + kStylisticAltEighteenOnSelector, + kStylisticAltEighteenOffSelector, + ); + toggle_open_type_feature( + font, + features.ss19, + kStylisticAlternativesType, + kStylisticAltNineteenOnSelector, + kStylisticAltNineteenOffSelector, + ); + toggle_open_type_feature( + font, + features.ss20, + kStylisticAlternativesType, + kStylisticAltTwentyOnSelector, + kStylisticAltTwentyOffSelector, + ); + toggle_open_type_feature( + font, + features.subs, + kVerticalPositionType, + kInferiorsSelector, + kNormalPositionSelector, + ); + toggle_open_type_feature( + font, + features.sups, + kVerticalPositionType, + kSuperiorsSelector, + kNormalPositionSelector, + ); + toggle_open_type_feature( + font, + features.swsh, + kContextualAlternatesType, + kSwashAlternatesOnSelector, + kSwashAlternatesOffSelector, + ); + toggle_open_type_feature( + font, + features.titl, + kStyleOptionsType, + kTitlingCapsSelector, + kNoStyleOptionsSelector, + ); + toggle_open_type_feature( + font, + features.tnum, + kNumberSpacingType, + kMonospacedNumbersSelector, + 4, + ); + toggle_open_type_feature( + font, + features.zero, + kTypographicExtrasType, + kSlashedZeroOnSelector, + kSlashedZeroOffSelector, + ); +} + +fn toggle_open_type_feature( + font: &mut Font, + enabled: Option, + type_identifier: i32, + on_selector_identifier: i32, + off_selector_identifier: i32, +) { + if let Some(enabled) = enabled { + let native_font = font.native_font(); + unsafe { + let selector_identifier = if enabled { + on_selector_identifier + } else { + off_selector_identifier + }; + let new_descriptor = CTFontDescriptorCreateCopyWithFeature( + native_font.copy_descriptor().as_concrete_TypeRef(), + CFNumber::from(type_identifier).as_concrete_TypeRef(), + CFNumber::from(selector_identifier).as_concrete_TypeRef(), + ); + let new_descriptor = CTFontDescriptor::wrap_under_create_rule(new_descriptor); + let new_font = CTFontCreateCopyWithAttributes( + font.native_font().as_concrete_TypeRef(), + 0.0, + ptr::null(), + new_descriptor.as_concrete_TypeRef(), + ); + let new_font = CTFont::wrap_under_create_rule(new_font); + *font = Font::from_native_font(new_font); + } + } +} + +#[link(name = "CoreText", kind = "framework")] +extern "C" { + fn CTFontCreateCopyWithAttributes( + font: CTFontRef, + size: CGFloat, + matrix: *const CGAffineTransform, + attributes: CTFontDescriptorRef, + ) -> CTFontRef; +} diff --git a/styles/src/styleTree/components.ts b/styles/src/styleTree/components.ts index 033c0c87254f81dad1d8c920db0ff9a9cff85b39..aa185a0cf7ff5f40687718b86584bfbf17edb93d 100644 --- a/styles/src/styleTree/components.ts +++ b/styles/src/styleTree/components.ts @@ -98,11 +98,78 @@ export interface TextProperties { weight?: FontWeight underline?: boolean color?: string, - features?: TextFeatures, + features?: FontFeatures, } -interface TextFeatures { - calt?: boolean +interface FontFeatures { + /** Contextual Alternates: Applies a second substitution feature based on a match of a character pattern within a context of surrounding patterns */ + calt?: boolean; + /** Case-Sensitive Forms: Shifts various punctuation marks up to a position that works better with all-capital sequences */ + case?: boolean; + /** Capital Spacing: Adjusts inter-glyph spacing for all-capital text */ + cpsp?: boolean; + /** Fractions: Replaces figures separated by a slash with diagonal fractions */ + frac?: boolean; + /** Standard Ligatures: Replaces a sequence of glyphs with a single glyph which is preferred for typographic purposes */ + liga?: boolean; + /** Oldstyle Figures: Changes selected figures from the default or lining style to oldstyle form. */ + onum?: boolean; + /** Ordinals: Replaces default alphabetic glyphs with the corresponding ordinal forms for use after figures */ + ordn?: boolean; + /** Proportional Figures: Replaces figure glyphs set on uniform (tabular) widths with corresponding glyphs set on proportional widths */ + pnum?: boolean; + /** Stylistic set 01 */ + ss01?: boolean; + /** Stylistic set 02 */ + ss02?: boolean; + /** Stylistic set 03 */ + ss03?: boolean; + /** Stylistic set 04 */ + ss04?: boolean; + /** Stylistic set 05 */ + ss05?: boolean; + /** Stylistic set 06 */ + ss06?: boolean; + /** Stylistic set 07 */ + ss07?: boolean; + /** Stylistic set 08 */ + ss08?: boolean; + /** Stylistic set 09 */ + ss09?: boolean; + /** Stylistic set 10 */ + ss10?: boolean; + /** Stylistic set 11 */ + ss11?: boolean; + /** Stylistic set 12 */ + ss12?: boolean; + /** Stylistic set 13 */ + ss13?: boolean; + /** Stylistic set 14 */ + ss14?: boolean; + /** Stylistic set 15 */ + ss15?: boolean; + /** Stylistic set 16 */ + ss16?: boolean; + /** Stylistic set 17 */ + ss17?: boolean; + /** Stylistic set 18 */ + ss18?: boolean; + /** Stylistic set 19 */ + ss19?: boolean; + /** Stylistic set 20 */ + ss20?: boolean; + /** Subscript: Replaces default glyphs with subscript glyphs */ + subs?: boolean; + /** Superscript: Replaces default glyphs with superscript glyphs */ + sups?: boolean; + /** Swash: Replaces default glyphs with swash glyphs for stylistic purposes */ + swsh?: boolean; + /** Titling: Replaces default glyphs with titling glyphs for use in large-size settings */ + titl?: boolean; + /** Tabular Figures: Replaces figure glyphs set on proportional widths with corresponding glyphs set on uniform (tabular) widths */ + tnum?: boolean; + /** Slashed Zero: Replaces default zero with a slashed zero for better distinction between "0" and "O" */ + zero?: boolean; } export function text( From 989c9f019648faeda3c79ba9ab96ee44c4d0d189 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 17 Mar 2023 13:48:34 +0100 Subject: [PATCH 6/9] Mention `calt: false` in the default settings to disable ligatures --- assets/settings/default.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/assets/settings/default.json b/assets/settings/default.json index 2f7ced922d28627c439b9696d7df5422aed02941..4a45449f2d9db8368b68874540c47ff991f9d787 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -5,7 +5,8 @@ "buffer_font_family": "Zed Mono", // The OpenType features to enable for text in the editor. "buffer_font_features": { - "calt": true + // Disable ligatures: + // "calt": false }, // The default font size for text in the editor "buffer_font_size": 15, From 4d915f45302b4829babff965e8cea00c203837af Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 17 Mar 2023 13:54:56 +0100 Subject: [PATCH 7/9] Don't make `fonts::Features` `Copy` --- crates/editor/src/display_map.rs | 16 ++++++++-------- crates/editor/src/display_map/block_map.rs | 6 +++--- crates/editor/src/display_map/wrap_map.rs | 2 +- crates/editor/src/editor.rs | 3 +-- crates/editor/src/movement.rs | 2 +- crates/editor/src/test.rs | 2 +- crates/gpui/examples/text.rs | 2 +- crates/gpui/src/font_cache.rs | 12 ++++++------ crates/gpui/src/fonts.rs | 6 +++--- crates/gpui/src/text_layout.rs | 4 ++-- crates/settings/src/settings.rs | 14 +++----------- crates/terminal_view/src/terminal_element.rs | 9 +++++---- crates/theme_testbench/src/theme_testbench.rs | 2 +- 13 files changed, 36 insertions(+), 44 deletions(-) diff --git a/crates/editor/src/display_map.rs b/crates/editor/src/display_map.rs index 6684d0ae56a94cf1d33149e1d088320ac7ec22d7..32810b4450c34e03fcc32d71ae44b724c1484aed 100644 --- a/crates/editor/src/display_map.rs +++ b/crates/editor/src/display_map.rs @@ -786,7 +786,7 @@ pub mod tests { let buffer_start_excerpt_header_height = rng.gen_range(1..=5); let excerpt_header_height = rng.gen_range(1..=5); let family_id = font_cache - .load_family(&["Helvetica"], Default::default()) + .load_family(&["Helvetica"], &Default::default()) .unwrap(); let font_id = font_cache .select_font(family_id, &Default::default()) @@ -1045,7 +1045,7 @@ pub mod tests { let font_cache = cx.font_cache(); let family_id = font_cache - .load_family(&["Helvetica"], Default::default()) + .load_family(&["Helvetica"], &Default::default()) .unwrap(); let font_id = font_cache .select_font(family_id, &Default::default()) @@ -1137,7 +1137,7 @@ pub mod tests { let buffer = MultiBuffer::build_simple(&text, cx); let family_id = cx .font_cache() - .load_family(&["Helvetica"], Default::default()) + .load_family(&["Helvetica"], &Default::default()) .unwrap(); let font_id = cx .font_cache() @@ -1222,7 +1222,7 @@ pub mod tests { let font_cache = cx.font_cache(); let family_id = font_cache - .load_family(&["Helvetica"], Default::default()) + .load_family(&["Helvetica"], &Default::default()) .unwrap(); let font_id = font_cache .select_font(family_id, &Default::default()) @@ -1312,7 +1312,7 @@ pub mod tests { let font_cache = cx.font_cache(); let family_id = font_cache - .load_family(&["Courier"], Default::default()) + .load_family(&["Courier"], &Default::default()) .unwrap(); let font_id = font_cache .select_font(family_id, &Default::default()) @@ -1386,7 +1386,7 @@ pub mod tests { let font_cache = cx.font_cache(); let family_id = font_cache - .load_family(&["Courier"], Default::default()) + .load_family(&["Courier"], &Default::default()) .unwrap(); let font_id = font_cache .select_font(family_id, &Default::default()) @@ -1504,7 +1504,7 @@ pub mod tests { let buffer = MultiBuffer::build_simple(text, cx); let font_cache = cx.font_cache(); let family_id = font_cache - .load_family(&["Helvetica"], Default::default()) + .load_family(&["Helvetica"], &Default::default()) .unwrap(); let font_id = font_cache .select_font(family_id, &Default::default()) @@ -1564,7 +1564,7 @@ pub mod tests { let buffer = MultiBuffer::build_simple("aaa\n\t\tbbb", cx); let font_cache = cx.font_cache(); let family_id = font_cache - .load_family(&["Helvetica"], Default::default()) + .load_family(&["Helvetica"], &Default::default()) .unwrap(); let font_id = font_cache .select_font(family_id, &Default::default()) diff --git a/crates/editor/src/display_map/block_map.rs b/crates/editor/src/display_map/block_map.rs index aeeb7bcc441c86bc2a62a4d039382fd29bbe2676..fffe20bb219970028b6aa8ef08b2fe677a8b1c1e 100644 --- a/crates/editor/src/display_map/block_map.rs +++ b/crates/editor/src/display_map/block_map.rs @@ -1017,7 +1017,7 @@ mod tests { let family_id = cx .font_cache() - .load_family(&["Helvetica"], Default::default()) + .load_family(&["Helvetica"], &Default::default()) .unwrap(); let font_id = cx .font_cache() @@ -1190,7 +1190,7 @@ mod tests { let family_id = cx .font_cache() - .load_family(&["Helvetica"], Default::default()) + .load_family(&["Helvetica"], &Default::default()) .unwrap(); let font_id = cx .font_cache() @@ -1249,7 +1249,7 @@ mod tests { let tab_size = 1.try_into().unwrap(); let family_id = cx .font_cache() - .load_family(&["Helvetica"], Default::default()) + .load_family(&["Helvetica"], &Default::default()) .unwrap(); let font_id = cx .font_cache() diff --git a/crates/editor/src/display_map/wrap_map.rs b/crates/editor/src/display_map/wrap_map.rs index deb7be3e6860f7964bfa96f387f713def56eac5c..0d5fb878e583a0269d33b8742e8c18733d19a8fb 100644 --- a/crates/editor/src/display_map/wrap_map.rs +++ b/crates/editor/src/display_map/wrap_map.rs @@ -1054,7 +1054,7 @@ mod tests { }; let tab_size = NonZeroU32::new(rng.gen_range(1..=4)).unwrap(); let family_id = font_cache - .load_family(&["Helvetica"], Default::default()) + .load_family(&["Helvetica"], &Default::default()) .unwrap(); let font_id = font_cache .select_font(family_id, &Default::default()) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 8eedda7c58b0d728f9f85ff9a46dce3d15f6047e..adcc4c1eba3b429c689f5967a901ecc2a42d6019 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -6769,7 +6769,6 @@ fn build_style( } } else { let font_family_id = settings.buffer_font_family; - let font_features = settings.buffer_font_features; let font_family_name = cx.font_cache().family_name(font_family_id).unwrap(); let font_properties = Default::default(); let font_id = font_cache @@ -6780,7 +6779,7 @@ fn build_style( text: TextStyle { color: settings.theme.editor.text_color, font_family_name, - font_features, + font_features: settings.buffer_font_features.clone(), font_family_id, font_id, font_size, diff --git a/crates/editor/src/movement.rs b/crates/editor/src/movement.rs index f554c88a4792e481ffb50af2550c74dbe3cf9fb3..3e5f896564f81a3eea5c3be3152f02a0d7e3b4fe 100644 --- a/crates/editor/src/movement.rs +++ b/crates/editor/src/movement.rs @@ -589,7 +589,7 @@ mod tests { cx.set_global(Settings::test(cx)); let family_id = cx .font_cache() - .load_family(&["Helvetica"], Default::default()) + .load_family(&["Helvetica"], &Default::default()) .unwrap(); let font_id = cx .font_cache() diff --git a/crates/editor/src/test.rs b/crates/editor/src/test.rs index 8024986ec5472804fd7cecbc0862507f7f85b4de..9d0c1c7f1ac1fa6cca3983f96712d068bcf9ca7e 100644 --- a/crates/editor/src/test.rs +++ b/crates/editor/src/test.rs @@ -27,7 +27,7 @@ pub fn marked_display_snapshot( let family_id = cx .font_cache() - .load_family(&["Helvetica"], Default::default()) + .load_family(&["Helvetica"], &Default::default()) .unwrap(); let font_id = cx .font_cache() diff --git a/crates/gpui/examples/text.rs b/crates/gpui/examples/text.rs index 82413787c68aaee8f9e3588507992ba5c8ee5381..e16ac440fdd97d0e349f5ac7dedeec612c49bb6b 100644 --- a/crates/gpui/examples/text.rs +++ b/crates/gpui/examples/text.rs @@ -58,7 +58,7 @@ impl gpui::Element for TextElement { let font_size = 12.; let family = cx .font_cache - .load_family(&["SF Pro Display"], Default::default()) + .load_family(&["SF Pro Display"], &Default::default()) .unwrap(); let normal = RunStyle { font_id: cx diff --git a/crates/gpui/src/font_cache.rs b/crates/gpui/src/font_cache.rs index e2884f038feeb04c74b8d50cb996e898b14b871c..4388ad4bcbd2bea66149c05258bfe39d5682af03 100644 --- a/crates/gpui/src/font_cache.rs +++ b/crates/gpui/src/font_cache.rs @@ -59,21 +59,21 @@ impl FontCache { .map(|family| family.name.clone()) } - pub fn load_family(&self, names: &[&str], features: Features) -> Result { + pub fn load_family(&self, names: &[&str], features: &Features) -> Result { for name in names { let state = self.0.upgradable_read(); if let Some(ix) = state .families .iter() - .position(|f| f.name.as_ref() == *name && f.font_features == features) + .position(|f| f.name.as_ref() == *name && f.font_features == *features) { return Ok(FamilyId(ix)); } let mut state = RwLockUpgradableReadGuard::upgrade(state); - if let Ok(font_ids) = state.fonts.load_family(name, &features) { + if let Ok(font_ids) = state.fonts.load_family(name, features) { if font_ids.is_empty() { continue; } @@ -87,7 +87,7 @@ impl FontCache { state.families.push(Family { name: Arc::from(*name), - font_features: features, + font_features: features.clone(), font_ids, }); return Ok(family_id); @@ -263,7 +263,7 @@ mod tests { let arial = fonts .load_family( &["Arial"], - Features { + &Features { calt: Some(false), ..Default::default() }, @@ -283,7 +283,7 @@ mod tests { let arial_with_calt = fonts .load_family( &["Arial"], - Features { + &Features { calt: Some(true), ..Default::default() }, diff --git a/crates/gpui/src/fonts.rs b/crates/gpui/src/fonts.rs index b474d8d00f8f9b9d8e714290b07dc1544b24baee..02fd288d81df44365f66a75b1e0efc7adb543e51 100644 --- a/crates/gpui/src/fonts.rs +++ b/crates/gpui/src/fonts.rs @@ -21,7 +21,7 @@ pub struct FontId(pub usize); pub type GlyphId = u32; -#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, JsonSchema)] +#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, JsonSchema)] pub struct Features { pub calt: Option, pub case: Option, @@ -155,7 +155,7 @@ impl TextStyle { font_cache: &FontCache, ) -> Result { let font_family_name = font_family_name.into(); - let font_family_id = font_cache.load_family(&[&font_family_name], font_features)?; + let font_family_id = font_cache.load_family(&[&font_family_name], &font_features)?; let font_id = font_cache.select_font(font_family_id, &font_properties)?; Ok(Self { color, @@ -299,7 +299,7 @@ impl Default for TextStyle { let font_family_name = Arc::from("Courier"); let font_family_id = font_cache - .load_family(&[&font_family_name], Default::default()) + .load_family(&[&font_family_name], &Default::default()) .unwrap(); let font_id = font_cache .select_font(font_family_id, &Default::default()) diff --git a/crates/gpui/src/text_layout.rs b/crates/gpui/src/text_layout.rs index 654922ea2defb2b6eae78d2afb5306e807f8da15..72ea0c8919b9081126a283cc0c163bf3b0e6bfa8 100644 --- a/crates/gpui/src/text_layout.rs +++ b/crates/gpui/src/text_layout.rs @@ -664,7 +664,7 @@ mod tests { let font_cache = cx.font_cache().clone(); let font_system = cx.platform().fonts(); let family = font_cache - .load_family(&["Courier"], Default::default()) + .load_family(&["Courier"], &Default::default()) .unwrap(); let font_id = font_cache.select_font(family, &Default::default()).unwrap(); @@ -728,7 +728,7 @@ mod tests { let text_layout_cache = TextLayoutCache::new(font_system.clone()); let family = font_cache - .load_family(&["Helvetica"], Default::default()) + .load_family(&["Helvetica"], &Default::default()) .unwrap(); let font_id = font_cache.select_font(family, &Default::default()).unwrap(); let normal = RunStyle { diff --git a/crates/settings/src/settings.rs b/crates/settings/src/settings.rs index 630cacf805b224aeecac1f254ab93c6a81baf7a7..4566776a342381c5bc01b79bee46b53dc302e461 100644 --- a/crates/settings/src/settings.rs +++ b/crates/settings/src/settings.rs @@ -406,7 +406,7 @@ impl Settings { buffer_font_family: font_cache .load_family( &[defaults.buffer_font_family.as_ref().unwrap()], - buffer_font_features, + &buffer_font_features, ) .unwrap(), buffer_font_family_name: defaults.buffer_font_family.unwrap(), @@ -473,7 +473,7 @@ impl Settings { } if family_changed { if let Some(id) = font_cache - .load_family(&[&self.buffer_font_family_name], self.buffer_font_features) + .load_family(&[&self.buffer_font_family_name], &self.buffer_font_features) .log_err() { self.buffer_font_family = id; @@ -504,14 +504,6 @@ impl Settings { merge(&mut self.default_dock_anchor, data.default_dock_anchor); merge(&mut self.base_keymap, data.base_keymap); - // Ensure terminal font is loaded, so we can request it in terminal_element layout - if let Some(terminal_font) = &data.terminal.font_family { - // TODO: enable font features for the terminal as well. - font_cache - .load_family(&[terminal_font], Default::default()) - .log_err(); - } - self.editor_overrides = data.editor; self.git_overrides = data.git.unwrap_or_default(); self.journal_overrides = data.journal; @@ -647,7 +639,7 @@ impl Settings { buffer_font_features: Default::default(), buffer_font_family: cx .font_cache() - .load_family(&["Monaco"], Default::default()) + .load_family(&["Monaco"], &Default::default()) .unwrap(), buffer_font_size: 14., active_pane_magnification: 1., diff --git a/crates/terminal_view/src/terminal_element.rs b/crates/terminal_view/src/terminal_element.rs index be210d490556e977a7fee52a88eea051cd0feb1f..f3c8cd37422316789f5f6edddcb78d70d5815a3b 100644 --- a/crates/terminal_view/src/terminal_element.rs +++ b/crates/terminal_view/src/terminal_element.rs @@ -514,11 +514,12 @@ impl TerminalElement { let font_features = settings .terminal_overrides .font_features - .or(settings.terminal_defaults.font_features) - .unwrap_or(settings.buffer_font_features); + .as_ref() + .or(settings.terminal_defaults.font_features.as_ref()) + .unwrap_or(&settings.buffer_font_features); let family_id = font_cache - .load_family(&[font_family_name], font_features) + .load_family(&[font_family_name], &font_features) .log_err() .unwrap_or(settings.buffer_font_family); @@ -536,7 +537,7 @@ impl TerminalElement { color: settings.theme.editor.text_color, font_family_id: family_id, font_family_name: font_cache.family_name(family_id).unwrap(), - font_features, + font_features: font_features.clone(), font_id, font_size, font_properties: Default::default(), diff --git a/crates/theme_testbench/src/theme_testbench.rs b/crates/theme_testbench/src/theme_testbench.rs index f21c631767a948e0ca665778a4c582551eb883a5..993e1bd8c3c818da5920cc9af815bbab55082181 100644 --- a/crates/theme_testbench/src/theme_testbench.rs +++ b/crates/theme_testbench/src/theme_testbench.rs @@ -243,7 +243,7 @@ impl ThemeTestbench { color: style.foreground, font_family_id: family_id, font_family_name: font_cache.family_name(family_id).unwrap(), - font_features: settings.buffer_font_features, + font_features: settings.buffer_font_features.clone(), font_id, font_size, font_properties: Default::default(), From 786d95b8c82e3281298df311c4be8e6b688e95f8 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 17 Mar 2023 15:12:02 +0100 Subject: [PATCH 8/9] Avoid storing `fonts::Features` in `TextStyle` We were only using it for debugging purposes and that was causing the `Theme` struct to become too big to hold on the stack. Co-Authored-By: Julia Risley --- crates/editor/src/editor.rs | 1 - crates/gpui/src/fonts.rs | 4 ---- crates/terminal_view/src/terminal_element.rs | 1 - crates/theme_testbench/src/theme_testbench.rs | 1 - 4 files changed, 7 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index adcc4c1eba3b429c689f5967a901ecc2a42d6019..66169be652ee1402c2a6359095e709a7c89f1911 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -6779,7 +6779,6 @@ fn build_style( text: TextStyle { color: settings.theme.editor.text_color, font_family_name, - font_features: settings.buffer_font_features.clone(), font_family_id, font_id, font_size, diff --git a/crates/gpui/src/fonts.rs b/crates/gpui/src/fonts.rs index 02fd288d81df44365f66a75b1e0efc7adb543e51..e0f037acb8fe1ec5b954b049930fbaac0e69313f 100644 --- a/crates/gpui/src/fonts.rs +++ b/crates/gpui/src/fonts.rs @@ -63,7 +63,6 @@ pub struct Features { pub struct TextStyle { pub color: Color, pub font_family_name: Arc, - pub font_features: Features, pub font_family_id: FamilyId, pub font_id: FontId, pub font_size: f32, @@ -160,7 +159,6 @@ impl TextStyle { Ok(Self { color, font_family_name, - font_features, font_family_id, font_id, font_size, @@ -307,7 +305,6 @@ impl Default for TextStyle { Self { color: Default::default(), font_family_name, - font_features: Default::default(), font_family_id, font_id, font_size: 14., @@ -389,7 +386,6 @@ impl ToJson for TextStyle { json!({ "color": self.color.to_json(), "font_family": self.font_family_name.as_ref(), - "font_features": serde_json::to_value(&self.font_features).unwrap(), "font_properties": self.font_properties.to_json(), }) } diff --git a/crates/terminal_view/src/terminal_element.rs b/crates/terminal_view/src/terminal_element.rs index f3c8cd37422316789f5f6edddcb78d70d5815a3b..d530a9858203332f2cf2e3ca540ca4f132777cf0 100644 --- a/crates/terminal_view/src/terminal_element.rs +++ b/crates/terminal_view/src/terminal_element.rs @@ -537,7 +537,6 @@ impl TerminalElement { color: settings.theme.editor.text_color, font_family_id: family_id, font_family_name: font_cache.family_name(family_id).unwrap(), - font_features: font_features.clone(), font_id, font_size, font_properties: Default::default(), diff --git a/crates/theme_testbench/src/theme_testbench.rs b/crates/theme_testbench/src/theme_testbench.rs index 993e1bd8c3c818da5920cc9af815bbab55082181..ad01f51a1535f8d49928f272f42c49624c858ab7 100644 --- a/crates/theme_testbench/src/theme_testbench.rs +++ b/crates/theme_testbench/src/theme_testbench.rs @@ -243,7 +243,6 @@ impl ThemeTestbench { color: style.foreground, font_family_id: family_id, font_family_name: font_cache.family_name(family_id).unwrap(), - font_features: settings.buffer_font_features.clone(), font_id, font_size, font_properties: Default::default(), From 1af8f4be19e40c93caf78312ebec60bf91de5379 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 17 Mar 2023 15:39:24 +0100 Subject: [PATCH 9/9] Deserialize `Theme` directly into the heap to avoid stack overflow Co-Authored-By: Julia Risley --- Cargo.lock | 27 +++++++++++++++++++++++++++ Cargo.toml | 1 + crates/auto_update/Cargo.toml | 1 + crates/cli/Cargo.toml | 1 + crates/client/Cargo.toml | 3 ++- crates/collab/Cargo.toml | 1 + crates/collab_ui/Cargo.toml | 1 + crates/db/Cargo.toml | 1 + crates/editor/Cargo.toml | 1 + crates/feedback/Cargo.toml | 3 ++- crates/fs/Cargo.toml | 1 + crates/gpui/Cargo.toml | 1 + crates/language/Cargo.toml | 1 + crates/live_kit_client/Cargo.toml | 4 +++- crates/live_kit_server/Cargo.toml | 1 + crates/lsp/Cargo.toml | 1 + crates/plugin/Cargo.toml | 1 + crates/plugin_macros/Cargo.toml | 1 + crates/plugin_runtime/Cargo.toml | 1 + crates/project/Cargo.toml | 1 + crates/rpc/Cargo.toml | 1 + crates/search/Cargo.toml | 1 + crates/settings/Cargo.toml | 1 + crates/terminal/Cargo.toml | 1 + crates/terminal_view/Cargo.toml | 1 + crates/theme/Cargo.toml | 1 + crates/theme/src/theme_registry.rs | 11 ++++++++--- crates/vim/Cargo.toml | 1 + crates/workspace/Cargo.toml | 3 ++- crates/zed/Cargo.toml | 1 + plugins/Cargo.lock | 3 +++ plugins/json_language/Cargo.toml | 1 + 32 files changed, 72 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a9c572ba6c763879cfc08d77321fe839deaeba25..ca99be02181cdce371acd8e1b2d7930079349cf3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -518,6 +518,7 @@ dependencies = [ "menu", "project", "serde", + "serde_derive", "serde_json", "settings", "smol", @@ -1097,6 +1098,7 @@ dependencies = [ "ipc-channel", "plist", "serde", + "serde_derive", ] [[package]] @@ -1119,6 +1121,7 @@ dependencies = [ "rand 0.8.5", "rpc", "serde", + "serde_derive", "settings", "smol", "sum_tree", @@ -1228,6 +1231,7 @@ dependencies = [ "sea-orm", "sea-query", "serde", + "serde_derive", "serde_json", "settings", "sha-1 0.9.8", @@ -1269,6 +1273,7 @@ dependencies = [ "postage", "project", "serde", + "serde_derive", "settings", "theme", "util", @@ -1739,6 +1744,7 @@ dependencies = [ "log", "parking_lot 0.11.2", "serde", + "serde_derive", "smol", "sqlez", "sqlez_macros", @@ -1947,6 +1953,7 @@ dependencies = [ "rand 0.8.5", "rpc", "serde", + "serde_derive", "settings", "smallvec", "smol", @@ -2100,6 +2107,7 @@ dependencies = [ "project", "search", "serde", + "serde_derive", "settings", "sysinfo", "theme", @@ -2296,6 +2304,7 @@ dependencies = [ "regex", "rope", "serde", + "serde_derive", "serde_json", "smol", "tempfile", @@ -2667,6 +2676,7 @@ dependencies = [ "schemars", "seahash", "serde", + "serde_derive", "serde_json", "simplelog", "smallvec", @@ -3276,6 +3286,7 @@ dependencies = [ "regex", "rpc", "serde", + "serde_derive", "serde_json", "settings", "similar", @@ -3471,6 +3482,7 @@ dependencies = [ "parking_lot 0.11.2", "postage", "serde", + "serde_derive", "serde_json", "sha2 0.10.6", "simplelog", @@ -3491,6 +3503,7 @@ dependencies = [ "prost-types 0.8.0", "reqwest", "serde", + "serde_derive", "sha2 0.10.6", ] @@ -3531,6 +3544,7 @@ dependencies = [ "parking_lot 0.11.2", "postage", "serde", + "serde_derive", "serde_json", "smol", "unindent", @@ -4450,6 +4464,7 @@ dependencies = [ "bincode", "plugin_macros", "serde", + "serde_derive", ] [[package]] @@ -4460,6 +4475,7 @@ dependencies = [ "proc-macro2", "quote", "serde", + "serde_derive", "syn", ] @@ -4471,6 +4487,7 @@ dependencies = [ "bincode", "pollster", "serde", + "serde_derive", "serde_json", "smol", "wasi-common", @@ -4628,6 +4645,7 @@ dependencies = [ "regex", "rpc", "serde", + "serde_derive", "serde_json", "settings", "sha2 0.10.6", @@ -5250,6 +5268,7 @@ dependencies = [ "rand 0.8.5", "rsa", "serde", + "serde_derive", "smol", "smol-timeout", "tempdir", @@ -5673,6 +5692,7 @@ dependencies = [ "postage", "project", "serde", + "serde_derive", "serde_json", "settings", "smallvec", @@ -5861,6 +5881,7 @@ dependencies = [ "postage", "schemars", "serde", + "serde_derive", "serde_json", "serde_path_to_error", "sqlez", @@ -6481,6 +6502,7 @@ dependencies = [ "procinfo", "rand 0.8.5", "serde", + "serde_derive", "settings", "shellexpand", "smallvec", @@ -6512,6 +6534,7 @@ dependencies = [ "project", "rand 0.8.5", "serde", + "serde_derive", "settings", "shellexpand", "smallvec", @@ -6571,6 +6594,7 @@ dependencies = [ "indexmap", "parking_lot 0.11.2", "serde", + "serde_derive", "serde_json", "serde_path_to_error", "toml", @@ -7564,6 +7588,7 @@ dependencies = [ "project", "search", "serde", + "serde_derive", "serde_json", "settings", "tokio", @@ -8347,6 +8372,7 @@ dependencies = [ "postage", "project", "serde", + "serde_derive", "serde_json", "settings", "smallvec", @@ -8473,6 +8499,7 @@ dependencies = [ "rust-embed", "search", "serde", + "serde_derive", "serde_json", "serde_path_to_error", "settings", diff --git a/Cargo.toml b/Cargo.toml index ab8bcd6de83d8f96853e4f4599bd3c51eced63d3..fd713d42421ec9d4349618edf5fb36f0cc6901ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,6 +68,7 @@ resolver = "2" [workspace.dependencies] serde = { version = "1.0", features = ["derive", "rc"] } +serde_derive = { version = "1.0", features = ["deserialize_in_place"] } serde_json = { version = "1.0", features = ["preserve_order", "raw_value"] } rand = { version = "0.8" } diff --git a/crates/auto_update/Cargo.toml b/crates/auto_update/Cargo.toml index 5f672e759f61065cb46624e6c39369442b3765ee..8edb1957afcf13b0e01c078d27ad75335ad09a3d 100644 --- a/crates/auto_update/Cargo.toml +++ b/crates/auto_update/Cargo.toml @@ -23,6 +23,7 @@ isahc = "1.7" lazy_static = "1.4" log = "0.4" serde = { version = "1.0", features = ["derive", "rc"] } +serde_derive = { version = "1.0", features = ["deserialize_in_place"] } serde_json = { version = "1.0", features = ["preserve_order"] } smol = "1.2.5" tempdir = "0.3.7" diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index f2bab22ea713594d041caa47b6c876798b4c8fc9..bf2e583d2cd56a6f49b07b3cb1f84d68be03fdcc 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -18,6 +18,7 @@ clap = { version = "3.1", features = ["derive"] } dirs = "3.0" ipc-channel = "0.16" serde = { version = "1.0", features = ["derive", "rc"] } +serde_derive = { version = "1.0", features = ["deserialize_in_place"] } [target.'cfg(target_os = "macos")'.dependencies] core-foundation = "0.9" diff --git a/crates/client/Cargo.toml b/crates/client/Cargo.toml index 347424d34e444fda74200ac6e6cc6676ea7fd807..6ff66b8ecc4d165cb5dddac2253f85825ea17279 100644 --- a/crates/client/Cargo.toml +++ b/crates/client/Cargo.toml @@ -35,7 +35,8 @@ time = { version = "0.3", features = ["serde", "serde-well-known"] } tiny_http = "0.8" uuid = { version = "1.1.2", features = ["v4"] } url = "2.2" -serde = { version = "*", features = ["derive"] } +serde = { version = "*", features = ["derive", "rc"] } +serde_derive = { version = "1.0", features = ["deserialize_in_place"] } settings = { path = "../settings" } tempfile = "3" diff --git a/crates/collab/Cargo.toml b/crates/collab/Cargo.toml index 873ff8aa44841aa5589bf6aab51157e56d0d3e0d..c25fc287695a1970200455ff447a135859b764f6 100644 --- a/crates/collab/Cargo.toml +++ b/crates/collab/Cargo.toml @@ -42,6 +42,7 @@ scrypt = "0.7" sea-orm = { git = "https://github.com/zed-industries/sea-orm", rev = "18f4c691085712ad014a51792af75a9044bacee6", features = ["sqlx-postgres", "postgres-array", "runtime-tokio-rustls"] } sea-query = "0.27" serde = { version = "1.0", features = ["derive", "rc"] } +serde_derive = { version = "1.0", features = ["deserialize_in_place"] } serde_json = "1.0" sha-1 = "0.9" sqlx = { version = "0.6", features = ["runtime-tokio-rustls", "postgres", "json", "time", "uuid", "any"] } diff --git a/crates/collab_ui/Cargo.toml b/crates/collab_ui/Cargo.toml index 2afeb8ad8ae755b1f8b554d8e4a9bc15732767f3..9b5ca9c1ea9b04995c518a7fd6334a6050de15e2 100644 --- a/crates/collab_ui/Cargo.toml +++ b/crates/collab_ui/Cargo.toml @@ -44,6 +44,7 @@ futures = "0.3" log = "0.4" postage = { version = "0.4.1", features = ["futures-traits"] } serde = { version = "1.0", features = ["derive", "rc"] } +serde_derive = { version = "1.0", features = ["deserialize_in_place"] } [dev-dependencies] call = { path = "../call", features = ["test-support"] } diff --git a/crates/db/Cargo.toml b/crates/db/Cargo.toml index 496e61b81148335d54bb528610914b6173253a17..16ec37019a70007bca4c9528d578d8d7efd353cd 100644 --- a/crates/db/Cargo.toml +++ b/crates/db/Cargo.toml @@ -24,6 +24,7 @@ lazy_static = "1.4.0" log = { version = "0.4.16", features = ["kv_unstable_serde"] } parking_lot = "0.11.1" serde = { version = "1.0", features = ["derive"] } +serde_derive = { version = "1.0", features = ["deserialize_in_place"] } smol = "1.2" [dev-dependencies] diff --git a/crates/editor/Cargo.toml b/crates/editor/Cargo.toml index 6cb7ef32ec41a3ccd8caa8de2c0ba932144962ab..6c52ec70e9355047be2a4eb2d30b04736b2edf80 100644 --- a/crates/editor/Cargo.toml +++ b/crates/editor/Cargo.toml @@ -54,6 +54,7 @@ parking_lot = "0.11" postage = { version = "0.4", features = ["futures-traits"] } rand = { version = "0.8.3", optional = true } serde = { workspace = true } +serde_derive = { version = "1.0", features = ["deserialize_in_place"] } smallvec = { version = "1.6", features = ["union"] } smol = "1.2" tree-sitter-rust = { version = "*", optional = true } diff --git a/crates/feedback/Cargo.toml b/crates/feedback/Cargo.toml index b224f91a2f2bca3a597fed6497fc0d9edb46ad5b..51f070dd1d314278ddf5760ad4aa812ec8b7a85e 100644 --- a/crates/feedback/Cargo.toml +++ b/crates/feedback/Cargo.toml @@ -25,10 +25,11 @@ postage = { version = "0.4", features = ["futures-traits"] } project = { path = "../project" } search = { path = "../search" } serde = { version = "1.0", features = ["derive", "rc"] } +serde_derive = { version = "1.0", features = ["deserialize_in_place"] } settings = { path = "../settings" } sysinfo = "0.27.1" theme = { path = "../theme" } tree-sitter-markdown = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "330ecab87a3e3a7211ac69bbadc19eabecdb1cca" } urlencoding = "2.1.2" util = { path = "../util" } -workspace = { path = "../workspace" } \ No newline at end of file +workspace = { path = "../workspace" } diff --git a/crates/fs/Cargo.toml b/crates/fs/Cargo.toml index cd6c8f969c8192de244d543852df80f2bf559b5a..66708943f94a2913c4bd394eea6a8c931cac94ed 100644 --- a/crates/fs/Cargo.toml +++ b/crates/fs/Cargo.toml @@ -24,6 +24,7 @@ smol = "1.2.5" regex = "1.5" git2 = { version = "0.15", default-features = false } serde = { workspace = true } +serde_derive = { version = "1.0", features = ["deserialize_in_place"] } serde_json = { workspace = true } log = { version = "0.4.16", features = ["kv_unstable_serde"] } libc = "0.2" diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index b3e9bda4ec27308ce884573d8b42bd665ea40b2d..65d36753e7bc1e80c4f6bb5ac6a6ff555c326b8e 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -42,6 +42,7 @@ resvg = "0.14" schemars = "0.8" seahash = "4.1" serde = { version = "1.0", features = ["derive", "rc"] } +serde_derive = { version = "1.0", features = ["deserialize_in_place"] } serde_json = "1.0" smallvec = { version = "1.6", features = ["union"] } smol = "1.2" diff --git a/crates/language/Cargo.toml b/crates/language/Cargo.toml index 3e6561e47109870b4fae7d89844c5ebf9ed11be1..26e2d8c53baef5ee1c503cac88e426b1c0f0442c 100644 --- a/crates/language/Cargo.toml +++ b/crates/language/Cargo.toml @@ -47,6 +47,7 @@ postage = { version = "0.4.1", features = ["futures-traits"] } rand = { version = "0.8.3", optional = true } regex = "1.5" serde = { version = "1.0", features = ["derive", "rc"] } +serde_derive = { version = "1.0", features = ["deserialize_in_place"] } serde_json = { version = "1", features = ["preserve_order"] } similar = "1.3" smallvec = { version = "1.6", features = ["union"] } diff --git a/crates/live_kit_client/Cargo.toml b/crates/live_kit_client/Cargo.toml index 01457375084ae9992467e185ecfc38ed38c5e1e0..55645732b8f104f327624fc0834657ad940bdb20 100644 --- a/crates/live_kit_client/Cargo.toml +++ b/crates/live_kit_client/Cargo.toml @@ -14,7 +14,7 @@ name = "test_app" [features] test-support = [ - "async-trait", + "async-trait", "collections/test-support", "gpui/test-support", "lazy_static", @@ -63,9 +63,11 @@ lazy_static = "1.4" objc = "0.2" parking_lot = "0.11.1" serde = { version = "1.0", features = ["derive", "rc"] } +serde_derive = { version = "1.0", features = ["deserialize_in_place"] } sha2 = "0.10" simplelog = "0.9" [build-dependencies] serde = { version = "1.0", features = ["derive", "rc"] } +serde_derive = { version = "1.0", features = ["deserialize_in_place"] } serde_json = { version = "1.0", features = ["preserve_order"] } diff --git a/crates/live_kit_server/Cargo.toml b/crates/live_kit_server/Cargo.toml index 17ee3cd62e21a200999161d8f5ad2dc302386b59..319a026456b0a2b3cd500c567b01152d30a63542 100644 --- a/crates/live_kit_server/Cargo.toml +++ b/crates/live_kit_server/Cargo.toml @@ -20,6 +20,7 @@ prost = "0.8" prost-types = "0.8" reqwest = "0.11" serde = { version = "1.0", features = ["derive", "rc"] } +serde_derive = { version = "1.0", features = ["deserialize_in_place"] } sha2 = "0.10" [build-dependencies] diff --git a/crates/lsp/Cargo.toml b/crates/lsp/Cargo.toml index eb6e02aac91b7aaa29b4ab283dd03b45da6438a5..f37b1c9a4536ebb95a8a10c7053adebb09dad2e4 100644 --- a/crates/lsp/Cargo.toml +++ b/crates/lsp/Cargo.toml @@ -23,6 +23,7 @@ lsp-types = "0.91" parking_lot = "0.11" postage = { version = "0.4.1", features = ["futures-traits"] } serde = { version = "1.0", features = ["derive", "rc"] } +serde_derive = { version = "1.0", features = ["deserialize_in_place"] } serde_json = { version = "1.0", features = ["raw_value"] } smol = "1.2" diff --git a/crates/plugin/Cargo.toml b/crates/plugin/Cargo.toml index 7bf551046597c416cef6d997536f446d8a17d228..6b86b19fc859ee2e40b2d3877a674bb617def09c 100644 --- a/crates/plugin/Cargo.toml +++ b/crates/plugin/Cargo.toml @@ -6,5 +6,6 @@ publish = false [dependencies] serde = "1.0" +serde_derive = { version = "1.0", features = ["deserialize_in_place"] } bincode = "1.3" plugin_macros = { path = "../plugin_macros" } diff --git a/crates/plugin_macros/Cargo.toml b/crates/plugin_macros/Cargo.toml index 32bfc6a01afe83c3dddb2a9243ed4fffc0cf42d2..e661485373f87940bdc38b3ae7b1e69ada36c321 100644 --- a/crates/plugin_macros/Cargo.toml +++ b/crates/plugin_macros/Cargo.toml @@ -12,4 +12,5 @@ syn = { version = "1.0", features = ["full", "extra-traits"] } quote = "1.0" proc-macro2 = "1.0" serde = "1.0" +serde_derive = { version = "1.0", features = ["deserialize_in_place"] } bincode = "1.3" diff --git a/crates/plugin_runtime/Cargo.toml b/crates/plugin_runtime/Cargo.toml index b5cfb9514f36ca936089fe2ccdb969399d0492bf..13efa10dc223162a1034eeb212fc73a0943904e2 100644 --- a/crates/plugin_runtime/Cargo.toml +++ b/crates/plugin_runtime/Cargo.toml @@ -10,6 +10,7 @@ wasmtime-wasi = "0.38" wasi-common = "0.38" anyhow = { version = "1.0", features = ["std"] } serde = "1.0" +serde_derive = { version = "1.0", features = ["deserialize_in_place"] } serde_json = "1.0" bincode = "1.3" pollster = "0.2.5" diff --git a/crates/project/Cargo.toml b/crates/project/Cargo.toml index 68dc57f61459bd5aaf3cfe242319ff538d96b9f1..89ed5563abef6d9cccf605e2efded09cdaf9250e 100644 --- a/crates/project/Cargo.toml +++ b/crates/project/Cargo.toml @@ -49,6 +49,7 @@ pulldown-cmark = { version = "0.9.1", default-features = false } rand = "0.8.3" regex = "1.5" serde = { version = "1.0", features = ["derive", "rc"] } +serde_derive = { version = "1.0", features = ["deserialize_in_place"] } serde_json = { version = "1.0", features = ["preserve_order"] } sha2 = "0.10" similar = "1.3" diff --git a/crates/rpc/Cargo.toml b/crates/rpc/Cargo.toml index 25c2ce1ca73c04d4f2b268909fa6972f18b87c0d..ff71a2493e8d7c60ae35559faa6d887103f5f110 100644 --- a/crates/rpc/Cargo.toml +++ b/crates/rpc/Cargo.toml @@ -27,6 +27,7 @@ prost = "0.8" rand = "0.8" rsa = "0.4" serde = { version = "1.0", features = ["derive", "rc"] } +serde_derive = { version = "1.0", features = ["deserialize_in_place"] } smol-timeout = "0.6" tracing = { version = "0.1.34", features = ["log"] } zstd = "0.11" diff --git a/crates/search/Cargo.toml b/crates/search/Cargo.toml index f36865a89b4bd21cae7d10f838ef5f5e1bdfd5e5..85215c15b264c6b83fd38f87eba99973837131bb 100644 --- a/crates/search/Cargo.toml +++ b/crates/search/Cargo.toml @@ -24,6 +24,7 @@ futures = "0.3" log = { version = "0.4.16", features = ["kv_unstable_serde"] } postage = { version = "0.4.1", features = ["futures-traits"] } serde = { version = "1.0", features = ["derive", "rc"] } +serde_derive = { version = "1.0", features = ["deserialize_in_place"] } smallvec = { version = "1.6", features = ["union"] } smol = "1.2" diff --git a/crates/settings/Cargo.toml b/crates/settings/Cargo.toml index c1ec2a6210cdcee41dbd208ddbd60eec3a3282cd..1711bb335bd3efc9de99bda8a5fbfdadfd9c3e59 100644 --- a/crates/settings/Cargo.toml +++ b/crates/settings/Cargo.toml @@ -25,6 +25,7 @@ json_comments = "0.2" postage = { version = "0.4.1", features = ["futures-traits"] } schemars = "0.8" serde = { workspace = true } +serde_derive = { version = "1.0", features = ["deserialize_in_place"] } serde_json = { workspace = true } serde_path_to_error = "0.1.4" toml = "0.5" diff --git a/crates/terminal/Cargo.toml b/crates/terminal/Cargo.toml index c6f33a0fc76ff714e170d142177ff28cea2033b2..56a8a3c45222c8d14a774e169ef91d1169135106 100644 --- a/crates/terminal/Cargo.toml +++ b/crates/terminal/Cargo.toml @@ -30,6 +30,7 @@ anyhow = "1" thiserror = "1.0" lazy_static = "1.4.0" serde = { version = "1.0", features = ["derive"] } +serde_derive = { version = "1.0", features = ["deserialize_in_place"] } [dev-dependencies] rand = "0.8.5" diff --git a/crates/terminal_view/Cargo.toml b/crates/terminal_view/Cargo.toml index f12e4be03bd84d52bb3621023a42767101aa3f41..1e5b9d6070b1ed5286ea1a0a11788c210f42c57e 100644 --- a/crates/terminal_view/Cargo.toml +++ b/crates/terminal_view/Cargo.toml @@ -34,6 +34,7 @@ anyhow = "1" thiserror = "1.0" lazy_static = "1.4.0" serde = { version = "1.0", features = ["derive"] } +serde_derive = { version = "1.0", features = ["deserialize_in_place"] } diff --git a/crates/theme/Cargo.toml b/crates/theme/Cargo.toml index 1e9883860fa6bd04ec034dd247d02501d8ce4aaf..a0ef4ad9f8c378f206c1fe60ec2fa83a4f82cbd3 100644 --- a/crates/theme/Cargo.toml +++ b/crates/theme/Cargo.toml @@ -14,6 +14,7 @@ anyhow = "1.0.38" indexmap = "1.6.2" parking_lot = "0.11.1" serde = { version = "1.0", features = ["derive", "rc"] } +serde_derive = { version = "1.0", features = ["deserialize_in_place"] } serde_json = { version = "1.0", features = ["preserve_order"] } serde_path_to_error = "0.1.4" toml = "0.5" diff --git a/crates/theme/src/theme_registry.rs b/crates/theme/src/theme_registry.rs index d47625289bfd693201c0ea18de1e0fb216cebae2..a82ede59f7633f1c96c8f3b646a0204ad5f4cf79 100644 --- a/crates/theme/src/theme_registry.rs +++ b/crates/theme/src/theme_registry.rs @@ -2,6 +2,7 @@ use crate::{Theme, ThemeMeta}; use anyhow::{Context, Result}; use gpui::{fonts, AssetSource, FontCache}; use parking_lot::Mutex; +use serde::Deserialize; use serde_json::Value; use std::{collections::HashMap, sync::Arc}; @@ -56,12 +57,16 @@ impl ThemeRegistry { .with_context(|| format!("failed to load theme file {}", asset_path))?; // Allocate into the heap directly, the Theme struct is too large to fit in the stack. - let mut theme: Arc = fonts::with_font_cache(self.font_cache.clone(), || { - serde_path_to_error::deserialize(&mut serde_json::Deserializer::from_slice(&theme_json)) + let mut theme = fonts::with_font_cache(self.font_cache.clone(), || { + let mut theme = Box::new(Theme::default()); + let mut deserializer = serde_json::Deserializer::from_slice(&theme_json); + let result = Theme::deserialize_in_place(&mut deserializer, &mut theme); + result.map(|_| theme) })?; // Reset name to be the file path, so that we can use it to access the stored themes - Arc::get_mut(&mut theme).unwrap().meta.name = name.into(); + theme.meta.name = name.into(); + let theme: Arc = theme.into(); self.themes.lock().insert(name.to_string(), theme.clone()); Ok(theme) } diff --git a/crates/vim/Cargo.toml b/crates/vim/Cargo.toml index bd94e48b9e7075c5b8e6fc9b74a5fbba3408d5f5..dd79d56d8fd24ab32c8959682476a6c01c088165 100644 --- a/crates/vim/Cargo.toml +++ b/crates/vim/Cargo.toml @@ -13,6 +13,7 @@ neovim = ["nvim-rs", "async-compat", "async-trait", "tokio"] [dependencies] serde = { version = "1.0", features = ["derive", "rc"] } +serde_derive = { version = "1.0", features = ["deserialize_in_place"] } itertools = "0.10" log = { version = "0.4.16", features = ["kv_unstable_serde"] } diff --git a/crates/workspace/Cargo.toml b/crates/workspace/Cargo.toml index a143e1a2400af479a8f08fae08c8d82d86135484..06b20684c60f157cdbd3ed9516792f13f528f691 100644 --- a/crates/workspace/Cargo.toml +++ b/crates/workspace/Cargo.toml @@ -45,6 +45,7 @@ log = { version = "0.4.16", features = ["kv_unstable_serde"] } parking_lot = "0.11.1" postage = { version = "0.4.1", features = ["futures-traits"] } serde = { version = "1.0", features = ["derive", "rc"] } +serde_derive = { version = "1.0", features = ["deserialize_in_place"] } serde_json = { version = "1.0", features = ["preserve_order"] } smallvec = { version = "1.6", features = ["union"] } indoc = "1.0.4" @@ -57,4 +58,4 @@ gpui = { path = "../gpui", features = ["test-support"] } project = { path = "../project", features = ["test-support"] } settings = { path = "../settings", features = ["test-support"] } fs = { path = "../fs", features = ["test-support"] } -db = { path = "../db", features = ["test-support"] } \ No newline at end of file +db = { path = "../db", features = ["test-support"] } diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 6f0227d748f1cca28bb5a64f2ad0846a71fe8b8f..6a2422f87ca8657d5cbca7b393c7ca7f5f602ea1 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -88,6 +88,7 @@ regex = "1.5" rsa = "0.4" rust-embed = { version = "6.3", features = ["include-exclude"] } serde = { version = "1.0", features = ["derive", "rc"] } +serde_derive = { version = "1.0", features = ["deserialize_in_place"] } serde_json = { version = "1.0", features = ["preserve_order"] } serde_path_to_error = "0.1.4" simplelog = "0.9" diff --git a/plugins/Cargo.lock b/plugins/Cargo.lock index 3a302d301b0387fd67259b5ee060a4bf90491aa2..1e51dd80856385026b6ce58f664b41869c38d1ea 100644 --- a/plugins/Cargo.lock +++ b/plugins/Cargo.lock @@ -23,6 +23,7 @@ version = "0.1.0" dependencies = [ "plugin", "serde", + "serde_derive", "serde_json", ] @@ -33,6 +34,7 @@ dependencies = [ "bincode", "plugin_macros", "serde", + "serde_derive", ] [[package]] @@ -43,6 +45,7 @@ dependencies = [ "proc-macro2", "quote", "serde", + "serde_derive", "syn", ] diff --git a/plugins/json_language/Cargo.toml b/plugins/json_language/Cargo.toml index 7e01b9793fd6f837e56c459531d820b85b51201e..effbf2ed8abbfa0f6bf35156227f2a8e4e21eeba 100644 --- a/plugins/json_language/Cargo.toml +++ b/plugins/json_language/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] plugin = { path = "../../crates/plugin" } serde = { version = "1.0", features = ["derive"] } +serde_derive = { version = "1.0", features = ["deserialize_in_place"] } serde_json = "1.0" [lib]