Compare commits
20 commits
main
...
gpui_extra
Author | SHA1 | Date | |
---|---|---|---|
![]() |
62949d20a7 | ||
![]() |
110bb84261 | ||
![]() |
576849c98a | ||
![]() |
f16105f391 | ||
![]() |
ac329e40dc | ||
![]() |
a9db466e67 | ||
![]() |
6f32431d33 | ||
![]() |
8342803ba5 | ||
![]() |
d033475565 | ||
![]() |
2a350e91b2 | ||
![]() |
fe17505100 | ||
![]() |
79179e8fff | ||
![]() |
95b4bd467b | ||
![]() |
978d074b1d | ||
![]() |
d0f287772b | ||
![]() |
cfecbc5522 | ||
![]() |
94cf1c3336 | ||
![]() |
f3b76e0571 | ||
![]() |
b4cba64fd6 | ||
![]() |
7516e91a56 |
61 changed files with 3108 additions and 2966 deletions
73
Cargo.lock
generated
73
Cargo.lock
generated
|
@ -1075,6 +1075,7 @@ dependencies = [
|
||||||
"fs",
|
"fs",
|
||||||
"futures 0.3.28",
|
"futures 0.3.28",
|
||||||
"gpui",
|
"gpui",
|
||||||
|
"gpui_platform",
|
||||||
"language",
|
"language",
|
||||||
"live_kit_client",
|
"live_kit_client",
|
||||||
"log",
|
"log",
|
||||||
|
@ -1383,6 +1384,7 @@ dependencies = [
|
||||||
"feature_flags",
|
"feature_flags",
|
||||||
"futures 0.3.28",
|
"futures 0.3.28",
|
||||||
"gpui",
|
"gpui",
|
||||||
|
"gpui_platform",
|
||||||
"image",
|
"image",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log",
|
"log",
|
||||||
|
@ -1539,6 +1541,7 @@ dependencies = [
|
||||||
"futures 0.3.28",
|
"futures 0.3.28",
|
||||||
"fuzzy",
|
"fuzzy",
|
||||||
"gpui",
|
"gpui",
|
||||||
|
"gpui_platform",
|
||||||
"language",
|
"language",
|
||||||
"log",
|
"log",
|
||||||
"menu",
|
"menu",
|
||||||
|
@ -1674,6 +1677,7 @@ dependencies = [
|
||||||
"fs",
|
"fs",
|
||||||
"futures 0.3.28",
|
"futures 0.3.28",
|
||||||
"gpui",
|
"gpui",
|
||||||
|
"gpui_platform",
|
||||||
"language",
|
"language",
|
||||||
"log",
|
"log",
|
||||||
"lsp",
|
"lsp",
|
||||||
|
@ -2343,6 +2347,7 @@ dependencies = [
|
||||||
"fuzzy",
|
"fuzzy",
|
||||||
"git",
|
"git",
|
||||||
"gpui",
|
"gpui",
|
||||||
|
"gpui_platform",
|
||||||
"indoc",
|
"indoc",
|
||||||
"itertools",
|
"itertools",
|
||||||
"language",
|
"language",
|
||||||
|
@ -3116,21 +3121,13 @@ dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-task",
|
"async-task",
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"bindgen 0.65.1",
|
|
||||||
"block",
|
|
||||||
"cc",
|
|
||||||
"cocoa",
|
|
||||||
"collections",
|
"collections",
|
||||||
"core-foundation",
|
|
||||||
"core-graphics",
|
|
||||||
"core-text",
|
|
||||||
"ctor",
|
"ctor",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
"dhat",
|
"dhat",
|
||||||
"env_logger 0.9.3",
|
"env_logger 0.9.3",
|
||||||
"etagere",
|
"etagere",
|
||||||
"font-kit",
|
"font-kit",
|
||||||
"foreign-types",
|
|
||||||
"futures 0.3.28",
|
"futures 0.3.28",
|
||||||
"gpui_macros",
|
"gpui_macros",
|
||||||
"image",
|
"image",
|
||||||
|
@ -3138,9 +3135,7 @@ dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log",
|
"log",
|
||||||
"media",
|
"media",
|
||||||
"metal",
|
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
"objc",
|
|
||||||
"ordered-float",
|
"ordered-float",
|
||||||
"parking",
|
"parking",
|
||||||
"parking_lot 0.11.2",
|
"parking_lot 0.11.2",
|
||||||
|
@ -3170,6 +3165,41 @@ dependencies = [
|
||||||
"waker-fn",
|
"waker-fn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gpui_mac"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"async-task",
|
||||||
|
"bindgen 0.65.1",
|
||||||
|
"block",
|
||||||
|
"cc",
|
||||||
|
"cocoa",
|
||||||
|
"collections",
|
||||||
|
"core-foundation",
|
||||||
|
"core-graphics",
|
||||||
|
"core-text",
|
||||||
|
"ctor",
|
||||||
|
"etagere",
|
||||||
|
"font-kit",
|
||||||
|
"foreign-types",
|
||||||
|
"gpui",
|
||||||
|
"log",
|
||||||
|
"media",
|
||||||
|
"metal",
|
||||||
|
"objc",
|
||||||
|
"ordered-float",
|
||||||
|
"parking_lot 0.11.2",
|
||||||
|
"pathfinder_geometry",
|
||||||
|
"postage",
|
||||||
|
"resvg",
|
||||||
|
"smol",
|
||||||
|
"time 0.3.27",
|
||||||
|
"tiny-skia",
|
||||||
|
"usvg",
|
||||||
|
"uuid 1.4.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui_macros"
|
name = "gpui_macros"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -3180,6 +3210,21 @@ dependencies = [
|
||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gpui_platform"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"gpui",
|
||||||
|
"gpui_mac",
|
||||||
|
"gpui_macros",
|
||||||
|
"itertools",
|
||||||
|
"log",
|
||||||
|
"postage",
|
||||||
|
"rand 0.8.5",
|
||||||
|
"serde",
|
||||||
|
"smol",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "grid"
|
name = "grid"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
|
@ -4096,6 +4141,7 @@ dependencies = [
|
||||||
"foreign-types",
|
"foreign-types",
|
||||||
"futures 0.3.28",
|
"futures 0.3.28",
|
||||||
"gpui",
|
"gpui",
|
||||||
|
"gpui_platform",
|
||||||
"hmac 0.12.1",
|
"hmac 0.12.1",
|
||||||
"jwt",
|
"jwt",
|
||||||
"live_kit_server",
|
"live_kit_server",
|
||||||
|
@ -5179,6 +5225,7 @@ dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
"gpui",
|
"gpui",
|
||||||
|
"gpui_platform",
|
||||||
"log",
|
"log",
|
||||||
"parking_lot 0.11.2",
|
"parking_lot 0.11.2",
|
||||||
"playground_macros",
|
"playground_macros",
|
||||||
|
@ -6116,6 +6163,7 @@ dependencies = [
|
||||||
"arrayvec 0.7.4",
|
"arrayvec 0.7.4",
|
||||||
"bromberg_sl2",
|
"bromberg_sl2",
|
||||||
"gpui",
|
"gpui",
|
||||||
|
"gpui_platform",
|
||||||
"log",
|
"log",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
|
@ -6146,6 +6194,7 @@ dependencies = [
|
||||||
"env_logger 0.9.3",
|
"env_logger 0.9.3",
|
||||||
"futures 0.3.28",
|
"futures 0.3.28",
|
||||||
"gpui",
|
"gpui",
|
||||||
|
"gpui_platform",
|
||||||
"parking_lot 0.11.2",
|
"parking_lot 0.11.2",
|
||||||
"prost 0.8.0",
|
"prost 0.8.0",
|
||||||
"prost-build",
|
"prost-build",
|
||||||
|
@ -6854,6 +6903,7 @@ dependencies = [
|
||||||
"fs",
|
"fs",
|
||||||
"futures 0.3.28",
|
"futures 0.3.28",
|
||||||
"gpui",
|
"gpui",
|
||||||
|
"gpui_platform",
|
||||||
"indoc",
|
"indoc",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"postage",
|
"postage",
|
||||||
|
@ -7663,6 +7713,7 @@ dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"fs",
|
"fs",
|
||||||
"gpui",
|
"gpui",
|
||||||
|
"gpui_platform",
|
||||||
"indexmap 1.9.3",
|
"indexmap 1.9.3",
|
||||||
"parking_lot 0.11.2",
|
"parking_lot 0.11.2",
|
||||||
"schemars",
|
"schemars",
|
||||||
|
@ -9600,6 +9651,7 @@ dependencies = [
|
||||||
"fs",
|
"fs",
|
||||||
"futures 0.3.28",
|
"futures 0.3.28",
|
||||||
"gpui",
|
"gpui",
|
||||||
|
"gpui_platform",
|
||||||
"indoc",
|
"indoc",
|
||||||
"install_cli",
|
"install_cli",
|
||||||
"itertools",
|
"itertools",
|
||||||
|
@ -9742,6 +9794,7 @@ dependencies = [
|
||||||
"fuzzy",
|
"fuzzy",
|
||||||
"go_to_line",
|
"go_to_line",
|
||||||
"gpui",
|
"gpui",
|
||||||
|
"gpui_platform",
|
||||||
"ignore",
|
"ignore",
|
||||||
"image",
|
"image",
|
||||||
"indexmap 1.9.3",
|
"indexmap 1.9.3",
|
||||||
|
|
|
@ -32,6 +32,8 @@ members = [
|
||||||
"crates/git",
|
"crates/git",
|
||||||
"crates/go_to_line",
|
"crates/go_to_line",
|
||||||
"crates/gpui",
|
"crates/gpui",
|
||||||
|
"crates/gpui_mac",
|
||||||
|
"crates/gpui_platform",
|
||||||
"crates/gpui/playground",
|
"crates/gpui/playground",
|
||||||
"crates/gpui/playground_macros",
|
"crates/gpui/playground_macros",
|
||||||
"crates/gpui_macros",
|
"crates/gpui_macros",
|
||||||
|
|
|
@ -13,6 +13,7 @@ test-support = [
|
||||||
"client/test-support",
|
"client/test-support",
|
||||||
"collections/test-support",
|
"collections/test-support",
|
||||||
"gpui/test-support",
|
"gpui/test-support",
|
||||||
|
"gpui_platform",
|
||||||
"live_kit_client/test-support",
|
"live_kit_client/test-support",
|
||||||
"project/test-support",
|
"project/test-support",
|
||||||
"util/test-support"
|
"util/test-support"
|
||||||
|
@ -24,6 +25,7 @@ channel = { path = "../channel" }
|
||||||
client = { path = "../client" }
|
client = { path = "../client" }
|
||||||
collections = { path = "../collections" }
|
collections = { path = "../collections" }
|
||||||
gpui = { path = "../gpui" }
|
gpui = { path = "../gpui" }
|
||||||
|
gpui_platform = {path = "../gpui_platform", optional = true}
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
live_kit_client = { path = "../live_kit_client" }
|
live_kit_client = { path = "../live_kit_client" }
|
||||||
fs = { path = "../fs" }
|
fs = { path = "../fs" }
|
||||||
|
|
|
@ -9,12 +9,13 @@ path = "src/client.rs"
|
||||||
doctest = false
|
doctest = false
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
test-support = ["collections/test-support", "gpui/test-support", "rpc/test-support"]
|
test-support = ["collections/test-support", "gpui/test-support", "gpui_platform", "rpc/test-support"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
collections = { path = "../collections" }
|
collections = { path = "../collections" }
|
||||||
db = { path = "../db" }
|
db = { path = "../db" }
|
||||||
gpui = { path = "../gpui" }
|
gpui = { path = "../gpui" }
|
||||||
|
gpui_platform = {path = "../gpui_platform", optional = true}
|
||||||
util = { path = "../util" }
|
util = { path = "../util" }
|
||||||
rpc = { path = "../rpc" }
|
rpc = { path = "../rpc" }
|
||||||
text = { path = "../text" }
|
text = { path = "../text" }
|
||||||
|
|
|
@ -15,6 +15,7 @@ test-support = [
|
||||||
"collections/test-support",
|
"collections/test-support",
|
||||||
"editor/test-support",
|
"editor/test-support",
|
||||||
"gpui/test-support",
|
"gpui/test-support",
|
||||||
|
"gpui_platform",
|
||||||
"project/test-support",
|
"project/test-support",
|
||||||
"settings/test-support",
|
"settings/test-support",
|
||||||
"util/test-support",
|
"util/test-support",
|
||||||
|
@ -34,6 +35,7 @@ editor = { path = "../editor" }
|
||||||
feedback = { path = "../feedback" }
|
feedback = { path = "../feedback" }
|
||||||
fuzzy = { path = "../fuzzy" }
|
fuzzy = { path = "../fuzzy" }
|
||||||
gpui = { path = "../gpui" }
|
gpui = { path = "../gpui" }
|
||||||
|
gpui_platform = {path = "../gpui_platform", optional = true}
|
||||||
language = { path = "../language" }
|
language = { path = "../language" }
|
||||||
menu = { path = "../menu" }
|
menu = { path = "../menu" }
|
||||||
picker = { path = "../picker" }
|
picker = { path = "../picker" }
|
||||||
|
|
|
@ -12,6 +12,7 @@ doctest = false
|
||||||
test-support = [
|
test-support = [
|
||||||
"collections/test-support",
|
"collections/test-support",
|
||||||
"gpui/test-support",
|
"gpui/test-support",
|
||||||
|
"gpui_platform",
|
||||||
"language/test-support",
|
"language/test-support",
|
||||||
"lsp/test-support",
|
"lsp/test-support",
|
||||||
"settings/test-support",
|
"settings/test-support",
|
||||||
|
@ -22,6 +23,7 @@ test-support = [
|
||||||
collections = { path = "../collections" }
|
collections = { path = "../collections" }
|
||||||
context_menu = { path = "../context_menu" }
|
context_menu = { path = "../context_menu" }
|
||||||
gpui = { path = "../gpui" }
|
gpui = { path = "../gpui" }
|
||||||
|
gpui_platform = {path = "../gpui_platform", optional = true}
|
||||||
language = { path = "../language" }
|
language = { path = "../language" }
|
||||||
settings = { path = "../settings" }
|
settings = { path = "../settings" }
|
||||||
theme = { path = "../theme" }
|
theme = { path = "../theme" }
|
||||||
|
|
|
@ -14,11 +14,13 @@ test-support = [
|
||||||
"text/test-support",
|
"text/test-support",
|
||||||
"language/test-support",
|
"language/test-support",
|
||||||
"gpui/test-support",
|
"gpui/test-support",
|
||||||
|
"gpui_platform",
|
||||||
"project/test-support",
|
"project/test-support",
|
||||||
"util/test-support",
|
"util/test-support",
|
||||||
"workspace/test-support",
|
"workspace/test-support",
|
||||||
"tree-sitter-rust",
|
"tree-sitter-rust",
|
||||||
"tree-sitter-typescript"
|
"tree-sitter-typescript",
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
@ -32,6 +34,7 @@ context_menu = { path = "../context_menu" }
|
||||||
fuzzy = { path = "../fuzzy" }
|
fuzzy = { path = "../fuzzy" }
|
||||||
git = { path = "../git" }
|
git = { path = "../git" }
|
||||||
gpui = { path = "../gpui" }
|
gpui = { path = "../gpui" }
|
||||||
|
gpui_platform = { path = "../gpui_platform", optional = true}
|
||||||
language = { path = "../language" }
|
language = { path = "../language" }
|
||||||
lsp = { path = "../lsp" }
|
lsp = { path = "../lsp" }
|
||||||
project = { path = "../project" }
|
project = { path = "../project" }
|
||||||
|
|
|
@ -14,6 +14,7 @@ doctest = false
|
||||||
test-support = ["backtrace", "dhat", "env_logger", "collections/test-support"]
|
test-support = ["backtrace", "dhat", "env_logger", "collections/test-support"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
anyhow.workspace = true
|
||||||
collections = { path = "../collections" }
|
collections = { path = "../collections" }
|
||||||
gpui_macros = { path = "../gpui_macros" }
|
gpui_macros = { path = "../gpui_macros" }
|
||||||
util = { path = "../util" }
|
util = { path = "../util" }
|
||||||
|
@ -55,10 +56,6 @@ usvg = { version = "0.14", features = [] }
|
||||||
uuid = { version = "1.1.2", features = ["v4"] }
|
uuid = { version = "1.1.2", features = ["v4"] }
|
||||||
waker-fn = "1.1.0"
|
waker-fn = "1.1.0"
|
||||||
|
|
||||||
[build-dependencies]
|
|
||||||
bindgen = "0.65.1"
|
|
||||||
cc = "1.0.67"
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
backtrace = "0.3"
|
backtrace = "0.3"
|
||||||
collections = { path = "../collections", features = ["test-support"] }
|
collections = { path = "../collections", features = ["test-support"] }
|
||||||
|
@ -69,14 +66,4 @@ simplelog = "0.9"
|
||||||
|
|
||||||
[target.'cfg(target_os = "macos")'.dependencies]
|
[target.'cfg(target_os = "macos")'.dependencies]
|
||||||
media = { path = "../media" }
|
media = { path = "../media" }
|
||||||
anyhow.workspace = true
|
|
||||||
block = "0.1"
|
|
||||||
cocoa = "0.24"
|
|
||||||
core-foundation = { version = "0.9.3", features = ["with-uuid"] }
|
|
||||||
core-graphics = "0.22.3"
|
|
||||||
core-text = "19.2"
|
|
||||||
font-kit = { git = "https://github.com/zed-industries/font-kit", rev = "b2f77d56f450338aa4f7dd2f0197d8c9acb0cf18" }
|
font-kit = { git = "https://github.com/zed-industries/font-kit", rev = "b2f77d56f450338aa4f7dd2f0197d8c9acb0cf18" }
|
||||||
foreign-types = "0.3"
|
|
||||||
log.workspace = true
|
|
||||||
metal = "0.21.0"
|
|
||||||
objc = "0.2"
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ path = "src/playground.rs"
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
derive_more.workspace = true
|
derive_more.workspace = true
|
||||||
gpui = { path = ".." }
|
gpui = { path = ".." }
|
||||||
|
gpui_platform = { path = "../../gpui_platform" }
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
playground_macros = { path = "../playground_macros" }
|
playground_macros = { path = "../playground_macros" }
|
||||||
parking_lot.workspace = true
|
parking_lot.workspace = true
|
||||||
|
|
|
@ -26,8 +26,11 @@ mod view;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger");
|
SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger");
|
||||||
|
let platform = gpui_platform::platform();
|
||||||
gpui::App::new(()).unwrap().run(|cx| {
|
let foreground =
|
||||||
|
std::rc::Rc::new(gpui::executor::Foreground::platform(platform.dispatcher()).unwrap());
|
||||||
|
let foreground = gpui_platform::foreground_platform(foreground);
|
||||||
|
gpui::App::new((), platform, foreground).unwrap().run(|cx| {
|
||||||
cx.add_window(
|
cx.add_window(
|
||||||
WindowOptions {
|
WindowOptions {
|
||||||
bounds: gpui::platform::WindowBounds::Fixed(RectF::new(
|
bounds: gpui::platform::WindowBounds::Fixed(RectF::new(
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -54,6 +54,7 @@ impl<K: Clone + Hash + Eq + Copy, F> Default for CallbackCollection<K, F> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K: Clone + Hash + Eq + Copy, F> CallbackCollection<K, F> {
|
impl<K: Clone + Hash + Eq + Copy, F> CallbackCollection<K, F> {
|
||||||
|
#[allow(dead_code)]
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.internal.lock().callbacks.is_empty()
|
self.internal.lock().callbacks.is_empty()
|
||||||
|
|
|
@ -33,8 +33,11 @@ impl ClipboardItem {
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|m| serde_json::from_str(m).ok())
|
.and_then(|m| serde_json::from_str(m).ok())
|
||||||
}
|
}
|
||||||
|
pub fn raw_metadata(&self) -> Option<&str> {
|
||||||
|
self.metadata.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn text_hash(text: &str) -> u64 {
|
pub fn text_hash(text: &str) -> u64 {
|
||||||
let mut hasher = SeaHasher::new();
|
let mut hasher = SeaHasher::new();
|
||||||
text.hash(&mut hasher);
|
text.hash(&mut hasher);
|
||||||
hasher.finish()
|
hasher.finish()
|
||||||
|
|
|
@ -216,72 +216,3 @@ impl ToJson for LabelStyle {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use crate::color::Color;
|
|
||||||
use crate::fonts::{Properties as FontProperties, Weight};
|
|
||||||
|
|
||||||
#[crate::test(self)]
|
|
||||||
fn test_layout_label_with_highlights(cx: &mut crate::AppContext) {
|
|
||||||
let default_style = TextStyle::new(
|
|
||||||
"Menlo",
|
|
||||||
12.,
|
|
||||||
Default::default(),
|
|
||||||
Default::default(),
|
|
||||||
Default::default(),
|
|
||||||
Color::black(),
|
|
||||||
cx.font_cache(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let highlight_style = TextStyle::new(
|
|
||||||
"Menlo",
|
|
||||||
12.,
|
|
||||||
*FontProperties::new().weight(Weight::BOLD),
|
|
||||||
Default::default(),
|
|
||||||
Default::default(),
|
|
||||||
Color::new(255, 0, 0, 255),
|
|
||||||
cx.font_cache(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let label = Label::new(
|
|
||||||
".αβγδε.ⓐⓑⓒⓓⓔ.abcde.".to_string(),
|
|
||||||
LabelStyle {
|
|
||||||
text: default_style.clone(),
|
|
||||||
highlight_text: Some(highlight_style.clone()),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.with_highlights(vec![
|
|
||||||
".α".len(),
|
|
||||||
".αβ".len(),
|
|
||||||
".αβγδ".len(),
|
|
||||||
".αβγδε.ⓐ".len(),
|
|
||||||
".αβγδε.ⓐⓑ".len(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
let default_run_style = RunStyle {
|
|
||||||
font_id: default_style.font_id,
|
|
||||||
color: default_style.color,
|
|
||||||
underline: default_style.underline,
|
|
||||||
};
|
|
||||||
let highlight_run_style = RunStyle {
|
|
||||||
font_id: highlight_style.font_id,
|
|
||||||
color: highlight_style.color,
|
|
||||||
underline: highlight_style.underline,
|
|
||||||
};
|
|
||||||
let runs = label.compute_runs();
|
|
||||||
assert_eq!(
|
|
||||||
runs.as_slice(),
|
|
||||||
&[
|
|
||||||
(".α".len(), default_run_style),
|
|
||||||
("βγ".len(), highlight_run_style),
|
|
||||||
("δ".len(), default_run_style),
|
|
||||||
("ε".len(), highlight_run_style),
|
|
||||||
(".ⓐ".len(), default_run_style),
|
|
||||||
("ⓑⓒ".len(), highlight_run_style),
|
|
||||||
("ⓓⓔ.abcde.".len(), default_run_style),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -643,375 +643,3 @@ impl<'a> sum_tree::SeekTarget<'a, ListItemSummary, ListItemSummary> for Height {
|
||||||
self.0.partial_cmp(&other.height).unwrap()
|
self.0.partial_cmp(&other.height).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use crate::{elements::Empty, geometry::vector::vec2f, Entity, PaintContext};
|
|
||||||
use rand::prelude::*;
|
|
||||||
use std::env;
|
|
||||||
|
|
||||||
#[crate::test(self)]
|
|
||||||
fn test_layout(cx: &mut crate::AppContext) {
|
|
||||||
cx.add_window(Default::default(), |cx| {
|
|
||||||
let mut view = TestView;
|
|
||||||
let constraint = SizeConstraint::new(vec2f(0., 0.), vec2f(100., 40.));
|
|
||||||
let elements = Rc::new(RefCell::new(vec![(0, 20.), (1, 30.), (2, 100.)]));
|
|
||||||
let state = ListState::new(elements.borrow().len(), Orientation::Top, 1000.0, {
|
|
||||||
let elements = elements.clone();
|
|
||||||
move |_, ix, _| {
|
|
||||||
let (id, height) = elements.borrow()[ix];
|
|
||||||
TestElement::new(id, height).into_any()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut list = List::new(state.clone());
|
|
||||||
let mut new_parents = Default::default();
|
|
||||||
let mut notify_views_if_parents_change = Default::default();
|
|
||||||
let mut layout_cx = LayoutContext::new(
|
|
||||||
cx,
|
|
||||||
&mut new_parents,
|
|
||||||
&mut notify_views_if_parents_change,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
let (size, _) = list.layout(constraint, &mut view, &mut layout_cx);
|
|
||||||
assert_eq!(size, vec2f(100., 40.));
|
|
||||||
assert_eq!(
|
|
||||||
state.0.borrow().items.summary().clone(),
|
|
||||||
ListItemSummary {
|
|
||||||
count: 3,
|
|
||||||
rendered_count: 3,
|
|
||||||
unrendered_count: 0,
|
|
||||||
height: 150.
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
state.0.borrow_mut().scroll(
|
|
||||||
&ListOffset {
|
|
||||||
item_ix: 0,
|
|
||||||
offset_in_item: 0.,
|
|
||||||
},
|
|
||||||
40.,
|
|
||||||
vec2f(0., -54.),
|
|
||||||
true,
|
|
||||||
&mut view,
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut layout_cx = LayoutContext::new(
|
|
||||||
cx,
|
|
||||||
&mut new_parents,
|
|
||||||
&mut notify_views_if_parents_change,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
let (_, logical_scroll_top) = list.layout(constraint, &mut view, &mut layout_cx);
|
|
||||||
assert_eq!(
|
|
||||||
logical_scroll_top,
|
|
||||||
ListOffset {
|
|
||||||
item_ix: 2,
|
|
||||||
offset_in_item: 4.
|
|
||||||
}
|
|
||||||
);
|
|
||||||
assert_eq!(state.0.borrow().scroll_top(&logical_scroll_top), 54.);
|
|
||||||
|
|
||||||
elements.borrow_mut().splice(1..2, vec![(3, 40.), (4, 50.)]);
|
|
||||||
elements.borrow_mut().push((5, 60.));
|
|
||||||
state.splice(1..2, 2);
|
|
||||||
state.splice(4..4, 1);
|
|
||||||
assert_eq!(
|
|
||||||
state.0.borrow().items.summary().clone(),
|
|
||||||
ListItemSummary {
|
|
||||||
count: 5,
|
|
||||||
rendered_count: 2,
|
|
||||||
unrendered_count: 3,
|
|
||||||
height: 120.
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut layout_cx = LayoutContext::new(
|
|
||||||
cx,
|
|
||||||
&mut new_parents,
|
|
||||||
&mut notify_views_if_parents_change,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
let (size, logical_scroll_top) = list.layout(constraint, &mut view, &mut layout_cx);
|
|
||||||
assert_eq!(size, vec2f(100., 40.));
|
|
||||||
assert_eq!(
|
|
||||||
state.0.borrow().items.summary().clone(),
|
|
||||||
ListItemSummary {
|
|
||||||
count: 5,
|
|
||||||
rendered_count: 5,
|
|
||||||
unrendered_count: 0,
|
|
||||||
height: 270.
|
|
||||||
}
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
logical_scroll_top,
|
|
||||||
ListOffset {
|
|
||||||
item_ix: 3,
|
|
||||||
offset_in_item: 4.
|
|
||||||
}
|
|
||||||
);
|
|
||||||
assert_eq!(state.0.borrow().scroll_top(&logical_scroll_top), 114.);
|
|
||||||
|
|
||||||
view
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[crate::test(self, iterations = 10)]
|
|
||||||
fn test_random(cx: &mut crate::AppContext, mut rng: StdRng) {
|
|
||||||
let operations = env::var("OPERATIONS")
|
|
||||||
.map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
|
|
||||||
.unwrap_or(10);
|
|
||||||
|
|
||||||
cx.add_window(Default::default(), |cx| {
|
|
||||||
let mut view = TestView;
|
|
||||||
|
|
||||||
let mut next_id = 0;
|
|
||||||
let elements = Rc::new(RefCell::new(
|
|
||||||
(0..rng.gen_range(0..=20))
|
|
||||||
.map(|_| {
|
|
||||||
let id = next_id;
|
|
||||||
next_id += 1;
|
|
||||||
(id, rng.gen_range(0..=200) as f32 / 2.0)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
));
|
|
||||||
let orientation = *[Orientation::Top, Orientation::Bottom]
|
|
||||||
.choose(&mut rng)
|
|
||||||
.unwrap();
|
|
||||||
let overdraw = rng.gen_range(1..=100) as f32;
|
|
||||||
|
|
||||||
let state = ListState::new(elements.borrow().len(), orientation, overdraw, {
|
|
||||||
let elements = elements.clone();
|
|
||||||
move |_, ix, _| {
|
|
||||||
let (id, height) = elements.borrow()[ix];
|
|
||||||
TestElement::new(id, height).into_any()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut width = rng.gen_range(0..=2000) as f32 / 2.;
|
|
||||||
let mut height = rng.gen_range(0..=2000) as f32 / 2.;
|
|
||||||
log::info!("orientation: {:?}", orientation);
|
|
||||||
log::info!("overdraw: {}", overdraw);
|
|
||||||
log::info!("elements: {:?}", elements.borrow());
|
|
||||||
log::info!("size: ({:?}, {:?})", width, height);
|
|
||||||
log::info!("==================");
|
|
||||||
|
|
||||||
let mut last_logical_scroll_top = None;
|
|
||||||
for _ in 0..operations {
|
|
||||||
match rng.gen_range(0..=100) {
|
|
||||||
0..=29 if last_logical_scroll_top.is_some() => {
|
|
||||||
let delta = vec2f(0., rng.gen_range(-overdraw..=overdraw));
|
|
||||||
log::info!(
|
|
||||||
"Scrolling by {:?}, previous scroll top: {:?}",
|
|
||||||
delta,
|
|
||||||
last_logical_scroll_top.unwrap()
|
|
||||||
);
|
|
||||||
state.0.borrow_mut().scroll(
|
|
||||||
last_logical_scroll_top.as_ref().unwrap(),
|
|
||||||
height,
|
|
||||||
delta,
|
|
||||||
true,
|
|
||||||
&mut view,
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
30..=34 => {
|
|
||||||
width = rng.gen_range(0..=2000) as f32 / 2.;
|
|
||||||
log::info!("changing width: {:?}", width);
|
|
||||||
}
|
|
||||||
35..=54 => {
|
|
||||||
height = rng.gen_range(0..=1000) as f32 / 2.;
|
|
||||||
log::info!("changing height: {:?}", height);
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
let mut elements = elements.borrow_mut();
|
|
||||||
let end_ix = rng.gen_range(0..=elements.len());
|
|
||||||
let start_ix = rng.gen_range(0..=end_ix);
|
|
||||||
let new_elements = (0..rng.gen_range(0..10))
|
|
||||||
.map(|_| {
|
|
||||||
let id = next_id;
|
|
||||||
next_id += 1;
|
|
||||||
(id, rng.gen_range(0..=200) as f32 / 2.)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
log::info!("splice({:?}, {:?})", start_ix..end_ix, new_elements);
|
|
||||||
state.splice(start_ix..end_ix, new_elements.len());
|
|
||||||
elements.splice(start_ix..end_ix, new_elements);
|
|
||||||
for (ix, item) in state.0.borrow().items.cursor::<()>().enumerate() {
|
|
||||||
if let ListItem::Rendered(element) = item {
|
|
||||||
let (expected_id, _) = elements[ix];
|
|
||||||
element.borrow().with_metadata(|metadata: Option<&usize>| {
|
|
||||||
assert_eq!(*metadata.unwrap(), expected_id);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut list = List::new(state.clone());
|
|
||||||
let window_size = vec2f(width, height);
|
|
||||||
let mut new_parents = Default::default();
|
|
||||||
let mut notify_views_if_parents_change = Default::default();
|
|
||||||
let mut layout_cx = LayoutContext::new(
|
|
||||||
cx,
|
|
||||||
&mut new_parents,
|
|
||||||
&mut notify_views_if_parents_change,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
let (size, logical_scroll_top) = list.layout(
|
|
||||||
SizeConstraint::new(vec2f(0., 0.), window_size),
|
|
||||||
&mut view,
|
|
||||||
&mut layout_cx,
|
|
||||||
);
|
|
||||||
assert_eq!(size, window_size);
|
|
||||||
last_logical_scroll_top = Some(logical_scroll_top);
|
|
||||||
|
|
||||||
let state = state.0.borrow();
|
|
||||||
log::info!("items {:?}", state.items.items(&()));
|
|
||||||
|
|
||||||
let scroll_top = state.scroll_top(&logical_scroll_top);
|
|
||||||
let rendered_top = (scroll_top - overdraw).max(0.);
|
|
||||||
let rendered_bottom = scroll_top + height + overdraw;
|
|
||||||
let mut item_top = 0.;
|
|
||||||
|
|
||||||
log::info!(
|
|
||||||
"rendered top {:?}, rendered bottom {:?}, scroll top {:?}",
|
|
||||||
rendered_top,
|
|
||||||
rendered_bottom,
|
|
||||||
scroll_top,
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut first_rendered_element_top = None;
|
|
||||||
let mut last_rendered_element_bottom = None;
|
|
||||||
assert_eq!(state.items.summary().count, elements.borrow().len());
|
|
||||||
for (ix, item) in state.items.cursor::<()>().enumerate() {
|
|
||||||
match item {
|
|
||||||
ListItem::Unrendered => {
|
|
||||||
let item_bottom = item_top;
|
|
||||||
assert!(item_bottom <= rendered_top || item_top >= rendered_bottom);
|
|
||||||
item_top = item_bottom;
|
|
||||||
}
|
|
||||||
ListItem::Removed(height) => {
|
|
||||||
let (id, expected_height) = elements.borrow()[ix];
|
|
||||||
assert_eq!(
|
|
||||||
*height, expected_height,
|
|
||||||
"element {} height didn't match",
|
|
||||||
id
|
|
||||||
);
|
|
||||||
let item_bottom = item_top + height;
|
|
||||||
assert!(item_bottom <= rendered_top || item_top >= rendered_bottom);
|
|
||||||
item_top = item_bottom;
|
|
||||||
}
|
|
||||||
ListItem::Rendered(element) => {
|
|
||||||
let (expected_id, expected_height) = elements.borrow()[ix];
|
|
||||||
let element = element.borrow();
|
|
||||||
element.with_metadata(|metadata: Option<&usize>| {
|
|
||||||
assert_eq!(*metadata.unwrap(), expected_id);
|
|
||||||
});
|
|
||||||
assert_eq!(element.size().y(), expected_height);
|
|
||||||
let item_bottom = item_top + element.size().y();
|
|
||||||
first_rendered_element_top.get_or_insert(item_top);
|
|
||||||
last_rendered_element_bottom = Some(item_bottom);
|
|
||||||
assert!(item_bottom > rendered_top || item_top < rendered_bottom);
|
|
||||||
item_top = item_bottom;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match orientation {
|
|
||||||
Orientation::Top => {
|
|
||||||
if let Some(first_rendered_element_top) = first_rendered_element_top {
|
|
||||||
assert!(first_rendered_element_top <= scroll_top);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Orientation::Bottom => {
|
|
||||||
if let Some(last_rendered_element_bottom) = last_rendered_element_bottom {
|
|
||||||
assert!(last_rendered_element_bottom >= scroll_top + height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
view
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TestView;
|
|
||||||
|
|
||||||
impl Entity for TestView {
|
|
||||||
type Event = ();
|
|
||||||
}
|
|
||||||
|
|
||||||
impl crate::View for TestView {
|
|
||||||
fn ui_name() -> &'static str {
|
|
||||||
"TestView"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render(&mut self, _: &mut ViewContext<Self>) -> AnyElement<Self> {
|
|
||||||
Empty::new().into_any()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TestElement {
|
|
||||||
id: usize,
|
|
||||||
size: Vector2F,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TestElement {
|
|
||||||
fn new(id: usize, height: f32) -> Self {
|
|
||||||
Self {
|
|
||||||
id,
|
|
||||||
size: vec2f(100., height),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<V: 'static> Element<V> for TestElement {
|
|
||||||
type LayoutState = ();
|
|
||||||
type PaintState = ();
|
|
||||||
|
|
||||||
fn layout(
|
|
||||||
&mut self,
|
|
||||||
_: SizeConstraint,
|
|
||||||
_: &mut V,
|
|
||||||
_: &mut LayoutContext<V>,
|
|
||||||
) -> (Vector2F, ()) {
|
|
||||||
(self.size, ())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn paint(
|
|
||||||
&mut self,
|
|
||||||
_: &mut SceneBuilder,
|
|
||||||
_: RectF,
|
|
||||||
_: RectF,
|
|
||||||
_: &mut (),
|
|
||||||
_: &mut V,
|
|
||||||
_: &mut PaintContext<V>,
|
|
||||||
) {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn rect_for_text_range(
|
|
||||||
&self,
|
|
||||||
_: Range<usize>,
|
|
||||||
_: RectF,
|
|
||||||
_: RectF,
|
|
||||||
_: &Self::LayoutState,
|
|
||||||
_: &Self::PaintState,
|
|
||||||
_: &V,
|
|
||||||
_: &ViewContext<V>,
|
|
||||||
) -> Option<RectF> {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn debug(&self, _: RectF, _: &(), _: &(), _: &V, _: &ViewContext<V>) -> serde_json::Value {
|
|
||||||
self.id.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn metadata(&self) -> Option<&dyn std::any::Any> {
|
|
||||||
Some(&self.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -399,51 +399,3 @@ pub fn layout_highlighted_chunks<'a>(
|
||||||
|
|
||||||
layouts
|
layouts
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use crate::{elements::Empty, fonts, AnyElement, AppContext, Entity, View, ViewContext};
|
|
||||||
|
|
||||||
#[crate::test(self)]
|
|
||||||
fn test_soft_wrapping_with_carriage_returns(cx: &mut AppContext) {
|
|
||||||
cx.add_window(Default::default(), |cx| {
|
|
||||||
let mut view = TestView;
|
|
||||||
fonts::with_font_cache(cx.font_cache().clone(), || {
|
|
||||||
let mut text = Text::new("Hello\r\n", Default::default()).with_soft_wrap(true);
|
|
||||||
let mut new_parents = Default::default();
|
|
||||||
let mut notify_views_if_parents_change = Default::default();
|
|
||||||
let mut layout_cx = LayoutContext::new(
|
|
||||||
cx,
|
|
||||||
&mut new_parents,
|
|
||||||
&mut notify_views_if_parents_change,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
let (_, state) = text.layout(
|
|
||||||
SizeConstraint::new(Default::default(), vec2f(f32::INFINITY, f32::INFINITY)),
|
|
||||||
&mut view,
|
|
||||||
&mut layout_cx,
|
|
||||||
);
|
|
||||||
assert_eq!(state.shaped_lines.len(), 2);
|
|
||||||
assert_eq!(state.wrap_boundaries.len(), 2);
|
|
||||||
});
|
|
||||||
view
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TestView;
|
|
||||||
|
|
||||||
impl Entity for TestView {
|
|
||||||
type Event = ();
|
|
||||||
}
|
|
||||||
|
|
||||||
impl View for TestView {
|
|
||||||
fn ui_name() -> &'static str {
|
|
||||||
"TestView"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render(&mut self, _: &mut ViewContext<Self>) -> AnyElement<Self> {
|
|
||||||
Empty::new().into_any()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -278,48 +278,3 @@ impl DerefMut for LineWrapperHandle {
|
||||||
self.wrapper.as_mut().unwrap()
|
self.wrapper.as_mut().unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use crate::{
|
|
||||||
fonts::{Style, Weight},
|
|
||||||
platform::{test, Platform as _},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_select_font() {
|
|
||||||
let platform = test::platform();
|
|
||||||
let fonts = FontCache::new(platform.fonts());
|
|
||||||
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))
|
|
||||||
.unwrap();
|
|
||||||
let arial_bold = fonts
|
|
||||||
.select_font(arial, Properties::new().weight(Weight::BOLD))
|
|
||||||
.unwrap();
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
mod app;
|
mod app;
|
||||||
pub use app::*;
|
pub use app::*;
|
||||||
mod assets;
|
mod assets;
|
||||||
#[cfg(any(test, feature = "test-support"))]
|
|
||||||
pub mod test;
|
|
||||||
pub use assets::*;
|
pub use assets::*;
|
||||||
pub mod elements;
|
pub mod elements;
|
||||||
pub mod font_cache;
|
pub mod font_cache;
|
||||||
|
@ -32,6 +30,8 @@ pub use window::{
|
||||||
WindowContext,
|
WindowContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
|
pub mod test;
|
||||||
pub use anyhow;
|
pub use anyhow;
|
||||||
pub use serde_json;
|
pub use serde_json;
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
mod event;
|
mod event;
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
pub mod mac;
|
pub(super) mod test;
|
||||||
pub mod test;
|
|
||||||
pub mod current {
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
pub use super::mac::*;
|
|
||||||
}
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
executor,
|
executor,
|
||||||
|
@ -88,7 +83,7 @@ pub trait Platform: Send + Sync {
|
||||||
fn restart(&self);
|
fn restart(&self);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) trait ForegroundPlatform {
|
pub trait ForegroundPlatform {
|
||||||
fn on_become_active(&self, callback: Box<dyn FnMut()>);
|
fn on_become_active(&self, callback: Box<dyn FnMut()>);
|
||||||
fn on_resign_active(&self, callback: Box<dyn FnMut()>);
|
fn on_resign_active(&self, callback: Box<dyn FnMut()>);
|
||||||
fn on_quit(&self, callback: Box<dyn FnMut()>);
|
fn on_quit(&self, callback: Box<dyn FnMut()>);
|
||||||
|
@ -312,9 +307,9 @@ impl Default for CursorStyle {
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct AppVersion {
|
pub struct AppVersion {
|
||||||
major: usize,
|
pub major: usize,
|
||||||
minor: usize,
|
pub minor: usize,
|
||||||
patch: usize,
|
pub patch: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for AppVersion {
|
impl FromStr for AppVersion {
|
||||||
|
|
|
@ -64,7 +64,7 @@ impl super::ForegroundPlatform for ForegroundPlatform {
|
||||||
fn on_resign_active(&self, _: Box<dyn FnMut()>) {}
|
fn on_resign_active(&self, _: Box<dyn FnMut()>) {}
|
||||||
fn on_quit(&self, _: Box<dyn FnMut()>) {}
|
fn on_quit(&self, _: Box<dyn FnMut()>) {}
|
||||||
fn on_reopen(&self, _: Box<dyn FnMut()>) {}
|
fn on_reopen(&self, _: Box<dyn FnMut()>) {}
|
||||||
fn on_event(&self, _: Box<dyn FnMut(crate::platform::Event) -> bool>) {}
|
fn on_event(&self, _: Box<dyn FnMut(super::Event) -> bool>) {}
|
||||||
fn on_open_urls(&self, _: Box<dyn FnMut(Vec<String>)>) {}
|
fn on_open_urls(&self, _: Box<dyn FnMut(Vec<String>)>) {}
|
||||||
|
|
||||||
fn run(&self, _on_finish_launching: Box<dyn FnOnce()>) {
|
fn run(&self, _on_finish_launching: Box<dyn FnOnce()>) {
|
||||||
|
@ -93,10 +93,6 @@ impl super::ForegroundPlatform for ForegroundPlatform {
|
||||||
fn reveal_path(&self, _: &Path) {}
|
fn reveal_path(&self, _: &Path) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn platform() -> Platform {
|
|
||||||
Platform::new()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Platform {
|
pub struct Platform {
|
||||||
dispatcher: Arc<dyn super::Dispatcher>,
|
dispatcher: Arc<dyn super::Dispatcher>,
|
||||||
fonts: Arc<dyn super::FontSystem>,
|
fonts: Arc<dyn super::FontSystem>,
|
||||||
|
@ -106,10 +102,10 @@ pub struct Platform {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Platform {
|
impl Platform {
|
||||||
fn new() -> Self {
|
pub fn new(fonts: Arc<dyn super::FontSystem>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
dispatcher: Arc::new(Dispatcher),
|
dispatcher: Arc::new(Dispatcher),
|
||||||
fonts: Arc::new(super::current::FontSystem::new()),
|
fonts,
|
||||||
current_clipboard_item: Default::default(),
|
current_clipboard_item: Default::default(),
|
||||||
cursor: Mutex::new(CursorStyle::Arrow),
|
cursor: Mutex::new(CursorStyle::Arrow),
|
||||||
active_window: Default::default(),
|
active_window: Default::default(),
|
||||||
|
@ -136,11 +132,11 @@ impl super::Platform for Platform {
|
||||||
|
|
||||||
fn quit(&self) {}
|
fn quit(&self) {}
|
||||||
|
|
||||||
fn screen_by_id(&self, _id: uuid::Uuid) -> Option<Rc<dyn crate::platform::Screen>> {
|
fn screen_by_id(&self, _id: uuid::Uuid) -> Option<Rc<dyn super::Screen>> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn screens(&self) -> Vec<Rc<dyn crate::platform::Screen>> {
|
fn screens(&self) -> Vec<Rc<dyn super::Screen>> {
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,7 +161,7 @@ impl super::Platform for Platform {
|
||||||
self.active_window.lock().clone()
|
self.active_window.lock().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_status_item(&self, handle: AnyWindowHandle) -> Box<dyn crate::platform::Window> {
|
fn add_status_item(&self, handle: AnyWindowHandle) -> Box<dyn super::Window> {
|
||||||
Box::new(Window::new(
|
Box::new(Window::new(
|
||||||
handle,
|
handle,
|
||||||
vec2f(24., 24.),
|
vec2f(24., 24.),
|
||||||
|
@ -301,10 +297,6 @@ impl Window {
|
||||||
active_window,
|
active_window,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn title(&self) -> Option<String> {
|
|
||||||
self.title.clone()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl super::Window for Window {
|
impl super::Window for Window {
|
||||||
|
@ -324,11 +316,11 @@ impl super::Window for Window {
|
||||||
24.
|
24.
|
||||||
}
|
}
|
||||||
|
|
||||||
fn appearance(&self) -> crate::platform::Appearance {
|
fn appearance(&self) -> super::Appearance {
|
||||||
crate::platform::Appearance::Light
|
super::Appearance::Light
|
||||||
}
|
}
|
||||||
|
|
||||||
fn screen(&self) -> Rc<dyn crate::platform::Screen> {
|
fn screen(&self) -> Rc<dyn super::Screen> {
|
||||||
Rc::new(Screen)
|
Rc::new(Screen)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,14 +328,9 @@ impl super::Window for Window {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_input_handler(&mut self, _: Box<dyn crate::platform::InputHandler>) {}
|
fn set_input_handler(&mut self, _: Box<dyn super::InputHandler>) {}
|
||||||
|
|
||||||
fn prompt(
|
fn prompt(&self, _: super::PromptLevel, _: &str, _: &[&str]) -> oneshot::Receiver<usize> {
|
||||||
&self,
|
|
||||||
_: crate::platform::PromptLevel,
|
|
||||||
_: &str,
|
|
||||||
_: &[&str],
|
|
||||||
) -> oneshot::Receiver<usize> {
|
|
||||||
let (done_tx, done_rx) = oneshot::channel();
|
let (done_tx, done_rx) = oneshot::channel();
|
||||||
self.pending_prompts.borrow_mut().push_back(done_tx);
|
self.pending_prompts.borrow_mut().push_back(done_tx);
|
||||||
done_rx
|
done_rx
|
||||||
|
@ -373,7 +360,7 @@ impl super::Window for Window {
|
||||||
|
|
||||||
fn toggle_full_screen(&self) {}
|
fn toggle_full_screen(&self) {}
|
||||||
|
|
||||||
fn on_event(&mut self, callback: Box<dyn FnMut(crate::platform::Event) -> bool>) {
|
fn on_event(&mut self, callback: Box<dyn FnMut(super::Event) -> bool>) {
|
||||||
self.event_handlers.push(callback);
|
self.event_handlers.push(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ use crate::{
|
||||||
fonts::{FontId, GlyphId},
|
fonts::{FontId, GlyphId},
|
||||||
geometry::{rect::RectF, vector::Vector2F},
|
geometry::{rect::RectF, vector::Vector2F},
|
||||||
json::ToJson,
|
json::ToJson,
|
||||||
platform::{current::Surface, CursorStyle},
|
platform::CursorStyle,
|
||||||
ImageData, WindowContext,
|
ImageData, WindowContext,
|
||||||
};
|
};
|
||||||
pub use mouse_event::*;
|
pub use mouse_event::*;
|
||||||
|
@ -171,6 +171,11 @@ pub struct Icon {
|
||||||
pub color: Color,
|
pub color: Color,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Surface {
|
||||||
|
pub bounds: RectF,
|
||||||
|
pub image_buffer: media::core_video::CVImageBuffer,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Default, Debug, JsonSchema)]
|
#[derive(Clone, Copy, Default, Debug, JsonSchema)]
|
||||||
pub struct Border {
|
pub struct Border {
|
||||||
pub width: f32,
|
pub width: f32,
|
||||||
|
|
|
@ -17,7 +17,6 @@ use crate::{
|
||||||
elements::Empty,
|
elements::Empty,
|
||||||
executor::{self, ExecutorEvent},
|
executor::{self, ExecutorEvent},
|
||||||
platform,
|
platform,
|
||||||
platform::Platform,
|
|
||||||
util::CwdBacktrace,
|
util::CwdBacktrace,
|
||||||
AnyElement, AppContext, Element, Entity, FontCache, Handle, Subscription, TestAppContext, View,
|
AnyElement, AppContext, Element, Entity, FontCache, Handle, Subscription, TestAppContext, View,
|
||||||
ViewContext,
|
ViewContext,
|
||||||
|
@ -35,6 +34,7 @@ fn init_logger() {
|
||||||
// static ALLOC: dhat::Alloc = dhat::Alloc;
|
// static ALLOC: dhat::Alloc = dhat::Alloc;
|
||||||
|
|
||||||
pub fn run_test(
|
pub fn run_test(
|
||||||
|
fonts: fn() -> std::sync::Arc<dyn crate::platform::FontSystem>,
|
||||||
mut num_iterations: u64,
|
mut num_iterations: u64,
|
||||||
mut starting_seed: u64,
|
mut starting_seed: u64,
|
||||||
max_retries: usize,
|
max_retries: usize,
|
||||||
|
@ -66,10 +66,10 @@ pub fn run_test(
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let result = panic::catch_unwind(|| {
|
let result = panic::catch_unwind(|| {
|
||||||
|
let fonts = fonts();
|
||||||
let foreground_platform = Rc::new(platform::test::foreground_platform());
|
let foreground_platform = Rc::new(platform::test::foreground_platform());
|
||||||
let platform = Arc::new(platform::test::platform());
|
let platform = Arc::new(platform::test::Platform::new(fonts.clone()));
|
||||||
let font_system = platform.fonts();
|
let font_cache = Arc::new(FontCache::new(fonts.clone()));
|
||||||
let font_cache = Arc::new(FontCache::new(font_system));
|
|
||||||
let mut prev_runnable_history: Option<Vec<ExecutorEvent>> = None;
|
let mut prev_runnable_history: Option<Vec<ExecutorEvent>> = None;
|
||||||
|
|
||||||
for _ in 0..num_iterations {
|
for _ in 0..num_iterations {
|
||||||
|
|
|
@ -528,7 +528,7 @@ pub struct ShapedBoundary {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Boundary {
|
impl Boundary {
|
||||||
fn new(ix: usize, next_indent: u32) -> Self {
|
pub fn new(ix: usize, next_indent: u32) -> Self {
|
||||||
Self { ix, next_indent }
|
Self { ix, next_indent }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -727,129 +727,3 @@ impl LineWrapper {
|
||||||
.width
|
.width
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use crate::fonts::{Properties, Weight};
|
|
||||||
|
|
||||||
#[crate::test(self)]
|
|
||||||
fn test_wrap_line(cx: &mut crate::AppContext) {
|
|
||||||
let font_cache = cx.font_cache().clone();
|
|
||||||
let font_system = cx.platform().fonts();
|
|
||||||
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);
|
|
||||||
assert_eq!(
|
|
||||||
wrapper
|
|
||||||
.wrap_line("aa bbb cccc ddddd eeee", 72.0)
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
&[
|
|
||||||
Boundary::new(7, 0),
|
|
||||||
Boundary::new(12, 0),
|
|
||||||
Boundary::new(18, 0)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
wrapper
|
|
||||||
.wrap_line("aaa aaaaaaaaaaaaaaaaaa", 72.0)
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
&[
|
|
||||||
Boundary::new(4, 0),
|
|
||||||
Boundary::new(11, 0),
|
|
||||||
Boundary::new(18, 0)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
wrapper.wrap_line(" aaaaaaa", 72.).collect::<Vec<_>>(),
|
|
||||||
&[
|
|
||||||
Boundary::new(7, 5),
|
|
||||||
Boundary::new(9, 5),
|
|
||||||
Boundary::new(11, 5),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
wrapper
|
|
||||||
.wrap_line(" ", 72.)
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
&[
|
|
||||||
Boundary::new(7, 0),
|
|
||||||
Boundary::new(14, 0),
|
|
||||||
Boundary::new(21, 0)
|
|
||||||
]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
wrapper
|
|
||||||
.wrap_line(" aaaaaaaaaaaaaa", 72.)
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
&[
|
|
||||||
Boundary::new(7, 0),
|
|
||||||
Boundary::new(14, 3),
|
|
||||||
Boundary::new(18, 3),
|
|
||||||
Boundary::new(22, 3),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[crate::test(self, retries = 5)]
|
|
||||||
fn test_wrap_shaped_line(cx: &mut crate::AppContext) {
|
|
||||||
// This is failing intermittently on CI and we don't have time to figure it out
|
|
||||||
let font_cache = cx.font_cache().clone();
|
|
||||||
let font_system = cx.platform().fonts();
|
|
||||||
let text_layout_cache = TextLayoutCache::new(font_system.clone());
|
|
||||||
|
|
||||||
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,
|
|
||||||
color: Default::default(),
|
|
||||||
underline: Default::default(),
|
|
||||||
};
|
|
||||||
let bold = RunStyle {
|
|
||||||
font_id: font_cache
|
|
||||||
.select_font(
|
|
||||||
family,
|
|
||||||
&Properties {
|
|
||||||
weight: Weight::BOLD,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.unwrap(),
|
|
||||||
color: Default::default(),
|
|
||||||
underline: Default::default(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let text = "aa bbb cccc ddddd eeee";
|
|
||||||
let line = text_layout_cache.layout_str(
|
|
||||||
text,
|
|
||||||
16.0,
|
|
||||||
&[(4, normal), (5, bold), (6, normal), (1, bold), (7, normal)],
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut wrapper = LineWrapper::new(font_id, 16., font_system);
|
|
||||||
assert_eq!(
|
|
||||||
wrapper
|
|
||||||
.wrap_shaped_line(text, &line, 72.0)
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
&[
|
|
||||||
ShapedBoundary {
|
|
||||||
run_ix: 1,
|
|
||||||
glyph_ix: 3
|
|
||||||
},
|
|
||||||
ShapedBoundary {
|
|
||||||
run_ix: 2,
|
|
||||||
glyph_ix: 3
|
|
||||||
},
|
|
||||||
ShapedBoundary {
|
|
||||||
run_ix: 4,
|
|
||||||
glyph_ix: 2
|
|
||||||
}
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
41
crates/gpui_mac/Cargo.toml
Normal file
41
crates/gpui_mac/Cargo.toml
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
[package]
|
||||||
|
name = "gpui_mac"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
resvg = "0.14"
|
||||||
|
gpui = {path = "../gpui"}
|
||||||
|
usvg = { version = "0.14", features = [] }
|
||||||
|
tiny-skia = "0.5"
|
||||||
|
uuid = { version = "1.1.2", features = ["v4"] }
|
||||||
|
time.workspace = true
|
||||||
|
etagere = "0.2"
|
||||||
|
ordered-float.workspace = true
|
||||||
|
postage.workspace = true
|
||||||
|
smol.workspace = true
|
||||||
|
ctor.workspace = true
|
||||||
|
parking_lot.workspace = true
|
||||||
|
collections = { path = "../collections" }
|
||||||
|
async-task = "4.0.3"
|
||||||
|
pathfinder_geometry = "0.5"
|
||||||
|
|
||||||
|
[target.'cfg(target_os = "macos")'.dependencies]
|
||||||
|
media = { path = "../media" }
|
||||||
|
anyhow.workspace = true
|
||||||
|
block = "0.1"
|
||||||
|
cocoa = "0.24"
|
||||||
|
core-foundation = { version = "0.9.3", features = ["with-uuid"] }
|
||||||
|
core-graphics = "0.22.3"
|
||||||
|
core-text = "19.2"
|
||||||
|
font-kit = { git = "https://github.com/zed-industries/font-kit", rev = "b2f77d56f450338aa4f7dd2f0197d8c9acb0cf18" }
|
||||||
|
foreign-types = "0.3"
|
||||||
|
log.workspace = true
|
||||||
|
metal = "0.21.0"
|
||||||
|
objc = "0.2"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
bindgen = "0.65.1"
|
||||||
|
cc = "1.0.67"
|
|
@ -12,10 +12,10 @@ fn main() {
|
||||||
|
|
||||||
fn generate_dispatch_bindings() {
|
fn generate_dispatch_bindings() {
|
||||||
println!("cargo:rustc-link-lib=framework=System");
|
println!("cargo:rustc-link-lib=framework=System");
|
||||||
println!("cargo:rerun-if-changed=src/platform/mac/dispatch.h");
|
println!("cargo:rerun-if-changed=src/dispatch.h");
|
||||||
|
|
||||||
let bindings = bindgen::Builder::default()
|
let bindings = bindgen::Builder::default()
|
||||||
.header("src/platform/mac/dispatch.h")
|
.header("src/dispatch.h")
|
||||||
.allowlist_var("_dispatch_main_q")
|
.allowlist_var("_dispatch_main_q")
|
||||||
.allowlist_function("dispatch_async_f")
|
.allowlist_function("dispatch_async_f")
|
||||||
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
|
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
|
||||||
|
@ -29,10 +29,10 @@ fn generate_dispatch_bindings() {
|
||||||
.expect("couldn't write dispatch bindings");
|
.expect("couldn't write dispatch bindings");
|
||||||
}
|
}
|
||||||
|
|
||||||
const SHADER_HEADER_PATH: &str = "./src/platform/mac/shaders/shaders.h";
|
const SHADER_HEADER_PATH: &str = "./src/shaders/shaders.h";
|
||||||
|
|
||||||
fn compile_metal_shaders() {
|
fn compile_metal_shaders() {
|
||||||
let shader_path = "./src/platform/mac/shaders/shaders.metal";
|
let shader_path = "./src/shaders/shaders.metal";
|
||||||
let air_output_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("shaders.air");
|
let air_output_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("shaders.air");
|
||||||
let metallib_output_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("shaders.metallib");
|
let metallib_output_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("shaders.metallib");
|
||||||
|
|
|
@ -1,30 +1,33 @@
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
|
|
||||||
use crate::platform::Appearance;
|
|
||||||
use cocoa::{
|
use cocoa::{
|
||||||
appkit::{NSAppearanceNameVibrantDark, NSAppearanceNameVibrantLight},
|
appkit::{NSAppearanceNameVibrantDark, NSAppearanceNameVibrantLight},
|
||||||
base::id,
|
base::id,
|
||||||
foundation::NSString,
|
foundation::NSString,
|
||||||
};
|
};
|
||||||
|
use gpui::platform::Appearance;
|
||||||
use objc::{msg_send, sel, sel_impl};
|
use objc::{msg_send, sel, sel_impl};
|
||||||
|
|
||||||
impl Appearance {
|
pub trait AppearanceFromNative {
|
||||||
pub unsafe fn from_native(appearance: id) -> Self {
|
unsafe fn from_native(appearance: id) -> Self;
|
||||||
|
}
|
||||||
|
impl AppearanceFromNative for Appearance {
|
||||||
|
unsafe fn from_native(appearance: id) -> Appearance {
|
||||||
let name: id = msg_send![appearance, name];
|
let name: id = msg_send![appearance, name];
|
||||||
if name == NSAppearanceNameVibrantLight {
|
if name == NSAppearanceNameVibrantLight {
|
||||||
Self::VibrantLight
|
Appearance::VibrantLight
|
||||||
} else if name == NSAppearanceNameVibrantDark {
|
} else if name == NSAppearanceNameVibrantDark {
|
||||||
Self::VibrantDark
|
Appearance::VibrantDark
|
||||||
} else if name == NSAppearanceNameAqua {
|
} else if name == NSAppearanceNameAqua {
|
||||||
Self::Light
|
Appearance::Light
|
||||||
} else if name == NSAppearanceNameDarkAqua {
|
} else if name == NSAppearanceNameDarkAqua {
|
||||||
Self::Dark
|
Appearance::Dark
|
||||||
} else {
|
} else {
|
||||||
println!(
|
println!(
|
||||||
"unknown appearance: {:?}",
|
"unknown appearance: {:?}",
|
||||||
CStr::from_ptr(name.UTF8String())
|
CStr::from_ptr(name.UTF8String())
|
||||||
);
|
);
|
||||||
Self::Light
|
Appearance::Light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,9 +1,9 @@
|
||||||
use crate::geometry::{
|
use etagere::BucketedAtlasAllocator;
|
||||||
|
use foreign_types::ForeignType;
|
||||||
|
use gpui::geometry::{
|
||||||
rect::RectI,
|
rect::RectI,
|
||||||
vector::{vec2i, Vector2I},
|
vector::{vec2i, Vector2I},
|
||||||
};
|
};
|
||||||
use etagere::BucketedAtlasAllocator;
|
|
||||||
use foreign_types::ForeignType;
|
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use metal::{Device, TextureDescriptor};
|
use metal::{Device, TextureDescriptor};
|
||||||
use objc::{msg_send, sel, sel_impl};
|
use objc::{msg_send, sel, sel_impl};
|
|
@ -10,7 +10,7 @@ use objc::{
|
||||||
};
|
};
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
|
|
||||||
use crate::platform;
|
use gpui::platform;
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/dispatch_sys.rs"));
|
include!(concat!(env!("OUT_DIR"), "/dispatch_sys.rs"));
|
||||||
|
|
|
@ -1,12 +1,3 @@
|
||||||
use crate::{
|
|
||||||
geometry::vector::vec2f,
|
|
||||||
keymap_matcher::Keystroke,
|
|
||||||
platform::{
|
|
||||||
Event, KeyDownEvent, KeyUpEvent, Modifiers, ModifiersChangedEvent, MouseButton,
|
|
||||||
MouseButtonEvent, MouseExitedEvent, MouseMovedEvent, NavigationDirection, ScrollDelta,
|
|
||||||
ScrollWheelEvent, TouchPhase,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
use cocoa::{
|
use cocoa::{
|
||||||
appkit::{NSEvent, NSEventModifierFlags, NSEventPhase, NSEventType},
|
appkit::{NSEvent, NSEventModifierFlags, NSEventPhase, NSEventType},
|
||||||
base::{id, YES},
|
base::{id, YES},
|
||||||
|
@ -18,6 +9,15 @@ use core_graphics::{
|
||||||
};
|
};
|
||||||
use ctor::ctor;
|
use ctor::ctor;
|
||||||
use foreign_types::ForeignType;
|
use foreign_types::ForeignType;
|
||||||
|
use gpui::{
|
||||||
|
geometry::vector::vec2f,
|
||||||
|
keymap_matcher::Keystroke,
|
||||||
|
platform::{
|
||||||
|
Event, KeyDownEvent, KeyUpEvent, Modifiers, ModifiersChangedEvent, MouseButton,
|
||||||
|
MouseButtonEvent, MouseExitedEvent, MouseMovedEvent, NavigationDirection, ScrollDelta,
|
||||||
|
ScrollWheelEvent, TouchPhase,
|
||||||
|
},
|
||||||
|
};
|
||||||
use objc::{class, msg_send, sel, sel_impl};
|
use objc::{class, msg_send, sel, sel_impl};
|
||||||
use std::{borrow::Cow, ffi::CStr, mem, os::raw::c_char, ptr};
|
use std::{borrow::Cow, ffi::CStr, mem, os::raw::c_char, ptr};
|
||||||
|
|
||||||
|
@ -86,8 +86,11 @@ unsafe fn read_modifiers(native_event: id) -> Modifiers {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Event {
|
pub trait EventFromNative {
|
||||||
pub unsafe fn from_native(native_event: id, window_height: Option<f32>) -> Option<Self> {
|
unsafe fn from_native(native_event: id, window_height: Option<f32>) -> Option<Event>;
|
||||||
|
}
|
||||||
|
impl EventFromNative for Event {
|
||||||
|
unsafe fn from_native(native_event: id, window_height: Option<f32>) -> Option<Event> {
|
||||||
let event_type = native_event.eventType();
|
let event_type = native_event.eventType();
|
||||||
|
|
||||||
// Filter out event types that aren't in the NSEventType enum.
|
// Filter out event types that aren't in the NSEventType enum.
|
|
@ -1,15 +1,5 @@
|
||||||
mod open_type;
|
mod open_type;
|
||||||
|
|
||||||
use crate::{
|
|
||||||
fonts::{Features, FontId, GlyphId, Metrics, Properties},
|
|
||||||
geometry::{
|
|
||||||
rect::{RectF, RectI},
|
|
||||||
transform2d::Transform2F,
|
|
||||||
vector::{vec2f, Vector2F},
|
|
||||||
},
|
|
||||||
platform::{self, RasterizationOptions},
|
|
||||||
text_layout::{Glyph, LineLayout, Run, RunStyle},
|
|
||||||
};
|
|
||||||
use cocoa::appkit::{CGFloat, CGPoint};
|
use cocoa::appkit::{CGFloat, CGPoint};
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use core_foundation::{
|
use core_foundation::{
|
||||||
|
@ -27,6 +17,16 @@ use core_text::{font::CTFont, line::CTLine, string_attributes::kCTFontAttributeN
|
||||||
use font_kit::{
|
use font_kit::{
|
||||||
handle::Handle, hinting::HintingOptions, source::SystemSource, sources::mem::MemSource,
|
handle::Handle, hinting::HintingOptions, source::SystemSource, sources::mem::MemSource,
|
||||||
};
|
};
|
||||||
|
use gpui::{
|
||||||
|
fonts::{Features, FontId, GlyphId, Metrics, Properties},
|
||||||
|
geometry::{
|
||||||
|
rect::{RectF, RectI},
|
||||||
|
transform2d::Transform2F,
|
||||||
|
vector::{vec2f, Vector2F},
|
||||||
|
},
|
||||||
|
platform::{self, RasterizationOptions},
|
||||||
|
text_layout::{Glyph, LineLayout, Run, RunStyle},
|
||||||
|
};
|
||||||
use parking_lot::RwLock;
|
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, sync::Arc};
|
||||||
|
|
||||||
|
@ -506,8 +506,8 @@ extern "C" {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::AppContext;
|
|
||||||
use font_kit::properties::{Style, Weight};
|
use font_kit::properties::{Style, Weight};
|
||||||
|
use gpui::AppContext;
|
||||||
use platform::FontSystem as _;
|
use platform::FontSystem as _;
|
||||||
|
|
||||||
#[crate::test(self, retries = 5)]
|
#[crate::test(self, retries = 5)]
|
||||||
|
@ -668,4 +668,39 @@ mod tests {
|
||||||
// There's no glyph for \u{feff}
|
// There's no glyph for \u{feff}
|
||||||
assert_eq!(layout.runs[0].glyphs[1].id, 69); // b
|
assert_eq!(layout.runs[0].glyphs[1].id, 69); // b
|
||||||
}
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_select_font() {
|
||||||
|
let platform = test::platform(FontSystem::new());
|
||||||
|
let fonts = FontCache::new(platform.fonts());
|
||||||
|
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))
|
||||||
|
.unwrap();
|
||||||
|
let arial_bold = fonts
|
||||||
|
.select_font(arial, Properties::new().weight(Weight::BOLD))
|
||||||
|
.unwrap();
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use crate::fonts::Features;
|
|
||||||
use cocoa::appkit::CGFloat;
|
use cocoa::appkit::CGFloat;
|
||||||
use core_foundation::{base::TCFType, number::CFNumber};
|
use core_foundation::{base::TCFType, number::CFNumber};
|
||||||
use core_graphics::geometry::CGAffineTransform;
|
use core_graphics::geometry::CGAffineTransform;
|
||||||
|
@ -13,6 +12,7 @@ use core_text::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use font_kit::font::Font;
|
use font_kit::font::Font;
|
||||||
|
use gpui::fonts::Features;
|
||||||
|
|
||||||
const kCaseSensitiveLayoutOffSelector: i32 = 1;
|
const kCaseSensitiveLayoutOffSelector: i32 = 1;
|
||||||
const kCaseSensitiveLayoutOnSelector: i32 = 0;
|
const kCaseSensitiveLayoutOnSelector: i32 = 0;
|
|
@ -1,12 +1,12 @@
|
||||||
use super::atlas::{AllocId, AtlasAllocator};
|
use super::atlas::{AllocId, AtlasAllocator};
|
||||||
use crate::{
|
use anyhow::anyhow;
|
||||||
|
use gpui::{
|
||||||
fonts::{FontId, GlyphId},
|
fonts::{FontId, GlyphId},
|
||||||
geometry::{rect::RectI, vector::Vector2I},
|
geometry::{rect::RectI, vector::Vector2I},
|
||||||
platform::{FontSystem, RasterizationOptions},
|
platform::{FontSystem, RasterizationOptions},
|
||||||
scene::ImageGlyph,
|
scene::ImageGlyph,
|
||||||
ImageData,
|
ImageData,
|
||||||
};
|
};
|
||||||
use anyhow::anyhow;
|
|
||||||
use metal::{MTLPixelFormat, TextureDescriptor, TextureRef};
|
use metal::{MTLPixelFormat, TextureDescriptor, TextureRef};
|
||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
use std::{collections::HashMap, mem, sync::Arc};
|
use std::{collections::HashMap, mem, sync::Arc};
|
|
@ -10,6 +10,7 @@ mod renderer;
|
||||||
mod screen;
|
mod screen;
|
||||||
mod sprite_cache;
|
mod sprite_cache;
|
||||||
mod status_item;
|
mod status_item;
|
||||||
|
|
||||||
mod window;
|
mod window;
|
||||||
|
|
||||||
use cocoa::{
|
use cocoa::{
|
||||||
|
@ -23,15 +24,15 @@ pub use renderer::Surface;
|
||||||
use std::{ops::Range, rc::Rc, sync::Arc};
|
use std::{ops::Range, rc::Rc, sync::Arc};
|
||||||
use window::MacWindow;
|
use window::MacWindow;
|
||||||
|
|
||||||
use crate::executor;
|
use gpui::executor;
|
||||||
|
|
||||||
pub(crate) fn platform() -> Arc<dyn super::Platform> {
|
pub fn platform() -> Arc<dyn gpui::platform::Platform> {
|
||||||
Arc::new(MacPlatform::new())
|
Arc::new(MacPlatform::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn foreground_platform(
|
pub fn foreground_platform(
|
||||||
foreground: Rc<executor::Foreground>,
|
foreground: Rc<executor::Foreground>,
|
||||||
) -> Rc<dyn super::ForegroundPlatform> {
|
) -> Rc<dyn gpui::platform::ForegroundPlatform> {
|
||||||
Rc::new(MacForegroundPlatform::new(foreground))
|
Rc::new(MacForegroundPlatform::new(foreground))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,3 +103,9 @@ unsafe impl objc::Encode for NSRange {
|
||||||
unsafe fn ns_string(string: &str) -> id {
|
unsafe fn ns_string(string: &str) -> id {
|
||||||
NSString::alloc(nil).init_str(string).autorelease()
|
NSString::alloc(nil).init_str(string).autorelease()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn font_system() -> Arc<dyn gpui::platform::FontSystem> {
|
||||||
|
Arc::new(FontSystem::new())
|
||||||
|
}
|
|
@ -1,13 +1,9 @@
|
||||||
|
use crate::event::EventFromNative;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
event::key_to_native, screen::Screen, status_item::StatusItem, BoolExt as _, Dispatcher,
|
event::key_to_native, screen::Screen, status_item::StatusItem, BoolExt as _, Dispatcher,
|
||||||
FontSystem, MacWindow,
|
FontSystem, MacWindow,
|
||||||
};
|
};
|
||||||
use crate::{
|
|
||||||
executor,
|
|
||||||
keymap_matcher::KeymapMatcher,
|
|
||||||
platform::{self, AppVersion, CursorStyle, Event},
|
|
||||||
Action, AnyWindowHandle, ClipboardItem, Menu, MenuItem,
|
|
||||||
};
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use block::ConcreteBlock;
|
use block::ConcreteBlock;
|
||||||
use cocoa::{
|
use cocoa::{
|
||||||
|
@ -30,6 +26,12 @@ use core_foundation::{
|
||||||
string::{CFString, CFStringRef},
|
string::{CFString, CFStringRef},
|
||||||
};
|
};
|
||||||
use ctor::ctor;
|
use ctor::ctor;
|
||||||
|
use gpui::{
|
||||||
|
executor,
|
||||||
|
keymap_matcher::KeymapMatcher,
|
||||||
|
platform::{self, AppVersion, CursorStyle, Event},
|
||||||
|
Action, AnyWindowHandle, ClipboardItem, Menu, MenuItem,
|
||||||
|
};
|
||||||
use objc::{
|
use objc::{
|
||||||
class,
|
class,
|
||||||
declare::ClassDecl,
|
declare::ClassDecl,
|
||||||
|
@ -235,12 +237,12 @@ impl MacForegroundPlatform {
|
||||||
.find(|binding| binding.action().eq(action.as_ref()))
|
.find(|binding| binding.action().eq(action.as_ref()))
|
||||||
.map(|binding| binding.keystrokes());
|
.map(|binding| binding.keystrokes());
|
||||||
let selector = match os_action {
|
let selector = match os_action {
|
||||||
Some(crate::OsAction::Cut) => selector("cut:"),
|
Some(gpui::OsAction::Cut) => selector("cut:"),
|
||||||
Some(crate::OsAction::Copy) => selector("copy:"),
|
Some(gpui::OsAction::Copy) => selector("copy:"),
|
||||||
Some(crate::OsAction::Paste) => selector("paste:"),
|
Some(gpui::OsAction::Paste) => selector("paste:"),
|
||||||
Some(crate::OsAction::SelectAll) => selector("selectAll:"),
|
Some(gpui::OsAction::SelectAll) => selector("selectAll:"),
|
||||||
Some(crate::OsAction::Undo) => selector("undo:"),
|
Some(gpui::OsAction::Undo) => selector("undo:"),
|
||||||
Some(crate::OsAction::Redo) => selector("redo:"),
|
Some(gpui::OsAction::Redo) => selector("redo:"),
|
||||||
None => selector("handleGPUIMenuItem:"),
|
None => selector("handleGPUIMenuItem:"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -611,14 +613,14 @@ impl platform::Platform for MacPlatform {
|
||||||
|
|
||||||
let text_bytes = NSData::dataWithBytes_length_(
|
let text_bytes = NSData::dataWithBytes_length_(
|
||||||
nil,
|
nil,
|
||||||
item.text.as_ptr() as *const c_void,
|
item.text().as_ptr() as *const c_void,
|
||||||
item.text.len() as u64,
|
item.text().len() as u64,
|
||||||
);
|
);
|
||||||
self.pasteboard
|
self.pasteboard
|
||||||
.setData_forType(text_bytes, NSPasteboardTypeString);
|
.setData_forType(text_bytes, NSPasteboardTypeString);
|
||||||
|
|
||||||
if let Some(metadata) = item.metadata.as_ref() {
|
if let Some(metadata) = item.raw_metadata() {
|
||||||
let hash_bytes = ClipboardItem::text_hash(&item.text).to_be_bytes();
|
let hash_bytes = ClipboardItem::text_hash(&item.text()).to_be_bytes();
|
||||||
let hash_bytes = NSData::dataWithBytes_length_(
|
let hash_bytes = NSData::dataWithBytes_length_(
|
||||||
nil,
|
nil,
|
||||||
hash_bytes.as_ptr() as *const c_void,
|
hash_bytes.as_ptr() as *const c_void,
|
||||||
|
@ -652,21 +654,12 @@ impl platform::Platform for MacPlatform {
|
||||||
|
|
||||||
if let Some((hash, metadata)) = hash_bytes.zip(metadata_bytes) {
|
if let Some((hash, metadata)) = hash_bytes.zip(metadata_bytes) {
|
||||||
if hash == ClipboardItem::text_hash(&text) {
|
if hash == ClipboardItem::text_hash(&text) {
|
||||||
Some(ClipboardItem {
|
Some(ClipboardItem::new(text).with_metadata(metadata))
|
||||||
text,
|
|
||||||
metadata: Some(metadata),
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
Some(ClipboardItem {
|
Some(ClipboardItem::new(text))
|
||||||
text,
|
|
||||||
metadata: None,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Some(ClipboardItem {
|
Some(ClipboardItem::new(text))
|
||||||
text,
|
|
||||||
metadata: None,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -868,7 +861,7 @@ impl platform::Platform for MacPlatform {
|
||||||
"macOS"
|
"macOS"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn os_version(&self) -> Result<crate::platform::AppVersion> {
|
fn os_version(&self) -> Result<gpui::platform::AppVersion> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let process_info = NSProcessInfo::processInfo(nil);
|
let process_info = NSProcessInfo::processInfo(nil);
|
||||||
let version = process_info.operatingSystemVersion();
|
let version = process_info.operatingSystemVersion();
|
||||||
|
@ -1096,7 +1089,7 @@ mod security {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::platform::Platform;
|
use gpui::platform::Platform;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -1,5 +1,14 @@
|
||||||
use super::{atlas::AtlasAllocator, image_cache::ImageCache, sprite_cache::SpriteCache};
|
use super::{atlas::AtlasAllocator, image_cache::ImageCache, sprite_cache::SpriteCache};
|
||||||
use crate::{
|
use crate::renderer::shaders::ColorToUchar4;
|
||||||
|
use cocoa::{
|
||||||
|
base::{NO, YES},
|
||||||
|
foundation::NSUInteger,
|
||||||
|
quartzcore::AutoresizingMask,
|
||||||
|
};
|
||||||
|
use core_foundation::base::TCFType;
|
||||||
|
use foreign_types::ForeignTypeRef;
|
||||||
|
pub use gpui::scene::Surface;
|
||||||
|
use gpui::{
|
||||||
color::Color,
|
color::Color,
|
||||||
geometry::{
|
geometry::{
|
||||||
rect::RectF,
|
rect::RectF,
|
||||||
|
@ -8,13 +17,6 @@ use crate::{
|
||||||
platform,
|
platform,
|
||||||
scene::{Glyph, Icon, Image, ImageGlyph, Layer, Quad, Scene, Shadow, Underline},
|
scene::{Glyph, Icon, Image, ImageGlyph, Layer, Quad, Scene, Shadow, Underline},
|
||||||
};
|
};
|
||||||
use cocoa::{
|
|
||||||
base::{NO, YES},
|
|
||||||
foundation::NSUInteger,
|
|
||||||
quartzcore::AutoresizingMask,
|
|
||||||
};
|
|
||||||
use core_foundation::base::TCFType;
|
|
||||||
use foreign_types::ForeignTypeRef;
|
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use media::core_video::{self, CVMetalTextureCache};
|
use media::core_video::{self, CVMetalTextureCache};
|
||||||
use metal::{CommandQueue, MTLPixelFormat, MTLResourceOptions, NSRange};
|
use metal::{CommandQueue, MTLPixelFormat, MTLResourceOptions, NSRange};
|
||||||
|
@ -49,11 +51,6 @@ struct PathSprite {
|
||||||
shader_data: shaders::GPUISprite,
|
shader_data: shaders::GPUISprite,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Surface {
|
|
||||||
pub bounds: RectF,
|
|
||||||
pub image_buffer: core_video::CVImageBuffer,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Renderer {
|
impl Renderer {
|
||||||
pub fn new(is_opaque: bool, fonts: Arc<dyn platform::FontSystem>) -> Self {
|
pub fn new(is_opaque: bool, fonts: Arc<dyn platform::FontSystem>) -> Self {
|
||||||
const PIXEL_FORMAT: MTLPixelFormat = MTLPixelFormat::BGRA8Unorm;
|
const PIXEL_FORMAT: MTLPixelFormat = MTLPixelFormat::BGRA8Unorm;
|
||||||
|
@ -1221,7 +1218,7 @@ mod shaders {
|
||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use crate::{
|
use gpui::{
|
||||||
color::Color,
|
color::Color,
|
||||||
geometry::vector::{Vector2F, Vector2I},
|
geometry::vector::{Vector2F, Vector2I},
|
||||||
};
|
};
|
||||||
|
@ -1260,9 +1257,11 @@ mod shaders {
|
||||||
self.to_f32().to_float2()
|
self.to_f32().to_float2()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub trait ColorToUchar4 {
|
||||||
impl Color {
|
fn to_uchar4(&self) -> vector_uchar4;
|
||||||
pub fn to_uchar4(&self) -> vector_uchar4 {
|
}
|
||||||
|
impl ColorToUchar4 for Color {
|
||||||
|
fn to_uchar4(&self) -> vector_uchar4 {
|
||||||
let mut vec = self.a as vector_uchar4;
|
let mut vec = self.a as vector_uchar4;
|
||||||
vec <<= 8;
|
vec <<= 8;
|
||||||
vec |= self.b as vector_uchar4;
|
vec |= self.b as vector_uchar4;
|
|
@ -1,5 +1,4 @@
|
||||||
use super::ns_string;
|
use super::ns_string;
|
||||||
use crate::platform;
|
|
||||||
use cocoa::{
|
use cocoa::{
|
||||||
appkit::NSScreen,
|
appkit::NSScreen,
|
||||||
base::{id, nil},
|
base::{id, nil},
|
||||||
|
@ -10,6 +9,7 @@ use core_foundation::{
|
||||||
uuid::{CFUUIDGetUUIDBytes, CFUUIDRef},
|
uuid::{CFUUIDGetUUIDBytes, CFUUIDRef},
|
||||||
};
|
};
|
||||||
use core_graphics::display::CGDirectDisplayID;
|
use core_graphics::display::CGDirectDisplayID;
|
||||||
|
use gpui::platform;
|
||||||
use pathfinder_geometry::{rect::RectF, vector::vec2f};
|
use pathfinder_geometry::{rect::RectF, vector::vec2f};
|
||||||
use std::{any::Any, ffi::c_void};
|
use std::{any::Any, ffi::c_void};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
|
@ -1,10 +1,10 @@
|
||||||
use super::atlas::AtlasAllocator;
|
use super::atlas::AtlasAllocator;
|
||||||
use crate::{
|
use collections::hash_map::Entry;
|
||||||
|
use gpui::{
|
||||||
fonts::{FontId, GlyphId},
|
fonts::{FontId, GlyphId},
|
||||||
geometry::vector::{vec2f, Vector2F, Vector2I},
|
geometry::vector::{vec2f, Vector2F, Vector2I},
|
||||||
platform::{self, RasterizationOptions},
|
platform::{self, RasterizationOptions},
|
||||||
};
|
};
|
||||||
use collections::hash_map::Entry;
|
|
||||||
use metal::{MTLPixelFormat, TextureDescriptor};
|
use metal::{MTLPixelFormat, TextureDescriptor};
|
||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
use std::{borrow::Cow, collections::HashMap, sync::Arc};
|
use std::{borrow::Cow, collections::HashMap, sync::Arc};
|
|
@ -1,15 +1,6 @@
|
||||||
use crate::{
|
use crate::appearance::AppearanceFromNative;
|
||||||
geometry::{
|
use crate::event::EventFromNative;
|
||||||
rect::RectF,
|
use crate::{platform::NSViewLayerContentsRedrawDuringViewResize, renderer::Renderer};
|
||||||
vector::{vec2f, Vector2F},
|
|
||||||
},
|
|
||||||
platform::{
|
|
||||||
self,
|
|
||||||
mac::{platform::NSViewLayerContentsRedrawDuringViewResize, renderer::Renderer},
|
|
||||||
Event, FontSystem, WindowBounds,
|
|
||||||
},
|
|
||||||
Scene,
|
|
||||||
};
|
|
||||||
use cocoa::{
|
use cocoa::{
|
||||||
appkit::{NSScreen, NSSquareStatusItemLength, NSStatusBar, NSStatusItem, NSView, NSWindow},
|
appkit::{NSScreen, NSSquareStatusItemLength, NSStatusBar, NSStatusItem, NSView, NSWindow},
|
||||||
base::{id, nil, YES},
|
base::{id, nil, YES},
|
||||||
|
@ -17,6 +8,14 @@ use cocoa::{
|
||||||
};
|
};
|
||||||
use ctor::ctor;
|
use ctor::ctor;
|
||||||
use foreign_types::ForeignTypeRef;
|
use foreign_types::ForeignTypeRef;
|
||||||
|
use gpui::{
|
||||||
|
geometry::{
|
||||||
|
rect::RectF,
|
||||||
|
vector::{vec2f, Vector2F},
|
||||||
|
},
|
||||||
|
platform::{self, Event, FontSystem, WindowBounds},
|
||||||
|
Scene,
|
||||||
|
};
|
||||||
use objc::{
|
use objc::{
|
||||||
class,
|
class,
|
||||||
declare::ClassDecl,
|
declare::ClassDecl,
|
||||||
|
@ -210,7 +209,7 @@ impl platform::Window for StatusItem {
|
||||||
|
|
||||||
fn prompt(
|
fn prompt(
|
||||||
&self,
|
&self,
|
||||||
_: crate::platform::PromptLevel,
|
_: gpui::platform::PromptLevel,
|
||||||
_: &str,
|
_: &str,
|
||||||
_: &[&str],
|
_: &[&str],
|
||||||
) -> postage::oneshot::Receiver<usize> {
|
) -> postage::oneshot::Receiver<usize> {
|
|
@ -1,19 +1,7 @@
|
||||||
|
use crate::appearance::AppearanceFromNative;
|
||||||
|
use crate::event::EventFromNative;
|
||||||
use crate::{
|
use crate::{
|
||||||
executor,
|
platform::NSViewLayerContentsRedrawDuringViewResize, renderer::Renderer, screen::Screen,
|
||||||
geometry::{
|
|
||||||
rect::RectF,
|
|
||||||
vector::{vec2f, Vector2F},
|
|
||||||
},
|
|
||||||
keymap_matcher::Keystroke,
|
|
||||||
platform::{
|
|
||||||
self,
|
|
||||||
mac::{
|
|
||||||
platform::NSViewLayerContentsRedrawDuringViewResize, renderer::Renderer, screen::Screen,
|
|
||||||
},
|
|
||||||
Event, InputHandler, KeyDownEvent, Modifiers, ModifiersChangedEvent, MouseButton,
|
|
||||||
MouseButtonEvent, MouseMovedEvent, Scene, WindowBounds, WindowKind,
|
|
||||||
},
|
|
||||||
AnyWindowHandle,
|
|
||||||
};
|
};
|
||||||
use block::ConcreteBlock;
|
use block::ConcreteBlock;
|
||||||
use cocoa::{
|
use cocoa::{
|
||||||
|
@ -28,6 +16,19 @@ use cocoa::{
|
||||||
use core_graphics::display::CGRect;
|
use core_graphics::display::CGRect;
|
||||||
use ctor::ctor;
|
use ctor::ctor;
|
||||||
use foreign_types::ForeignTypeRef;
|
use foreign_types::ForeignTypeRef;
|
||||||
|
use gpui::{
|
||||||
|
executor,
|
||||||
|
geometry::{
|
||||||
|
rect::RectF,
|
||||||
|
vector::{vec2f, Vector2F},
|
||||||
|
},
|
||||||
|
keymap_matcher::Keystroke,
|
||||||
|
platform::{
|
||||||
|
self, Event, InputHandler, KeyDownEvent, Modifiers, ModifiersChangedEvent, MouseButton,
|
||||||
|
MouseButtonEvent, MouseMovedEvent, WindowBounds, WindowKind,
|
||||||
|
},
|
||||||
|
AnyWindowHandle, Scene,
|
||||||
|
};
|
||||||
use objc::{
|
use objc::{
|
||||||
class,
|
class,
|
||||||
declare::ClassDecl,
|
declare::ClassDecl,
|
|
@ -9,8 +9,8 @@ use syn::{
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn test(args: TokenStream, function: TokenStream) -> TokenStream {
|
pub fn test(args: TokenStream, function: TokenStream) -> TokenStream {
|
||||||
let mut namespace = format_ident!("gpui");
|
let namespace = format_ident!("gpui");
|
||||||
|
let mut platform_namespace = format_ident!("gpui_platform");
|
||||||
let args = syn::parse_macro_input!(args as AttributeArgs);
|
let args = syn::parse_macro_input!(args as AttributeArgs);
|
||||||
let mut max_retries = 0;
|
let mut max_retries = 0;
|
||||||
let mut num_iterations = 1;
|
let mut num_iterations = 1;
|
||||||
|
@ -23,7 +23,7 @@ pub fn test(args: TokenStream, function: TokenStream) -> TokenStream {
|
||||||
NestedMeta::Meta(Meta::Path(name))
|
NestedMeta::Meta(Meta::Path(name))
|
||||||
if name.get_ident().map_or(false, |n| n == "self") =>
|
if name.get_ident().map_or(false, |n| n == "self") =>
|
||||||
{
|
{
|
||||||
namespace = format_ident!("crate");
|
platform_namespace = format_ident!("crate");
|
||||||
}
|
}
|
||||||
NestedMeta::Meta(Meta::NameValue(meta)) => {
|
NestedMeta::Meta(Meta::NameValue(meta)) => {
|
||||||
let key_name = meta.path.get_ident().map(|i| i.to_string());
|
let key_name = meta.path.get_ident().map(|i| i.to_string());
|
||||||
|
@ -157,8 +157,8 @@ pub fn test(args: TokenStream, function: TokenStream) -> TokenStream {
|
||||||
#[test]
|
#[test]
|
||||||
fn #outer_fn_name() {
|
fn #outer_fn_name() {
|
||||||
#inner_fn
|
#inner_fn
|
||||||
|
|
||||||
#namespace::test::run_test(
|
#namespace::test::run_test(
|
||||||
|
#platform_namespace::font_system,
|
||||||
#num_iterations as u64,
|
#num_iterations as u64,
|
||||||
#starting_seed as u64,
|
#starting_seed as u64,
|
||||||
#max_retries,
|
#max_retries,
|
||||||
|
@ -234,8 +234,8 @@ pub fn test(args: TokenStream, function: TokenStream) -> TokenStream {
|
||||||
#[test]
|
#[test]
|
||||||
fn #outer_fn_name() {
|
fn #outer_fn_name() {
|
||||||
#inner_fn
|
#inner_fn
|
||||||
|
|
||||||
#namespace::test::run_test(
|
#namespace::test::run_test(
|
||||||
|
#platform_namespace::font_system,
|
||||||
#num_iterations as u64,
|
#num_iterations as u64,
|
||||||
#starting_seed as u64,
|
#starting_seed as u64,
|
||||||
#max_retries,
|
#max_retries,
|
||||||
|
|
25
crates/gpui_platform/Cargo.toml
Normal file
25
crates/gpui_platform/Cargo.toml
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
[package]
|
||||||
|
name = "gpui_platform"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[features]
|
||||||
|
test-support = ["gpui/test-support"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
gpui = {path = "../gpui", optional = true}
|
||||||
|
gpui_macros = { path = "../gpui_macros" }
|
||||||
|
|
||||||
|
[target.'cfg(target_os = "macos")'.dependencies]
|
||||||
|
current_platform = {path = "../gpui_mac", package = "gpui_mac"}
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
gpui = {path = "../gpui", features = ["test-support"]}
|
||||||
|
postage.workspace = true
|
||||||
|
log.workspace = true
|
||||||
|
itertools = "0.10"
|
||||||
|
smol.workspace = true
|
||||||
|
serde.workspace = true
|
||||||
|
rand.workspace = true
|
5
crates/gpui_platform/src/lib.rs
Normal file
5
crates/gpui_platform/src/lib.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
pub use current_platform::*;
|
||||||
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
|
mod tests;
|
||||||
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
|
use gpui_macros::test;
|
2103
crates/gpui_platform/src/tests/app.rs
Normal file
2103
crates/gpui_platform/src/tests/app.rs
Normal file
File diff suppressed because it is too large
Load diff
67
crates/gpui_platform/src/tests/elements/label.rs
Normal file
67
crates/gpui_platform/src/tests/elements/label.rs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
use gpui::color::Color;
|
||||||
|
use gpui::elements::{Label, LabelStyle};
|
||||||
|
use gpui::fonts::{Properties as FontProperties, TextStyle, Weight};
|
||||||
|
use gpui::text_layout::RunStyle;
|
||||||
|
use gpui::AppContext;
|
||||||
|
|
||||||
|
#[crate::test(self)]
|
||||||
|
fn test_layout_label_with_highlights(cx: &mut AppContext) {
|
||||||
|
let default_style = TextStyle::new(
|
||||||
|
"Menlo",
|
||||||
|
12.,
|
||||||
|
Default::default(),
|
||||||
|
Default::default(),
|
||||||
|
Default::default(),
|
||||||
|
Color::black(),
|
||||||
|
cx.font_cache(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let highlight_style = TextStyle::new(
|
||||||
|
"Menlo",
|
||||||
|
12.,
|
||||||
|
*FontProperties::new().weight(Weight::BOLD),
|
||||||
|
Default::default(),
|
||||||
|
Default::default(),
|
||||||
|
Color::new(255, 0, 0, 255),
|
||||||
|
cx.font_cache(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let label = Label::new(
|
||||||
|
".αβγδε.ⓐⓑⓒⓓⓔ.abcde.".to_string(),
|
||||||
|
LabelStyle {
|
||||||
|
text: default_style.clone(),
|
||||||
|
highlight_text: Some(highlight_style.clone()),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.with_highlights(vec![
|
||||||
|
".α".len(),
|
||||||
|
".αβ".len(),
|
||||||
|
".αβγδ".len(),
|
||||||
|
".αβγδε.ⓐ".len(),
|
||||||
|
".αβγδε.ⓐⓑ".len(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
let default_run_style = RunStyle {
|
||||||
|
font_id: default_style.font_id,
|
||||||
|
color: default_style.color,
|
||||||
|
underline: default_style.underline,
|
||||||
|
};
|
||||||
|
let highlight_run_style = RunStyle {
|
||||||
|
font_id: highlight_style.font_id,
|
||||||
|
color: highlight_style.color,
|
||||||
|
underline: highlight_style.underline,
|
||||||
|
};
|
||||||
|
let runs = label.compute_runs();
|
||||||
|
assert_eq!(
|
||||||
|
runs.as_slice(),
|
||||||
|
&[
|
||||||
|
(".α".len(), default_run_style),
|
||||||
|
("βγ".len(), highlight_run_style),
|
||||||
|
("δ".len(), default_run_style),
|
||||||
|
("ε".len(), highlight_run_style),
|
||||||
|
(".ⓐ".len(), default_run_style),
|
||||||
|
("ⓑⓒ".len(), highlight_run_style),
|
||||||
|
("ⓓⓔ.abcde.".len(), default_run_style),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
380
crates/gpui_platform/src/tests/elements/list.rs
Normal file
380
crates/gpui_platform/src/tests/elements/list.rs
Normal file
|
@ -0,0 +1,380 @@
|
||||||
|
use gpui::elements::list::ListItem;
|
||||||
|
use gpui::elements::List;
|
||||||
|
use gpui::elements::ListOffset;
|
||||||
|
use gpui::elements::ListState;
|
||||||
|
use gpui::elements::Orientation;
|
||||||
|
use gpui::geometry::rect::RectF;
|
||||||
|
use gpui::geometry::vector::Vector2F;
|
||||||
|
use gpui::serde_json;
|
||||||
|
use gpui::AnyElement;
|
||||||
|
use gpui::AppContext;
|
||||||
|
use gpui::Element;
|
||||||
|
use gpui::LayoutContext;
|
||||||
|
use gpui::SceneBuilder;
|
||||||
|
use gpui::SizeConstraint;
|
||||||
|
use gpui::View;
|
||||||
|
use gpui::ViewContext;
|
||||||
|
use gpui::{elements::Empty, geometry::vector::vec2f, Entity, PaintContext};
|
||||||
|
use rand::prelude::*;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::env;
|
||||||
|
use std::ops::Range;
|
||||||
|
use std::rc::Rc;
|
||||||
|
#[crate::test(self)]
|
||||||
|
fn test_layout(cx: &mut AppContext) {
|
||||||
|
cx.add_window(Default::default(), |cx| {
|
||||||
|
let mut view = TestView;
|
||||||
|
let constraint = SizeConstraint::new(vec2f(0., 0.), vec2f(100., 40.));
|
||||||
|
let elements = Rc::new(RefCell::new(vec![(0, 20.), (1, 30.), (2, 100.)]));
|
||||||
|
let state = ListState::new(elements.borrow().len(), Orientation::Top, 1000.0, {
|
||||||
|
let elements = elements.clone();
|
||||||
|
move |_, ix, _| {
|
||||||
|
let (id, height) = elements.borrow()[ix];
|
||||||
|
TestElement::new(id, height).into_any()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut list = List::new(state.clone());
|
||||||
|
let mut new_parents = Default::default();
|
||||||
|
let mut notify_views_if_parents_change = Default::default();
|
||||||
|
let mut layout_cx = LayoutContext::new(
|
||||||
|
cx,
|
||||||
|
&mut new_parents,
|
||||||
|
&mut notify_views_if_parents_change,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
let (size, _) = list.layout(constraint, &mut view, &mut layout_cx);
|
||||||
|
assert_eq!(size, vec2f(100., 40.));
|
||||||
|
assert_eq!(
|
||||||
|
state.0.borrow().items.summary().clone(),
|
||||||
|
ListItemSummary {
|
||||||
|
count: 3,
|
||||||
|
rendered_count: 3,
|
||||||
|
unrendered_count: 0,
|
||||||
|
height: 150.
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
state.0.borrow_mut().scroll(
|
||||||
|
&ListOffset {
|
||||||
|
item_ix: 0,
|
||||||
|
offset_in_item: 0.,
|
||||||
|
},
|
||||||
|
40.,
|
||||||
|
vec2f(0., -54.),
|
||||||
|
true,
|
||||||
|
&mut view,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut layout_cx = LayoutContext::new(
|
||||||
|
cx,
|
||||||
|
&mut new_parents,
|
||||||
|
&mut notify_views_if_parents_change,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
let (_, logical_scroll_top) = list.layout(constraint, &mut view, &mut layout_cx);
|
||||||
|
assert_eq!(
|
||||||
|
logical_scroll_top,
|
||||||
|
ListOffset {
|
||||||
|
item_ix: 2,
|
||||||
|
offset_in_item: 4.
|
||||||
|
}
|
||||||
|
);
|
||||||
|
assert_eq!(state.0.borrow().scroll_top(&logical_scroll_top), 54.);
|
||||||
|
|
||||||
|
elements.borrow_mut().splice(1..2, vec![(3, 40.), (4, 50.)]);
|
||||||
|
elements.borrow_mut().push((5, 60.));
|
||||||
|
state.splice(1..2, 2);
|
||||||
|
state.splice(4..4, 1);
|
||||||
|
assert_eq!(
|
||||||
|
state.0.borrow().items.summary().clone(),
|
||||||
|
ListItemSummary {
|
||||||
|
count: 5,
|
||||||
|
rendered_count: 2,
|
||||||
|
unrendered_count: 3,
|
||||||
|
height: 120.
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut layout_cx = LayoutContext::new(
|
||||||
|
cx,
|
||||||
|
&mut new_parents,
|
||||||
|
&mut notify_views_if_parents_change,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
let (size, logical_scroll_top) = list.layout(constraint, &mut view, &mut layout_cx);
|
||||||
|
assert_eq!(size, vec2f(100., 40.));
|
||||||
|
assert_eq!(
|
||||||
|
state.0.borrow().items.summary().clone(),
|
||||||
|
ListItemSummary {
|
||||||
|
count: 5,
|
||||||
|
rendered_count: 5,
|
||||||
|
unrendered_count: 0,
|
||||||
|
height: 270.
|
||||||
|
}
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
logical_scroll_top,
|
||||||
|
ListOffset {
|
||||||
|
item_ix: 3,
|
||||||
|
offset_in_item: 4.
|
||||||
|
}
|
||||||
|
);
|
||||||
|
assert_eq!(state.0.borrow().scroll_top(&logical_scroll_top), 114.);
|
||||||
|
|
||||||
|
view
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[crate::test(self, iterations = 10)]
|
||||||
|
fn test_random(cx: &mut AppContext, mut rng: StdRng) {
|
||||||
|
let operations = env::var("OPERATIONS")
|
||||||
|
.map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
|
||||||
|
.unwrap_or(10);
|
||||||
|
|
||||||
|
cx.add_window(Default::default(), |cx| {
|
||||||
|
let mut view = TestView;
|
||||||
|
|
||||||
|
let mut next_id = 0;
|
||||||
|
let elements = Rc::new(RefCell::new(
|
||||||
|
(0..rng.gen_range(0..=20))
|
||||||
|
.map(|_| {
|
||||||
|
let id = next_id;
|
||||||
|
next_id += 1;
|
||||||
|
(id, rng.gen_range(0..=200) as f32 / 2.0)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
));
|
||||||
|
let orientation = *[Orientation::Top, Orientation::Bottom]
|
||||||
|
.choose(&mut rng)
|
||||||
|
.unwrap();
|
||||||
|
let overdraw = rng.gen_range(1..=100) as f32;
|
||||||
|
|
||||||
|
let state = ListState::new(elements.borrow().len(), orientation, overdraw, {
|
||||||
|
let elements = elements.clone();
|
||||||
|
move |_, ix, _| {
|
||||||
|
let (id, height) = elements.borrow()[ix];
|
||||||
|
TestElement::new(id, height).into_any()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut width = rng.gen_range(0..=2000) as f32 / 2.;
|
||||||
|
let mut height = rng.gen_range(0..=2000) as f32 / 2.;
|
||||||
|
log::info!("orientation: {:?}", orientation);
|
||||||
|
log::info!("overdraw: {}", overdraw);
|
||||||
|
log::info!("elements: {:?}", elements.borrow());
|
||||||
|
log::info!("size: ({:?}, {:?})", width, height);
|
||||||
|
log::info!("==================");
|
||||||
|
|
||||||
|
let mut last_logical_scroll_top = None;
|
||||||
|
for _ in 0..operations {
|
||||||
|
match rng.gen_range(0..=100) {
|
||||||
|
0..=29 if last_logical_scroll_top.is_some() => {
|
||||||
|
let delta = vec2f(0., rng.gen_range(-overdraw..=overdraw));
|
||||||
|
log::info!(
|
||||||
|
"Scrolling by {:?}, previous scroll top: {:?}",
|
||||||
|
delta,
|
||||||
|
last_logical_scroll_top.unwrap()
|
||||||
|
);
|
||||||
|
state.0.borrow_mut().scroll(
|
||||||
|
last_logical_scroll_top.as_ref().unwrap(),
|
||||||
|
height,
|
||||||
|
delta,
|
||||||
|
true,
|
||||||
|
&mut view,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
30..=34 => {
|
||||||
|
width = rng.gen_range(0..=2000) as f32 / 2.;
|
||||||
|
log::info!("changing width: {:?}", width);
|
||||||
|
}
|
||||||
|
35..=54 => {
|
||||||
|
height = rng.gen_range(0..=1000) as f32 / 2.;
|
||||||
|
log::info!("changing height: {:?}", height);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let mut elements = elements.borrow_mut();
|
||||||
|
let end_ix = rng.gen_range(0..=elements.len());
|
||||||
|
let start_ix = rng.gen_range(0..=end_ix);
|
||||||
|
let new_elements = (0..rng.gen_range(0..10))
|
||||||
|
.map(|_| {
|
||||||
|
let id = next_id;
|
||||||
|
next_id += 1;
|
||||||
|
(id, rng.gen_range(0..=200) as f32 / 2.)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
log::info!("splice({:?}, {:?})", start_ix..end_ix, new_elements);
|
||||||
|
state.splice(start_ix..end_ix, new_elements.len());
|
||||||
|
elements.splice(start_ix..end_ix, new_elements);
|
||||||
|
for (ix, item) in state.0.borrow().items.cursor::<()>().enumerate() {
|
||||||
|
if let ListItem::Rendered(element) = item {
|
||||||
|
let (expected_id, _) = elements[ix];
|
||||||
|
element.borrow().with_metadata(|metadata: Option<&usize>| {
|
||||||
|
assert_eq!(*metadata.unwrap(), expected_id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut list = List::new(state.clone());
|
||||||
|
let window_size = vec2f(width, height);
|
||||||
|
let mut new_parents = Default::default();
|
||||||
|
let mut notify_views_if_parents_change = Default::default();
|
||||||
|
let mut layout_cx = LayoutContext::new(
|
||||||
|
cx,
|
||||||
|
&mut new_parents,
|
||||||
|
&mut notify_views_if_parents_change,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
let (size, logical_scroll_top) = list.layout(
|
||||||
|
SizeConstraint::new(vec2f(0., 0.), window_size),
|
||||||
|
&mut view,
|
||||||
|
&mut layout_cx,
|
||||||
|
);
|
||||||
|
assert_eq!(size, window_size);
|
||||||
|
last_logical_scroll_top = Some(logical_scroll_top);
|
||||||
|
|
||||||
|
let state = state.0.borrow();
|
||||||
|
log::info!("items {:?}", state.items.items(&()));
|
||||||
|
|
||||||
|
let scroll_top = state.scroll_top(&logical_scroll_top);
|
||||||
|
let rendered_top = (scroll_top - overdraw).max(0.);
|
||||||
|
let rendered_bottom = scroll_top + height + overdraw;
|
||||||
|
let mut item_top = 0.;
|
||||||
|
|
||||||
|
log::info!(
|
||||||
|
"rendered top {:?}, rendered bottom {:?}, scroll top {:?}",
|
||||||
|
rendered_top,
|
||||||
|
rendered_bottom,
|
||||||
|
scroll_top,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut first_rendered_element_top = None;
|
||||||
|
let mut last_rendered_element_bottom = None;
|
||||||
|
assert_eq!(state.items.summary().count, elements.borrow().len());
|
||||||
|
for (ix, item) in state.items.cursor::<()>().enumerate() {
|
||||||
|
match item {
|
||||||
|
ListItem::Unrendered => {
|
||||||
|
let item_bottom = item_top;
|
||||||
|
assert!(item_bottom <= rendered_top || item_top >= rendered_bottom);
|
||||||
|
item_top = item_bottom;
|
||||||
|
}
|
||||||
|
ListItem::Removed(height) => {
|
||||||
|
let (id, expected_height) = elements.borrow()[ix];
|
||||||
|
assert_eq!(
|
||||||
|
*height, expected_height,
|
||||||
|
"element {} height didn't match",
|
||||||
|
id
|
||||||
|
);
|
||||||
|
let item_bottom = item_top + height;
|
||||||
|
assert!(item_bottom <= rendered_top || item_top >= rendered_bottom);
|
||||||
|
item_top = item_bottom;
|
||||||
|
}
|
||||||
|
ListItem::Rendered(element) => {
|
||||||
|
let (expected_id, expected_height) = elements.borrow()[ix];
|
||||||
|
let element = element.borrow();
|
||||||
|
element.with_metadata(|metadata: Option<&usize>| {
|
||||||
|
assert_eq!(*metadata.unwrap(), expected_id);
|
||||||
|
});
|
||||||
|
assert_eq!(element.size().y(), expected_height);
|
||||||
|
let item_bottom = item_top + element.size().y();
|
||||||
|
first_rendered_element_top.get_or_insert(item_top);
|
||||||
|
last_rendered_element_bottom = Some(item_bottom);
|
||||||
|
assert!(item_bottom > rendered_top || item_top < rendered_bottom);
|
||||||
|
item_top = item_bottom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match orientation {
|
||||||
|
Orientation::Top => {
|
||||||
|
if let Some(first_rendered_element_top) = first_rendered_element_top {
|
||||||
|
assert!(first_rendered_element_top <= scroll_top);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Orientation::Bottom => {
|
||||||
|
if let Some(last_rendered_element_bottom) = last_rendered_element_bottom {
|
||||||
|
assert!(last_rendered_element_bottom >= scroll_top + height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
view
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TestView;
|
||||||
|
|
||||||
|
impl Entity for TestView {
|
||||||
|
type Event = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl View for TestView {
|
||||||
|
fn ui_name() -> &'static str {
|
||||||
|
"TestView"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render(&mut self, _: &mut ViewContext<Self>) -> AnyElement<Self> {
|
||||||
|
Empty::new().into_any()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TestElement {
|
||||||
|
id: usize,
|
||||||
|
size: Vector2F,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestElement {
|
||||||
|
fn new(id: usize, height: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
id,
|
||||||
|
size: vec2f(100., height),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V: 'static> Element<V> for TestElement {
|
||||||
|
type LayoutState = ();
|
||||||
|
type PaintState = ();
|
||||||
|
|
||||||
|
fn layout(&mut self, _: SizeConstraint, _: &mut V, _: &mut LayoutContext<V>) -> (Vector2F, ()) {
|
||||||
|
(self.size, ())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn paint(
|
||||||
|
&mut self,
|
||||||
|
_: &mut SceneBuilder,
|
||||||
|
_: RectF,
|
||||||
|
_: RectF,
|
||||||
|
_: &mut (),
|
||||||
|
_: &mut V,
|
||||||
|
_: &mut PaintContext<V>,
|
||||||
|
) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
_: Range<usize>,
|
||||||
|
_: RectF,
|
||||||
|
_: RectF,
|
||||||
|
_: &Self::LayoutState,
|
||||||
|
_: &Self::PaintState,
|
||||||
|
_: &V,
|
||||||
|
_: &ViewContext<V>,
|
||||||
|
) -> Option<RectF> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn debug(&self, _: RectF, _: &(), _: &(), _: &V, _: &ViewContext<V>) -> serde_json::Value {
|
||||||
|
self.id.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn metadata(&self) -> Option<&dyn std::any::Any> {
|
||||||
|
Some(&self.id)
|
||||||
|
}
|
||||||
|
}
|
3
crates/gpui_platform/src/tests/elements/mod.rs
Normal file
3
crates/gpui_platform/src/tests/elements/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
mod label;
|
||||||
|
mod list;
|
||||||
|
mod text;
|
48
crates/gpui_platform/src/tests/elements/text.rs
Normal file
48
crates/gpui_platform/src/tests/elements/text.rs
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
use gpui::elements::Text;
|
||||||
|
use gpui::geometry::vector::vec2f;
|
||||||
|
use gpui::Element;
|
||||||
|
use gpui::LayoutContext;
|
||||||
|
use gpui::SizeConstraint;
|
||||||
|
use gpui::{elements::Empty, fonts, AnyElement, AppContext, Entity, View, ViewContext};
|
||||||
|
|
||||||
|
#[crate::test(self)]
|
||||||
|
fn test_soft_wrapping_with_carriage_returns(cx: &mut AppContext) {
|
||||||
|
cx.add_window(Default::default(), |cx| {
|
||||||
|
let mut view = TestView;
|
||||||
|
fonts::with_font_cache(cx.font_cache().clone(), || {
|
||||||
|
let mut text = Text::new("Hello\r\n", Default::default()).with_soft_wrap(true);
|
||||||
|
let mut new_parents = Default::default();
|
||||||
|
let mut notify_views_if_parents_change = Default::default();
|
||||||
|
let mut layout_cx = LayoutContext::new(
|
||||||
|
cx,
|
||||||
|
&mut new_parents,
|
||||||
|
&mut notify_views_if_parents_change,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
let (_, state) = text.layout(
|
||||||
|
SizeConstraint::new(Default::default(), vec2f(f32::INFINITY, f32::INFINITY)),
|
||||||
|
&mut view,
|
||||||
|
&mut layout_cx,
|
||||||
|
);
|
||||||
|
assert_eq!(state.shaped_lines.len(), 2);
|
||||||
|
assert_eq!(state.wrap_boundaries.len(), 2);
|
||||||
|
});
|
||||||
|
view
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TestView;
|
||||||
|
|
||||||
|
impl Entity for TestView {
|
||||||
|
type Event = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl View for TestView {
|
||||||
|
fn ui_name() -> &'static str {
|
||||||
|
"TestView"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render(&mut self, _: &mut ViewContext<Self>) -> AnyElement<Self> {
|
||||||
|
Empty::new().into_any()
|
||||||
|
}
|
||||||
|
}
|
125
crates/gpui_platform/src/tests/mod.rs
Normal file
125
crates/gpui_platform/src/tests/mod.rs
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
mod app;
|
||||||
|
mod elements;
|
||||||
|
|
||||||
|
use gpui::fonts::{Properties, Weight};
|
||||||
|
use gpui::text_layout::*;
|
||||||
|
|
||||||
|
#[crate::test]
|
||||||
|
fn test_wrap_line(cx: &mut gpui::AppContext) {
|
||||||
|
let font_cache = cx.font_cache().clone();
|
||||||
|
let font_system = cx.platform().fonts();
|
||||||
|
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);
|
||||||
|
assert_eq!(
|
||||||
|
wrapper
|
||||||
|
.wrap_line("aa bbb cccc ddddd eeee", 72.0)
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
&[
|
||||||
|
Boundary::new(7, 0),
|
||||||
|
Boundary::new(12, 0),
|
||||||
|
Boundary::new(18, 0)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
wrapper
|
||||||
|
.wrap_line("aaa aaaaaaaaaaaaaaaaaa", 72.0)
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
&[
|
||||||
|
Boundary::new(4, 0),
|
||||||
|
Boundary::new(11, 0),
|
||||||
|
Boundary::new(18, 0)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
wrapper.wrap_line(" aaaaaaa", 72.).collect::<Vec<_>>(),
|
||||||
|
&[
|
||||||
|
Boundary::new(7, 5),
|
||||||
|
Boundary::new(9, 5),
|
||||||
|
Boundary::new(11, 5),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
wrapper
|
||||||
|
.wrap_line(" ", 72.)
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
&[
|
||||||
|
Boundary::new(7, 0),
|
||||||
|
Boundary::new(14, 0),
|
||||||
|
Boundary::new(21, 0)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
wrapper
|
||||||
|
.wrap_line(" aaaaaaaaaaaaaa", 72.)
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
&[
|
||||||
|
Boundary::new(7, 0),
|
||||||
|
Boundary::new(14, 3),
|
||||||
|
Boundary::new(18, 3),
|
||||||
|
Boundary::new(22, 3),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[crate::test(retries = 5)]
|
||||||
|
fn test_wrap_shaped_line(cx: &mut gpui::AppContext) {
|
||||||
|
// This is failing intermittently on CI and we don't have time to figure it out
|
||||||
|
let font_cache = cx.font_cache().clone();
|
||||||
|
let font_system = cx.platform().fonts();
|
||||||
|
let text_layout_cache = TextLayoutCache::new(font_system.clone());
|
||||||
|
|
||||||
|
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,
|
||||||
|
color: Default::default(),
|
||||||
|
underline: Default::default(),
|
||||||
|
};
|
||||||
|
let bold = RunStyle {
|
||||||
|
font_id: font_cache
|
||||||
|
.select_font(
|
||||||
|
family,
|
||||||
|
&Properties {
|
||||||
|
weight: Weight::BOLD,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
color: Default::default(),
|
||||||
|
underline: Default::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let text = "aa bbb cccc ddddd eeee";
|
||||||
|
let line = text_layout_cache.layout_str(
|
||||||
|
text,
|
||||||
|
16.0,
|
||||||
|
&[(4, normal), (5, bold), (6, normal), (1, bold), (7, normal)],
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut wrapper = LineWrapper::new(font_id, 16., font_system);
|
||||||
|
assert_eq!(
|
||||||
|
wrapper
|
||||||
|
.wrap_shaped_line(text, &line, 72.0)
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
&[
|
||||||
|
ShapedBoundary {
|
||||||
|
run_ix: 1,
|
||||||
|
glyph_ix: 3
|
||||||
|
},
|
||||||
|
ShapedBoundary {
|
||||||
|
run_ix: 2,
|
||||||
|
glyph_ix: 3
|
||||||
|
},
|
||||||
|
ShapedBoundary {
|
||||||
|
run_ix: 4,
|
||||||
|
glyph_ix: 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ test-support = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"collections/test-support",
|
"collections/test-support",
|
||||||
"gpui/test-support",
|
"gpui/test-support",
|
||||||
|
"gpui_platform",
|
||||||
"live_kit_server",
|
"live_kit_server",
|
||||||
"nanoid",
|
"nanoid",
|
||||||
]
|
]
|
||||||
|
@ -24,6 +25,7 @@ test-support = [
|
||||||
[dependencies]
|
[dependencies]
|
||||||
collections = { path = "../collections", optional = true }
|
collections = { path = "../collections", optional = true }
|
||||||
gpui = { path = "../gpui", optional = true }
|
gpui = { path = "../gpui", optional = true }
|
||||||
|
gpui_platform = {path = "../gpui_platform", optional = true}
|
||||||
live_kit_server = { path = "../live_kit_server", optional = true }
|
live_kit_server = { path = "../live_kit_server", optional = true }
|
||||||
media = { path = "../media" }
|
media = { path = "../media" }
|
||||||
|
|
||||||
|
|
|
@ -19,3 +19,4 @@ util = { path = "../util" }
|
||||||
rand.workspace = true
|
rand.workspace = true
|
||||||
util = { path = "../util", features = ["test-support"] }
|
util = { path = "../util", features = ["test-support"] }
|
||||||
gpui = { path = "../gpui", features = ["test-support"] }
|
gpui = { path = "../gpui", features = ["test-support"] }
|
||||||
|
gpui_platform = {path = "../gpui_platform" }
|
||||||
|
|
|
@ -10,12 +10,13 @@ path = "src/rpc.rs"
|
||||||
doctest = false
|
doctest = false
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
test-support = ["collections/test-support", "gpui/test-support"]
|
test-support = ["collections/test-support", "gpui/test-support", "gpui_platform"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clock = { path = "../clock" }
|
clock = { path = "../clock" }
|
||||||
collections = { path = "../collections" }
|
collections = { path = "../collections" }
|
||||||
gpui = { path = "../gpui", optional = true }
|
gpui = { path = "../gpui", optional = true }
|
||||||
|
gpui_platform = {path = "../gpui_platform", optional = true}
|
||||||
util = { path = "../util" }
|
util = { path = "../util" }
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
async-lock = "2.4"
|
async-lock = "2.4"
|
||||||
|
|
|
@ -9,11 +9,12 @@ path = "src/settings.rs"
|
||||||
doctest = false
|
doctest = false
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
test-support = ["gpui/test-support", "fs/test-support"]
|
test-support = ["gpui/test-support", "fs/test-support", "gpui_platform"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
collections = { path = "../collections" }
|
collections = { path = "../collections" }
|
||||||
gpui = { path = "../gpui" }
|
gpui = { path = "../gpui" }
|
||||||
|
gpui_platform = { path = "../gpui_platform", optional = true}
|
||||||
sqlez = { path = "../sqlez" }
|
sqlez = { path = "../sqlez" }
|
||||||
fs = { path = "../fs" }
|
fs = { path = "../fs" }
|
||||||
feature_flags = { path = "../feature_flags" }
|
feature_flags = { path = "../feature_flags" }
|
||||||
|
|
|
@ -7,6 +7,7 @@ publish = false
|
||||||
[features]
|
[features]
|
||||||
test-support = [
|
test-support = [
|
||||||
"gpui/test-support",
|
"gpui/test-support",
|
||||||
|
"gpui_platform",
|
||||||
"fs/test-support",
|
"fs/test-support",
|
||||||
"settings/test-support"
|
"settings/test-support"
|
||||||
]
|
]
|
||||||
|
@ -17,6 +18,7 @@ doctest = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
gpui = { path = "../gpui" }
|
gpui = { path = "../gpui" }
|
||||||
|
gpui_platform = {path = "../gpui_platform", optional = true}
|
||||||
fs = { path = "../fs" }
|
fs = { path = "../fs" }
|
||||||
settings = { path = "../settings" }
|
settings = { path = "../settings" }
|
||||||
util = { path = "../util" }
|
util = { path = "../util" }
|
||||||
|
|
|
@ -28,6 +28,7 @@ context_menu = { path = "../context_menu" }
|
||||||
drag_and_drop = { path = "../drag_and_drop" }
|
drag_and_drop = { path = "../drag_and_drop" }
|
||||||
fs = { path = "../fs" }
|
fs = { path = "../fs" }
|
||||||
gpui = { path = "../gpui" }
|
gpui = { path = "../gpui" }
|
||||||
|
gpui_platform = { path = "../gpui_platform", optional = true }
|
||||||
install_cli = { path = "../install_cli" }
|
install_cli = { path = "../install_cli" }
|
||||||
language = { path = "../language" }
|
language = { path = "../language" }
|
||||||
menu = { path = "../menu" }
|
menu = { path = "../menu" }
|
||||||
|
|
|
@ -80,7 +80,7 @@ impl View for SharedScreen {
|
||||||
vec2f(frame.width() as f32, frame.height() as f32),
|
vec2f(frame.width() as f32, frame.height() as f32),
|
||||||
);
|
);
|
||||||
let origin = bounds.origin() + (bounds.size() / 2.) - size / 2.;
|
let origin = bounds.origin() + (bounds.size() / 2.) - size / 2.;
|
||||||
scene.push_surface(gpui::platform::mac::Surface {
|
scene.push_surface(gpui::scene::Surface {
|
||||||
bounds: RectF::new(origin, size),
|
bounds: RectF::new(origin, size),
|
||||||
image_buffer: frame.image(),
|
image_buffer: frame.image(),
|
||||||
});
|
});
|
||||||
|
|
|
@ -72,6 +72,7 @@ vim = { path = "../vim" }
|
||||||
workspace = { path = "../workspace" }
|
workspace = { path = "../workspace" }
|
||||||
welcome = { path = "../welcome" }
|
welcome = { path = "../welcome" }
|
||||||
zed-actions = {path = "../zed-actions"}
|
zed-actions = {path = "../zed-actions"}
|
||||||
|
gpui_platform = {path = "../gpui_platform"}
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
async-compression = { version = "0.3", features = ["gzip", "futures-bufread"] }
|
async-compression = { version = "0.3", features = ["gzip", "futures-bufread"] }
|
||||||
async-tar = "0.4.2"
|
async-tar = "0.4.2"
|
||||||
|
|
|
@ -53,6 +53,7 @@ use uuid::Uuid;
|
||||||
use welcome::{show_welcome_experience, FIRST_OPEN};
|
use welcome::{show_welcome_experience, FIRST_OPEN};
|
||||||
|
|
||||||
use fs::RealFs;
|
use fs::RealFs;
|
||||||
|
use gpui_platform::{foreground_platform, platform};
|
||||||
use util::{channel::RELEASE_CHANNEL, paths, ResultExt, TryFutureExt};
|
use util::{channel::RELEASE_CHANNEL, paths, ResultExt, TryFutureExt};
|
||||||
use workspace::AppState;
|
use workspace::AppState;
|
||||||
use zed::{
|
use zed::{
|
||||||
|
@ -60,7 +61,6 @@ use zed::{
|
||||||
build_window_options, handle_keymap_file_changes, initialize_workspace, languages, menus,
|
build_window_options, handle_keymap_file_changes, initialize_workspace, languages, menus,
|
||||||
only_instance::{ensure_only_instance, IsOnlyInstance},
|
only_instance::{ensure_only_instance, IsOnlyInstance},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let http = http::client();
|
let http = http::client();
|
||||||
init_paths();
|
init_paths();
|
||||||
|
@ -71,7 +71,11 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
log::info!("========== starting zed ==========");
|
log::info!("========== starting zed ==========");
|
||||||
let mut app = gpui::App::new(Assets).unwrap();
|
let platform = platform();
|
||||||
|
let foreground =
|
||||||
|
std::rc::Rc::new(gpui::executor::Foreground::platform(platform.dispatcher()).unwrap());
|
||||||
|
let fplatform = foreground_platform(foreground);
|
||||||
|
let mut app = gpui::App::new(Assets, platform, fplatform).unwrap();
|
||||||
|
|
||||||
let installation_id = app.background().block(installation_id()).ok();
|
let installation_id = app.background().block(installation_id()).ok();
|
||||||
init_panic_hook(&app, installation_id.clone());
|
init_panic_hook(&app, installation_id.clone());
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue