diff --git a/Cargo.lock b/Cargo.lock index 386fac6f3d..22e0de3845 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7573,6 +7573,7 @@ dependencies = [ "uuid", "waker-fn", "wasm-bindgen", + "web-sys", "web-time", "windows 0.61.3", "zed-font-kit", diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index 86d1460c93..025107fe53 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -149,6 +149,7 @@ reqwest_client = { workspace = true, features = ["test-support"] } [target.'cfg(target_family = "wasm")'.dev-dependencies] wasm-bindgen = { workspace = true } +web-sys = { version = "0.3", features = ["console"] } [build-dependencies] embed-resource = { version = "3.0", optional = true } diff --git a/crates/gpui/examples/a11y.rs b/crates/gpui/examples/a11y.rs index 6e37354ae8..ff389f330c 100644 --- a/crates/gpui/examples/a11y.rs +++ b/crates/gpui/examples/a11y.rs @@ -30,6 +30,9 @@ //! - "2. Run tests" //! - "3. Ship it" +#[path = "example_support/fonts.rs"] +mod example_support; + use gpui::{ AccessibleAction, App, Bounds, Context, FocusHandle, KeyBinding, Role, SharedString, Toggled, Window, WindowBounds, WindowOptions, actions, div, prelude::*, px, rgb, size, text, @@ -226,6 +229,9 @@ impl Render for A11yDemo { fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } cx.bind_keys([ KeyBinding::new("tab", Tab, None), KeyBinding::new("shift-tab", TabPrev, None), diff --git a/crates/gpui/examples/anchor.rs b/crates/gpui/examples/anchor.rs index 7aa9bb4cf9..b4b280b714 100644 --- a/crates/gpui/examples/anchor.rs +++ b/crates/gpui/examples/anchor.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use gpui::{ Anchor, AnchoredPositionMode, App, Axis, Bounds, Context, Half as _, InteractiveElement, ParentElement, Pixels, Point, Render, SharedString, Size, Window, WindowBounds, WindowOptions, @@ -168,6 +171,9 @@ impl Render for AnchorDemo { fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } cx.open_window( WindowOptions { window_bounds: Some(WindowBounds::Windowed(Bounds::centered( diff --git a/crates/gpui/examples/animation.rs b/crates/gpui/examples/animation.rs index 4e09d15c41..e055b7da47 100644 --- a/crates/gpui/examples/animation.rs +++ b/crates/gpui/examples/animation.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use std::time::Duration; use anyhow::Result; @@ -306,6 +309,9 @@ impl Render for AnimationExample { fn run_example() { application().with_assets(Assets {}).run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } let options = WindowOptions { window_bounds: Some(WindowBounds::Windowed(Bounds::centered( None, diff --git a/crates/gpui/examples/data_table.rs b/crates/gpui/examples/data_table.rs index b3f8737ec4..2bee47634d 100644 --- a/crates/gpui/examples/data_table.rs +++ b/crates/gpui/examples/data_table.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use std::{ops::Range, rc::Rc, time::Duration}; use gpui::{ @@ -451,6 +454,9 @@ impl Render for DataTable { fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } cx.open_window( WindowOptions { focus: true, diff --git a/crates/gpui/examples/drag_drop.rs b/crates/gpui/examples/drag_drop.rs index b233bc4107..8f038ef330 100644 --- a/crates/gpui/examples/drag_drop.rs +++ b/crates/gpui/examples/drag_drop.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use gpui::{ App, Bounds, Context, Half, Hsla, Pixels, Point, Window, WindowBounds, WindowOptions, div, prelude::*, px, rgb, size, @@ -125,6 +128,9 @@ impl Render for DragDrop { fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } let bounds = Bounds::centered(None, size(px(800.), px(600.0)), cx); cx.open_window( WindowOptions { diff --git a/crates/gpui/examples/example_support/fonts.rs b/crates/gpui/examples/example_support/fonts.rs new file mode 100644 index 0000000000..39c3be1918 --- /dev/null +++ b/crates/gpui/examples/example_support/fonts.rs @@ -0,0 +1,44 @@ +#[cfg(target_family = "wasm")] +use std::borrow::Cow; + +use gpui::App; + +#[cfg(target_family = "wasm")] +pub fn load_fonts(cx: &App) -> bool { + let fonts = [ + Cow::Borrowed( + include_bytes!("../../../../assets/fonts/ibm-plex-sans/IBMPlexSans-Regular.ttf") + .as_slice(), + ), + Cow::Borrowed( + include_bytes!("../../../../assets/fonts/ibm-plex-sans/IBMPlexSans-Italic.ttf") + .as_slice(), + ), + Cow::Borrowed( + include_bytes!("../../../../assets/fonts/ibm-plex-sans/IBMPlexSans-SemiBold.ttf") + .as_slice(), + ), + Cow::Borrowed( + include_bytes!("../../../../assets/fonts/ibm-plex-sans/IBMPlexSans-SemiBoldItalic.ttf") + .as_slice(), + ), + Cow::Borrowed( + include_bytes!("../../../../assets/fonts/lilex/Lilex-Regular.ttf").as_slice(), + ), + Cow::Borrowed(include_bytes!("../../../../assets/fonts/lilex/Lilex-Bold.ttf").as_slice()), + Cow::Borrowed(include_bytes!("../../../../assets/fonts/lilex/Lilex-Italic.ttf").as_slice()), + Cow::Borrowed( + include_bytes!("../../../../assets/fonts/lilex/Lilex-BoldItalic.ttf").as_slice(), + ), + ]; + if let Err(error) = cx.text_system().add_fonts(fonts.into()) { + web_sys::console::error_1(&format!("failed to load application fonts: {error:#}").into()); + return false; + } + true +} + +#[cfg(not(target_family = "wasm"))] +pub fn load_fonts(_cx: &App) -> bool { + true +} diff --git a/crates/gpui/examples/focus_visible.rs b/crates/gpui/examples/focus_visible.rs index 02a171da21..c5b3d5dfec 100644 --- a/crates/gpui/examples/focus_visible.rs +++ b/crates/gpui/examples/focus_visible.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use gpui::{ App, Bounds, Context, Div, ElementId, FocusHandle, KeyBinding, SharedString, Stateful, Window, WindowBounds, WindowOptions, actions, div, prelude::*, px, size, @@ -196,6 +199,9 @@ impl Render for Example { fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } cx.bind_keys([ KeyBinding::new("tab", Tab, None), KeyBinding::new("shift-tab", TabPrev, None), diff --git a/crates/gpui/examples/gif_viewer.rs b/crates/gpui/examples/gif_viewer.rs index 59fb8d3794..80b56aa7c5 100644 --- a/crates/gpui/examples/gif_viewer.rs +++ b/crates/gpui/examples/gif_viewer.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use gpui::{App, Context, Render, Window, WindowOptions, div, img, prelude::*}; use gpui_platform::application; use std::path::PathBuf; @@ -27,6 +30,9 @@ impl Render for GifViewer { fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } let gif_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("examples/image/black-cat-typing.gif"); diff --git a/crates/gpui/examples/gradient.rs b/crates/gpui/examples/gradient.rs index 97321f1071..df1398fff5 100644 --- a/crates/gpui/examples/gradient.rs +++ b/crates/gpui/examples/gradient.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use gpui::{ App, Bounds, ColorSpace, Context, Half, Render, Window, WindowOptions, canvas, div, linear_color_stop, linear_gradient, point, prelude::*, px, size, @@ -247,6 +250,9 @@ impl Render for GradientViewer { fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } cx.open_window( WindowOptions { focus: true, diff --git a/crates/gpui/examples/grid_layout.rs b/crates/gpui/examples/grid_layout.rs index 9c6d723eba..51f9b13e41 100644 --- a/crates/gpui/examples/grid_layout.rs +++ b/crates/gpui/examples/grid_layout.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use gpui::{ App, Bounds, Context, Hsla, Window, WindowBounds, WindowOptions, container_query, div, prelude::*, px, rgb, size, @@ -63,6 +66,9 @@ impl Render for HolyGrailExample { fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } let bounds = Bounds::centered(None, size(px(500.), px(500.0)), cx); cx.open_window( WindowOptions { diff --git a/crates/gpui/examples/hello_world.rs b/crates/gpui/examples/hello_world.rs index aa67ada33f..d18cb04872 100644 --- a/crates/gpui/examples/hello_world.rs +++ b/crates/gpui/examples/hello_world.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use gpui::{ App, Bounds, Context, SharedString, Window, WindowBounds, WindowOptions, div, prelude::*, px, rgb, size, @@ -91,6 +94,9 @@ impl Render for HelloWorld { fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } let bounds = Bounds::centered(None, size(px(500.), px(500.0)), cx); cx.open_window( WindowOptions { diff --git a/crates/gpui/examples/image/image.rs b/crates/gpui/examples/image/image.rs index 2a885714c8..30160c65dd 100644 --- a/crates/gpui/examples/image/image.rs +++ b/crates/gpui/examples/image/image.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "../example_support/fonts.rs"] +mod example_support; + use std::fs; use std::path::PathBuf; use std::sync::Arc; @@ -159,6 +162,9 @@ fn run_example() { base: manifest_dir.join("examples"), }) .run(move |cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } #[cfg(not(target_family = "wasm"))] { let http_client = ReqwestClient::user_agent("gpui example").unwrap(); diff --git a/crates/gpui/examples/image_gallery.rs b/crates/gpui/examples/image_gallery.rs index b4c2887755..16b9b17a3f 100644 --- a/crates/gpui/examples/image_gallery.rs +++ b/crates/gpui/examples/image_gallery.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use futures::FutureExt; use gpui::{ App, AppContext, Asset as _, AssetLogger, Bounds, ClickEvent, Context, ElementId, Entity, @@ -254,6 +257,9 @@ fn run_example() { let app = gpui_platform::single_threaded_web(); app.run(move |cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } #[cfg(not(target_family = "wasm"))] { let http_client = ReqwestClient::user_agent("gpui example").unwrap(); diff --git a/crates/gpui/examples/image_loading.rs b/crates/gpui/examples/image_loading.rs index c2aab95f12..b6828915bd 100644 --- a/crates/gpui/examples/image_loading.rs +++ b/crates/gpui/examples/image_loading.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use std::{path::Path, sync::Arc, time::Duration}; use gpui::{ @@ -196,6 +199,9 @@ impl Render for ImageLoadingExample { fn run_example() { application().with_assets(Assets {}).run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } let options = WindowOptions { window_bounds: Some(WindowBounds::Windowed(Bounds::centered( None, diff --git a/crates/gpui/examples/input.rs b/crates/gpui/examples/input.rs index 370e27de7d..eadc2d2f39 100644 --- a/crates/gpui/examples/input.rs +++ b/crates/gpui/examples/input.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use std::ops::Range; use gpui::{ @@ -696,6 +699,9 @@ impl Render for InputExample { fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } let bounds = Bounds::centered(None, size(px(300.0), px(300.0)), cx); cx.bind_keys([ KeyBinding::new("backspace", Backspace, None), diff --git a/crates/gpui/examples/list_example.rs b/crates/gpui/examples/list_example.rs index 7aeff7c24e..542b7e320a 100644 --- a/crates/gpui/examples/list_example.rs +++ b/crates/gpui/examples/list_example.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use gpui::{ App, Bounds, Context, ListAlignment, ListState, Render, Window, WindowBounds, WindowOptions, div, list, prelude::*, px, rgb, size, @@ -143,6 +146,9 @@ impl Render for BottomListDemo { fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } let bounds = Bounds::centered(None, size(px(400.), px(500.)), cx); cx.open_window( WindowOptions { diff --git a/crates/gpui/examples/mouse_pressure.rs b/crates/gpui/examples/mouse_pressure.rs index d3519b2a54..3470bf1869 100644 --- a/crates/gpui/examples/mouse_pressure.rs +++ b/crates/gpui/examples/mouse_pressure.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use gpui::{ App, Bounds, Context, MousePressureEvent, PressureStage, Window, WindowBounds, WindowOptions, div, prelude::*, px, rgb, size, @@ -48,6 +51,9 @@ impl MousePressureExample { fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } let bounds = Bounds::centered(None, size(px(500.), px(500.0)), cx); cx.open_window( diff --git a/crates/gpui/examples/move_entity_between_windows.rs b/crates/gpui/examples/move_entity_between_windows.rs index eaefabfe29..e0f16467a6 100644 --- a/crates/gpui/examples/move_entity_between_windows.rs +++ b/crates/gpui/examples/move_entity_between_windows.rs @@ -8,6 +8,9 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use std::time::Duration; use gpui::{ @@ -128,6 +131,9 @@ impl Render for HelloWorld { fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } let bounds = Bounds::centered(None, size(px(500.0), px(500.0)), cx); cx.open_window( WindowOptions { diff --git a/crates/gpui/examples/on_window_close_quit.rs b/crates/gpui/examples/on_window_close_quit.rs index 347401c6d9..d61e23e445 100644 --- a/crates/gpui/examples/on_window_close_quit.rs +++ b/crates/gpui/examples/on_window_close_quit.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use gpui::{ App, Bounds, Context, FocusHandle, KeyBinding, Window, WindowBounds, WindowOptions, actions, div, prelude::*, px, rgb, size, @@ -39,6 +42,9 @@ impl Render for ExampleWindow { fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } let mut bounds = Bounds::centered(None, size(px(500.), px(500.0)), cx); cx.bind_keys([KeyBinding::new("cmd-w", CloseWindow, None)]); diff --git a/crates/gpui/examples/opacity.rs b/crates/gpui/examples/opacity.rs index 413c40c826..c2af3424b6 100644 --- a/crates/gpui/examples/opacity.rs +++ b/crates/gpui/examples/opacity.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use std::{fs, path::PathBuf}; use anyhow::Result; @@ -163,6 +166,9 @@ fn run_example() { base: PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("examples"), }) .run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } let bounds = Bounds::centered(None, size(px(500.0), px(500.0)), cx); cx.open_window( WindowOptions { diff --git a/crates/gpui/examples/ownership_post.rs b/crates/gpui/examples/ownership_post.rs index a4421b970b..04a0b6fe37 100644 --- a/crates/gpui/examples/ownership_post.rs +++ b/crates/gpui/examples/ownership_post.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use gpui::{App, Context, Entity, EventEmitter, prelude::*}; use gpui_platform::application; @@ -15,6 +18,9 @@ impl EventEmitter for Counter {} fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } let counter: Entity = cx.new(|_cx| Counter { count: 0 }); let subscriber = cx.new(|cx: &mut Context| { cx.subscribe(&counter, |subscriber, _emitter, event, _cx| { diff --git a/crates/gpui/examples/painting.rs b/crates/gpui/examples/painting.rs index 41cbcb2802..3d89b0ff52 100644 --- a/crates/gpui/examples/painting.rs +++ b/crates/gpui/examples/painting.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use gpui::{ Background, Bounds, ColorSpace, Context, MouseDownEvent, Path, PathBuilder, PathStyle, Pixels, Point, Render, StrokeOptions, Window, WindowOptions, canvas, div, linear_color_stop, @@ -443,6 +446,9 @@ impl Render for PaintingViewer { fn run_example() { application().run(|cx| { + if !example_support::load_fonts(cx) { + return; + } cx.open_window( WindowOptions { focus: true, diff --git a/crates/gpui/examples/paths_bench.rs b/crates/gpui/examples/paths_bench.rs index 4e12f1e50a..236e70e9fc 100644 --- a/crates/gpui/examples/paths_bench.rs +++ b/crates/gpui/examples/paths_bench.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use gpui::{ Background, Bounds, ColorSpace, Context, Path, PathBuilder, Pixels, Render, TitlebarOptions, Window, WindowBounds, WindowOptions, canvas, div, linear_color_stop, linear_gradient, point, @@ -73,6 +76,9 @@ impl Render for PaintingViewer { fn run_example() { application().run(|cx| { + if !example_support::load_fonts(cx) { + return; + } cx.open_window( WindowOptions { titlebar: Some(TitlebarOptions { diff --git a/crates/gpui/examples/pattern.rs b/crates/gpui/examples/pattern.rs index 3113d39d80..7d2e98d16e 100644 --- a/crates/gpui/examples/pattern.rs +++ b/crates/gpui/examples/pattern.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use gpui::{ App, AppContext, Bounds, Context, Window, WindowBounds, WindowOptions, div, linear_color_stop, linear_gradient, pattern_slash, prelude::*, px, rgb, size, @@ -103,6 +106,9 @@ impl Render for PatternExample { fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } let bounds = Bounds::centered(None, size(px(600.0), px(600.0)), cx); cx.open_window( WindowOptions { diff --git a/crates/gpui/examples/popover.rs b/crates/gpui/examples/popover.rs index e4f0ac0a3c..7678a6a3ed 100644 --- a/crates/gpui/examples/popover.rs +++ b/crates/gpui/examples/popover.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use gpui::{ Anchor, App, Context, Div, Hsla, Stateful, Window, WindowOptions, anchored, deferred, div, prelude::*, px, @@ -167,6 +170,9 @@ impl Render for HelloWorld { fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } cx.open_window(WindowOptions::default(), |_, cx| { cx.new(|_| HelloWorld { open: false, diff --git a/crates/gpui/examples/scrollable.rs b/crates/gpui/examples/scrollable.rs index 39864c834a..c817956188 100644 --- a/crates/gpui/examples/scrollable.rs +++ b/crates/gpui/examples/scrollable.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use gpui::{App, Bounds, Context, Window, WindowBounds, WindowOptions, div, prelude::*, px, size}; use gpui_platform::application; @@ -46,6 +49,9 @@ impl Render for Scrollable { fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } let bounds = Bounds::centered(None, size(px(500.), px(500.0)), cx); cx.open_window( WindowOptions { diff --git a/crates/gpui/examples/set_menus.rs b/crates/gpui/examples/set_menus.rs index a07f3c36ab..508a60e977 100644 --- a/crates/gpui/examples/set_menus.rs +++ b/crates/gpui/examples/set_menus.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use gpui::{ App, Context, Global, Menu, MenuItem, SharedString, SystemMenuType, Window, WindowOptions, actions, div, prelude::*, @@ -24,6 +27,9 @@ impl Render for SetMenus { fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } cx.set_global(AppState::new()); // Bring the menu bar to the foreground (so you can see the menu bar) diff --git a/crates/gpui/examples/shadow.rs b/crates/gpui/examples/shadow.rs index 375ccac68d..2d8dc09456 100644 --- a/crates/gpui/examples/shadow.rs +++ b/crates/gpui/examples/shadow.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use gpui::{ App, Bounds, BoxShadow, Context, Div, SharedString, Window, WindowBounds, WindowOptions, div, hsla, prelude::*, px, relative, rgb, size, @@ -589,6 +592,9 @@ impl Render for Shadow { fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } let bounds = Bounds::centered(None, size(px(1000.0), px(800.0)), cx); cx.open_window( WindowOptions { diff --git a/crates/gpui/examples/svg/svg.rs b/crates/gpui/examples/svg/svg.rs index e9d2341677..c5ac9b4e1b 100644 --- a/crates/gpui/examples/svg/svg.rs +++ b/crates/gpui/examples/svg/svg.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "../example_support/fonts.rs"] +mod example_support; + use std::fs; use std::path::PathBuf; @@ -76,6 +79,9 @@ fn run_example() { base: PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("examples"), }) .run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } let bounds = Bounds::centered(None, size(px(300.0), px(300.0)), cx); cx.open_window( WindowOptions { diff --git a/crates/gpui/examples/system_notifications.rs b/crates/gpui/examples/system_notifications.rs index 70071dc96f..faf6919120 100644 --- a/crates/gpui/examples/system_notifications.rs +++ b/crates/gpui/examples/system_notifications.rs @@ -2,6 +2,9 @@ //! Demonstrates posting, replacing, dismissing, and responding to system notifications. +#[path = "example_support/fonts.rs"] +mod example_support; + use gpui::{ App, Bounds, Context, Div, SharedString, Stateful, SystemNotification, SystemNotificationAction, SystemNotificationResponse, Window, WindowBounds, WindowOptions, div, @@ -97,6 +100,9 @@ fn button(id: &'static str, label: &'static str) -> Stateful
{ fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } cx.set_app_identity("dev.zed.gpui.system-notifications", "GPUI Notifications"); let view = cx.new(|_| SystemNotificationExample { diff --git a/crates/gpui/examples/tab_stop.rs b/crates/gpui/examples/tab_stop.rs index 3fec59ad9e..cc7c34a997 100644 --- a/crates/gpui/examples/tab_stop.rs +++ b/crates/gpui/examples/tab_stop.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use gpui::{ App, Bounds, Context, Div, ElementId, FocusHandle, KeyBinding, SharedString, Stateful, Window, WindowBounds, WindowOptions, actions, div, prelude::*, px, size, @@ -182,6 +185,9 @@ impl Render for Example { fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } cx.bind_keys([ KeyBinding::new("tab", Tab, None), KeyBinding::new("shift-tab", TabPrev, None), diff --git a/crates/gpui/examples/testing.rs b/crates/gpui/examples/testing.rs index f6e15791d6..76e3b77352 100644 --- a/crates/gpui/examples/testing.rs +++ b/crates/gpui/examples/testing.rs @@ -1,4 +1,5 @@ #![cfg_attr(target_family = "wasm", no_main)] + //! Example demonstrating GPUI's testing infrastructure. //! //! When run normally, this displays an interactive counter window. @@ -7,6 +8,9 @@ //! Run the app: cargo run -p gpui --example testing //! Run tests: cargo test -p gpui --example testing --features test-support +#[path = "example_support/fonts.rs"] +mod example_support; + use gpui::{ App, Bounds, Context, FocusHandle, Focusable, Render, Task, Window, WindowBounds, WindowOptions, actions, div, prelude::*, px, rgb, size, @@ -179,6 +183,9 @@ impl Render for Counter { fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } cx.bind_keys([ gpui::KeyBinding::new("up", Increment, Some("Counter")), gpui::KeyBinding::new("down", Decrement, Some("Counter")), diff --git a/crates/gpui/examples/text.rs b/crates/gpui/examples/text.rs index 418ebaabf6..a1244eba37 100644 --- a/crates/gpui/examples/text.rs +++ b/crates/gpui/examples/text.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use std::{ borrow::Cow, ops::{Deref, DerefMut}, @@ -348,6 +351,9 @@ impl Render for TextExample { fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } cx.set_menus(vec![Menu { name: "GPUI Typography".into(), disabled: false, diff --git a/crates/gpui/examples/text_layout.rs b/crates/gpui/examples/text_layout.rs index 4bb930e052..07f560ab6e 100644 --- a/crates/gpui/examples/text_layout.rs +++ b/crates/gpui/examples/text_layout.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use gpui::{ App, Bounds, Context, FontStyle, FontWeight, StyledText, Window, WindowBounds, WindowOptions, div, prelude::*, px, size, @@ -85,6 +88,9 @@ impl Render for HelloWorld { fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } let bounds = Bounds::centered(None, size(px(800.0), px(600.0)), cx); cx.open_window( WindowOptions { diff --git a/crates/gpui/examples/text_wrapper.rs b/crates/gpui/examples/text_wrapper.rs index 3750c3e32b..51e58fc7e3 100644 --- a/crates/gpui/examples/text_wrapper.rs +++ b/crates/gpui/examples/text_wrapper.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use gpui::{ App, Bounds, Context, TextOverflow, Window, WindowBounds, WindowOptions, div, prelude::*, px, size, @@ -112,6 +115,9 @@ impl Render for HelloWorld { fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } let bounds = Bounds::centered(None, size(px(800.0), px(600.0)), cx); cx.open_window( WindowOptions { diff --git a/crates/gpui/examples/tree.rs b/crates/gpui/examples/tree.rs index 9c4ea2cd12..891be4790a 100644 --- a/crates/gpui/examples/tree.rs +++ b/crates/gpui/examples/tree.rs @@ -1,6 +1,10 @@ #![cfg_attr(target_family = "wasm", no_main)] + //! Renders a div with deep children hierarchy. This example is useful to exemplify that Zed can //! handle deep hierarchies (even though it cannot just yet!). +#[path = "example_support/fonts.rs"] +mod example_support; + use std::sync::LazyLock; use gpui::{App, Bounds, Context, Window, WindowBounds, WindowOptions, div, prelude::*, px, size}; @@ -32,6 +36,9 @@ impl Render for Tree { fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } let bounds = Bounds::centered(None, size(px(300.0), px(300.0)), cx); cx.open_window( WindowOptions { diff --git a/crates/gpui/examples/uniform_list.rs b/crates/gpui/examples/uniform_list.rs index fabcde5c4b..4a2c4788b1 100644 --- a/crates/gpui/examples/uniform_list.rs +++ b/crates/gpui/examples/uniform_list.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use gpui::{ App, Bounds, Context, Window, WindowBounds, WindowOptions, div, prelude::*, px, rgb, size, uniform_list, @@ -40,6 +43,9 @@ impl Render for UniformListExample { fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } let bounds = Bounds::centered(None, size(px(300.0), px(300.0)), cx); cx.open_window( WindowOptions { diff --git a/crates/gpui/examples/view_example/view_example_main.rs b/crates/gpui/examples/view_example/view_example_main.rs index 0eac8494ff..d2e4991d53 100644 --- a/crates/gpui/examples/view_example/view_example_main.rs +++ b/crates/gpui/examples/view_example/view_example_main.rs @@ -13,6 +13,9 @@ //! //! Run: `cargo run -p gpui --example view_example` +#[path = "../example_support/fonts.rs"] +mod example_support; + mod example_editor; mod example_input; mod example_text_area; @@ -134,6 +137,9 @@ fn section(title: &str) -> Div { fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } let bounds = Bounds::centered(None, size(px(560.0), px(480.0)), cx); cx.bind_keys([ KeyBinding::new("backspace", Backspace, None), diff --git a/crates/gpui/examples/window.rs b/crates/gpui/examples/window.rs index 959ea4981c..51dbe7276d 100644 --- a/crates/gpui/examples/window.rs +++ b/crates/gpui/examples/window.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use gpui::{ App, Bounds, Context, KeyBinding, PromptButton, PromptLevel, Window, WindowBounds, WindowKind, WindowOptions, actions, div, prelude::*, px, rgb, size, @@ -310,6 +313,9 @@ actions!(window, [Quit]); fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } let bounds = Bounds::centered(None, size(px(800.0), px(600.0)), cx); cx.open_window( diff --git a/crates/gpui/examples/window_movable.rs b/crates/gpui/examples/window_movable.rs index 587a2dbfea..b5fb26030b 100644 --- a/crates/gpui/examples/window_movable.rs +++ b/crates/gpui/examples/window_movable.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use gpui::{ App, Bounds, Context, FocusHandle, Window, WindowBounds, WindowOptions, div, prelude::*, px, rgb, size, @@ -78,6 +81,9 @@ fn open_test_window( fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } let window_size = size(px(420.), px(280.0)); let base = Bounds::centered(None, window_size, cx); diff --git a/crates/gpui/examples/window_positioning.rs b/crates/gpui/examples/window_positioning.rs index 036a2fcdba..22c9b359c0 100644 --- a/crates/gpui/examples/window_positioning.rs +++ b/crates/gpui/examples/window_positioning.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use gpui::{ App, Bounds, Context, DisplayId, Hsla, Pixels, SharedString, Size, Window, WindowBackgroundAppearance, WindowBounds, WindowKind, WindowOptions, div, point, prelude::*, @@ -72,6 +75,9 @@ fn build_window_options(display_id: DisplayId, bounds: Bounds) -> Window fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } // Create several new windows, positioned in the top right corner of each screen let size = Size { width: px(350.), diff --git a/crates/gpui/examples/window_shadow.rs b/crates/gpui/examples/window_shadow.rs index f4a55b4bc3..fba5e91c0e 100644 --- a/crates/gpui/examples/window_shadow.rs +++ b/crates/gpui/examples/window_shadow.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_family = "wasm", no_main)] +#[path = "example_support/fonts.rs"] +mod example_support; + use gpui::{ App, Bounds, Context, CursorStyle, Decorations, HitboxBehavior, Hsla, MouseButton, Pixels, Point, ResizeEdge, Size, Window, WindowBackgroundAppearance, WindowBounds, WindowDecorations, @@ -211,6 +214,9 @@ fn resize_edge(pos: Point, shadow_size: Pixels, size: Size) -> O fn run_example() { application().run(|cx: &mut App| { + if !example_support::load_fonts(cx) { + return; + } let bounds = Bounds::centered(None, size(px(600.0), px(600.0)), cx); cx.open_window( WindowOptions { diff --git a/crates/gpui_web/examples/hello_web/Cargo.toml b/crates/gpui_web/examples/hello_web/Cargo.toml index 925f47c71e..92a11dbd71 100644 --- a/crates/gpui_web/examples/hello_web/Cargo.toml +++ b/crates/gpui_web/examples/hello_web/Cargo.toml @@ -13,5 +13,5 @@ path = "main.rs" [dependencies] gpui = { path = "../../../gpui" } gpui_platform = { path = "../../../gpui_platform" } -web-sys = { version = "0.3", features = ["Location", "Window"] } +web-sys = { version = "0.3", features = ["console", "Location", "Window"] } web-time = "1" diff --git a/crates/gpui_web/examples/hello_web/main.rs b/crates/gpui_web/examples/hello_web/main.rs index 605fdf090e..abda6895cb 100644 --- a/crates/gpui_web/examples/hello_web/main.rs +++ b/crates/gpui_web/examples/hello_web/main.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + use gpui::prelude::*; use gpui::{ App, Bounds, Context, ElementId, SharedString, Task, Window, WindowBounds, WindowOptions, div, @@ -429,6 +431,17 @@ fn requested_backend() -> gpui_platform::WebBackendPreference { fn main() { gpui_platform::web_init(); gpui_platform::application_with_web_backend(requested_backend()).run(|cx: &mut App| { + if let Err(error) = cx + .text_system() + .add_fonts(vec![Cow::Borrowed(include_bytes!( + "../../../../assets/fonts/ibm-plex-sans/IBMPlexSans-Regular.ttf" + ))]) + { + web_sys::console::error_1( + &format!("failed to load application fonts: {error:#}").into(), + ); + return; + } let bounds = Bounds::centered(None, size(px(640.), px(560.)), cx); cx.open_window( WindowOptions { diff --git a/crates/gpui_web/src/platform.rs b/crates/gpui_web/src/platform.rs index a546173198..70d643e542 100644 --- a/crates/gpui_web/src/platform.rs +++ b/crates/gpui_web/src/platform.rs @@ -15,7 +15,6 @@ use gpui::{ }; use gpui_wgpu::{PreparedWebGraphics, WebBackendPreference, WgpuContext, wgpu}; use std::{ - borrow::Cow, cell::{Cell, RefCell}, path::{Path, PathBuf}, rc::Rc, @@ -23,17 +22,10 @@ use std::{ }; use wasm_bindgen::prelude::*; -static BUNDLED_FONTS: &[&[u8]] = &[ - include_bytes!("../../../assets/fonts/ibm-plex-sans/IBMPlexSans-Regular.ttf"), - include_bytes!("../../../assets/fonts/ibm-plex-sans/IBMPlexSans-Italic.ttf"), - include_bytes!("../../../assets/fonts/ibm-plex-sans/IBMPlexSans-SemiBold.ttf"), - include_bytes!("../../../assets/fonts/ibm-plex-sans/IBMPlexSans-SemiBoldItalic.ttf"), - include_bytes!("../../../assets/fonts/lilex/Lilex-Regular.ttf"), - include_bytes!("../../../assets/fonts/lilex/Lilex-Bold.ttf"), - include_bytes!("../../../assets/fonts/lilex/Lilex-Italic.ttf"), - include_bytes!("../../../assets/fonts/lilex/Lilex-BoldItalic.ttf"), -]; - +/// Provides the GPUI platform implementation for web browsers. +/// +/// The platform starts with an empty font database. Applications must add fonts +/// through [`gpui::App::text_system`] before opening a window. pub struct WebPlatform { browser_window: web_sys::Window, dispatcher: Arc, @@ -135,13 +127,6 @@ impl WebPlatform { let text_system = Arc::new(gpui_wgpu::CosmicTextSystem::new_without_system_fonts( "IBM Plex Sans", )); - let fonts = BUNDLED_FONTS - .iter() - .map(|bytes| Cow::Borrowed(*bytes)) - .collect(); - if let Err(error) = text_system.add_fonts(fonts) { - log::error!("failed to load bundled fonts: {error:#}"); - } let text_system: Arc = text_system; let active_display: Rc = Rc::new(WebDisplay::new(browser_window.clone()));