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.
This commit is contained in:
ZacharyZhang-NY committed 2026-09-28 20:30:17 -04:00
1 parent 25b8a6f22c
commit 4c3ed1bbb9
199 files changed
+2513 -2643

No files matched your search

+5 -3
View File
@@ -1,9 +1,10 @@
use std::{rc::Rc, time::Duration};
use gpui::{
App, Bounds, Corners, DragMoveEvent, ElementId, EmptyView, EntityId, InteractiveElement,
IntoElement, MouseButton, ParentElement, Pixels, Point, RenderOnce, StatefulInteractiveElement,
Styled, Window, canvas, div, fill, point, prelude::*, relative, size, transparent_black,
App, Bounds, Corners, DragMoveEvent, ElementId, EmptyView, EntityId, HoverListenerMode,
InteractiveElement, IntoElement, MouseButton, ParentElement, Pixels, Point, RenderOnce,
StatefulInteractiveElement, Styled, Window, canvas, div, fill, point, prelude::*, relative,
size, transparent_black,
};
use super::scrubber::{OnTime, clock, time_at, time_tip};
@@ -157,6 +158,7 @@ impl RenderOnce for AudioWaveform {
cx.notify();
})
})
.hover_listener_mode(HoverListenerMode::InputModalityIndependent)
.on_hover(move |inside, _, cx| {
if !inside {
left.update(cx, |wave, cx| {
+6 -4
View File
@@ -154,15 +154,17 @@ fn wake(watch: &Entity<Watch>, window: &mut Window, cx: &mut App) {
loop {
let wait = watch.read_with(cx, |watch, cx| {
IDLE.saturating_sub(cx.background_executor().now().duration_since(watch.moved))
})?;
});
if wait.is_zero() {
break;
}
cx.background_executor().timer(wait).await;
}
watch.update(cx, |watch, cx| {
watch.waking = false;
cx.notify();
cx.update(|_, cx| {
watch.update(cx, |watch, cx| {
watch.waking = false;
cx.notify();
})
})
})
.detach_and_log_err(cx);
+5 -4
View File
@@ -1,9 +1,9 @@
use std::{rc::Rc, time::Duration};
use gpui::{
App, Bounds, Div, DragMoveEvent, ElementId, EmptyView, EntityId, InteractiveElement,
IntoElement, MouseButton, ParentElement, Pixels, Point, Rems, RenderOnce, SharedString,
StatefulInteractiveElement, Styled, Window, canvas, div, prelude::*, relative,
App, Bounds, Div, DragMoveEvent, ElementId, EmptyView, EntityId, HoverListenerMode,
InteractiveElement, IntoElement, MouseButton, ParentElement, Pixels, Point, Rems, RenderOnce,
SharedString, StatefulInteractiveElement, Styled, Window, canvas, div, prelude::*, relative,
transparent_black,
};
@@ -183,7 +183,7 @@ impl RenderOnce for Scrubber {
.relative()
.h(line)
.flex_basis(relative(share(end - start)))
.flex_grow()
.flex_grow_1()
.rounded_full()
.bg(lane)
.child(
@@ -275,6 +275,7 @@ impl RenderOnce for Scrubber {
cx.notify();
})
})
.hover_listener_mode(HoverListenerMode::InputModalityIndependent)
.on_hover(move |inside, _, cx| {
if !inside {
left.update(cx, |track, cx| {
+3 -3
View File
@@ -157,7 +157,7 @@ fn a_shaped_crop_keeps_its_shape_as_a_corner_moves(cx: &mut TestAppContext) {
#[gpui::test]
fn a_cropper_with_no_handler_takes_no_tab(cx: &mut TestAppContext) {
let (_, cx) = cropping(HALF, None, false, cx);
cx.update(|window, _| window.focus_next());
cx.update(|window, cx| window.focus_next(cx));
assert!(cx.update(|window, cx| window.focused(cx)).is_none());
}
@@ -226,9 +226,9 @@ fn a_picked_picture_crops_from_a_fitted_box_and_remove_empties_it(cx: &mut TestA
};
let fitted = crop.is_some_and(|crop| near(crop, square));
assert!(fitted && heard == 1, "{crop:?} after {heard}");
cx.update(|window, _| {
cx.update(|window, cx| {
for _ in 0..2 {
window.focus_next();
window.focus_next(cx);
}
});
press("enter", cx);
+3 -3
View File
@@ -247,7 +247,7 @@ fn a_picture_that_cannot_open_says_so(cx: &mut TestAppContext) {
let cx = viewing(std::env::temp_dir().join("ely-media-missing.png"), cx);
assert!(cx.debug_bounds("image-viewer-failed").is_some());
assert!(cx.debug_bounds("image-viewer-picture").is_none());
cx.update(|window, _| window.focus_next());
cx.update(|window, cx| window.focus_next(cx));
let focused = cx.update(|window, cx| window.focused(cx));
assert!(focused.is_none(), "with nothing to show, nothing takes Tab");
}
@@ -284,9 +284,9 @@ fn only_a_thumbnail_with_a_handler_takes_tab_and_opens_on_enter(cx: &mut TestApp
let (_, cx) = cx.add_window_view(|_, _| Strip(seen, path));
cx.update(|window, _| window.activate_window());
settle(cx);
cx.update(|window, _| window.focus_next());
cx.update(|window, cx| window.focus_next(cx));
let first = cx.update(|window, cx| window.focused(cx));
cx.update(|window, _| window.focus_next());
cx.update(|window, cx| window.focus_next(cx));
let wrapped = cx.update(|window, cx| window.focused(cx));
assert!(
first.is_some() && first == wrapped,
+3 -3
View File
@@ -59,10 +59,10 @@ pub(super) fn across(
/// Moves focus to the `nth` Tab stop from none.
pub(super) fn tab_to(nth: usize, cx: &mut VisualTestContext) {
cx.update(|window, _| {
window.blur();
cx.update(|window, cx| {
window.blur(cx);
for _ in 0..nth {
window.focus_next();
window.focus_next(cx);
}
});
settle(cx);
+8 -8
View File
@@ -97,10 +97,10 @@ fn watching(cx: &mut TestAppContext) -> (Entity<Watching>, &mut VisualTestContex
#[gpui::test]
fn space_on_a_focused_bar_button_presses_it_once(cx: &mut TestAppContext) {
let (view, cx) = watching(cx);
cx.update(|window, _| {
window.blur();
cx.update(|window, cx| {
window.blur(cx);
for _ in 0..3 {
window.focus_next();
window.focus_next(cx);
}
});
press("space", cx);
@@ -145,7 +145,7 @@ fn a_long_caption_wraps_inside_a_narrow_player(cx: &mut TestAppContext) {
#[gpui::test]
fn a_caption_stays_while_the_controls_rest(cx: &mut TestAppContext) {
let (view, cx) = watching_at(480.0, "Light falls on the stair", true, cx);
cx.update(|window, _| window.blur());
cx.update(|window, cx| window.blur(cx));
view.update(cx, |view, cx| {
view.playing = true;
cx.notify();
@@ -181,7 +181,7 @@ fn space_plays_l_and_j_jump_ten_seconds_and_c_turns_captions(cx: &mut TestAppCon
#[gpui::test]
fn controls_rest_once_the_pointer_is_still_while_it_plays(cx: &mut TestAppContext) {
let (view, cx) = watching(cx);
cx.update(|window, _| window.blur());
cx.update(|window, cx| window.blur(cx));
view.update(cx, |view, cx| {
view.playing = true;
cx.notify();
@@ -203,7 +203,7 @@ fn controls_rest_once_the_pointer_is_still_while_it_plays(cx: &mut TestAppContex
/// Rests a playing player's bar, focus outside it and the pointer still at `spot`.
fn rest(spot: Point<Pixels>, view: &Entity<Watching>, cx: &mut VisualTestContext) {
cx.update(|window, _| window.blur());
cx.update(|window, cx| window.blur(cx));
view.update(cx, |view, cx| {
view.playing = true;
cx.notify();
@@ -244,7 +244,7 @@ fn shift_tab_into_a_resting_bar_keeps_focus_on_its_last_button(cx: &mut TestAppC
let (view, cx) = watching(cx);
let frame = cx.debug_bounds("video-player").expect("the player draws");
rest(frame.center(), &view, cx);
cx.update(|window, _| window.focus_prev());
cx.update(|window, cx| window.focus_prev(cx));
settle(cx);
press("enter", cx);
assert_eq!(view.read_with(cx, |view, _| view.fullscreens), 1);
@@ -288,7 +288,7 @@ fn the_bar_stays_up_while_a_button_in_it_has_focus(cx: &mut TestAppContext) {
let (_, cx) = cx.add_window_view(|_, _| Paced { path });
cx.update(|window, _| window.activate_window());
settle(cx);
cx.update(|window, _| window.focus_next());
cx.update(|window, cx| window.focus_next(cx));
settle(cx);
cx.executor().advance_clock(Duration::from_millis(2600));
settle(cx);
+3 -3
View File
@@ -250,10 +250,10 @@ fn captioning_at<'a>(
/// Tabs to the `nth` stop and types over it.
fn retype(nth: usize, text: &str, cx: &mut VisualTestContext) {
cx.update(|window, _| {
window.blur();
cx.update(|window, cx| {
window.blur(cx);
for _ in 0..nth {
window.focus_next();
window.focus_next(cx);
}
});
press("enter", cx);