| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
kit: Point the hidden gpui re-export at the Kit itself (#3306) ## Why GPUI's macros (`IntoElement`, `Render`, `Action`, `actions!`, `#[gpui::test]` …) expand to plain `gpui::` paths, resolved in the crate that uses them. gpui-pre rewrites them to gpui-kit when it is published; other GPUI sources (e.g. longbridge/gpui-fast) do not. Applications can make those paths resolve through the Kit, whatever GPUI it is built on, with one line per crate root: ```rust extern crate gpui_kit as gpui; ``` (longbridge/longbridge-pro#3847, longbridge/ai-chat#266). But `gpui_kit::gpui` currently re-exports the **GPUI crate**, so in any module that does `use gpui_kit::*;` the glob brings in a second, different `gpui` and rustc reports `` `gpui` is ambiguous `` (E0659). ## What `#[doc(hidden)] pub use ::gpui;` → `#[doc(hidden)] pub use crate as gpui;`, plus a comment explaining why. Dependencies stay on gpui-pre; nothing else changes. - `gpui_kit::gpui::Window` and other GPUI items still resolve, through the root `pub use ::gpui::*` glob (`kit/tests/exports.rs` keeps passing). - Behaviour change on this hidden compatibility path: where the Kit root defines its own item with the same name as a GPUI item (`test`, `init`, `open_window`, `platform`, `application`), `gpui_kit::gpui::<name>` now means the Kit's item. ## Verification - On gpui-pre: `cargo clippy --workspace --lib --bins --tests --examples` is clean (excluding the two wasm members), and so is `cargo clippy -p gpui-kit --all-targets --all-features`. `gpui-base`'s `text_view_scroll` bench fails on main already (criterion `Measurement`); it is upstream of the Kit and not affected by this change. - With GPUI swapped to gpui-fast locally (not part of this PR): the story and every example compile with the alias alongside their 52 `use gpui_kit::*;` globs, where they failed with E0659 before this change. The only remaining failure is `kit/tests/exports.rs`: gpui-kit's own tests also see the GPUI crate as a direct dependency. That only matters when gpui-kit itself switches GPUI. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 23 小时前 | |
table, menu: Show keyboard focus on `DataTable` and keep menu highlights on key presses (#3307) Follow-up to #3299 / #3300, which noted that List / ListItem, Table and the menus are focusable or keyboard-navigable but don't go through `focus_style`. This PR checks each one and fixes the two that were actually broken. ## Audit With `focus_ring = false` and `focus_ring = true` (same result in both unless stated): | Component | Tab stop | Arrow keys | Keyboard focus / navigation (before) | Mouse hover | Selection | Verdict | | --- | --- | --- | --- | --- | --- | --- | | **DataTable** (`TableState`) | **Yes** (`tab_stop(true)`) | Up/Down/Left/Right, Home/End, PgUp/PgDn, Tab moves cells | **Nothing** when tabbed in. Rows only show once a key selects one. | `table_hover` row bg, hidden while typing (GPUI) | `accent` / `table_active` row or cell | **Fixed**: focus ring on keyboard focus | | **PopupMenu / ContextMenu / DropdownMenu** items | No: the menu holds focus while open | Up/Down/Left/Right | The `accent` highlight is the cursor. **Bug 1:** hover item A, press `down` → A **and** B both lit. **Bug 2:** hover A, press a key with no binding → highlight goes out, next `down` restarts at the top. | Hovering moves the highlight, the native menu convention | same highlight | **Fixed** both | | **AppMenuBar** | Titles are ghost `Button`s, so Tab stops with the #3299 edge line | Left/Right between menus | Open title shows the ghost `open` bg, and the popup is a `PopupMenu` (above) | ghost hover | — | Covered by `Button` + the PopupMenu fix | | **List / ListItem** | No. `ListState`'s handle isn't a tab stop. A searchable list focuses its query `Input`. | Up/Down | Selected row (`list_active` / `accent`) is the cursor, and it looks different from hover | `list_hover`, hidden while typing (GPUI) | same as keyboard cursor | **No change needed**, covered by a new test | Not changed, worth a separate decision: a List's selected row looks the same whether or not the list has focus, and `ListState` isn't a Tab stop. Native table views grey out the selection when unfocused. Doing that would change selection styling, which is out of scope here. ## Changes - **`DataTable`**: calls `focus_ring_style` when its handle is focused **and** `window.last_input_was_keyboard()`. That is GPUI's `focus_visible` rule; it matters here because clicking a row also focuses the table. - Bordered (default): the border is tinted `ring`, plus the outer ring when `focus_ring = true`. - `bordered(false)`: the #3299 1px edge line. - No layout change. The line is appended after the table content, so rows don't paint over it. - **`MenuItemElement`**: `group_hover` on its own group → `hover`. - GPUI computes an element's style *before* it pushes the element's group hitbox. A `group_hover` on the element's own group therefore takes the `hover_state.group` fallback, which ignores keyboard modality, so the pointer's item stayed lit next to the keyboard cursor. - `hover` uses the hitbox, which GPUI already suppresses after a key press. Mouse-hover look is unchanged. - The now-unused `group_name` is removed. - **`PopupMenu`**: the `on_hover(false)` that clears the highlight is skipped when the last input was a key press. GPUI ends hover under a still pointer on any key press, so the highlight used to vanish and the next arrow key restarted from the top. A real pointer exit still clears it. ## Tests `crates/kit/tests/rendering.rs` (main thread, `harness = false`, Metal). `Capture` now takes its scale from the window, so it works for any window size. - `menu_highlight_is_the_keyboard_cursor`: exactly one highlighted row after each step. - Hover `Beta` → `[1]`. - `down` → `[2]`. Fails with `[1, 2]` when `group_hover` is restored. - Hover `Beta` again → `[1]`. - Unbound `x` → `[1]`. Fails with `[]` without the `on_hover` guard. - `down` → `[2]`. - `list_selection_is_the_keyboard_cursor`: - Hover row 1 → only row 1 is lit. - `down` → only row 0 is lit, and its fill differs from the hover fill. - Fails with `[]` when the selection isn't forwarded to the item. Nothing needed fixing for List, so this one locks existing behaviour. - `table_shows_keyboard_focus_only`, for `focus_ring = false` and `true`: - Tab from a button into the table → `ring` pixels on its top border. With `true`, the outer band changes too. - In a fresh window, hover then click a row → the table is focused, but the border and outer band are identical to the hovered capture. - Fails without the fix, and also fails when the keyboard gate is dropped. ``` cargo test -p gpui-kit --features test-support,component,assets --test rendering # 10 passed (Metal) cargo test -p gpui-kit --features test-support,component,assets # 278 passed cargo test -p gpui-component # 575 passed cargo clippy -p gpui-component -p gpui-kit --features gpui-kit/test-support,gpui-kit/component,gpui-kit/assets --all-targets -- -D warnings ``` Note: `last_input_was_keyboard` flips back when the mouse moves, so the table's ring disappears on mouse movement, the same as GPUI's own `focus_visible` style. Switching modality already triggers a single `window.refresh()` in GPUI, so this adds no idle redraws. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 1 天前 | |
Bump v0.7.0 | 2 天前 | |
docs: Update gpui-kit dependency version to 0.7 in READMEs (#3304) ## Description The README examples use `gpui_kit::open_window`, which was added in 0.7.0 (#3152). The install snippets next to them still say `gpui-kit = "0.6"`. For 0.x crates, Cargo treats `"0.6"` as `>=0.6.0, <0.7.0`, so anyone who copies the README gets 0.6.6. The example then fails to compile: ``` error[E0425]: cannot find function `open_window` in crate `gpui_kit` ``` This PR changes every hardcoded `gpui-kit` requirement in Markdown from `0.6` to `0.7`: - `README.md` - `README.zh-CN.md` - `crates/kit/README.md` (the crates.io readme; the published page updates with the next release) - `crates/base/README.md` - `examples/app_assets/README.md` - `skills/gpui-kit/references/usage.md` The website docs are not affected because they use `{{gpui_kit_version}}`. `script/bump-version.sh` only runs `cargo set-version`, which does not touch Markdown. These snippets will need a manual update again on the next minor release. ## How to Test - `git grep -nE 'gpui-kit = (\{ *version = )?"[0-9]' -- '*.md'` lists only `0.7`. - A new project with `gpui-kit = "0.7"` and the README example resolves to 0.7.0 and calls `gpui_kit::open_window`. ## Checklist - [ ] I have read the [CONTRIBUTING](../CONTRIBUTING.md) document and followed the guidelines. - [ ] Reviewed the changes in this PR and confirmed AI generated code (If any) is accurate. - [ ] Passed `cargo run` for story tests related to the changes. - [ ] Tested macOS, Windows and Linux platforms performance (if the change is platform-specific) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> | 1 天前 | |
input: Cover UI workflows and fix disabled focus and vertical selection (#3256) ## Summary Expand Input, Textarea and Editor interaction regressions from 82 to **159 UI cases**, with an operation matrix and a single local gate: `script/test-input`. The aim is to replace the routine manual editing tour with reproducible assertions and make this suite an example for future component UI tests. Coverage includes typing/replacement, character/word/line/document/page movement, forward/reverse selection, Unicode and CRLF, pointer/word/paragraph selection, drag autoscroll, clipboard, Undo/Redo, validation and masks, readonly/disabled transitions, focus/lifecycle, wrapping/resizing, pairs/indentation, folding, multi-cursor editing, search/replace, deterministic completion/code-action/inline/definition providers, and IME protocol transitions on all three controls. Assertions inspect text together with selections, caret geometry, focus, history or host callbacks as appropriate. ### Production fixes exposed by the tests - Preserve disabled Input pointer protection, document-edge selection, preferred columns after horizontal selection/Alt-click/offscreen navigation, and visual-row affinity through Shift-End followed by Down or Shift-Down. - Clamp drag selection to laid-out text while autoscroll reveals subsequent rows, instead of immediately selecting to EOF. - Cancel stale completion/inline requests on editing, Escape, blur, protection changes and popup acceptance. - Report the IME selection direction correctly and prevent canceled preedit from merging surrounding typing into one Undo transaction. - Preserve replacement-field focus when its mode change echoes through overlay synchronization. - Make the existing GoToDefinition action query its provider without requiring prior hover. Separate explicit navigation from hover cancellation; reject superseded responses and responses after text/caret/focus changes. No new default keybinding. The runtime changes are limited to these paths. No public API signatures change. The existing `press` helper correction pairs key-down/up and avoids simulated IME text injection for Enter/Tab; its regressions remain included. The branch starts from main after #3253 and does not depend on #3254's accessibility behavior. It also carries the isolated gallery-fixture CI correction shared with #3254: materialize registered surfaces in separate frames without changing production execution budgets. ## Verification (Linux) - `script/test-input`: **536 passed**, comprising Base **300**, Component **44**, Input UI **159**, focus **4**, keyboard helpers **16**, touch selection **13**; no failures or ignored cases in the selected runs. - All **17 Kit interaction targets: 270 passed** (includes the Input/focus/helper/touch cases above). - `cargo clippy -p gpui-kit --features test-support,assets --test input --test input_focus --test interactions --test touch_selection --locked -- --deny warnings`: passed. - Scoped rustfmt, `bash -n script/test-input`, and `git diff --check`: passed. - Five independent review/test scopes were used. Observed failing cases were corrected and rerun; tests retain explicit blur observation, distinct clipboard sentinels and controlled provider responses rather than incidental cancellation/reset steps. The existing CI matrix runs the relevant targets on Linux, macOS and Windows. Results for the new head must be checked before merging. ## Review gate and boundaries See [`crates/kit/tests/input/README.md`](crates/kit/tests/input/README.md) for the operation matrix, fixtures, exact commands and instructions for adding a failing regression for each changed interaction. For ordinary editing changes, use that regression plus the full gate and platform CI. This covers repeatable interaction contracts, not every possible document/configuration/event ordering. Composition tests call the public `ElementInputHandler` bridge for mounted controls; they do not drive a real OS input method or the platform-installed handler. Native IME/candidate windows, accessibility dispatch, clipboard/menu adapters and pixel rendering retain their relevant platform checks. The in-flight completion disposal fixture is inactive because TestPlatform retains the active window's input handler after removal; it does not certify active-window platform disposal. Unicode movement preserves the existing scalar-boundary contract; grapheme movement, regex search, duplicate/move-line commands and Shift-Page selection are not introduced by these tests. ## AI assistance Implementation, tests, documentation and review were assisted by OpenAI Codex. | 3 天前 |
GPUI Kit
One dependency for building desktop applications with GPUI:
[dependencies]
gpui-kit = "0.7"
gpui-kit depends on the matching set of GPUI crates, so an application
never lists GPUI itself. use gpui_kit::*; is GPUI, and each layer is
reachable by name:
| Path | Crate | Feature |
|---|---|---|
gpui_kit::* |
gpui |
always |
gpui_kit::platform |
gpui_platform |
always |
gpui_kit::base |
gpui-base |
always |
gpui_kit::component |
gpui-component |
component (on) |
gpui_kit::assets |
gpui-kit-assets |
assets (on) |
gpui_kit::application() opens the platform and gpui_kit::init()
initializes the enabled layers:
use gpui_kit::component::button::*;
use gpui_kit::*;
struct Hello;
impl Render for Hello {
fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
div().child(Button::new("ok").primary().label("Let's Go!"))
}
}
fn main() {
gpui_kit::application().run(|cx| {
gpui_kit::init(cx);
gpui_kit::open_window(WindowOptions::default(), cx, |_, cx| cx.new(|_| Hello))
.expect("failed to open window");
});
}
The gpui-component features (inspector, decimal, tree-sitter,
tree-sitter-languages, and each tree-sitter-<language>) are available on
gpui-kit under the same names. test-support turns on GPUI's test harness
for #[gpui_kit::test], TestAppContext, VisualTestContext, and native-platform
rendering support; enable it under [dev-dependencies]. It also exposes
gpui_kit::test::{TestWindowExt, TestAppContextExt, TestSupportExt, ElementSnapshot} for
UI integration testing: render real components in headless windows, simulate input,
and verify state, focus, layout and application callbacks. gpui_kit::TestSupportExt is also
available without the feature: .test_support() keeps production render chains
intact and returns the original element in normal builds. Snapshots read native
accessibility properties without hand-supplied state. See UI integration testing for usage.
The independent profiler feature enables GPUI frame-event instrumentation and is off by default.
See https://gpui-kit.com for the guides.