An embeddable, high-performance code editor component for Zgui applications — from a small syntax-highlighted field inside another app up to the foundation of a full editor or IDE.
use zgui::prelude::*;
use zgui_editor::{Editor, EditorProps};
view! {
Editor(class = "my-editor", text = source, language = "rust")
}- Very large files. One retained element paints only the visible lines; the scroll model is
the editor's own
f64fractional line, so a ten-million-line buffer scrolls to pixel precision and a keystroke costs a keystroke. The buffer is a rope (ropey); snapshots for background work are O(1). - Tree-sitter highlighting, incrementally. A worker thread owns the parser and the tree;
edits cross as
tree.editdeltas, queries run only over the viewport (± overscan), and stale results are dropped by revision. Grammars are pluggable throughLanguageRegistry; common ones are bundled behind cargo features (lang-rust,lang-toml,lang-markdown). - App-definable key handling. An
on_keyfilter hears every key before the editor does. The bundled vim example (examples/vim) implements modal editing — counts, operators, registers,/search — entirely outside the component, over the publicCommandvocabulary and the synchronousEditorHandle::queryAPI. - Editing model. Multi-cursor-capable selections, grapheme-aware movement, vim-style undo coalescing, word motions, plain-text search.
- One buffer, several windows. A
Documenthanded to twoEditors is two views of one file: an edit in either is the edit, either can undo it, and each keeps its own carets, scroll position and theme. A change reports the replacements that made it, in the order they applied — which is what a language server's incremental synchronisation is. - Marks an application draws. Named layers of bands, squiggles and gutter marks, each naming a
custom property of its own, so diagnostics, search hits and git hunks replace one at a time.
point_for_byteturns a byte into a place on the window, which is what a hover card, an inline diagnostic or a leap label is positioned by. - Mouse. Click/drag selection with pointer capture and edge autoscroll, double-click word and triple-click line selection, middle-click primary-selection paste on Linux, scrollbar dragging.
- Smooth scrolling. Wheel input glides (critically-damped), trackpads track exactly,
scrolloff-style caret margins are configurable. - Line numbers. Absolute, relative (vim-style), or none.
- Completion popovers. The caret's window rectangle is a signal (
handle.caret_rect()), edits and selection moves are events, and the key filter lets an open popover steal its keys — seeexamples/completion.rs.
The element's color is the text and its background is the background; everything else is a
custom property, inheriting through the cascade like any other:
.my-editor {
font-family: 'JetBrains Mono', monospace;
font-size: 14px;
tab-size: 4;
--editor-selection: rgba(137, 180, 250, 0.3);
--editor-cursor: #f5e0dc;
--editor-current-line: rgba(88, 91, 112, 0.35);
--editor-gutter-fg: #6c7086;
--syntax-keyword: #cba6f7;
--syntax-function: #89b4fa;
--syntax-string: #a6e3a1;
--syntax-comment: #6c7086;
}Syntax colours map from tree-sitter capture names with dots as hyphens
(function.method → --syntax-function-method), falling back along the dots and then to the
foreground.
Everything is a Command, applied through the EditorHandle delivered by on_ready (and via
local context). The handle also answers synchronous reads — query(|snapshot| ...) exposes the
rope, the selections, motion ranges, and search — and publishes signals (cursor_position(),
scroll_state(), caret_rect(), revision()) for status lines and custom chrome.
cargo run --example basic --features lang-rust [-- path/to/file]
cargo run --example vim --features lang-rust [-- path/to/file]
cargo run --example completion --features lang-rust- IME: input methods do not compose over the editor yet. The platform only starts
compositions over the runtime's intrinsic editable elements; see
src/ime.rsfor the limitation and the upstream path. Dead-key composition works. - No soft wrap: long lines scroll horizontally. The line cache and scroll model keep the seam open for it.
- Injections (markdown embedding rust) are parsed single-layer for now.
The framework is pre-1.0; .cargo/config.toml patches the git dependencies to a local
checkout. Tests run headlessly:
cargo test --all-features # unit + component + pipeline tests
cargo test --example vim --features lang-rust # the vim layer, end to end