Editor Architecture
hone-editor is the embeddable code editor component (@honeide/editor). It is used by hone-ide but can also be embedded independently. The editor has three layers: core (platform-independent logic), view-model (reactive state bridge), and native (Rust FFI rendering per platform).
core/ – Platform-Independent
All editor logic lives here. No platform dependencies, no FFI, no rendering.
Buffer (buffer/)
Text storage uses a piece table backed by a rope with a line index:
- Piece table tracks original and add buffers with a sequence of pieces
- Rope provides O(log n) random access and efficient insertions/deletions
- Line index maintains a mapping from line numbers to buffer offsets
- Supports large files without loading entire content into a flat string
Cursor (cursor/)
Multi-cursor management:
- Multiple independent cursors with selection ranges
- Word boundary detection for double-click selection and ctrl+arrow navigation
- Cursor affinity (left/right) for ambiguous positions at line wraps
- Selection operations: expand to word, line, bracket, all
History (history/)
Undo/redo with time-based coalescing:
- Changes within a 500ms window are grouped into a single undo step
- Maximum undo stack depth: 10,000 entries
- Branching undo (redo stack preserved until a new edit diverges)
Viewport (viewport/)
Virtual scrolling for performance with large files:
- Only renders visible lines plus a 10-line buffer zone above and below
- Hidden line tracking for code folding integration
- Smooth scrolling with pixel-level offset tracking
- Viewport resize handling
Tokenizer (tokenizer/)
Incremental syntax highlighting via two engines:
- Lezer parser integration – 8 language grammars: TypeScript, HTML, CSS, JSON, Markdown, Python, Rust, C++
- Keyword-based fallback engine – for languages without a Lezer grammar
- Incremental re-tokenization on edits (only re-parses changed regions)
- Token types map to theme color scopes
Search (search/)
Find and replace across the document:
- Literal and regex search modes
- Chunked search for large files (avoids blocking the main thread)
- Incremental live search (results update as the user types)
- Match highlighting with current-match distinction
Folding (folding/)
Two folding strategies:
- Indent-based – folds regions where indentation increases
- Syntax-based – uses Lezer parse tree to identify foldable nodes (functions, classes, blocks)
- Nested folding with level tracking
Diff (diff/)
Myers diff algorithm implementation:
- O(ND) complexity for computing minimal edit scripts
- Hunk-based operations (apply hunk, revert hunk)
- Inline character-level diff within changed lines
- Used by the git diff view and AI review
Document (document/)
Wraps TextBuffer with document metadata:
- URI, languageId, version counter
isDirtytracking- Encoding detection (UTF-8, UTF-16, etc.)
- Line-ending detection and normalization (LF, CRLF)
Commands (commands/)
Command registry with 5 command modules:
- Editing – insert, delete, indent, comment toggle, auto-close brackets
- Navigation – go to line, go to definition, go to bracket
- Selection – select all, expand selection, shrink selection
- Clipboard – cut, copy, paste with multi-cursor support
- Multi-cursor – add cursor above/below, add cursor at next occurrence
LSP Client (lsp/)
Language Server Protocol client implementation:
- JSON-RPC 2.0 transport layer
- Typed request/response methods:
textDocument/completion– autocompletetextDocument/hover– hover informationtextDocument/publishDiagnostics– errors and warningstextDocument/codeAction– quick fixes and refactoringstextDocument/definition– go to definitiontextDocument/references– find all referencestextDocument/formatting– document formatting
DAP Client (dap/)
Debug Adapter Protocol client:
- Session management: launch and attach configurations
- Breakpoint management (line, conditional, logpoint)
- Execution control: continue, step over, step into, step out, pause
- Stack frame inspection
- Variable inspection with scopes (local, closure, global)
Snippets (snippets/)
- Template processing with tab stops and placeholders
- Language-specific snippet registries
- Variable expansion (
$TM_FILENAME,$CLIPBOARD, etc.)
view-model/ – Reactive State Bridge
EditorViewModel orchestrates all core subsystems and exposes reactive state for rendering:
- Cursor state – positions, selections, blink timer
- Decorations – inline decorations, line decorations, overlay widgets
- Diff view model – side-by-side and inline diff rendering state
- Find widget – search state, match counts, replace mode
- Ghost text – AI inline completion overlay
- Gutter – line numbers, fold indicators, breakpoint markers, diagnostics
- Line layout – computed line heights, wrapped line mapping
- Minimap – scaled-down document overview with viewport indicator
- Overlays – autocomplete popover, hover card, parameter hints
- Theme – resolved token colors and editor colors
native/ – Rust FFI Per Platform
The editor uses a TS-authoritative model: TypeScript is the single source of truth for all document state. The Rust layer is a rendering cache that receives pre-computed line content and viewport state via FFI.
NativeEditorFFI Interface
93+ FFI functions organized by concern:
- Document operations (set content, apply edit, get line)
- Viewport management (scroll, resize, set visible range)
- Cursor rendering (set positions, blink state)
- Selection rendering (set selection ranges)
- Decoration management (add/remove/update decorations)
- Theme application (set colors, font metrics)
- Input handling (key events, mouse events, IME)
Platform Crates
| Platform | Rendering | Text Layout |
|---|---|---|
| macOS | Metal | CoreText |
| iOS | UIKit / Metal | CoreText |
| Windows | Direct2D | DirectWrite |
| Linux | Cairo | Pango |
| Android | Skia | HarfBuzz |
| Web | WASM + Canvas | Browser layout |
Each platform crate implements the same NativeEditorFFI interface, so the TypeScript layer is entirely platform-agnostic.