Patterns / Media
Markdown
Markdown apps/gallery/src/patterns/dialect.rs
let doc = markdown::parse(source);
let source = markdown::serialize(&doc);The document model is Notion's — a flat list of blocks, each carrying an indent — and markdown is its wire form. parse and serialize are inverses up to a fixed point: parse, serialize, parse again, and nothing has moved.
Blocks
| Spelling | Block |
|---|---|
# … ###### |
Heading, levels 1–6 |
| plain text | Paragraph |
- , * , + |
Bullet |
1. |
Ordered item, keeping the number it starts at |
- [ ] , - [x] |
Task |
> |
Quote |
``` |
Fence |
--- |
Rule |
| a | b | |
Table |
 alone on a line |
Picture |
| a link alone on a line | Bookmark |
A newline inside a block is a line break, here and in Notion both.
Marks
**bold**, _italic_ or *italic*, ~~strikethrough~~, `code`, and [text](url). Nesting order survives a round trip — **_x_** and _**x**_ are different documents, which is why marks are spans over the text rather than flags on a run.
Typing ## makes a heading because pasting ## would have; inline marks close on the last delimiter. Emphasis will not open or close against a space, and an underscore inside a word is not emphasis, which is the only reason snake_case_names survive being typed.
Fences
```rs
fn main() {}
```A tag names the grammar syntax highlights with. A tag nothing claims paints plain and never fails. markdown::set_block_renderer hands a tag and its source to a function of yours, so ```chart paints as a chart and still holds a caret, still round trips byte for byte, and still degrades to its own source where the renderer is not installed.
Links and pictures
<https://bezel.gallery>
[https://bezel.gallery](https://bezel.gallery "chip")
[https://bezel.gallery](https://bezel.gallery "embed")
A link with a line to itself is a card; chip and embed have no shorthand, so they say their name in the title slot. What a card shows past its URL is the app's, through markdown::set_link_preview — the crate fetches nothing. A picture's caption is its alt text, and a dragged width is written after it in whole pixels.
Limits
| nesting | Four spaces per level, list nesting only. > - a flattens to the bullet it reads as; a list inside a quote inside a list does not survive. |
| normalized on parse | Edge whitespace, blank lines at block edges, headings and table cells flattened to one line, ordered runs renumbered. |
| escaping | Only at the start of a line, where the character would mean something — escape # everywhere and #123 becomes \#123, which no reader matches. |
| HTML | Arrives as the text it spells and is written back escaped. |
| not carried | Footnotes and reference-style definitions. A setext heading is read and written back as #. |
Tables are GFM's, alignment row included — :---, :---:, ---:. Every cell is one line and holds a caret.
The source is at apps/gallery/src/patterns/dialect.rs. Copy the file.