Closes https://github.com/zed-industries/zed/issues/37621
Improves https://github.com/zed-industries/zed/issues/24623
Adding scrollbars withing Zed's UI currently is rather cumbersome, as it
requires the copying of a lot of code in order for these to work. Wiring
up settings for scrollbar visibilty always has to be done at the call
site and the state has to be saved and maintained by the caller as well.
Similarly, reserving space has to also be handled by the caller.
This PR changes the way scrollbars work in Zed fundamentally by making
use of the new `use_keyed_state` APIs: Instead of saving the state at
the call site, the window now keeps track of the state corresponding to
scrollbars. This enables us to add scrollbars with e.g. one simple call
on divs:
```rust
div()
.vertical_scrollbar(window, cx)
```
will add a scrollbar to the corresponding container. There are some more
improvements regarding tracking of scrollbar visibility settings (which
is now handled by a trait for each setting that supports this) as well
as reserving space.
Additionally, all needed stuff for layouting, catching events and
reserving space is also now managed by the scrollbar component instead.
This drastically reduces the amount of event listeners and makes
layouting of two scrollbars easier.
Furthermore, this paves the way for more improvements to scrollbars,
such as graceful auto-hide. Only downsight here is that we lose some
customizability in a few areas. However, once this lands, we gain the
ability to quickly follow these up without breaking stuff elsewhere.
This also already fixes a few bugs:
- Scrollbars no longer flicker on first render.
- Auto-hide now properly works for all scrollbars.
- If the content size changes, the scrollbar is updated on the same
frame. Both of these happened because we were computing the scrollbar
sizes too early, causing us to use the sizes from the previous frame or
unitialized sizes.
- The project panel no longer jumps if scrolled all the way to the
bottom and the scrollbar actually auto-hides.
Still TODO:
- [x] Fix scrolling in the debugger memory view
- [x] Clean up some more in the scrollbar component and reduce clones
there
- [x] Ensure we don't over-notify the entity the scrollbar is rendered
within
- [x] Make sure auto-hide properly works for all cases
- [x] Check whether we want to implement the scrollbar trait for
`UniformList`s as well
- ~~ [ ] Use for uniformlist where possible~~ Postponed
- [x] Improve layout for cases where we render both scrollbars.
Release Notes:
- N/A
Follows on from
https://github.com/zed-industries/zed/pull/37716#pullrequestreview-3195695110
by @SomeoneToIgnore
After this the doctests will be run in CI to check that the examples are
still accurate.
Note that doctests aren't run by Nextest: you can run them locally with
`cargo test --doc`.
Summary:
* Run tests from CI
* Loosen an exact float comparison to match approximately (otherwise it
fails)
* Fixed one actual bug in the tests for `dilate` where the test code
assumed that `dilate` mutates `self` rather than returning a new object
* Add some `must_use` on some functions that seemed at risk of similar
bugs, following the Rust stdlib style to add it where ignoring the
result is almost certainly a bug.
* Fix some cases where the doc examples seem to have gone out of date
with the code
* Add imports to doctests that need them
* Add some dev-dependencies to make the tests build
* Fix the `key_dispatch` module docstring, which was accidentally
attached to objects within that module
* Skip some doctest examples that seem like they need an async
environment or that just looked hard to get running
AI usage: I asked Claude to do some of the repetitive tests. I checked
the output and fixed up some things that seemed to not be in the right
spirit of the test, or too longwinded.
I think we could reasonably run the tests on only Linux to save CI
CPU-seconds and latency, but I haven't done that yet, partly because of
how it's implemented in the action.
Release Notes:
- N/A
We've had problems in the past with bumping past 0.5.2 due to perf
regressions reported by @huacnlee; 0.5.1 was fine though.
Hence, let's bump taffy to 0.5.1 as a safe bet and then try to push past
0.5.2 (after we identify the root cause of regression
Related to #19189
Release Notes:
- N/A
Editing JSON styles is not very helpful for bringing style changes back
to the actual code. This PR adds a buffer that pretends to be Rust,
applying any style attribute identifiers it finds. Also supports
completions with display of documentation. The effect of the currently
selected completion is previewed. Warning diagnostics appear on any
unrecognized identifier.
https://github.com/user-attachments/assets/af39ff0a-26a5-4835-a052-d8f642b2080c
Adds a `#[derive_inspector_reflection]` macro which allows these methods
to be enumerated and called by their name. The macro code changes were
95% generated by Zed Agent + Opus 4.
Release Notes:
* Added an element inspector for development. On debug builds,
`dev::ToggleInspector` will open a pane allowing inspecting of element
info and modifying styles.
Open inspector with `dev: toggle inspector` from command palette or
`cmd-alt-i` on mac or `ctrl-alt-i` on linux.
https://github.com/user-attachments/assets/54c43034-d40b-414e-ba9b-190bed2e6d2f
* Picking of elements via the mouse, with scroll wheel to inspect
occluded elements.
* Temporary manipulation of the selected element.
* Layout info and JSON-based style manipulation for `Div`.
* Navigation to code that constructed the element.
Big thanks to @as-cii and @maxdeviant for sorting out how to implement
the core of an inspector.
Release Notes:
- N/A
---------
Co-authored-by: Antonio Scandurra <me@as-cii.com>
Co-authored-by: Marshall Bowers <git@maxdeviant.com>
Co-authored-by: Federico Dionisi <code@fdionisi.me>
There's still a bit more work to do on this, but this PR is compiling
(with warnings) after eliminating the key types. When the tasks below
are complete, this will be the new narrative for GPUI:
- `Entity<T>` - This replaces `View<T>`/`Model<T>`. It represents a unit
of state, and if `T` implements `Render`, then `Entity<T>` implements
`Element`.
- `&mut App` This replaces `AppContext` and represents the app.
- `&mut Context<T>` This replaces `ModelContext` and derefs to `App`. It
is provided by the framework when updating an entity.
- `&mut Window` Broken out of `&mut WindowContext` which no longer
exists. Every method that once took `&mut WindowContext` now takes `&mut
Window, &mut App` and every method that took `&mut ViewContext<T>` now
takes `&mut Window, &mut Context<T>`
Not pictured here are the two other failed attempts. It's been quite a
month!
Tasks:
- [x] Remove `View`, `ViewContext`, `WindowContext` and thread through
`Window`
- [x] [@cole-miller @mikayla-maki] Redraw window when entities change
- [x] [@cole-miller @mikayla-maki] Get examples and Zed running
- [x] [@cole-miller @mikayla-maki] Fix Zed rendering
- [x] [@mikayla-maki] Fix todo! macros and comments
- [x] Fix a bug where the editor would not be redrawn because of view
caching
- [x] remove publicness window.notify() and replace with
`AppContext::notify`
- [x] remove `observe_new_window_models`, replace with
`observe_new_models` with an optional window
- [x] Fix a bug where the project panel would not be redrawn because of
the wrong refresh() call being used
- [x] Fix the tests
- [x] Fix warnings by eliminating `Window` params or using `_`
- [x] Fix conflicts
- [x] Simplify generic code where possible
- [x] Rename types
- [ ] Update docs
### issues post merge
- [x] Issues switching between normal and insert mode
- [x] Assistant re-rendering failure
- [x] Vim test failures
- [x] Mac build issue
Release Notes:
- N/A
---------
Co-authored-by: Antonio Scandurra <me@as-cii.com>
Co-authored-by: Cole Miller <cole@zed.dev>
Co-authored-by: Mikayla <mikayla@zed.dev>
Co-authored-by: Joseph <joseph@zed.dev>
Co-authored-by: max <max@zed.dev>
Co-authored-by: Michael Sloan <michael@zed.dev>
Co-authored-by: Mikayla Maki <mikaylamaki@Mikaylas-MacBook-Pro.local>
Co-authored-by: Mikayla <mikayla.c.maki@gmail.com>
Co-authored-by: joão <joao@zed.dev>
Taffy maintains a mapping of NodeId <-> Context anyways (and does the
lookup), so it's redundant for us to store it separately. Tl;dr: we get
rid of one map and one map lookup per layout request.
Release Notes:
- N/A
Again. https://github.com/zed-industries/zed/pull/4070
Let's see how it goes this time around. The only thing that might've
been related to that revert on our Slack was about crashing in collab
panel.
Release Notes:
- N/A
I noticed a few places where we were storing `&'static str`s in
`static`s instead of `const`s.
This PR updates them to use `const`.
Release Notes:
- N/A
A minor thing I've spotted and decided to fix on the spot.
It was being cloned twice within the body of that function (one of which
was redundant even without this PR); now in most cases we go down from 2
clones to 0.
Release Notes:
- N/A
This pull request introduces the new
`ElementContext::request_autoscroll(bounds)` and
`ElementContext::take_autoscroll()` methods in GPUI. These new APIs
enable container elements such as `List` to change their scroll position
if one of their children requested an autoscroll. We plan to use this in
the revamped assistant.
As a drive-by, we also:
- Renamed `Element::before_layout` to `Element::request_layout`
- Renamed `Element::after_layout` to `Element::prepaint`
- Introduced a new `List::splice_focusable` method to splice focusable
elements into the list, which enables rendering offscreen elements that
are focused.
Release Notes:
- N/A
---------
Co-authored-by: Nathan <nathan@zed.dev>
See https://zed.dev/channel/gpui-536
Fixes https://github.com/zed-industries/zed/issues/9010
Fixes https://github.com/zed-industries/zed/issues/8883
Fixes https://github.com/zed-industries/zed/issues/8640
Fixes https://github.com/zed-industries/zed/issues/8598
Fixes https://github.com/zed-industries/zed/issues/8579
Fixes https://github.com/zed-industries/zed/issues/8363
Fixes https://github.com/zed-industries/zed/issues/8207
### Problem
After transitioning Zed to GPUI 2, we started noticing that interacting
with the mouse on many UI elements would lead to a pretty annoying
flicker. The main issue with the old approach was that hover state was
calculated based on the previous frame. That is, when computing whether
a given element was hovered in the current frame, we would use
information about the same element in the previous frame.
However, inspecting the previous frame tells us very little about what
should be hovered in the current frame, as elements in the current frame
may have changed significantly.
### Solution
This pull request's main contribution is the introduction of a new
`after_layout` phase when redrawing the window. The key idea is that
we'll give every element a chance to register a hitbox (see
`ElementContext::insert_hitbox`) before painting anything. Then, during
the `paint` phase, elements can determine whether they're the topmost
and draw their hover state accordingly.
We are also removing the ability to give an arbitrary z-index to
elements. Instead, we will follow the much simpler painter's algorithm.
That is, an element that gets painted after will be drawn on top of an
element that got painted earlier. Elements can still escape their
current "stacking context" by using the new `ElementContext::defer_draw`
method (see `Overlay` for an example). Elements drawn using this method
will still be logically considered as being children of their original
parent (for keybinding, focus and cache invalidation purposes) but their
layout and paint passes will be deferred until the currently-drawn
element is done.
With these changes we also reworked geometry batching within the
`Scene`. The new approach uses an AABB tree to determine geometry
occlusion, which allows the GPU to render non-overlapping geometry in
parallel.
### Performance
Performance is slightly better than on `main` even though this new
approach is more correct and we're maintaining an extra data structure
(the AABB tree).

Release Notes:
- Fixed a bug that was causing popovers to flicker.
---------
Co-authored-by: Nathan Sobo <nathan@zed.dev>
Co-authored-by: Thorsten <thorsten@zed.dev>
Upgraded Taffy to v0.4.0 from crates.io (previously using prerelease
version from git).
Code changes required were minor as gpui was already using a recent
version of Taffy.
Release Notes:
- N/A
Reverts zed-industries/zed#7481
This would regress performance because we'd be using the standard
library's hash maps everywhere, so reverting for now.