Skip to content

gpui-rhai 0.4.2

Choose a tag to compare

@eddix eddix released this 06 Nov 18:39
· 30 commits to main since this release

gpui-rhai 0.4.2

Release date: 2026-11-06. A release that is not compatible with 0.4.1 in
places, numbered 0.4.2 by the maintainer's choice rather than 0.5.0: read
Not compatible with 0.4.1 before upgrading.
Runtime API stays 3 and gpui-pre/core/platform stay 0.3.9; gpui-fast 0.1.9
is a second backend; MSRV moves to 1.99. Upgrade core, registry and CLI
together.

This release works through the feedback from oh-my-traex, an agent workbench
that runs a gpui-fast UI (nsh) and a gpui-rhai UI side by side. gpui-rhai now
builds on gpui-fast, so both fit in one binary; editors let the script above
them take keys first; overlays leave their trigger's layout alone; scripts read
any theme's colors and reach notifications and the Dock badge; and a dozen
smaller items, from interval to error messages that say where the mistake is.
Item numbers below are that feedback's. The full list is in the
CHANGELOG.

One binary with a gpui-fast UI

Two GPUI forks register the same Objective-C classes at load time, so a binary
that links both aborts before main, and an application with a gpui-fast UI
had to ship a second binary for gpui-rhai. gpui-rhai now builds on either fork:

gpui-rhai = { version = "0.4", default-features = false, features = ["gpui-fast"] }

gpui-pre stays the default; the two features exclude each other, and
gpui_rhai::gpui and gpui_rhai::gpui_platform name the selected fork's
crates. gpui-fast is pinned at 0.1.9, the version nsh-platform-gpui 0.4 builds
on. On gpui-fast, cache islands are off and a Host starts the process with
GPUI_SCROLL_LAYERS=0 (embedding).
gpui-rhai check reads the backend from the dependency, rejects a direct
dependency on the other fork, and warns when the lockfile resolves both;
gpui-rhai init --backend fast writes the dependency. A test binary linking
nsh's window and the Gallery on gpui-fast opened both in one application.

Field text sat 4pt high on gpui-fast: its Taffy resolves a percentage height
under a min-height as CSS does, and the centering on gpui-pre came from the
older resolution. Aligned primitive nodes now lay out as flex boxes, so fields
center on both backends.

