You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Build a `quadraui::RichTextPopup` primitive that lets both TUI and GTK render the LSP/editor hover popup from one shared codepath. Today the hover popup is the largest remaining bespoke-renderer surface in the chrome migration (#205 deferred slice 4).
What it needs to support
The existing TUI `render_editor_hover_popup` (`src/tui_main/panels.rs:2714`) and GTK `draw_editor_hover_popup` (`src/gtk/draw.rs:1860`) collectively need:
Feature
Used by
Multi-line styled text rendered inside a bordered box
Fenced code blocks with tree-sitter syntax highlighting
LSP hover for Rust/etc. examples
Focus state (border colour changes when popup has keyboard focus)
Hover with K, click-to-pin
Vertical scroll + scrollbar
Long doc strings
Text selection (drag-select chars, multi-line)
Copy text out of the popup
Clickable links with focus-cycle navigation (Tab)
LSP hover with hyperlinked types
Auto-place above-or-below anchor
Position relative to cursor
Why not just extend Tooltip
Tooltip is "static text in a box". The editor hover is "an interactive document viewer". Conflating them leaves Tooltip's API messy for everyone else (signature help, diff peek, simple LSP hovers) without buying much. A separate primitive captures the "this surface is interactive and stateful" distinction at the type level.
Goal
Build a `quadraui::RichTextPopup` primitive that lets both TUI and GTK render the LSP/editor hover popup from one shared codepath. Today the hover popup is the largest remaining bespoke-renderer surface in the chrome migration (#205 deferred slice 4).
What it needs to support
The existing TUI `render_editor_hover_popup` (`src/tui_main/panels.rs:2714`) and GTK `draw_editor_hover_popup` (`src/gtk/draw.rs:1860`) collectively need:
Why not just extend Tooltip
Tooltip is "static text in a box". The editor hover is "an interactive document viewer". Conflating them leaves Tooltip's API messy for everyone else (signature help, diff peek, simple LSP hovers) without buying much. A separate primitive captures the "this surface is interactive and stateful" distinction at the type level.
Suggested shape
```rust
pub struct RichTextPopup {
pub id: WidgetId,
pub rendered: RichTextDocument, // pre-laid-out lines + spans + code-highlight info
pub scroll_top: usize,
pub has_focus: bool,
pub selection: Option,
pub links: Vec,
pub focused_link: Option,
pub placement: TooltipPlacement,
}
pub struct RichTextPopupLayout {
pub bounds: Rect,
pub visible_lines: Vec,
pub scrollbar: Option,
pub link_hit_regions: Vec<(Rect, usize)>, // for click-to-open
pub char_hit_regions: Vec<(Rect, usize, usize)>, // (line, col) for selection
pub hit_regions: Vec<(Rect, RichTextPopupHit)>,
}
pub enum RichTextPopupEvent {
LinkClicked { idx: usize },
LinkFocused { idx: usize },
SelectionChanged(Option),
Scrolled { new_offset: usize },
Closed,
KeyPressed { key, modifiers },
}
```
The `RichTextDocument` shape already exists in vimcode (`core::markdown::Rendered` or similar) — it would move to or be referenced from quadraui.
Migration order (suggested)
Closes
Closes #205 slice 4 (deferred). Eliminates the largest remaining bespoke chrome renderer in both backends.
Rough sizing
Bigger than any individual slice on #205. Worth its own focused wave.