Build a Smaller Helix
Rebuild the ownership and event machinery, not a toy clone of modal syntax.
Build a tiny editor whose foreground loop owns all mutable state, applies invertible transactions, renders dynamic layers, and accepts asynchronous results only through version-aware callbacks.
1. Start with one concrete editor
Use String, a cursor index, and insert(char). Read scripted input events and
print the buffer after each one. Write down the invariant that the cursor is on
a UTF-8 boundary.
2. Introduce transactions
Represent retain/delete/insert operations, apply them only to a matching input length, map a cursor through them, compose adjacent edits, and construct an inverse from the pre-edit snapshot. Add undo before async code.
3. Separate document, view, and application
Let a document own text, version, and history; a view own viewport and selection; and the application own documents, views, and current focus. Open two views on one document and prove both selections map through an edit.
4. Add a dynamic compositor
Define Component { handle_event, render }, store boxed layers, and bubble
events from the top layer down. Add a prompt overlay that consumes keys without
teaching the base editor about prompts.
5. Replace the blocking loop with Tokio
Select over an input channel, redraw notification, timer, and job callback
channel. Keep Editor as a plain owned field—do not introduce a mutex.
6. Add the job/callback bridge
Spawn a fake “language service” that receives an owned text snapshot and version, waits, and returns a boxed callback. Apply its diagnostics only if the document still exists and its version matches. Test an out-of-order result.
7. Coalesce rendering
Make ten background notifications request redraw. Render at most once per frame interval, but process input immediately. Count renders in a deterministic test.
8. Add shutdown obligations
Classify jobs as detachable or must-finish. Stop admission, await required jobs under a deadline, execute their returned callbacks, and abort or drop the rest. Simulate a child service that never answers.
9. Compare with production
Map your types to Application, Editor, Document, Transaction,
Compositor, Component, Jobs, Callback, redraw events, and LSP transport.
Helix adds a mature rope, syntax trees, multi-selection editing, protocols,
terminal compatibility, plugins, debouncing, cancellation, and thousands of
commands. Your smaller version should still preserve its architectural center:
many things wait concurrently, one owner commits editor state.