Keys above editors (#27)

Input and Textarea bind their keys as GPUI actions, which run before any raw
key listener, so an on_capture("key:…") above an editor never saw Up, Down or
Enter. An editor now runs its ancestors' capture handlers for a key before it
acts; one that returns event_response().prevent_default() or .stop() keeps
the editor from acting. A completion list above a Composer takes Up, Down and
Enter while it is open and returns a plain event_response() when closed.

Overlays leave the trigger's layout alone (#26)

The box between an overlay and its trigger was a flex row that took the
trigger's content width, so a ContextMenu around a sidebar row shrank the row
and pushed a long title past the sidebar. The box is now a column that may
shrink: the trigger lays out as it would unwrapped, for every overlay.

Theme colors, a third surface, and radius names (#1, #16, #17, #35)

ctx.theme_colors(family, name[, keys]) returns any variant's resolved colors,
so a theme picker paints each variant's swatch while the window shows another.
ctx.theme_variants() already reported each variant's mode.

The token base adds surface.chrome, halfway from surface to
surface_raised, for an application's sidebars and title bars between the
window canvas and raised cards.

The markers' capsule was named radius.sm, so a box meant to be slightly
rounded came out a pill. The capsule is now radius.pill, and radius.sm is
a fixed 4px rounded rectangle for an application's own shapes (thumbnails,
swatches), which no built-in component takes. D83.

Notifications, the Dock badge and attention (#29)

gpui_rhai::system gives a Host notifications_available() (macOS posts
notifications only for a bundle with an identifier, and an unbundled binary
shows none), set_badge_label for the Dock badge, and
ScriptApplication::app_identity for Linux and Windows. The SystemServices
extension gives scripts system.notification@1 (show, dismiss, available, and
a responses subscription for clicks), system.badge@1 and
system.attention@1 (capabilities).

Timers (#2, #19)

A mounted view without a Host clock now follows GPUI's executor clock: the
system clock in an application, the scheduler's in a GPUI test, so
advance_clock and run_until_parked fire due timers and move animation in
tests and offscreen captures. Before, a one-second counter in an offscreen test
moved only when something else woke the view.

interval(key, period_ms, paused, Fn("callback"), payload) calls back every
period, 16ms at least, in the timeout key space, so ctx.pause_timeout,
resume_timeout and cancel_timeout apply. A late tick is one call; missed
ticks are not made up.

Names from content (#20)

A button, tab, option, menu item, checkbox, radio, switch, tree item, row,
cell, header, heading or tooltip without a label takes its accessible name
from the text its subtree shows, as ARIA's name from content does. A row drawn
with accessibility_role("button") reads as its text and automation finds it
by name, without a separate accessibility_label.

Errors that say where (#15, #24, #25, #32, #36)

  • A duplicate key names the keys from the root to the parent and where the
    script created both children, instead of a runtime node number:
    duplicate key goalin child groupchildren of work > completion-panel, created at ui/main.rhai:42:9 and ui/main.rhai:43:9. Inside an
    error_boundary's child it no longer fails the view: the boundary shows its
    fallback, which carries the error as boundary_error.
  • A function allows an expression depth of 64, as the top level does; a node
    with a style chain built in a closure failed at 32.
  • Files beside the images in ui/assets (a license, .DS_Store) no longer
    fail check; non-image files are skipped with a warning and left out of embed.
  • A Rhai keyword where a name belongs fails with an error that names it; the
    generated Switch reference imported the module as switch, which does not
    parse, and now uses switch_component.
  • import "themes/…" explains that a theme is not a module and points to
    ctx.theme_colors.

Collapsible, Composer and viewers (#5, #8, #9)

Collapsible's content is optional, for a disclosure row whose content the
caller lays out elsewhere, such as rows of a virtual collection. Composer's
editor shows the Composer's surface, so a root background covers the whole
field. The document viewers take part_styles like every component;
document viewers shows restyling one on a raised
card.

Not compatible with 0.4.1

  • Rust 1.99. The toolchain and MSRV move from 1.95.
  • --all-features no longer builds gpui-rhai: gpui-pre and
    gpui-fast exclude each other. List features explicitly.
  • radius.sm means 4px. A script or theme override that used sm for a
    capsule uses pill. A shape whose shorter side is 8px or less still reads as
    a capsule at 4px, since radii clamp to half the shorter side.
  • Editors and capture handlers. An ancestor's on_capture("key:…") that
    returns prevent_default() or stop() now keeps an editor from acting on
    that key; before, the editor acted and the handler never ran.
  • Overlay triggers stretch across a column parent as they would unwrapped,
    and may shrink. Wrap a trigger that should keep its content width, for
    example in a start-aligned Stack.
  • Timers in tests. Without a Host clock, a GPUI test's timers and motion
    follow the scheduler's clock: advance it rather than sleeping.
  • Accessible names. Nodes in the roles above that had no name now have
    their text; automation that matched them by an empty name matches the text.
  • Rust API. ReconcileError::DuplicateKey gains path and sources;
    KnownCallDiagnostic gains module; TimerError gains IntervalTooShort.
    An exhaustive match or a struct literal needs the new names. New, so
    breaking nothing: the gpui-fast feature, gpui_rhai::system,
    SystemServices, ScriptViewExtension::poll (empty by default),
    ScriptApplication::app_identity, UiContext::theme_colors,
    RetainedUiTree::reconcile_contained, TimerDescriptor::repeating and
    repeats, and SourceLocation's Display.

Upgrading from 0.4.1

Upgrade the CLI first, then run gpui-rhai update. It merges the token base
and the nine modules this release changed, which take 0.4.2: Badge, Carousel,
Collapsible, SplitPane, Switch, Tabs, Tag, Toast and Composer. Merges keep
local edits and write conflicts to .gpui-rhai/conflicts/. Then replace
theme_radius("sm") with theme_radius("pill") where a script meant a
capsule.

To move a Host to gpui-fast, depend on gpui-rhai with
default-features = false, features = ["gpui-fast"], reach GPUI through
gpui_rhai::gpui, drop direct gpui-pre dependencies, and start the process
with GPUI_SCROLL_LAYERS=0.

Verification

Before the release, on macOS: format and strict Clippy for the workspace,
tests/native-keyboard and the apps on both backends; cargo doc with
warnings denied on both backends; the workspace tests (892 on each backend),
the default-feature library tests (627), the native suite (701 on gpui-pre,
also with every subtree an island, and 689 on gpui-fast with scroll layers
off), all tests/native-keyboard tests (702), the token reload tests (5) and
the apps' tests (51). Each code commit of the release passes the workspace
tests, the app component check, the native suite in both island modes, strict
Clippy, and the gpui-fast Clippy, workspace tests and native suite on its own.

gallery_profile: Window::draw p95 at most 3.27 ms over every interaction,
within the 8.3 ms budget.

Visuals: the 57 committed baselines (38 example, 19 Gallery) render identical
in RGB. Every Gallery page in both densities was compared with 0.4.1: 100 of
102 are identical in each; the ContextMenu page's row now fills its section
(#26) and the Calendar's today mark moved with the date. When the layout fix
landed, the Gallery offscreen on gpui-fast differed from gpui-pre only in
rounded-corner antialiasing and gpui-fast's own CJK line breaks. The theme
appearance probes (light, dark) reported no error and the appearance
lifecycle passed. The release smoke launched its 25 cases and the artifact
audit passed for its 11 binaries. disktree: key_harness passes, and its
screenshots in dark and light show the treemap filling the stage beside the
SplitPane panel. cargo package packaged and built gpui-rhai and
gpui-rhai-registry.

One binary: a test application linking nsh-platform-gpui 0.4 and gpui-rhai on
gpui-fast opened an nsh window and the Gallery in one process and exited
cleanly; its dependency tree holds no gpui-pre crate.

Upgrade: a copy of oh-my-traex, whose 34 modules the 0.4.0 CLI installed,
passes the 0.4.2 check as it is. gpui-rhai update merged the token base and
the nine changed modules with no conflict and added SelectableList; check
passed for its 35 modules, and a second update changed nothing.
Its Rust crate, pointed at 0.4.2 through a local path, type-checks with all its
targets unchanged.