Skip to content

feat: migrate to gpui-kit 0.6 and add Shift+Esc panel zoom - #118

Merged
devnull03 merged 14 commits into
mainfrom
gpui-kit-migration
Sep 8, 2026
Merged

devnull03 merged 14 commits into
mainfrom
gpui-kit-migration

Conversation

@devnull03

@devnull03 devnull03 commented Sep 6, 2026 •

Copy link
Copy Markdown
Owner

Summary

This PR migrates the workspace from gpui-component 0.5.2 to gpui-kit 0.6. It also adds Zed-style panel zoom on Shift+Esc.

The migration uses the crates.io gpui-pre 0.3 line. The current lockfile selects 0.3.3. Cargo treats the old git gpui and registry gpui-pre as different crates, so their GPUI types do not unify. All workspace members must therefore move in one change.

UI stack and dock migration

  • Rename the workspace packages through Cargo's package = support. Existing Rust import paths stay unchanged.
  • Split panel behavior into gpui_base::dock::Panel and presentation into gpui_component::dock::Panel.
  • Port the workspace dock to DockLayout, PaneTree, DockSkin, and panel_handle.
  • Use the library's move_panel and dock toggle operations instead of local state mirrors.
  • Convert multiline editors from InputState::multi_line(true) to TextareaState and Textarea.
  • Remove the obsolete accordion.hover.background theme keys.

Panel zoom

The app binds Shift+Esc to dock::ToggleZoom. Each panel now reports that it supports zoom.

The focused tab group handles the action. Plain Esc keeps its existing grid, panel, and viewer behavior.

Fixes found during migration testing

  • Constrain tool-panel dragging to valid dock targets.
  • Preserve focus across panel moves and viewer transitions.
  • Close the file viewer without reading its GPUI entity during an active update.
  • Create rows from files when a blank project starts from a folder.
  • Keep the blank-folder path compatible with local CSV, TSV, Excel, ODS, and Google Sheet imports from main.
  • Treat untargeted published-GPUI teardown messages as GPUI log records.
  • Demote only the known optional DXGI debug-layer probe error. Real Direct3D failures remain errors.
  • Disable update polling, manual checks, and release-receipt handling in development builds.
  • Add a native PowerShell fetcher for PDFium and ffmpeg on Windows.

Linux development

flake.nix and shell.nix share nix/devshell.nix. The shell supplies GPUI's build and runtime libraries, including Wayland, X11, Vulkan, fontconfig, ALSA, and OpenSSL.

The Zed tasks include Nix wrappers. The standard CI task uses the shared scripts/ci.sh command and its isolated target/ci directory.

Upgrade note

A dock layout that gpui-kit 0.6 cannot deserialize is discarded. The app then uses the default layout. Existing users can see one panel-layout reset after the upgrade.

Verification

The final branch includes the latest main changes and passes the local Windows CI gate:

  • cargo fmt --all --check
  • cargo clippy --workspace --all-targets -- -D warnings -A dead_code
  • cargo test --workspace

Tests cover panel zoom routing, keybinding precedence, blank-folder rows, viewer focus restoration, and reentrant viewer close behavior.

A Windows development launch selected Direct3D 11.1, loaded the embedded Pi runtime, and started its ConPTY process. Final visual verification is pending before merge.

The Copilot review comment about the stale single-line editor comment is resolved.

Open in Delta

Copilot AI lite review requested due to automatic review settings September 6, 2026 20:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It’s a large cross-workspace UI/docking dependency migration with behavioral changes that merits final human verification despite tests passing.

Pull request overview

Migrates qrate’s UI stack and docking system to gpui-kit/gpui-component 0.6 (and gpui-pre), while adding a global Zed-style panel zoom action on Shift+Esc that zooms the currently focused panel/tab group.

Changes:

  • Update workspace dependencies to gpui-pre 0.3 + gpui-component/gpui-kit-assets 0.6, and port docking/panel APIs to the new pane-tree model (BasePanel vs Panel, DockLayout, DockSkin).
  • Convert multi-line editors from InputState::multi_line(true) to TextareaState/Textarea.
  • Add Nix dev-shell entry points (flake.nix, shell.nix, shared nix/devshell.nix) and editor tasks, plus logging filter tweaks to handle untargeted gpui logs.
