edamame 0.1.3

A fast TUI Markdown editor and viewer
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::options_for` enables the matching metadata-block extension 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.
- **Four consumers must be told the mapping is the identity**, because their defaults are wrong here in different ways. `sub_lines_in_block` joins code blocks in the verbatim branch — a blank line inside frontmatter is data and renders a row, while the prose walk would drift the cursor up a row per blank. The overlay painter (`rendered_view::paint`) and the click mapper (`mouse_ops::coord`, via `LineMapping::Verbatim`) must not consult `InlineColMap`, which re-parses the line as Markdown (a quoted YAML value picks up smart quotes; a `*` in a glob opens emphasis). And `RenderedView`'s cursor-indicator `visual_col` chain needs its metadata arm **ahead of the list arm**, since `  - tag` is a YAML sequence entry the list-marker text sniff would shift. (`coord`'s list branch is AST-gated, so only the sniffing sites need the ordering.)
- **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 applies the same gate.** `export::html` keeps its own base option list and takes the metadata half from the shared `metadata_options_for`; without it an export reproduces the misparse. pulldown-cmark's HTML writer treats a metadata block as non-writing, which is also the wanted behavior.
- **The extensions are enabled per *document*, gated on its first line.** Unconditionally on, pulldown-cmark claims *any* later `---` line followed by non-blank text and eventually closed by another `---`, so an ordinary section separator (a rule above a heading, a Marp slide break) parses 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. Every parse of a document — AST, offset scan, HTML export — must pass *that document's* text through `options_for`, 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.