Port · Build: Zed's gpui at 1a28cff

gpui and gpui_platform now come from Zed's repo by git at 1a28cff,
the code gpui-pre 0.3.7 republishes, so the gallery can later build
for the browser. gpui takes stacker, as 0.2.2 always did, and
gpui_platform takes font-kit, without which macOS draws no text;
runtime_shaders moves to gpui_platform.

The API moved: focus, blur and Tab steps take cx, Corner is Anchor,
shaped lines paint with an alignment, defer_draw takes a content
mask, the inspector registers a factory, async updates return their
value, and wrapped lines are shared, not cloned. Updates through a
window context go through the window, so a closed window still ends
them as it did.

Where the new gpui behaves differently, Ely keeps its old intent.
Holds and reveals under a resting pointer survive typing through
gpui's input-modality-independent hover; previews the keyboard also
moves keep the default, and the calendar's leave ignores a key press.
Enter reaches a button inside the code editor, since gpui now arms a
key click on the press. The event logger skips a lone modifier. A
video and an image grid keep their shape in a flex column under
taffy 0.13, as a picture does.

AGENTS.md records the new stack and the rules this port changes; the
rest of the old gpui and taffy rules are re-tested in T44c.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ZacharyZhang-NYandClaude Opus 5.5 committed 2026-09-28 20:30:17 -04:00
1 parent e49c93bb6f
commit 94deeaed52
199 files changed
+2513 -2643

No files matched your search