File summaries
File Description
shell.nix Adds non-flake Nix shell entry point that imports the shared dev shell.
nix/devshell.nix Defines shared build/runtime deps + LD_LIBRARY_PATH for GPUI on Linux/Nix.
flake.nix Adds flake-based devShell using the shared devshell definition.
flake.lock Pins nixpkgs revision for reproducible nix develop.
crates/workspace/src/views/mod.rs Ports center panel to BasePanel/new dock APIs; updates tests for new layout construction.
crates/workspace/src/panels/details.rs Converts field editor to TextareaState; ports panel traits and enables zoom.
crates/workspace/src/panels/agent.rs Ports panel traits and enables zoom.
crates/workspace/src/panel_registry.rs Reworks placement tracking and panel activation using pane-tree APIs and move_panel.
crates/workspace/src/lib.rs Adopts DockSkin::dock_area, DockLayout, and new dock toggling; adds Shift+Esc zoom integration test.
crates/workspace/src/dock_button.rs Updates dock-open checks to new is_dock_open signature.
crates/table/src/panel.rs Migrates cell/note editors to TextareaState + uses Textarea in editor box.
crates/table/src/note.rs Uses Textarea instead of Input for note editing UI.
crates/table/src/delegate.rs Updates editor fields to TextareaState in delegate/state wiring.
crates/settings/src/lib.rs Updates usage of RenderOptions size accessors (size() API drift).
crates/diagnostics/src/panel.rs Ports Problems panel traits and enables zoom.
crates/app/src/logging.rs Treats empty log targets as gpui-emitted to keep teardown noise filtered; adds tests.
crates/app/src/actions.rs Adds global keybinding for dock::ToggleZoom on shift-escape with coverage.
CONTRIBUTING.md Documents Linux deps and Nix-based setup options for GPUI.
Cargo.toml Switches to gpui-pre/gpui-component 0.6 + renamed assets crate via package = renames.
Cargo.lock Locks new dependency graph for gpui-pre/gpui-kit migration.
assets/themes/qrate.json Removes deprecated accordion.hover.background keys.
.zed/tasks.json Adds CI-check tasks and Nix-wrapped variants for Linux/NixOS.
.envrc Enables direnv flake integration (use flake).
Review details
  • Files reviewed: 21/23 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread crates/table/src/delegate.rs Outdated
