Skip to content

Sync with zed 08cbb88 - #87

Merged
huacnlee merged 28 commits into
mainfrom
sync/zed-08cbb88
Oct 26, 2026
Merged

huacnlee merged 28 commits into
mainfrom
sync/zed-08cbb88

Conversation

@huacnlee

Copy link
Copy Markdown
Member

Important

Merge with a merge commit, never squash. The vendor commits must land in main's history, or the next sync's merge base falls back to the first import. Enable "Allow merge commits" in the repository settings before merging.

Range

zed b4ecc45422..08cbb88a15: 118 commits, 26 touching tracked crates, replayed one-per-commit on upstream/zed-08cbb88 (vendor commit 63cebdecae). No crates added or removed; window composition (zed#62379) still unmerged upstream.

Notable upstream changes

  • ScrollWheelEvent → ScrollEvent (PlatformInput::Scroll, new source field); iOS back gesture + trackpad scrolling
  • list: scroll state rewritten around ScrollAnchor, provisional measurements (set_item_measurement_readiness)
  • Taffy 0.13 → 0.15
  • Font resolution cache (CachedFont)
  • gpui_macos migrated from cocoa/objc to objc2
  • Keystroke display per platform, credentials write-if-absent, path normalization

Conflicts and ports

  • div.rs: renamed listener field + new back_gesture_listeners, both kept as fast::interactivity::LazyVec.
  • list.rs: took upstream's anchor code, re-applied our hooks (layout_as_list_item, keeps_row, begin_list/end_list, version bumps). fast::dependencies / fast::layers::lists read scroll_anchor (new StateInner::scroll_pending: pending adjustment, provisional or pending end). ScrollAnchor/PendingScroll are pub(crate); to keep elements' globs unambiguous, elements/mod.rs re-exports div::ScrollAnchor explicitly (public API unchanged).
  • taffy.rs: upstream now does what fast::layout::MeasuredTaffy did; wrapper removed, measure tally folded into MeasureTally::measured to stay within taffy.rs's budget. The API-difference entry for Taffy in docs/upstream-sync.md is gone.
  • text_system.rs: our resolve_font hook kept; fast::text now uses upstream's cache and falls back to upstream's resolve_font_uncached. To satisfy upstream's new caches_resolved_font_fallbacks test, fallbacks now keep the requested features (tabular digits) but take upstream's plain weight/style.
  • gpui_macos/window.rs: hooks re-applied on the objc2 code; gpui_macos/src/fast/composition.rs ported to objc2.
  • Redirect (fast/bounds_tree.rs) and removed= files: no upstream changes to port.

Cargo

Root Cargo.toml: taffy =0.15.0, proptest 1.12.0, zed's objc2-app-kit / objc2-foundation / objc2-ui-kit feature lists.

Verification

  • script/check-upstream: 0 violations, no budget changes
  • cargo check --workspace --all-targets: clean except pre-existing gpui_wgpu lib-test error (rounded_clip_tests gated on test-support, unchanged files)
  • cargo clippy --workspace --all-targets: only pre-existing warnings (upstream FrameDirtyAccumulator private interface, gpui_apple build script on Linux), same as main
  • cargo test -p gpui --features test-support: 744 passed
  • cargo test -p gpui_perf -p util -p path -p gpui_linux: pass
  • cargo build -p gpui_perf --release --examples: ok
  • macOS: gpui_macos lib + tests type-check for aarch64-apple-darwin from Linux (shader file stubbed); not built or run on a Mac — please smoke-test composition there.

Follow-up

Upstream's set_item_measurement_readiness keeps measurements provisional until the app signals readiness; view retention may skip re-laying out such a list until it's notified. Nothing we know of uses this API yet.

🤖 Generated with Claude Code

SomeoneToIgnore and others added 28 commits October 19, 2026 14:16
Closes zed-industries/zed#65618

Release Notes:

- [GPUI] N/A

Upstream-commit: zed-industries/zed@febcb5b
## Summary

I think we are getting closer to fully making `PathStyle` a mirrored,
cross-platform counterpart to `Path` on top of #65782. Before the final
step — a separate change focused solely on the `join_path`-related
methods — this PR clears up the remaining odds and ends and removes the
leftover helpers from the `path` crate.

The `normalize_path` function is moved to `crates/util/src/paths.rs`, as
it has no cross-platform behavior, so `util` is a more appropriate home
for it.

`PathStyle::split()` is removed. Its functionality can be replaced by
`PathStyle::file_name()` plus stripping the file name from the original
path, and since there is only one caller, the migration is
straightforward.

## Testing

Mostly a refactor. For the only caller of `PathStyle::split()`, the
multi-buffer header, I manually tested that the header still renders the
file name and parent directory correctly.

## Self-review

- [x] I've reviewed my diff for quality, security, reliability, and
performance.
- [x] UI changes follow the
[checklist](https://zed.dev/docs/development/ui-checklist).
- [x] Tests cover the new or changed behavior.

Release Notes:

- N/A

Upstream-commit: zed-industries/zed@042e040
…olling on iOS (#65805)

Scrolling in GPUI comes from mouse wheels and trackpads reported by the
OS, and from touch pans that GPUI recognizes itself. All of them arrived
as `ScrollWheelEvent`, and handlers had no way to tell a finger pan from
anything else.

## API change

- `ScrollWheelEvent` → `ScrollEvent`, with a new `source: ScrollSource`
field.
- `ScrollSource` has two variants:
- `Pointer` (the default): a scroll the platform reported from a mouse
wheel or trackpad. `ScrollDelta::precise()` still tells continuous
devices apart from wheel notches.
- `Touch`: a finger pan recognized by GPUI, including its synthesized
momentum.
- `on_scroll_wheel` → `on_scroll`.
- `PlatformInput::ScrollWheel` → `PlatformInput::Scroll`.

### Compatibility

Existing app code keeps compiling: `ScrollWheelEvent` and
`on_scroll_wheel` remain as deprecated aliases. Two things still need
changes:
- Platform backends must switch to `PlatformInput::Scroll`. Rust can't
alias an enum variant.
- `ScrollEvent` literals that list every field must add `source`.
Literals using `..Default::default()` get `ScrollSource::Pointer`.

## Trackpad and mouse-wheel scrolling on iOS

`gpui_ios` previously handled only raw touches, so trackpads and mice on
iPad couldn't scroll. The backend now adds a `UIPanGestureRecognizer` to
the Metal view that accepts all scroll types and sends each step as a
`ScrollEvent` with the pointer position and modifiers.

The recognizer has an empty `allowedTouchTypes` and
`cancelsTouchesInView = false`. That way it never claims finger touches,
which keep going to `touchesBegan` and GPUI's touch recognizer.

UIKit ends these gestures when the fingers lift and leaves momentum to
the app. So for now a trackpad scroll on iOS stops when the fingers
lift, without the post-release glide that native views have.

## Verification

Done on Linux:
- `cargo test -p gpui --features test-support --lib -- gestures list::
scroll`: 72 passed.
- `./script/clippy -p gpui -p gpui_linux`: clean.
- `cargo clippy` for `gpui_ios` (`aarch64-apple-ios`) and `gpui_macos`
(`aarch64-apple-darwin`): clean.
- `cargo check -p gpui_web` (`wasm32-unknown-unknown`): clean.
- A temporary downstream-style test confirmed that code using
`ScrollWheelEvent` and `.on_scroll_wheel(...)` still compiles and
receives scrolls.

Not verified:
- **Windows:** wasn't type-checked locally, because `gpui`'s build
script needs the Windows resource compiler. CI covers it.
- **iOS behavior:** trackpad and wheel scrolling on an iPad hasn't been
tried. Specifically unconfirmed: scroll direction under natural
scrolling, and that finger pans don't also trigger the scroll
recognizer.

Release Notes:

- [GPUI] Renamed `ScrollWheelEvent` to `ScrollEvent` and
`on_scroll_wheel` to `on_scroll` (old names remain as deprecated
aliases), added `ScrollEvent::source` to distinguish pointer scrolling
from GPUI-recognized touch pans, and added trackpad and mouse-wheel
scrolling on iOS

---------

Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>

Upstream-commit: zed-industries/zed@e39fb7c
## Summary

Forward iOS Universal Links through the existing
`Application::on_open_urls` callback, without adding a new public API.

- Handle browsing-web NSUserActivity values from cold-launch scene
connection options and warm-launch continuation callbacks.
- Preserve URL queries and fragments; ignore unrelated activities and
absent URLs.
- Add a focused delivery/filtering regression test.

## Scope

This PR is iOS-only. macOS support, request metadata, callback
deprecation, and buffering redesign are intentionally out of scope.
Domain association and signing configuration remain application
responsibilities.

## Validation

- Simulator-target library compilation passed.
- Built the library test binary for aarch64-apple-ios-sim and ran the
focused regression test inside the iOS simulator: passed.
- rustfmt check for application.rs and git diff --check passed.
- Built a GPUI example with temporary callback logging. Hosted a
synthetic association file via a temporary HTTPS tunnel; Apple CDN
retrieved the expected file.
- A separate UIKit test app used openURL with universalLinksOnly to
exercise actual OS routing, not direct callback injection.
- iOS 18.6: cold and warm URLs delivered with query/fragment preserved,
same receiver PID 58259. An excluded /join/stable path returned false.
- iOS 27: cold and warm URLs delivered with query/fragment preserved,
same receiver PID 58368.
- Temporary instrumentation removed; HTTPS servers and tunnel stopped.

### Test setup findings and limits

Device-style entitlements on the ad-hoc simulator code signature caused
process launch failures. Embedding simulator entitlements in
__TEXT,__entitlements while retaining plain ad-hoc signing allowed
launch.

Localhost developer-mode association downloaded and was approved, but
the localhost open still failed; that setup issue is not resolved.
Successful end-to-end tests used the HTTPS tunnel and normal association
mode. No manual Safari tap, physical-device/TestFlight test, production
delta.dev deployment, or Delta thread-navigation test is claimed.

Release Notes:

- [GPUI] Added iOS Universal Link delivery through the existing
incoming-URL callback.

---------

Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>

Upstream-commit: zed-industries/zed@2c626b3
Two iOS features for GPUI apps that draw their own navigation and
sheets.

## Display corner radii

Content near a rounded display edge should round its corners
concentrically with the display's, as native iOS sheets do. GPUI apps
had no way to know the display's corner radius.

- **API:** `WindowInsets` gains `corner_radii: Corners<Pixels>`, zero
where corners are square or the platform can't tell. Updates arrive
through the existing `on_insets_changed` callback.
- **iOS 26+:** the Metal view, which fills the window, gets a
container-concentric `cornerConfiguration`, and
`effectiveRadiusForCorner:` reports the radius UIKit resolved. This only
sets the layer's corner radius; without `masksToBounds` the drawable
isn't clipped.
- **Earlier iOS and other platforms:** zero. The view's
`respondsToSelector` check skips the configuration on older iOS; the
private `_displayCornerRadius` is deliberately not used.

## `on_back_gesture`

This listener fires only for back-navigation *gestures*, not for every
back input such as the mouse back button or Alt+Left, which is why the
name includes "gesture".

```rust
div().on_back_gesture(cx.listener(|this, event: &BackGestureEvent, window, cx| match event.phase {
    BackGesturePhase::Started | BackGesturePhase::Progressed => { /* follow event.progress */ }
    BackGesturePhase::Committed => { /* go back */ }
    BackGesturePhase::Cancelled => { /* snap back */ }
}))
```

- **`BackGestureEvent`:** `phase` (`Started`, `Progressed`, `Committed`,
`Cancelled`), `start_position`, and `progress` from 0 to 1.
- **Dispatch:** positional, like `TouchDragEvent`. The innermost element
with `on_back_gesture` under the start position claims the gesture, and
every later phase is delivered at the same position. If no element
claims it, the platform doesn't start the gesture.
- **iOS:** a `UIScreenEdgePanGestureRecognizer` on the leading edge (the
right edge in right-to-left layouts). Its delegate offers `Started` to
GPUI and only lets the gesture begin when an element claims it, so
without an `on_back_gesture` listener an edge swipe stays an ordinary
pan. On release it commits past halfway or on a fast flick, like
`UINavigationController`.
- **Other platforms:** no source yet. Touchpad swipes (macOS swipe
tracking, libadwaita-style two-finger swipes) and Android predictive
back can produce the same event later.

## Verification

- `back_gesture_is_claimed_by_the_innermost_listener`: nested listeners,
innermost claims, unclaimed returns not-default-prevented.
- `./script/clippy -p gpui` and `cargo clippy -p gpui_ios --target
aarch64-apple-ios -- --deny warnings`: clean. 44 gesture tests pass.
- iOS simulators, with `gpui_ios`'s example app and real touches through
DeviceHub:
- **Corner radii:** iPhone 17 / iOS 27 reports 62 pt on every corner,
and pixel checks show rendering isn't clipped. iPhone 16 / iOS 18.6
reports zero and runs normally.
- **`on_back_gesture`:** a long edge swipe commits at 0.73, a short slow
one cancels at 0.15, and a fast 90 pt flick commits at 0.20. Mid-screen
swipes and taps are unaffected. Without a listener, the same edge swipe
scrolls normally.

Not verified: a physical device, iPad (Stage Manager window corners,
trackpad back swipe), and right-to-left layouts.

Release Notes:

- [GPUI] Added `WindowInsets::corner_radii`, reporting the display's
corner radii on iOS 26 and later
- [GPUI] Added `on_back_gesture` and `BackGestureEvent` for
back-navigation gestures, recognized on iOS from the leading screen edge

Upstream-commit: zed-industries/zed@c4a82ab
…Style` (#65782)

## Summary

Follow-up to #64149 and an intermediate step toward the composable join
API discussed in
zed-industries/zed#63102 (comment).

This PR removes the handwritten `PathStyle::normalize()` and migrates
its call sites, then introduces two new methods:
`PathStyle::normalize_separators()` and
`PathStyle::normalize_lexically()`. `normalize_separators()` collects a
path's components into a `PathBuf` for the target `PathStyle`; the `/`
to `\` rewrite only happens on Windows, and not inside verbatim paths.
`normalize_lexically()` additionally resolves `.` and `..`.

The standard library has no direct equivalent of
`normalize_separators()`. The closest operation is
`Path::components().collect::<PathBuf>()`, but that implementation
pushes each component as a path and corrupts verbatim paths on Windows
(rust-lang/rust#164467). I rewrote the collection in a dedicated
`collect_components()` function that appends each component's raw
`OsStr` with a `PathStyle`-aware separator; `normalize_separators()` is
a thin wrapper around it. It removes redundant and trailing separators
and interior `.` components, and it does not resolve `..`. One thing to
note is that it does not normalize the prefix:
`//server/share/user/project` becomes `//server/share\user\project`.
This is necessary to prevent `//?/` from being transformed into `\\?\`:
`//?/C:` is parsed as `UNC("?", "C:")`, while `\\?\C:` is a verbatim
path with stricter separator rules. It may still be reasonable to
canonicalize other prefixes such as plain UNC or device paths, but that
would need an explicit exception for `//?/`; I kept the simpler
raw-prefix rule for now. Happy to discuss.

`normalize_lexically()` has a counterpart in std
`Path::normalize_lexically()`, but that method is still unstable and
under development. Combining the current std implementation with the
discussion in
rust-lang/rust#134694 (comment),
I implemented `PathStyle::normalize_lexically()` to return `PathBuf`
instead of `Result<PathBuf>`, preserve leading `..` components, and
discard `..` above a root instead of returning an error; this follows
the suggestion in that discussion that `a/../..` should normalize to
`..` rather than error. It mostly matches the old
`PathStyle::normalize()` behavior, with a few intentional differences: a
non-empty path that normalizes to nothing now returns `.` instead of an
empty path, Windows prefixes are preserved as written, `/` is not
treated as a separator inside verbatim paths, and `C:..\worktrees` keeps
`..` instead of collapsing to `C:worktrees`. It also normalizes
separators.

As discussed in
zed-industries/zed#63102 (comment),
although these two methods overlap, they expose different layers of
normalization that callers can opt into on demand. The next step is to
replace the three join helpers (`PathStyle::join`,
`PathStyle::join_path`, and
`PathStyle::join_path_preserving_components`) with a plain
`PathStyle::join` that mirrors `std::path::Path::join`, leaving
separator and lexical normalization as explicit steps that callers
compose.

## Testing

Added tests for both methods across Unix and Windows styles, covering
the scenarios described above.

## Self-review

- [x] I've reviewed my diff for quality, security, reliability, and
performance.
- [x] UI changes follow the
[checklist](https://zed.dev/docs/development/ui-checklist).
- [x] Tests cover the new or changed behavior.

Release Notes:

- N/A

Upstream-commit: zed-industries/zed@a4a3a96
Record where each app borrow group begins and include that location when
a conflicting borrow panics, helping investigate
[DELTA-SITE-6J](https://zed-dev.sentry.io/issues/7801086851/) without
capturing stacks or adding per-borrow logging. Includes coverage for
overlapping shared borrows and recovery after unwinding; the focused
test and Wasm compile check pass. Runtime overhead has not been
benchmarked.

Release Notes:

- [GPUI] Improved app borrow panic diagnostics to include the
conflicting borrow origins.

Upstream-commit: zed-industries/zed@d94887e
Adds an `extension` value to `project_panel.sort_order` so files with
the same extension appear consecutively.

- Files are grouped by lowercased last extension in ascending order
(`foo.tar.gz` groups under `gz`).
- Extensionless files and dotfiles come first.
- Within a group, names use the existing natural sort.
- `sort_mode` still controls directories vs. files. Directories count as
having no extension so `mixed` mode keeps a consistent (transitive)
ordering.

Includes unit tests in `util`, a panel-level test, a benchmark entry,
and settings/docs updates.

Release Notes:

- Added an `extension` option to `project_panel.sort_order` that groups
files by extension

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: Kirill Bulatov <mail4score@gmail.com>

Upstream-commit: zed-industries/zed@d7adf3e
Use typed NSEvent bindings, objc2 Carbon object pointers, and a
null-safe NSString conversion.

Keep the legacy string conversion and cast the two window event call
sites until window bindings migrate.

Release Notes:

- [GPUI] Migrated macOS keyboard and event bindings to objc2

Upstream-commit: zed-industries/zed@0a9eb81
Use retained NSScreen objects and objc2 main-thread checks while
preserving refresh-rate and display-bounds fallbacks.

Release Notes:

- [GPUI] Migrated macOS display and display-link bindings to objc2

Upstream-commit: zed-industries/zed@cb1937a
Use typed pasteboards and retained Foundation objects while preserving
clipboard formats and metadata.

Cover embedded NUL and Unicode text and autorelease lifetimes.

Release Notes:

- [GPUI] Migrated macOS clipboard bindings to objc2

Upstream-commit: zed-industries/zed@e83f1c9
## Summary

Opening an agent thread previously materialized parsed Markdown for
message and tool-output blocks before those blocks were laid out,
including blocks far off-screen.
Parsed Markdown can retain events, per-code-block syntax highlights, and
rasterized Mermaid diagrams.

The original debug-build profiling with two large threads open
attributed approximately 295 MiB to `markdown`, with individual
assistant or tool blocks accounting for tens of MiB.
The profiling figures below are from the original measurements and were
not rerun during the final review.

The thread view uses a virtualized `gpui::list` (`ListState`), but
layout also includes overdraw and can include focused off-screen rows.
Previously, parsing started at entity creation in `acp_thread`,
independently of list layout.

With `MarkdownOptions::defer_parsing`, `Markdown` records the source
without parsing until one of these occurs:

- `MarkdownElement::request_layout` lays out the block.
- `Markdown::ensure_parsed(cx)` is called explicitly.

While deferred, source updates through `append` and `reset` do not start
parsing.
Once parsing starts, later source updates parse normally, including when
the block is off-screen.
This is one-time lazy activation, not eviction of previously parsed
blocks.

`acp_thread` enables deferral for message content created through
`ContentBlock::create_markdown`, including assistant and tool messages
and compaction summaries, and for tool-call raw input and output.
Tool-call labels and error text remain eager.

The numbered `read_file` output bypasses `MarkdownElement` to draw its
own gutter.
Its `RenderOnce` component now calls `ensure_parsed` before reading the
code-block language for highlighting.
Raw source remains available before parsing for search, copy/export, and
content-visibility checks.

Restoring a thread applies its saved scroll position before deferred
Markdown has finished measuring.
`ListState::set_item_measurement_readiness` lets the thread report
pending Markdown parsing and Mermaid rendering, including compaction
summaries and errors.
The list preserves scroll intent while measurements remain provisional.
Leading overdraw stops at the first unready preceding row rather than
traversing the entire zero-height prefix.
Search autoscroll also waits for parsing and Mermaid rendering to
finish.

## Original memory measurements

The original before/after heap profiles used uncapped dumps of the same
view: two large threads and one expanded tool card.

|                                          |    Before |     After |
| ---------------------------------------- | --------: | --------: |
| `markdown` category                      | 273.7 MiB | 109.5 MiB |
| Parsed events (`start_background_parse`) | 213.0 MiB |  11.0 MiB |

Deferred blocks that have not been laid out or explicitly activated do
not retain a parsed representation.
Raw source remains available, and blocks that have already been parsed
are not evicted merely because they leave the viewport.

Companion PR: #65444.

## Testing

- Agent UI library suite: 519 passed.
- Three scroll-restoration regressions across 20 scheduler seeds each:
60 successful runs.
- GPUI list tests: 36 passed.
- Focused Markdown/Mermaid tests: 21 passed.
- ACP compaction regression: passed.
- Five regression assertions fail with the corresponding fixes removed.
- Two adapted controls fail on main with production code unchanged.
- Scoped `rustfmt` and `git diff --check` passed.

Validation used isolated Cargo build artifacts and `INPUTRC=/dev/null`
for the agent-UI suite.
Interactive visual behavior was not manually validated during this
review.

Release Notes:

- Improved agent panel memory usage by parsing thread message Markdown
on first layout instead of at thread load.
- [GPUI] Added `ListState::set_item_measurement_readiness` to preserve
scroll intent while asynchronously measured list items settle.

---------

Co-authored-by: Kirill Bulatov <kirill@zed.dev>
Co-authored-by: Kirill Bulatov <mail4score@gmail.com>

Upstream-commit: zed-industries/zed@f41ac64
Updates Taffy from 0.13 to 0.15. Upstream reports roughly 60% faster
grid layout and 15% faster flexbox layout, alongside layout caching
improvements and fixes to sizing, alignment, and absolute positioning.
This adapts GPUI to the updated measurement and alignment APIs while
retaining its explicit relative-positioning default; performance
improvements have not been benchmarked in Zed.

Validation: All 469 existing GPUI library tests passed with `corgi test
-p gpui --lib -F gpui_platform/runtime_shaders`; formatting and diff
checks passed. Runtime shaders were enabled to bypass a local Metal
compiler failure.

Release Notes:

- [Gpui] Update taffy version

Upstream-commit: zed-industries/zed@b488c4e
## Summary

The `window_positioning` example opens nine popups on each display, but
five of them (Top Left, Top Center, Left Center, Right Center and Bottom
Center) work out their position from `(0, 0)` or from the display's size
instead of from the display's bounds. That works on the primary display,
but on any other display those spots end up off the display. On Windows,
gpui then falls back to the default bounds, so those popups open
display-sized instead of where they should be.

This changes those five to use `screen.bounds()` (`origin`, `left()`,
`right()`, `top()`, `bottom()`), like the other four already do. Only
the example is changed.

Screenshots of both displays, primary on the left. Both builds have
#65002 applied, since without it the popups on the 100% display come out
the wrong size, which gets in the way of the comparison.

**Before**

<img width="1000" alt="zed-window-positioning-before"
src="https://github.com/user-attachments/assets/4707993d-efb9-4d15-95ac-8433c61d4a0f"
/>

**After**

<img width="1000" alt="zed-window-positioning-after"
src="https://github.com/user-attachments/assets/ebbaea7c-ef82-4512-9522-921e9fe5fd99"
/>

In the before shot the second display is mostly black because Right
Center opened display-sized on top of the others. Its label shows it
asked for `940, 412.5` and got `2560, -4` at 1440x900.

## Testing

Windows 11 (build 26300), a 2560x1600 primary display at 150% and a
1440x900 display at 100% to its right. I ran the example before and
after and checked where each popup ended up on its display:

- Displays aligned at the top: 6 of 9 popups in place on the second
display before, 9 of 9 after.
- Second display moved 696px down: 4 of 9 before (and Bottom Center sits
partly above the display), 9 of 9 after.
- Primary display: 9 of 9 in every run.

`cargo fmt` and `cargo clippy -p gpui --example window_positioning --
--deny warnings` pass. I haven't tried macOS or Linux, but nothing in
the change is platform-specific.

## Self-review

- [x] I've reviewed my diff for quality, security, reliability, and
performance.
- [x] UI changes follow the
[checklist](https://zed.dev/docs/development/ui-checklist). (No UI
changes in Zed, only a gpui example.)
- [ ] Tests cover the new or changed behavior. (The examples have no
automated tests. I tested it by hand on two displays, see Testing.)

I used Claude to help investigate this and write the change. I've
reviewed it and understand it.

Release Notes:

- [GPUI] N/A

Upstream-commit: zed-industries/zed@0a39cdb
Closes zed-industries/zed#65777

Release Notes:

- [GPUI] Fixed font lookup causing performance issues

Upstream-commit: zed-industries/zed@3389d87
Migrate application delegates, menus, platform services, and retained
AppKit objects while preserving checked ivar access.

Kept legacy window string allocation and an appearance pointer cast
until the window migration (next PR).

Release Notes:

- [GPUI] Migrate macOS application and menu bindings to objc2

---------

Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com>

Upstream-commit: zed-industries/zed@d86aa6e
Migrate window classes, callbacks, native geometry, ownership, and
appearance handling to objc2.

Remove the temporary legacy adapters and the now-unused objc and cocoa
dependencies.

Release Notes:

- [GPUI] Migrate macOS window and appearance bindings to objc2

Upstream-commit: zed-industries/zed@10cfb45
Reuse a thread-local `Option<MainThreadMarker>` for platform creation,
display queries, and display-link assertions.

Preserve background-thread rejection and cache both successful and
unsuccessful checks.

An instrumented standalone check observed one pthread_main_np call per
thread across repeated main-thread and worker-thread lookups; the
uncached implementation failed with 1000 calls.

Release Notes:

- [GPUI] Cache macOS main-thread checks per thread.

Upstream-commit: zed-industries/zed@2d6c664
This introduces a new PlatformInfo abstraction that allows querying a
gpui app's platform from runtime facts.
This is necessary for correctness when dealing with web applications, as
their host platform there is a runtime fact, not a compile time fact.

Release Notes:

- [GPUI] Fixed platform-dependent modifiers and keybinding parsing and
formatting in web applications by querying the host operating system at
runtime.

Upstream-commit: zed-industries/zed@389c22e
AppKit can return nil from `+[NSOpenPanel openPanel]` despite its
nonnull annotation. The generated objc2 binding treats that as a fatal
Rust panic, crashing the application before callers can handle the
failure. So far we have seen 134 crashes in stable Zed.

Use nullable retained return values for the open and save panel factory
messages. If panel creation fails, return a descriptive error through
the existing result channel. Zed workspace callers already display these
errors and fall back to the built-in picker.

Closes ZED-C1J
Closes ZED-C15
Closes ZED-CAR

Release Notes:

- [GPUI] Fixed a crash when macOS fails to create a native open or save
dialog.

Upstream-commit: zed-industries/zed@9f305aa
On macOS and iOS, `read_credentials()` returned same value both when no
credentials were saved and when the user cancelled the Keychain access
prompt. Callers treated a cancelled prompt as missing credentials and
stored new ones, which can overwrite a shared secret such as an
encryption key.

The fix is to return `KeychainError::UserCanceled` instead. This matches
Linux, where a dismissed unlock prompt is already an error. Existing Zed
callers already treat read errors as missing credentials, so their
behavior is unchanged.

Release Notes:

- [GPUI] Fixed a cancelled macOS Keychain prompt being reported as
missing credentials

Upstream-commit: zed-industries/zed@abd9b3c
Apps that keep a shared secret in the system keychain, such as an
encryption key, create it on first use. With only `read_credentials` and
`write_credentials`, two processes can both find no secret, and the
second write then replaces the first. Data encrypted with the replaced
secret can no longer be read.

Add `write_credentials_if_not_exists`, which returns `true` if it wrote
the credentials and `false` if they already existed. It never replaces
an existing secret.

On macOS this is a single atomic `SecItemAdd`: an existing item with the
same URL and username makes it return `false`. Other platforms and
providers get a default that reads and then writes. That default never
overwrites credentials it can see, but two concurrent callers can still
race. A failed read, including a cancelled Keychain prompt, never
writes.

`write_credentials` keeps its update behavior.

Release Notes:

- [GPUI] Added `write_credentials_if_not_exists`, which never replaces
existing credentials and is atomic on macOS

Upstream-commit: zed-industries/zed@79fe6a6
## Summary

Fix Windows file links into WSL projects, including Agent links and `zed
path:line`. Preserve the original path prefix in
`PathWithPosition::parse_str` instead of rebuilding it with the host
platform's separator.

Closes #65323. Fixes a regression introduced in #64748.

Windows regression test output before the fix:

```text
 left: "/home/user/project/src\\main.rs"
right: "/home/user/project/src/main.rs"
```

The test passes after the fix. It compares raw `OsStr` values because
Windows `Path` equality hides separator differences.

## Testing

- Manually tested the patched Windows client connected to WSL: clicking
the previously failing Agent link opens the correct file as expected.
- Verified that the development CLI opens `llm_engine.py:49:7` at line
49, column 7 in the Windows GUI.
- Utility tests: **122 passed** on Linux; path-position tests: **7
passed** with each Windows GNU/MSVC target.
- Windows client, CLI, and matching WSL server builds passed, along with
Clippy, formatting, and `git diff --check`.

To verify, connect a patched Windows client to a WSL project. Have the
Agent produce a Markdown link to an existing file using its absolute WSL
path with `:line` or `:line:column`. Click it and verify the file and
cursor position. Also check the same path through the matching
development CLI.

## Self-review

- [ ] I've reviewed my diff for quality, security, reliability, and
performance.
- [ ] UI changes follow the
[checklist](https://zed.dev/docs/development/ui-checklist). (N/A: no
visual changes.)
- [x] Tests cover the new or changed behavior.

Release Notes:

- Fixed file links with line numbers failing to open WSL files when
using Zed on Windows.

---------

Co-authored-by: Kirill Bulatov <kirill@zed.dev>
Co-authored-by: Kirill Bulatov <mail4score@gmail.com>

Upstream-commit: zed-industries/zed@347f171
… (#66097)

Closes zed-industries/zed#65931
Closes zed-industries/zed#66021
Closes zed-industries/zed#66094

Follow-up to zed-industries/zed#65065

Release Notes:

- Fixed pwsh-related issues with local and remote env variables
detection

Upstream-commit: zed-industries/zed@18f9d7e
Merge zed b4ecc45422..08cbb88a15 (26 commits touching tracked crates).

- list.rs: re-apply hooks onto upstream's ScrollAnchor rewrite; fast reads
  the anchor through pub(crate) bumps (div's ScrollAnchor re-exported
  explicitly to keep the elements globs unambiguous)
- taffy 0.15: upstream lays leaves out itself; drop fast::layout::MeasuredTaffy
- text_system: fast fallback resolution sits on upstream's font cache and
  keeps requested font features only
- gpui_macos objc2 migration: port fast::composition to objc2
- ScrollWheelEvent -> ScrollEvent in fast/ and gpui_perf

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gpui-pre predates upstream's ScrollWheelEvent -> ScrollEvent rename, and
the Windows CI links the showcase against it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@huacnlee
huacnlee merged commit 8f332d7 into main Oct 26, 2026
4 checks passed
@huacnlee
huacnlee deleted the sync/zed-08cbb88 branch October 26, 2026 03:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.