input: dispatch editing keys through actions

This commit is contained in:
2026-10-29 15:27:56 +07:00
parent e2331f2ba5
commit 5f53e0c89f
6 changed files with 656 additions and 184 deletions
+2 -2
View File
@@ -221,7 +221,7 @@ Deferred until a real need: Markdown/TextView, Dock, VirtualList, window-wide te
Our divergence from gpui-kit held: the per-size metrics resolve from **the theme's size table at paint time**, not from constants in the component layer. All ten controls implement `Sizable`; `Size::Custom(side)` derives the other metrics from the side length. Still open, when a real need arrives: TOML overrides for the size table in `ThemeDefinition`, and per-platform size tables from the Phase F native-metrics work.
### 6.2 Input completion (unit 10 finishing pass) — in progress (steps 1–3 landed 2026-10-29)
### 6.2 Input completion (unit 10 finishing pass) — in progress (steps 1–4 landed 2026-10-29)
Gap analysis against gpuikit's input (2026-10-29; source read as an API reference, §9 — no porting). gpuikit splits input three ways: core state whose edits are actions, infrastructure (`bindings` / `blink` / `bidi`), and a chrome-less element with chrome in wrapper elements. We keep one component with chrome included; only the ideas below are adopted.
@@ -234,7 +234,7 @@ Remaining, in order:
| 1 | macOS modifier split | ✅ Landed. `cmd-left/right` → home/end, `cmd-up/down` → start/end of field, `cmd-backspace` → delete to start, `alt` modifiers → word ops. The handler used to treat cmd and alt alike — wrong on macOS (D8); ctrl stays the word-modifier fallback off-mac |
| 2 | Undo/redo | ✅ Landed. Patch-based history (range, replaced text, new length, prior selection), 300 ms grouping (`set_group_interval`, `Duration::ZERO` disables merging), `cmd-z` / `cmd-shift-z`, 100-entry cap; `set_value` clears the stacks, any new edit clears redo. Unlike gpuikit — which skips recording inside the interval and so undoes groups lossily — entries merge so a group fully reverses. Redo lands the caret at the end of the restored text; undo restores the pre-edit selection |
| 3 | Read-only, Escape-blur, triple-click | ✅ Landed. Read-only: focus, movement, selection, copy still work; edits, paste, cut (clipboard included), undo/redo and IME refused — distinct from disabled; programmatic setters unaffected; the caret is hidden while read-only (a caret promises typing lands there). Escape → `window.blur()`. Triple-click selects all (single-line) |
| 4 | Actions + key context | Replace the monolithic `on_key_down` match with `actions!(input, [...])` + an `"Input"` key context; `bind_input_keys(cx, overrides)` over a per-platform-default `InputBindings` table of `Option<KeyBinding>` fields (override or unbind each). Step 1's bindings become data |
| 4 | Actions + key context | ✅ Landed. 25 `actions!(input, …)` + an `"Input"` key context; the element registers `on_action` handlers and the residual `on_key_down` only inserts printable typed chars. `InputBindings` table of `Option<KeyBinding>` fields — `Default` is platform defaults (cmd/alt on macOS, ctrl elsewhere), `empty()` starts bare, any field replaceable/unbindable; `bind_input_keys(cx, None | table)` registers at startup (gallery + tests call it). Verified gpui semantics first: matched bindings consume the keystroke before `on_key_down`, and actions claim by default in bubble (`cx.propagate()` yields — Copy does when the selection is empty). macOS jump extras (`cmd-left/right/up/down`, `cmd-shift-left/right`) are appended in `into_bindings`, not field-configurable |
| 5 | Caret blink | 500 ms tick on the GPUI executor, paused (caret visible) while typing or moving, suppressed in read-only |
| 6 | Paint polish | IME marked-text underline; I-beam cursor on hover; two-sided horizontal scroll (clamped offset in state, follows caret) plus horizontal wheel scroll |