SuperMD

Writing a Plugin

A SuperMD plugin is a WebAssembly component plus a plugin.toml manifest, in a folder under ~/.supermd/plugins/. This page walks the whole path from template to installed plugin. You'll need Rust and about ten minutes.

Start from the template

Copy plugins/template/ from the repo. It's a complete, buildable plugin where every surface returns "not implemented" — you fill in the ones you want.

The manifest

plugin.toml declares what your plugin contributes. A complete example using several surfaces:

name = "my-plugin"
version = "0.1.0"

# Render ```mylang fences as SVG.
fences = ["mylang"]

# Command palette entries.
[[commands]]
id = "my-plugin.hello"
title = "Say Hello"

# Inline pattern replacement (regex, one match consumed whole).
[[inline]]
id = "shortcode"
pattern = ":([a-z]+):"

# Regex → style highlighting, no code involved.
[[decorations]]
pattern = "\\b(TODO|FIXME)\\b"
style = "accent"        # accent | muted | strong | highlight

formats = true          # adds "Format: my-plugin" to the palette
paste = true            # transform pasted text

# Export formats: "Export: HTML" in the palette.
[[exports]]
id = "html"
name = "HTML"
extension = "html"

# Rendered views for file types (content in, markdown out).
[[viewers]]
extensions = ["csv"]

# Status-strip text.
[[widgets]]
id = "words"

# "New: Daily Note" in the palette.
[[templates]]
id = "daily"
name = "Daily Note"

# Run on every save.
hooks = ["save"]

Declare only what you use — the host never calls surfaces you didn't declare.

Implement the surfaces

Each manifest entry maps to one exported function in src/lib.rs:

ManifestExportSignature (in, out)
fencesrender-blocklanguage + source + theme → SVG
[[commands]]run-commandid + document + selection → replacement
[[inline]]render-inlinepattern id + matched text → replacement text
formatsformat-documentdocument → document
pasteprocess-pastetext → optional replacement
[[exports]]export-documentdocument + format + theme → files (bytes)
[[viewers]]render-viewfilename + content → markdown
[[widgets]]status-textdocument → one line of text
[[templates]]render-templateid + date/context → filename + content
hookson-savepath + document → optional replacement

Everything is a pure function call: data in, data out, errors as strings. Returning an error shows a message; it never crashes the editor.

Build and install

rustup target add wasm32-wasip2
cargo build --release --target wasm32-wasip2
mkdir -p ~/.supermd/plugins/my-plugin
cp target/wasm32-wasip2/release/*.wasm ~/.supermd/plugins/my-plugin/plugin.wasm
cp plugin.toml ~/.supermd/plugins/my-plugin/

Run Reload Plugins from the palette. Your fences render, your commands appear.

If your plugin needs to read the workspace or fetch from the web, read Capabilities. For syntax-highlighting plugins, see Grammar Plugins — they're data-only, no Rust required.

Troubleshooting