Expand description
A hybrid markdown editor: raw text editing with live inline rendering (markers
like **, #, and - are hidden when the cursor is elsewhere) plus an inline
git diff against HEAD, rendered on winit + wgpu + Vello + Parley.
writ ships as both a desktop application (the writ binary) and a library. The
library’s centerpiece is MarkdownView — a headless, render-only markdown
renderer you can embed in your own winit/wgpu/Vello app.
§The application
- Live inline rendering: Markdown syntax is hidden when not editing
- Syntax highlighting: Code blocks with tree-sitter based highlighting
- Smart continuation: Shift+Enter continues lists, blockquotes, etc.
- Inline git diff: Renders the working file’s diff against git HEAD, refreshed live as the file or HEAD changes (an external commit updates the diff too)
// `writ --file notes.md` — the shell reads the path from the CLI and runs the app.
writ::shell::run()?;§Using writ as a library
MarkdownView turns markdown into a Vello Scene (a CPU display
list) with no window, GPU device, editor, or diff machinery — the consumer owns its
surface and rasterizes the scene however it likes. It supports streaming: feed
content incrementally with MarkdownView::push_str (e.g. tokens from an LLM) and
re-render.
use vello::Scene;
use writ::MarkdownView;
let mut view = MarkdownView::new();
view.push_str("# Streaming\n\n");
view.push_str("More text arrives later.\n");
let mut scene = Scene::new();
view.render(&mut scene, 800.0, 600.0, 1.0); // scene is now a display list
// ... hand `scene` to a vello::Renderer to rasterize onto your own surface.See examples/streaming_markdown.rs for an end-to-end headless render to PNG (via
rasterize_scene_to_png). For image support the component stays IO-free: it lists
referenced URLs via MarkdownView::image_urls and you push decoded bytes back in
with MarkdownView::set_image_bytes.
§Feature flags
Depend on writ with default-features = false to get just the renderer without the
app’s editor/git/GitHub/networking stack:
writ = { version = "0.16", default-features = false }- (none) — the render-only base:
MarkdownView,rasterize_scene_to_png, the diff algorithm, layout, and syntax highlighting. Pulls no winit/tokio/reqwest/ gix/notify. editor— the headlessEditororchestration hub (git diff vs HEAD, GitHub ref validation, file watching). Enables thecoremodule.app(default) — the full desktop application: the winitshell, clipboard, config file, mermaid + math + remote images. Implieseditor.- Individual toggles:
git,github,watch,remote-images,mermaid,math.
Re-exports§
pub use core::Editor;pub use editor::Direction;pub use editor::EditorTheme;pub use image_load::RepaintSignal;pub use markdown_view::MarkdownView;pub use raster::rasterize_scene_to_png;
Modules§
- buffer
- callout
- Obsidian-style callouts / admonitions.
- chrome
- Window chrome for the new shell (see MIGRATION-PLAN.md, Phase 6): an in-window title bar (filename + dirty marker) and a status bar (nesting context + cursor position). Drawn as opaque strips above/below the editor, which is inset between them. CSD (custom window frame) and the async-blocked overlays are deferred.
- config
- consts
- Appearance / frame constants, in one place so the shell (which renders) and the layout tests (which reproduce the frame) share a single source of truth rather than each hardcoding the same numbers. All values are logical px unless noted.
- core
- Headless editor model — the gpui-free core (see MIGRATION-PLAN.md, Phase 2).
- cursor
- diff
- Inline diff computation for the git HEAD-vs-working view.
- doc_
layout - Document viewport: per-line Parley layouts stacked by a prefix-sum height
model, plus scroll (see MIGRATION-PLAN.md, Phase 3). Replaces gpui’s
ListState(which gave virtualization + scroll-to-reveal for free) with hand-rolled math. - editor
- fold
- Folding: pure geometry over the document’s ATX headings and list items.
- git
- github
- GitHub API client using GraphQL.
- highlight
- image_
cache - Shared, cheaply-cloneable cache of decoded images for standalone-image rendering.
- image_
load - Standalone-image IO: resolving URLs to local paths, reading/decoding local files,
fetching + decoding remote images, and the spawn/blocking entry points that feed
decoded images into the shared
ImageCache. Kept off the shell so the god-object doesn’t carry the reqwest/decode plumbing. - inline
- Inline style extraction for markdown text.
- markdown_
view - Headless, render-only markdown view: turns markdown text into a Vello
Scene(a CPU display list) with no window, GPU device, editor, or diff machinery. It is the reusable core of writ’s renderer, meant to be embedded in another app that owns its own surface and rasterizes the scene however it likes. - marker
- Line markers for markdown block-level elements.
- math
- LaTeX math rendering: turn
$…$/$$…$$source into a rasterized image via RaTeX (parse → layout → tiny-skia PNG, with the KaTeX fonts embedded), then route it through writ’s existing image pipeline (image_cache::decode→LoadedImage→ the standalone- /inline-image draw path). Glyph color is set to the theme foreground at layout time so math is legible on the dark editor; the background is transparent. Rendering runs off the UI thread, cached by a key over(latex, display, size, color). - mermaid
- Mermaid diagram rendering: detect a
```mermaidfence, render its source to SVG viamermaid-rs-renderer, and route the SVG through writ’s existing image pipeline (image_cache::decode→LoadedImage→ the standalone-image draw path). The diagram is cached under a syntheticmermaid:<hash>key so it renders once per distinct source, not per frame; rendering runs off the UI thread. - outline
- The document-map / outline panel: a right-docked list of the document’s ATX headings, the current section highlighted, click a heading to scroll to it.
- overlay
- Overlay rendering: the GitHub-ref hover popover and the autocomplete dropdown, plus the styled-segment machinery (issue/user/title markdown) they share and the hover hit-testing that finds the ref under the pointer.
- parser
- paste
- Context-aware paste handling for markdown.
- raster
- Headless rasterization: turn a Vello
Sceneinto a PNG on disk via wgpu, with no window or surface. Shared by the golden-image snapshot harness (crate::shell) and by library consumers/examples so they don’t reimplement the device/renderer/readback dance. On Apple Silicon Fedora (Asahi) setWGPU_BACKEND=vulkanso wgpu picks a working adapter. - render
- Per-line styling for the new render path (see MIGRATION-PLAN.md, Phase 3).
- segment_
map - Display↔buffer segment map (see MIGRATION-PLAN.md, Phase 3b) — the load-bearing invariant of the new render path.
- shell
- winit + wgpu + Vello application shell — the gpui replacement (see MIGRATION-PLAN.md).
- status_
bar - table
- GFM pipe-table model extraction (headless).
- text_
engine - Parley text layout + Vello glyph drawing — the core of writ’s render path. Lays out a styled line with browser-grade (Chromium) soft-wrap and hanging indent, and paints its glyphs into a Vello scene. Drives the per-line layout cache and the display↔buffer map.
- text_
input - A reusable, headless single-line text-input core. No winit, no drawing — pure text/caret/selection state. Adapters (find bar, filter box, goto-line prompt) layer input handling and rendering on top of this.
- tokenize
- Hand-written syntax-highlight tokenizers for languages that have no publishable
tree-sitter grammar crate: Mermaid diagram source and LaTeX math. Each is a small
lexical scanner (keyword-match + punctuation/arrow patterns) that emits
HighlightSpans using the shared capture categories (seehighlight_id), so aHighlightertreats them as ordinary registered languages and they render through the same theme color map as the tree-sitter grammars. Token→category choices follow the consensus of the canonical tree-sitter grammars (monaqa/tree-sitter-mermaid, latex-lsp/tree-sitter-latex) and their Helix/nvim overrides. - validation
- GitHub reference validation model and cache.