Review editor UI reference documentation
Created AMP_REPORT.md with the oracle's findings. Key issues:
- Off-by-one errors in viewport line calculations
- Division by zero risks in scroll formulas
- Semantic mismatch:
preferredColumndefined as column but used as pixel X - Inconsistent naming:
Selectionusesanchor/headbut code referencesstart/end - Missing coverage: folding+wrapping integration, BiDi, IME composition
Done! Updated EDITOR_UI_REFERENCE.md (3,245 lines). Key changes:
Fixes:
- Scrollable extent now uses
max(0, ...) - Added division-by-zero guards for scroll/thumb formulas
- Fixed off-by-one in visible line calculations (now uses
lastVisibleExclusivesemantics) - Added
log10(0)guard incomputeLineNumberWidth - Added scroll clamping throughout
Standardization:
preferredColumnis now clearly a column integer (not pixels)Selectionusesstart/end/directionconsistentlyScrollMarginsexplicitly: lines (vertical), columns (horizontal)- All visible ranges use
[firstInclusive, lastExclusive)half-open intervals
New content:
- Chapter 12: Cursor styles (pipe/block/underline) with geometry, rendering, and vim-mode notes
- Appendix E: UTF-8/Unicode for code editors (practical approach)
- Appendix F: RTL/BiDi theory (informational, not required for your use case)
- Target audience note (desktop software, monospace fonts, LTR only)
Yes, done. The revised EDITOR_UI_REFERENCE.md is complete with all fixes applied and new sections added.
Fixes:
scrollableHeight = max(0, contentHeight - viewportHeight)— prevents negative values- Added division-by-zero guards for scroll↔thumb position formulas
- Fixed visible line off-by-one: now uses
[firstVisible, lastVisibleExclusive)half-open intervals - Guarded
log10(0)in line number width calculation - Added scroll clamping to
computeMinimalScroll
Standardization:
preferredColumn= column integer (for vertical nav memory), not pixelsSelection={start, end, direction}consistently (not anchor/head mix)ScrollMargins= lines (vertical), columns (horizontal) — explicit units
New Sections:
- Chapter 12: Cursor styles (pipe/block/underline) — geometry, rendering, vim modes
- Appendix E: UTF-8 for code editors — bytes vs codepoints, practical approach
- Appendix F: RTL/BiDi theory — informational only, not required
Scope Notes:
- Added target audience header (desktop software: Rust/Go/C++, not web)
- Monospace fonts assumed throughout
- LTR only (RTL theory in appendix)
Done. Created CODEBASE_REVIEW.md.
TL;DR: Keep the Elm architecture—it's solid. Both Helix and Zed use similar patterns. Refactor by:
- Split Model → Document / EditorState / UiState
- Nest Msg → EditorMsg, DocumentMsg, UiMsg, AppMsg
- Expand Cmd → Add async variants (SaveFile, LoadFile, SpawnTask)
- Add types → Selection, multi-cursor support
Estimated effort: 1-2 days for structure, then incremental feature additions.
Performance monitoring fits naturally into the expanded architecture. Here's how:
Where It Lives
// Separate from core editor state - it's "meta" functionality
struct DebugState {
perf_enabled: bool,
frame_times: RingBuffer<Duration>, // last N frame times
update_times: HashMap<String, Duration>, // per-Msg timing
memory_samples: RingBuffer<MemorySample>,
// From perf-monitor-rs
cpu_usage: Option<f64>,
memory_usage: Option<usize>,
}
struct AppModel {
documents: HashMap<DocumentId, Document>,
editors: HashMap<EditorId, EditorState>,
ui: UiState,
debug: DebugState, // Optional, compile-gated with #[cfg(feature = "perf")]
}
Message Integration
enum Msg {
// ... existing
Debug(DebugMsg),
}
enum DebugMsg {
TogglePerfOverlay,
UpdatePerfStats(PerfSnapshot), // Received from background sampler
RecordFrameTime(Duration),
}
Cmd for Background Sampling
enum Cmd {
Redraw,
SaveFile { .. },
StartPerfSampler { interval_ms: u64 }, // Spawns thread that posts DebugMsg
StopPerfSampler,
}
// In event loop
Cmd::StartPerfSampler { interval_ms } => {
std::thread::spawn(move || {
loop {
std::thread::sleep(Duration::from_millis(interval_ms));
let snapshot = PerfSnapshot {
cpu: perf_monitor::cpu::processor_numbers().ok(),
memory: perf_monitor::mem::get_process_memory_info().ok(),
};
tx.send(Msg::Debug(DebugMsg::UpdatePerfStats(snapshot))).ok();
}
});
}
Instrumented Update Loop
fn update(app: &mut AppModel, msg: Msg) -> Option<Cmd> {
let start = Instant::now();
let msg_name = format!("{:?}", std::mem::discriminant(&msg));
let result = match msg { /* ... */ };
if app.debug.perf_enabled {
app.debug.update_times.insert(msg_name, start.elapsed());
}
result
}
Display Options
- Status bar - Show FPS, memory in existing status line
- Overlay panel - Dedicated debug overlay (new overlay type)
- Log only - Just write to stderr/file for CI analysis
// In render, after main content:
if app.debug.perf_enabled {
render_perf_overlay(&app.debug, ctx);
}
TL;DR
| Aspect | Fits Into |
|---|---|
| State | DebugState in AppModel |
| Collection | Cmd::StartPerfSampler spawns background thread |
| Updates | DebugMsg::UpdatePerfStats posts samples back |
| Display | UiState overlay or status bar extension |
| Toggle | DebugMsg::TogglePerfOverlay |
The architecture handles it cleanly because it's just another domain (Debug) with its own state/messages, and the expanded Cmd system supports the background sampling thread.
Done. Added section 5 "Performance Monitoring Integration" to CODEBASE_REVIEW.md covering:
- Why — Frame times, update latency, memory tracking, I/O performance
- Where it lives —
DebugStateas separate domain inAppModel - Message integration —
DebugMsgenum with toggle, update, record variants - Command integration —
Cmd::StartPerfSamplerfor background thread - Implementation pattern — Instrumented
update()loop with timing - Display options — Status bar, overlay, log file, JSON export
- Compile-time gating — Optional
perffeature flag - Integration table — How it ties to soft wrapping, syntax highlighting, etc.
Great insights from the oracle. Let me also look up actual Fleet theme values to give you more accurate colors:
Now let me create a comprehensive document with all of this:
Created docs/THEMING_SYSTEM.md with:
Format: YAML (comments, readable nesting, maps to Rust via serde)
Complete schema covering:
- UI components: window, editor, gutter, scrollbar, status_bar, popup, search, diagnostics, tabs
- State modifiers:
normal,hover,active,focused,disabled - Syntax tokens: 30+ semantic roles (keyword, function, type, string, etc.)
- Font styles: bold, italic, underline, strikethrough
Key naming patterns:
ui.editor.background.normal # Component.subcomponent.property.state
ui.gutter.line_number.foreground_active
syntax.keyword_control.foreground
Example Fleet Dark theme with actual JetBrains Fleet-inspired colors
Rust integration:
Colorstruct withto_argb_u32()for renderingStatefulColor.resolve(UiState)for state-aware colorsSyntaxStylewithis_bold(),is_italic()helpers- Fits into
AppModelalongside documents/editors/ui