gpui-kit-markdown-editor
A block-based WYSIWYG Markdown editor for GPUI, built on
gpui-kit's public editor host API
(gpui_kit::base::text::editor_host). It edits real Markdown: paragraphs,
headings, nested lists, task lists, block quotes, fenced code blocks, tables,
links, and bold/italic/strike/inline-code marks. It has cross-block selection,
IME, undo/redo, input rules (# , - , ```), copy/paste as Markdown,
and culling of off-screen blocks.
Usage
[]
= "0.8.0"
= { = "https://github.com/wabzqem/gpui-kit-markdown-editor" }
The library is imported as markdown_editor.
use *;
use ;
A themed, content-sized wrapper lives in markdown_editor::component.
Images load by default. Use ImagePolicy::Placeholder to show a placeholder
instead and never resolve URLs, decode data or read paths.
Features and keys
Cargo features forward to gpui-kit's syntax highlighting for fenced code blocks; gpui-kit only highlights when one is on:
| Feature | Effect |
|---|---|
syntect (default) |
About 200 languages, no syntax tree |
tree-sitter |
Tree-sitter highlighting (takes precedence if both are on) |
Disable default features to build without highlighting.
Keys (Cmd instead of Ctrl on macOS): Enter, Backspace/Delete, arrows,
Home/End, Ctrl+Home/End (document start/end), Shift to select, Ctrl+A,
Ctrl+B/I/E (bold, italic, code), Ctrl+K (edit link), Ctrl+Alt+0 (normal
text: the block, or each selected block, becomes a paragraph; Backspace at the
start of a heading, a Backspace/Delete that empties it, and Enter in an empty
heading do the same), Ctrl+Z / Ctrl+Shift+Z
(or Ctrl+Y), Ctrl+C/X/V, Ctrl+Shift+V (plain paste), Tab/Shift+Tab (indent
list items, move between table cells), Shift+Enter (soft break, also in a
table cell). In a table (caret or cell selection): Ctrl+Alt+Left/Right insert
a column left/right, Ctrl+Alt+Up/Down insert a row above/below, and
Ctrl+Alt+Backspace deletes the selected column(s) when whole columns are
selected, otherwise the current row(s) (never the header row). Hovering a table
shows a grip above the column and left of the row; clicking it selects that
column / row and opens a menu (insert, delete, column alignment). Cmd/Ctrl-click a link emits LinkClicked; the editor never
opens a browser.
Drag to reorder (D22): drag a table or code block by its edge handle (the strip left of it; the pointer becomes an open hand) and a line shows where it will drop between top-level blocks. One undo step. Other blocks are not draggable.
Text-editing keys (D21). Word deletes: Option+Backspace / Option+Delete on macOS, Ctrl+Backspace / Ctrl+Delete elsewhere (word motion is Option+arrows / Ctrl+arrows). macOS also has Cmd+Backspace / Cmd+Delete (delete to the start / end of the visual line; in a code block, of the code line), Cmd+Left/Right and Shift (visual line start / end, like Home/End), Option+Up/Down and Shift (block start / end; Ctrl+Up/Down and Shift on Windows/Linux), and the Cocoa emacs keys Ctrl+A/E (and Shift), Ctrl+D/H (delete forward / back) and Ctrl+K (delete to the line end; no kill ring). With a selection, every delete key removes just the selection. At the start of a block, word and line deletes act as Backspace (join, lift, heading to paragraph); at its end, forward ones act as Delete. In a table cell they stay in the cell and do nothing at its edges. A run of word deletes is one undo step (separate from plain Backspace/Delete); a line delete is its own.
Known limitations
- Copying across blocks writes Markdown and pastes back as blocks (headings, lists, quotes, code, tables, tasks, marks). A table the selection touches is copied whole, and a selection starting inside a nested list lifts the nested items out instead of copying an empty parent item. Pasting a list directly after another list joins them.
- Empty paragraphs have no Markdown form and disappear on save; list tightness can change once on the first save, after which output is stable.
- A
BlockEditoris as tall as its text. Give itmin_h_full()(and padding on the editor, not an outer wrapper) if the whole area should be clickable. - Accessibility exposes the document as one multi-line text input plus a node per laid-out top-level block; nested items, table cells and inline roles are not exposed, and screen-reader behaviour is unverified.
- Culling covers top-level blocks and long top-level lists; nested long lists and long tables are laid out in full.
- No
source_offsetmapping, no pluggable input-rule registry, and events carry no change summaries yet. - Developed and tested on Linux (under a virtual display). macOS and Windows key bindings and IME are implemented but unverified here.
- Bold text only looks bold if the theme font has a bold face (the same as
gpui-kit's own
TextView).
Build and run
Linux needs the same system libraries as gpui-kit
(script/install-linux.sh in that repo). Then:
Everything builds from public dependencies only.
Design
docs/design.md: the editor design.docs/host-contract.md: what the editor needs from the gpui-kit host API.docs/design-notes.md: implementation notes from the spike.
History and credits
The code began as the block editor spike in gpui-kit (#3049, #3566); its commit history is preserved in this repository.
Licence
Apache-2.0, the same as gpui-kit. See LICENSE-APACHE.