Expand description
A block-based WYSIWYG Markdown editor for GPUI, built on gpui-kit’s
public editor host API (gpui_kit::base::text::editor_host).
The design began as a spike in
longbridge/gpui-kit#3049
and #3566; see
docs/design.md. Call init once, after gpui_kit::init.
BlockEditorModel: the headless model. It has stableBlockIds, validatedBlockPositions, normalized inline mark runs, invertible steps grouped into transactions, undo coalescing, commands on nested blocks (EditorCommand), and a Markdown serializer.BlockEditorState: the entity that owns a model, focus, IME and key bindings, and emitsBlockEditorEvents.BlockEditor: the view. It renders through gpui-kit’s own text renderer (a direct model-to-node projection) and culls off-screen blocks.
ⓘ
let scroll = ScrollHandle::new();
let editor = cx.new(|cx| {
let mut state = BlockEditorState::new(window, cx).with_source("# Hello");
// Optional: keep the caret in view inside your scroll container.
state.set_scroll_handle(scroll.clone());
state
});
cx.subscribe(&editor, |_, editor, event: &BlockEditorEvent, cx| {
if let BlockEditorEvent::Changed { .. } = event {
let markdown = editor.read(cx).source();
}
});
// in render:
div().id("doc").overflow_y_scroll().track_scroll(&scroll)
.child(BlockEditor::new(&editor))Keys: Enter, Backspace/Delete, arrows/Home/End (+Shift), Cmd/Ctrl+A, B, I,
E, Z, Shift+Z, C, X, V, and Shift+V (plain paste); Tab/Shift+Tab indent
list items; Cmd/Ctrl+Alt+0 makes the block (or each selected block) a
paragraph. Input rules: # ..###### , - , * , + , 1. .
The scroll handle is optional: without it, blocks outside the visible
area are still culled, but moving the caret never scrolls (a no-op).
Modules§
- component
- Themed, content-sized Markdown editor. Base retains all editing behavior.
Structs§
- Block
Editor - A block-based WYSIWYG Markdown editor (spike). Hold an
Entity<BlockEditorState>and pass it here inrender. Instance styling applies to the native input root; it installs no padding or height defaults. - Block
Editor Model - Headless editor facade (spike name). Phase 3 wraps this in the
BlockEditorStateentity. - Block
Editor State - Block
Editor Style - Presentation seam for
super::BlockEditor. Private fields,with_*setters and readers (ARCHITECTURE.md invariant 12). Unset colours are transparent and are filled from the theme tokens bySelf::resolved, mirroringInputEditorStyle::resolved. - BlockId
- Opaque, process-unique block identity (design D1).
- Block
Position - A caret location. Plain value type: its fields are the definition.
- Block
Ref - Borrowed read projection of one block.
- Captured
Range - An opaque range tied to one editor, revision and navigation epoch. Successful replacement advances the capture to cover just the inserted text. Any other edit, load, undo/redo or navigation invalidates it, even if text is unchanged.
- Document
Ref - Borrowed read projection of the document, like the dock’s
PaneRef. - Input
Rule - One input rule. Construct the built-in rules with the associated
functions, or take them all with
InputRule::markdown_defaults. - Mark
Change - A change to apply over a range. Builder with private fields.
- MarkSet
- Read-only view of the marks at a position.
TextMarkstays internal. - Paste
Request - An intercepted semantic paste tied to the editor’s current document and
selection. Resolve once; no synthetic key events or OS clipboard access is
needed when delivering an explicit
ClipboardItem. - Source
Snapshot - Immutable canonical source derived once per document revision. Cloning this value shares the text; it is not another writable document owner.
- Transaction
- A committed group of steps. Opaque.
Enums§
- Affinity
- Caret side at a soft wrap or mark boundary. Not part of ordering.
- Block
Editor Event - Events emitted by
BlockEditorState. - Block
Kind - Public, payload-light projection of a block’s kind, for matching in
toolbar code. Payloads (code language, table alignments, definition
targets) stay in the crate-internal
BlockKindData. - Block
Selection - Captured
Range Error - Clipboard
Policy - Whether paste uses editor defaults or is first offered to the host.
- Column
Align - The alignment of a table column.
- Command
Error - Edit
Origin - Why an edit happened; drives undo coalescing.
- Editor
Command - Image
Policy - Whether image atoms may load resources while the editor presents them.
Placeholderkeeps the atomic document, source and selection but never resolves URLs, decodes data, reads paths or creates image elements. - Mark
Kind - A kind of inline mark, keyed on exactly
TextMark’s attributes (D12). - Mark
State - Whether a mark covers a whole range, none of it, or part of it.
- Position
Error - Selection
Error - Submit
Policy - Which Enter action requests submission. Newline is the document-editor default.
- Table
Edit - Which table edit to make at the caret’s cell, or across the rows and columns of a cell selection (D20).
- Table
Line - A table row or column, as a grip names it.
Functions§
- init
- Registers the editor’s key bindings. Call once at startup, after
gpui_kit::init.