# Coding guidelines - Prioritize code correctness and clarity. Speed and efficiency are secondary priorities unless otherwise specified. - Do not write organizational or comments that summarize the code. Comments should only be written to explain "why" the code is written in some way in the case there is a reason that is tricky / non-obvious. - Keep doc comments and comments simple, one line, straightforward, and unbloated. - Prefer implementing functionality in existing files unless it is a new logical component. Avoid creating many small files. - Prefer `impl` blocks over standalone functions: place functionality as methods or associated functions on the relevant type, extending the type's existing `impl` block instead of creating a duplicate one in another file. - Always use generic parameters with a `where` clause instead of argument-position `impl Trait` in function signatures (`fn extend(&mut self, elements: I) where I: IntoIterator`); return-position `impl Trait` stays. - Do not wrap dependency APIs in project structs or pass-through helper functions; call their methods directly where needed. Extract a helper only when it holds real logic that is used in more than one place. - Bind a global store handle to a local before using it (`let theme = Theme::global(cx);` then `theme.…`) instead of chaining `::global(cx)` inline. - Avoid using functions that panic like `unwrap()`; instead use mechanisms like `?` to propagate errors. - Be careful with operations like indexing which may panic if the indexes are out of bounds. - Never silently discard errors with `let _ =` on fallible operations. Always handle errors appropriately: - Propagate errors with `?` when the calling function should handle them. - Use `.log_err()` or similar when you need to ignore errors but want visibility. - Use explicit error handling with `match` or `if let Err(...)` when you need custom logic. - When implementing async operations that may fail, ensure errors propagate to the UI layer so users get meaningful feedback. - Avoid creative additions unless explicitly requested. - Use full words for variable names (no abbreviations like "q" for "queue"). - Use variable shadowing to scope clones in async contexts for clarity, minimizing the lifetime of borrowed references. ## Tests - Keep only meaningful and critical tests: each test must lock state semantics (activation, state transitions, style priority, a11y mapping) or a non-obvious lifecycle invariant. - Drop tests that assert mechanical passthroughs, getter/setter round-trips, compile-time API availability, or duplicate the same behavior at a second layer. ## Timers in tests - In GPUI tests, prefer GPUI executor timers over `smol::Timer::after(...)` for timeouts, delays, or driving `run_until_parked()`: - Use `cx.background_executor().timer(duration).await` (or `cx.background_executor.timer(duration).await` in `TestAppContext`) so work is scheduled on GPUI's dispatcher. - Avoid `smol::Timer::after(...)` for test timeouts when you rely on `run_until_parked()`; it may not be tracked by GPUI's scheduler. # GPUI GPUI is a UI framework which also provides primitives for state and concurrency management. ## Context - Context types allow interaction with global state, windows, entities, and system services. They are typically passed as the argument named `cx`. When a function takes callbacks they come after the `cx` parameter. - `App` is the root context type, providing access to global state and read and update of entities. - `Context` is provided when updating an `Entity`. It dereferences into `App`, so functions which take `&App` can also take `&Context`. - `AsyncApp` and `AsyncWindowContext` are provided by `cx.spawn` and `cx.spawn_in` and can be held across await points. ## Window - `Window` provides access to the state of an application window. It is passed as `window` and comes before `cx` when present. ## Entities - With `thing: Entity`: `thing.entity_id()`, `thing.downgrade()`, `thing.read(cx)`, `thing.read_with(cx, |thing, cx| ...)`, `thing.update(cx, |thing, cx| ...)`, `thing.update_in(cx, |thing, window, cx| ...)`. - Within update closures, use the inner `cx` provided to the closure, not the outer one. - Never update an entity while it is already being updated; this panics. - `WeakEntity` methods return `anyhow::Result` and fail when the entity no longer exists; treat that as a normal lifecycle outcome. Prefer weak back-references to avoid ownership cycles. ## Concurrency - All use of entities and UI rendering occurs on a single foreground thread. - `cx.spawn(async move |cx| ...)` runs on the foreground thread; from a `Context` it looks like `cx.spawn(async move |this, cx| ...)`. - `cx.background_spawn(async move { ... })` runs work on other threads. - Both return a `Task`; dropping it cancels the work. Prevent cancellation by awaiting, detaching deliberately, or storing the task in a field. - Prefer keeping a task in a field over `.detach()` when the work belongs to a view or store; a detached task outlives its owner. A finished `Task` held in a container is not reaped — drop finished handles or hold a single `Option>`. ## Rendering and state - `Render` builds an element tree from entity state; `RenderOnce` (with `#[derive(IntoElement)]`) is for value-like components whose `render` takes `self` and `&mut App`. - Keep `render` declarative; use `.when(...)` / `.when_some(...)` for small conditional refinements. - Controlled components: the owner passes the current value, callbacks report intent, the owner updates state and calls `cx.notify()`. No second source of truth. - Call `cx.notify()` after a mutation that changes rendering; notify the narrowest owning entity. Never notify from `render`. - Use `cx.emit(...)` for semantic events (declare `impl EventEmitter`), `cx.subscribe(...)` / `cx.observe(...)` for reactions, and store returned `Subscription`s in the owner (commonly `_subscriptions: Vec`). - Use stable domain-derived `ElementId`s (`("delete-project", project.id)`); never list indexes or freshly generated random IDs for reorderable content. - `cx.listener(...)` adapts event handlers to update the current entity. - Actions: `actions!(namespace, [Action])` for data-free actions, the `Action` derive otherwise; register `on_action` on the focused region with a matching `key_context`. - Retain a `FocusHandle` in the entity that owns keyboard interaction; a tracked handle is a Tab stop only when built with `tab_stop(true)`. # Project rules - Dependency direction is one-way: `gpui-native-kit` (facade) → `gpui-native-core` / `gpui-native-editor` / … → `gpui-native-theme` + `gpui-native-icons` → gpui. No cycles. Nothing depends on `gpui-component`, `gpui-kit`, `gpuikit`, `bezel`, `native-theme`, or any gpui fork. - `crates/theme` owns the native theme engine and every color, radius, spacing, and metric value — no raw `rgb`/`rgba`/`hsla` or layout `px(...)` literals anywhere else. - `crates/icons` owns icon resolution; components reference icons by semantic role — no glyph names, unicode symbols, or SVG paths anywhere else. - `crates/core` and its sibling crates own components: each one is a small self-contained implementation gated behind its own cargo feature. Features are additive, gate whole modules only, and may depend on other features. Behavior and presentation live together. No separate behavior layer — promote a shared helper only when a third component needs it. - Components are written in-tree. Other UI toolkits are read for API ideas only; never port their code or depend on them. - gpui/gpui_platform come from zed's repository at the rev pinned in `docs/PLAN.md`; bump the pin deliberately and re-verify. - `SharedString` for UI text retained across frames; `String` only for mutable buffers. - Behavioral seams use private fields + builders/readers. Boolean readers are `is_`/`has_`; general builders use `with_`; in-place mutation uses `set_`; callbacks use `on_`; retained models end in `State`; pluggable owners in `Delegate`/`Provider`. - Never invent an API: search the gpui source for the real signature before writing code. - Prefer `.SystemUIFont` and rem-based helpers (`p_2()`, `text_sm()`, `gap_3()`) over pixel literals. # Pull request hygiene - Use a clear, correctly capitalized, imperative PR title (for example, `fix crash in project panel`). - Avoid conventional commit prefixes in PR titles (`fix:`, `feat:`, `docs:`, etc.). - Avoid trailing punctuation in PR titles. - Optionally prefix the title with a crate name when one crate is the clear scope (for example, `kit: add button port unit`). - Include a `Release Notes:` section as the final section in the PR body, with one bullet: - `- Added ...`, `- Fixed ...`, or `- Improved ...` for user-facing changes, or `- N/A` otherwise. Release Notes: - N/A