EditorController exposes the active buffer's EditorSettings (parsed from the
buffer payload, refreshed on editor.settings-changed). EditorView takes over Tab
to insert the configured indent (spaces or a tab) and Shift+Tab to dedent — only
when a source has an opinion, otherwise Flutter's focus traversal stands. A
max_line_length draws a 1px wrap-guide ruler painted behind the text.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 25s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
test / dart doc (lib API) (push) Failing after 24s
Follow-up to the multi-tab editor: extends the controller and view
tests to the close-tab, type-to-edit, and Ctrl+S-save paths, plus a
handful of controller edge branches (read errors, null-id events, the
suppressed self-echo, sibling-dirty marking). Adds a SyntaxTextController
suite driving a fake TreeSitterService so the span→TextSpan rendering
and byte→char mapping (including surrogate pairs) are exercised without
the native grammar. Restores total line coverage above the 95% floor.
Co-Authored-By: Claude <noreply@anthropic.com>
The editor pane showed a single buffer — opening a second file
replaced the first, even though the daemon's EditorRegistry has
always been multi-buffer (editor.list / activate / close). This wires
the UI up to that: EditorController now tracks the full open-buffer
list (via editor.list on hydrate, kept in sync by editor.opened /
closed / saved / edited events), and EditorView renders the buffers
as tabs through the shared MultitabPane — the same strip the Claude
pane uses. The daemon stays the source of truth: the local tab
controller is reconciled from it, and tab select / close route back
as editor.activate / editor.close. Reorder is disabled for now
(daemon order is authoritative).
Co-Authored-By: Claude <noreply@anthropic.com>