update plan

This commit is contained in:
2026-10-28 08:54:15 +07:00
parent 0aad422f70
commit 823f4b245c
2 changed files with 281 additions and 316 deletions
+99
View File
@@ -0,0 +1,99 @@
# 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.
- Prefer generic parameters with a `where` clause over argument-position `impl Trait` in function signatures (`fn extend<I>(&mut self, elements: I) where I: IntoIterator<Item = AnyElement>`); 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<T>` is provided when updating an `Entity<T>`. It dereferences into `App`, so functions which take `&App` can also take `&Context<T>`.
- `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<T>`: `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<T>` 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<T>` it looks like `cx.spawn(async move |this, cx| ...)`.
- `cx.background_spawn(async move { ... })` runs work on other threads.
- Both return a `Task<R>`; 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<Task<_>>`.
## 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<EventType>`), `cx.subscribe(...)` / `cx.observe(...)` for reactions, and store returned `Subscription`s in the owner (commonly `_subscriptions: Vec<Subscription>`).
- 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