edamame 0.1.6

A Terminal Markdown editor that stays rendered while you edit
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
# Frontmatter (YAML / TOML metadata blocks)

> Part of the edamame contributor deep-dives. Index and project-wide conventions: [`AGENTS.md`](../../AGENTS.md). Sibling docs live in [`docs/dev/`](.).


- **The block is rendered *verbatim*, and that is load-bearing rather than visual.** `parse_offsets::DocParser` applies the matching metadata-block extension to the frontmatter so `---` YAML and `+++` TOML become `Block::MetadataBlock` instead of the thematic-break-plus-setext-H2 pair that made a Hugo/Jekyll/Obsidian file's keys the loudest element on the page (issue #34). `render_metadata_block` emits **one rendered row per source line, every character in its source column** — rendering adds only color. That keeps the raw↔rendered column relation the identity function and the row count 1:1, which the raw reveal, the gutter's inverse and the scroll math all assume; a prettier treatment would owe every one of those a block-specific arm.
- **The column mapping is the identity, and the rows say so.** `render_metadata_block` records each body row as `Verbatim` (its own source line, a blank one inside the frontmatter included) and each delimiter row as `Chrome`, so `row_map` maps a body row's columns one for one and never consults `InlineColMap`, which would re-parse the line as Markdown (a quoted YAML value picks up smart quotes; a `*` in a glob opens emphasis; `  - tag` reads as a list item). A `Verbatim` row also never de-renders: the cursor's row keeps its key/value colors and gains only the indicator.
- **The delimiter lines are reproduced from `MetadataKind`, not stored** — pulldown-cmark hands the AST builder the inner text only, so a YAML block closed with `...` renders as a plain `---`. Same three columns, and entering the block reveals the true source.
- **The key/value split is cosmetic and deliberately shallow.** `metadata_key_end` finds the first `:` / `=` followed by a space or end-of-line, requires a non-empty key, and otherwise declines (so `- https://example.com` doesn't split at the scheme's colon). It must not become a YAML or TOML parse: the two spans always concatenate back to the source line byte for byte, which is what makes the identity mapping true.
- **The export path parses the same way.** `export::html` keeps its own base option list and passes it to `DocParser::with_options`; parsing the export any other way reproduces the misparse below. pulldown-cmark's HTML writer treats a metadata block as non-writing, which is also the wanted behavior.
- **The extensions see the frontmatter and nothing else.** pulldown-cmark's are not anchored to the document start: with one on, a `---` opening *any* block, top-level or the first line inside a quote or list item, starts a metadata block whenever a closing `---` follows below. So an ordinary section separator (a rule above a heading, a Marp slide break, a rule in a quote) would parse as metadata: dim key/value styling, `block_allows_inline_markdown_at` refusing emphasis inside it, and *nothing* emitted by the HTML writer, silently dropping content from the export. Gating the extension on the document's first line once kept it off only in documents *without* frontmatter. `DocParser` instead finds the byte-0 block itself (`frontmatter_end`, which restates pulldown-cmark's rules and is tested against them), parses exactly that slice with the extension on, and parses the rest with both off, shifting its ranges to document offsets. Every parse of a document (AST, offset scans, HTML export) goes through it, or the 1:1 blocks↔ranges pairing breaks.
- **A `---` is still a rule almost everywhere.** Every `---` past the first line is one unconditionally; even the opening one is frontmatter only when the delimiter run is exactly three characters, the line below is non-blank, and a closing delimiter exists. `edit_ops`'s inline-snippet gate excludes the block: emphasis or a link inside frontmatter is data corruption, not formatting.