+1
View File
@@ -105,6 +105,7 @@ pub fn styles(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
offset: point(px(shadow.x), px(shadow.y)),
blur_radius: px(shadow.blur),
spread_radius: px(shadow.spread),
inset: false,
})
.collect(),
);
+1 -4
View File
@@ -185,7 +185,7 @@ pub fn realtime(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
cx.background_executor()
.timer(Duration::from_millis(900))
.await;
let pushed = cx.update(|cx| {
cx.update(|cx| {
stream.update(cx, |(values, pushed), cx| {
let last = values.last().copied().unwrap_or(60.0);
values.push((last + (rng() - 0.5) * 10.0).clamp(20.0, 100.0));
@@ -194,9 +194,6 @@ pub fn realtime(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
cx.notify();
})
});
if pushed.is_err() {
return;
}
}
})
.detach();
+3 -3
View File
@@ -199,7 +199,7 @@ pub fn streaming(window: &mut Window, cx: &mut App) -> impl IntoElement + use<>
cx.background_executor().timer(Duration::from_millis(600)).await;
loop {
cx.background_executor().timer(Duration::from_millis(45)).await;
let more = feeder.update(cx, |stream, cx| {
let more = cx.update(|_, cx| feeder.update(cx, |stream, cx| {
let next = (stream.arrived + 7).min(ANSWER.len());
stream.arrived = (next..=ANSWER.len())
.find(|at| ANSWER.is_char_boundary(*at))
@@ -207,8 +207,8 @@ pub fn streaming(window: &mut Window, cx: &mut App) -> impl IntoElement + use<>
stream.live = stream.arrived < ANSWER.len();
cx.notify();
stream.live
});
if !matches!(more, Ok(true)) {
}));
if !matches!(more.and_then(|inner| inner), Ok(true)) {
break;
}
}
+1 -2
View File
@@ -221,8 +221,7 @@ pub fn playground(window: &mut Window, cx: &mut App) -> impl IntoElement + use<>
},
cx,
)
})
.ok();
});
})
.detach();
});
+1 -2
View File
@@ -117,8 +117,7 @@ pub fn panel(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
settings.enhancing = false;
settings.suggestion = Some(text.into());
})
})
.ok();
});
})
.detach();
})
+1 -1
View File
@@ -298,7 +298,7 @@ pub fn focus(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
.on_click(move |_, window, cx| {
change(&show, cx, |focusing| focusing.field = !focusing.field);
let focus = focus.clone();
window.defer(cx, move |window, _| window.focus(&focus));
window.defer(cx, move |window, cx| window.focus(&focus, cx));
}),
)
.when(shown, |column| column.child(Input::new(&field))),
+1 -1
View File
@@ -67,7 +67,7 @@ pub fn infinite(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
let more = more.clone();
cx.spawn(async move |cx| {
cx.background_executor().timer(Duration::from_millis(700)).await;
cx.update(|cx| set(&more, (rows + PAGE, false), cx)).ok();
cx.update(|cx| set(&more, (rows + PAGE, false), cx));
})
.detach();
}),
+1 -2
View File
@@ -144,8 +144,7 @@ pub fn tree(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
items.push(item("logo", "logo.svg", Some(&key), false));
items.push(item("inter", "Inter.ttf", Some(&key), false));
})
})
.ok();
});
})
.detach();
})
+17 -13
View File
@@ -4,7 +4,9 @@ use ely_gpui_component::media::{
AudioPlayer, AudioSpectrum, AudioWaveform, MediaControls, PlaybackSpeedControl, Playlist,
Repeat, Track, VolumeControl,
};
use gpui::{App, Entity, IntoElement, ParentElement, SharedString, Styled, Window, div, px};
use gpui::{
App, Entity, IntoElement, ParentElement, SharedString, Styled, TaskExt as _, Window, div, px,
};
use crate::{
probe::probe,
@@ -98,19 +100,21 @@ fn tick(state: &Entity<Listening>, window: &mut Window, cx: &mut App) {
.spawn(cx, async move |cx| {
loop {
cx.background_executor().timer(TICK).await;
let going = state.update(cx, |now, cx| {
now.at = (now.at + TICK.mul_f32(now.speed)).min(now.length());
if now.at == now.length() {
match now.repeat {
Repeat::One => now.at = Duration::ZERO,
Repeat::All => now.skip(1),
Repeat::Off if now.song + 1 < SONGS.len() => now.skip(1),
Repeat::Off => now.playing = false,
let going = cx.update(|_, cx| {
state.update(cx, |now, cx| {
now.at = (now.at + TICK.mul_f32(now.speed)).min(now.length());
if now.at == now.length() {
match now.repeat {
Repeat::One => now.at = Duration::ZERO,
Repeat::All => now.skip(1),
Repeat::Off if now.song + 1 < SONGS.len() => now.skip(1),
Repeat::Off => now.playing = false,
}
}
}
now.ticking = now.playing;
cx.notify();
now.playing
now.ticking = now.playing;
cx.notify();
now.playing
})
})?;
if !going {
return anyhow::Ok(());
+12 -8
View File
@@ -1,7 +1,9 @@
use std::{path::Path, time::Duration};
use ely_gpui_component::media::{Cue, Scrubber, SubtitleEditor, VideoPlayer, VideoThumbnailStrip};
use gpui::{App, Entity, IntoElement, ParentElement, SharedString, Styled, Window, div, px};
use gpui::{
App, Entity, IntoElement, ParentElement, SharedString, Styled, TaskExt as _, Window, div, px,
};
use crate::{
probe::probe,
@@ -61,13 +63,15 @@ fn tick(state: &Entity<Playback>, window: &mut Window, cx: &mut App) {
.spawn(cx, async move |cx| {
loop {
cx.background_executor().timer(TICK).await;
let going = state.update(cx, |now, cx| {
let step = TICK.mul_f32(now.speed);
now.at = (now.at + step).min(LENGTH);
now.playing &= now.at < LENGTH;
now.ticking = now.playing;
cx.notify();
now.playing
let going = cx.update(|_, cx| {
state.update(cx, |now, cx| {
let step = TICK.mul_f32(now.speed);
now.at = (now.at + step).min(LENGTH);
now.playing &= now.at < LENGTH;
now.ticking = now.playing;
cx.notify();
now.playing
})
})?;
if !going {
return anyhow::Ok(());
+1 -3
View File
@@ -24,9 +24,7 @@ pub fn later<T: 'static>(state: &Entity<T>, value: T, wait: Duration, cx: &mut A
let state = state.clone();
cx.spawn(async move |cx| {
cx.background_executor().timer(wait).await;
if let Err(error) = cx.update(|cx| set(&state, value, cx)) {
log::error!("gallery: the demo closed before its answer: {error:#}");
}
cx.update(|cx| set(&state, value, cx));
})
.detach();
}
+6 -4
View File
@@ -23,11 +23,13 @@ pub fn animated_number(window: &mut Window, cx: &mut App) -> impl IntoElement +
_task: cx.spawn_in(window, async move |ticker, cx| {
loop {
cx.background_executor().timer(STEP).await;
let advanced = ticker.update(cx, |ticker: &mut Ticker, cx| {
ticker.index = (ticker.index + 1) % VALUES.len();
cx.notify();
let advanced = cx.update(|_, cx| {
ticker.update(cx, |ticker: &mut Ticker, cx| {
ticker.index = (ticker.index + 1) % VALUES.len();
cx.notify();
})
});
if advanced.is_err() {
if advanced.and_then(|inner| inner).is_err() {
return;
}
}