@@ -64,11 +64,11 @@ pub struct QrateTableDelegate {
pub(crate) selected_rows: BTreeSet<usize>,
pub(crate) editing: EditState,
/// Shared single-line editor, reused across whichever cell is being edited.
devnull03 added a commit that referenced this pull request Sep 6, 2026
The field has been multi-line since long before this branch — `TablePanel`
built it with `.multi_line(true)` — so the comment was already wrong; naming
the type `TextareaState` only made the contradiction visible. Says what it is
and why, since the reason is not obvious from the type: a long value has to
wrap inside the editor box rather than run off its right edge, which is what
`editor_box` sizes for.

Found by Copilot's review on #118.
Measures the cost of the gpui-component 0.5.2 -> 0.6 move. Upstream renamed
the repo to gpui-kit and switched its gpui dependency from zed's git repo to
the crates.io `gpui-pre` snapshot, so `gpui` and `gpui-component` become
different crates to cargo and the whole workspace has to move at once.

Uses cargo's `package =` rename rather than new import paths, so every
existing `use gpui::*` / `use gpui_component::*` keeps resolving and the
compile errors that remain are genuine API drift rather than path churn.

Resolved so far:
- settings: `RenderOptions` fields are private, use the `size()` accessor.
- Panel split into `gpui_base::dock::Panel` (behaviour) and the styled
  `Panel` (presentation); `zoomable` moved to base as `-> bool` and
  `zoom_control` took over the affordance. Splits the four panel impls.
- Multi-line inputs are a type now, not a flag: `InputState.multi_line(true)`
  becomes `TextareaState`, rendered with `Textarea`.

Also enables panel zoom (was uniformly `None`) and binds Shift+Esc to
`dock::ToggleZoom`, which 0.6 mounts on every tab panel's own frame.

Remaining: crates/workspace's dock layer. `DockItem` and the
left/right/bottom dock accessors are gone in favour of base's pane-tree
model. `app` and `project-wizard` are still unmeasured behind it.
The 0.6 dock replaces `DockItem` and the per-side accessors with base's
pane-tree model, so this is a port rather than a rename:

- `DockArea` is built through `DockSkin::dock_area`, which installs the
  component appearance as the area's renderer and hands back the handle its
  settings (the toggle-button visibility) are reached through.
- Layouts are described with `DockLayout` and installed with `set_center` /
  `set_dock` + `set_dock_size`, instead of `DockItem` and `set_*_dock`.
- Panels reach the dock as `panel_handle(entity)`. Base stores what it is
  given and a skin can only recover presentation from the wrapper, so a bare
  entity would draw its `panel_name` where its title belongs.
- `register_panel` builders take a `PanelBuildContext` and return an `Arc`.
- The registry reads placements out of the `PaneTree` rather than tracking
  them by hand, and `move_panel` is now the library's own — which keeps the
  panel alive and carries its active state across, so the `remove_panel` +
  `add_panel` workaround and the stale-snapshot warning both go away.
- `toggle_dock_immediately` is down to a guard plus `DockArea::toggle_dock`,
  which collapses the tree and emits `LayoutChanged` itself.

The whole workspace compiles: `app` and `project-wizard`, unmeasured behind
this crate until now, needed no changes at all.

cargo fmt and cargo clippy -D warnings are clean.
- 0.6 dropped `accordion.hover.background` from `ThemeConfigColors`, so it
  comes out of our own theme. The embedded-theme schema test is what caught
  it — the one key, in the one file that set it. Nothing here draws an
  accordion, so it only ever fed the library's own hover fallback.
- `PanelRegistry::move_panel` gives a dock a tab group before moving into it.
  `move_panel` needs a node to aim at, and a dock that was never built or
  that an earlier move emptied has none; `add_panel_view` would make one but
  does not detach the panel from where it already is.
- A Nix dev shell, shared by `flake.nix` and `shell.nix` through
  `nix/devshell.nix` so the two cannot drift. GPUI links fontconfig, freetype,
  alsa and openssl through pkg-config and dlopens xkbcommon, wayland, vulkan
  and the X11 libraries, so `LD_LIBRARY_PATH` is set for `cargo run` too —
  without pkg-config the build stops in yeslogic-fontconfig-sys, which is
  what this machine did before the shell existed.

cargo fmt --check, cargo clippy -D warnings and cargo test --workspace all
pass: 348 tests, no failures.
Two halves of one shortcut, asserted where each half lives.

`workspace` builds the real workspace, focuses a docked panel and dispatches
`dock::ToggleZoom`, which is the only way to see the whole path: the skin's
frame carries the sole handler, so the action has to travel from the focused
panel up to its group. A panel that answers `zoomable() -> false` is skipped
in silence — no error, no zoom — and every panel here did exactly that before
the 0.6 port, so nothing else would catch a regression back to it.

`app` asserts the keymap half: shift-escape resolves to `dock::ToggleZoom` in
each context Escape already means something else in, and a bare Escape still
means what it did. The two keys share a base key and differ only by the
modifier, so a binding that captured Escape here would take the grid
selection and the viewer's close with it.
The plain cargo tasks stay exactly as they were — on Windows and macOS the
toolchain and system libraries are already on PATH and want no wrapper.

Added beside them: "(nix)" variants for Linux, where they usually are not.
GPUI links fontconfig, freetype, alsa and openssl through pkg-config and
dlopens vulkan, wayland and xkbcommon, so a bare `cargo build` there dies in
`yeslogic-fontconfig-sys` and a bare `cargo run` can link and still fail to
start. They use `nix-shell` rather than `nix develop` so they work whether or
not the nix-command/flakes features are enabled.

Also a "CI checks" task running fmt, clippy and test in CI's own order, so
the pre-PR gate is one keystroke instead of three remembered commands.
The first run on 0.6 put 162 "window not found" errors in one session's log
and terminal. The filter that used to demote them was still there and still
correct; what changed is that it could no longer tell the messages came from
gpui.

gpui's error helper derives its log target from the caller's file path by
splitting on a `crates/` segment. That segment exists in zed's own checkout,
where the file is `crates/gpui/src/window.rs`, so the target came through as
`gpui::window`. The published `gpui-pre` unpacks to `gpui-pre-0.3.3/src/`,
which has no such segment, so the helper falls back to `""` and every error
it logs arrives untargeted.

Treats the empty target as one of gpui's. Our own modules always have a
target, so nothing of ours starts being swallowed — the tests pin both
directions, including that an untargeted error still has to say it is a
teardown to be demoted.
The field has been multi-line since long before this branch — `TablePanel`
built it with `.multi_line(true)` — so the comment was already wrong; naming
the type `TextareaState` only made the contradiction visible. Says what it is
and why, since the reason is not obvious from the type: a long value has to
wrap inside the editor box rather than run off its right edge, which is what
`editor_box` sizes for.

Found by Copilot's review on #118.
@devnull03
devnull03 merged commit 66014a9 into main Sep 8, 2026
3 checks passed
devnull03 added a commit that referenced this pull request Sep 8, 2026
The field has been multi-line since long before this branch — `TablePanel`
built it with `.multi_line(true)` — so the comment was already wrong; naming
the type `TextareaState` only made the contradiction visible. Says what it is
and why, since the reason is not obvious from the type: a long value has to
wrap inside the editor box rather than run off its right edge, which is what
`editor_box` sizes for.

Found by Copilot's review on #118.
@devnull03
devnull03 deleted the gpui-kit-migration branch September 8, 2026 04:10
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.

2 participants