Part of #275 (Phase C umbrella).
Goal
Lift the editor "widget" paint into a published quadraui::Editor primitive + dual rasterisers, so vimcode's tui_main/render_impl.rs::render_window and gtk/draw.rs::draw_window collapse to delegators. Net -1500 to -2000 LOC vimcode-private paint code. Phase 1 only — engine slice extraction explicitly deferred to a separate later wave.
Scope
New module quadraui/src/primitives/editor.rs:
pub struct Editor mirroring render::RenderedWindow. Carries lines: Vec<EditorLine>, cursor: Option<EditorCursor>, scroll_top: usize, scroll_left: usize, gutter_chars: usize, selection: Option<Selection>, find_matches: Vec<Match>, optional dap_current_line, etc.
pub struct EditorLine mirroring render::RenderedLine: spans: Vec<StyledSpan>, gutter_text, git_status, is_cursorline, is_diff, is_dap_current, bp_state, diagnostic, fold_marker, virtual_text, indent_guides: Vec<u16>, color_columns: Vec<u16>, wrap_continuation: bool, etc.
- Supporting types:
EditorCursor, Selection, BreakpointState, GitLineStatus, DiagnosticSeverity. Lift from render.rs or reuse from quadraui::types.
New rasterisers:
quadraui/src/tui/editor.rs::draw_editor(buf, rect, editor, theme) — verbatim port of tui_main/render_impl.rs::render_window body. Same paint categories in same order: bg fills (cursorline / diff / DAP-stopped) → gutter (BP, git, line numbers, diagnostic icon, lightbulb, fold marker) → text spans → indent guides → color columns → virtual text → diagnostic underlines → spell underlines → bracket-match highlights → selection overlay → yank-flash → scrollbars.
quadraui/src/gtk/editor.rs::draw_editor(cr, layout, rect, editor, theme, line_height, char_width) — verbatim port of gtk/draw.rs::draw_window.
Theme growth: 2-4 new fields on quadraui::Theme for editor-specific colors (cursorline_bg, diff line tints, BP marker colors). Mapped from vimcode's rich render::Theme via q_theme() adapter. Matches the +5 fields #266 added.
Vimcode adoption:
src/render.rs — add build_editor_primitive(engine, window_id) -> quadraui::Editor builder filling the primitive from existing engine state. RenderedWindow keeps existing for transition compatibility.
src/tui_main/render_impl.rs::render_window — body collapses to quadraui::tui::draw_editor(buf, rect, &editor, &theme).
src/gtk/draw.rs::draw_window — body collapses similarly.
src/tui_main/quadraui_tui.rs (q_theme), src/gtk/quadraui_gtk.rs (q_theme) — populate new theme fields.
Untouched: click/mouse handlers (operate on engine state directly). Win-GUI editor (waits for B.6). Engine slice extraction (Phase 2, separate wave).
Reuse principle
RenderedWindow / RenderedLine field shapes are the source of truth. Don't redesign — translate verbatim. The TUI tests in core::engine::tests exercise editor state through to RenderedWindow; they continue to validate end-to-end via the new primitive without modification.
Verification
cargo build --no-default-features
cargo build
cargo clippy --no-default-features -- -D warnings
cargo clippy -- -D warnings
cargo test --no-default-features
cd quadraui && cargo test --features tui --features gtk
cd .. && cargo build -p kubeui && cargo build -p kubeui-gtk
cd quadraui && cargo build --example tui_app --features tui && cargo build --example gtk_app --features gtk
Smoke: open vimcode + vcd, navigate (j/k/h/l, page up/down, scroll), verify cursor / line numbers / git diff markers / syntax colors / selection / diagnostic squiggles / cursorline / scrollbars / wrap continuation render identically before vs after. Open a file with active LSP diagnostics + git changes + a fold to exercise the harder paint categories.
Part of #275 (Phase C umbrella).
Goal
Lift the editor "widget" paint into a published
quadraui::Editorprimitive + dual rasterisers, so vimcode'stui_main/render_impl.rs::render_windowandgtk/draw.rs::draw_windowcollapse to delegators. Net -1500 to -2000 LOC vimcode-private paint code. Phase 1 only — engine slice extraction explicitly deferred to a separate later wave.Scope
New module
quadraui/src/primitives/editor.rs:pub struct Editormirroringrender::RenderedWindow. Carrieslines: Vec<EditorLine>,cursor: Option<EditorCursor>,scroll_top: usize,scroll_left: usize,gutter_chars: usize,selection: Option<Selection>,find_matches: Vec<Match>, optionaldap_current_line, etc.pub struct EditorLinemirroringrender::RenderedLine:spans: Vec<StyledSpan>,gutter_text,git_status,is_cursorline,is_diff,is_dap_current,bp_state,diagnostic,fold_marker,virtual_text,indent_guides: Vec<u16>,color_columns: Vec<u16>,wrap_continuation: bool, etc.EditorCursor,Selection,BreakpointState,GitLineStatus,DiagnosticSeverity. Lift fromrender.rsor reuse fromquadraui::types.New rasterisers:
quadraui/src/tui/editor.rs::draw_editor(buf, rect, editor, theme)— verbatim port oftui_main/render_impl.rs::render_windowbody. Same paint categories in same order: bg fills (cursorline / diff / DAP-stopped) → gutter (BP, git, line numbers, diagnostic icon, lightbulb, fold marker) → text spans → indent guides → color columns → virtual text → diagnostic underlines → spell underlines → bracket-match highlights → selection overlay → yank-flash → scrollbars.quadraui/src/gtk/editor.rs::draw_editor(cr, layout, rect, editor, theme, line_height, char_width)— verbatim port ofgtk/draw.rs::draw_window.Theme growth: 2-4 new fields on
quadraui::Themefor editor-specific colors (cursorline_bg, diff line tints, BP marker colors). Mapped from vimcode's richrender::Themeviaq_theme()adapter. Matches the +5 fields #266 added.Vimcode adoption:
src/render.rs— addbuild_editor_primitive(engine, window_id) -> quadraui::Editorbuilder filling the primitive from existing engine state.RenderedWindowkeeps existing for transition compatibility.src/tui_main/render_impl.rs::render_window— body collapses toquadraui::tui::draw_editor(buf, rect, &editor, &theme).src/gtk/draw.rs::draw_window— body collapses similarly.src/tui_main/quadraui_tui.rs(q_theme),src/gtk/quadraui_gtk.rs(q_theme) — populate new theme fields.Untouched: click/mouse handlers (operate on engine state directly). Win-GUI editor (waits for B.6). Engine slice extraction (Phase 2, separate wave).
Reuse principle
RenderedWindow/RenderedLinefield shapes are the source of truth. Don't redesign — translate verbatim. The TUI tests incore::engine::testsexercise editor state through toRenderedWindow; they continue to validate end-to-end via the new primitive without modification.Verification
Smoke: open vimcode + vcd, navigate (j/k/h/l, page up/down, scroll), verify cursor / line numbers / git diff markers / syntax colors / selection / diagnostic squiggles / cursorline / scrollbars / wrap continuation render identically before vs after. Open a file with active LSP diagnostics + git changes + a fold to exercise the harder paint categories.