Skip to main content

Block

Enum Block 

Source
pub enum Block {
Show 13 variants Heading { level: u8, children: Vec<Inline>, id: Option<String>, }, Paragraph(Vec<Inline>), Callout { kind: CalloutKind, fold: Option<Fold>, title: Option<String>, children: Vec<Block>, }, List { ordered: bool, start: Option<u64>, items: Vec<Vec<Block>>, item_source_lines: Vec<Option<usize>>, }, CodeBlock { lang: Option<String>, value: String, }, Table { header: Vec<Vec<Inline>>, rows: Vec<Vec<Vec<Inline>>>, alignments: Vec<ColumnAlignment>, header_source_line: Option<usize>, row_source_lines: Vec<Option<usize>>, }, BlockQuote(Vec<Block>), Shortcode(Shortcode), ThematicBreak, Figure { image: Inline, caption: Option<Vec<Inline>>, width: Option<String>, align: Option<String>, class_names: Vec<String>, img_style: Option<String>, }, LinkCard { url: Url, children: Vec<Block>, }, FootnoteDefinition { label: String, children: Vec<Block>, }, Other(String),
}
Expand description

A block-level AST node.

Variants§

§

Heading

# Heading (level 1) through ###### Heading (level 6).

Fields

§level: u8
§children: Vec<Inline>
§id: Option<String>

Heading anchor id (slug). Computed by the parser via crate::heading::anchor::obsidian_heading_anchor.

§

Paragraph(Vec<Inline>)

A paragraph of inline content.

§

Callout

> [!type] body — typed callouts. The kind is canonicalized via CalloutKind::from_raw (Obsidian-dialect aliases collapse to the canonical 16-kind set). Foldable callouts (> [!type]+ open by default, > [!type]- closed) carry the Fold state; non-foldable callouts have fold: None.

Phase 4 PR4 extended the shape from kind: String to kind: CalloutKind + added fold: Option<Fold> and title: Option<String>. Title is the optional inline text following the marker (> [!note] My titletitle: Some("My title")).

Fields

§fold: Option<Fold>
§children: Vec<Block>
§

List

- item / 1. item. Each item is a list of blocks (so list items can carry paragraphs, sub-lists, etc).

item_source_lines is a parallel-to-items vec of 1-based source line numbers, populated by the parser only when crate::ast::ParseConfig::emit_source_lines is true. When tracking is off (production publish builds, the ~40 in-crate parse() callers that use the default config), the vec is empty (vec![]) and the renderer treats every item as None — no data-source-line on the emitted <li>. When tracking is on, length matches items.len() exactly; individual entries may still be None for synthesized items that have no faithful source position (none today, but kept for symmetry with crate::ast::document::BlockMeta::source_line).

Phase 4 source-lines followup (2026-05-28): added because the preview’s scroll-sync (cm-scroll-sync via frontend/bridge/iframe-bridge.ts) interpolates editor positions proportionally between annotated DOM elements. A 30-item list spanning 50 source lines without per-<li> annotations forces interpolation between the outer <ul> and the next top-level block — potentially 100 lines away. Legacy transform_events (commit f91aca8fa, 2026-04-01) emitted on <li> and <tr> for this reason; the typed-AST renderer now matches.

Fields

§ordered: bool
§start: Option<u64>

Explicit ordered-list start number (pulldown-cmark’s Tag::List(Option<u64>) payload). Some(N) when the source is N. item and the renderer should emit <ol start="N">; None for unordered lists and for ordered lists where N is the implicit default 1. CommonMark only honors the FIRST item’s number as the list start; subsequent numbers are re-derived. Phase 4 followup B (2026-05-28): added because <ol> was previously emitted for any ordered list, silently dropping the explicit start number — 3. foo rendered as <ol><li>foo</li></ol> instead of <ol start="3"><li>foo</li></ol>.

§items: Vec<Vec<Block>>
§item_source_lines: Vec<Option<usize>>
§

CodeBlock

A fenced code block.

Fields

§value: String
§

Table

Markdown table.

header_source_line and row_source_lines are populated by the parser only when crate::ast::ParseConfig::emit_source_lines is true. When tracking is off, header_source_line is None and row_source_lines is empty (vec![]); the renderer emits no data-source-line attributes. When tracking is on, row_source_lines.len() == rows.len().

Phase 4 source-lines followup (2026-05-28): see the corresponding doc comment on Block::List for the scroll-sync interpolation rationale.

Fields

§header: Vec<Vec<Inline>>
§rows: Vec<Vec<Vec<Inline>>>
§alignments: Vec<ColumnAlignment>

Per-column GFM alignment, parallel to header. Empty (the common case) means the author declared no alignment on any column. skip_serializing_if keeps previously-serialized ASTs and snapshot fixtures byte-stable when there is no alignment to record.

§header_source_line: Option<usize>
§row_source_lines: Vec<Option<usize>>
§

BlockQuote(Vec<Block>)

> blockquote

§

Shortcode(Shortcode)

A typed shortcode block (:::name ...args\n body :::).

§

ThematicBreak

<hr> thematic break.

§

Figure

Image-only paragraph promoted to a typed figure.

Detected by the parser’s Tag::Paragraph arm (Phase 4 PR3, 2026-05-27): a paragraph that contains exactly one Inline::Image modulo whitespace text and line breaks. The renderer emits <figure class="moss-image">…<figcaption>…</figcaption></figure>, wrapping the image hook’s output and appending the caption when present.

image is constrained by the parser to be an Inline::Image; the renderer pattern-matches and falls back gracefully if the variant is anything else.

caption defaults to the image’s alt text at parse time. None means “figure wrap but no <figcaption>” — reserved for the empty-alt case (omit caption when there is nothing to read).

The figure-level display params (width, align, class_names, img_style) are populated only when a figure originates from a parameterized wikilink embed (![[photo.jpg|wide cover]]) — the image-embed synth-collapse routes such embeds through this typed node so width/fit/position/align survive (previously dropped by the markdown round-trip). The CommonMark ![](url) promotion path (try_promote_to_figure) leaves them at their defaults, so its rendered output is byte-identical to before the collapse.

Fields

§image: Inline
§caption: Option<Vec<Inline>>
§width: Option<String>

Canonical width token (body | wide | page | screen) emitted as data-width="…" on the <figure>. None omits the attribute. String (not &'static str) so Block keeps its Deserialize derive; the value is always one of the canonical tokens.

§align: Option<String>

Figure-level align class (moss-align-left / moss-align-right), appended to the <figure> class list. None omits it.

§class_names: Vec<String>

Extra author-supplied class names appended to the <figure> class list (after moss-image and any align class). Empty = none.

§img_style: Option<String>

Inline style= fragment for the INNER <img> (e.g. object-fit:cover;object-position:left from a |cover left embed). None omits it. Distinct from any figure-level attribute: fit/position style belongs on the image element, not the figure.

§

LinkCard

Compound-link grid cell: the entire cell is a single markdown link [inner](url) whose inner is parsed as block-level content (images, headings, paragraphs, emphasis). The SoCiviC Theatre pattern: [![[poster]] ### Title *date* description](/url).

Phase 4 PR4.5 (2026-05-28): added because CommonMark restricts Inline::Link.children to inline-level content; a markdown link wrapping ### Heading + paragraphs cannot round-trip through pulldown-cmark’s inline parser. The cell-string-level shape ([...](url) with multi-paragraph inner content) is detected by crate::ast::shortcode_extract::parse_grid BEFORE the cell flows through crate::ast::parser::parse; the matched cell yields a single-element vec![Block::LinkCard { url, children }] with the inner markdown parsed into typed blocks.

Render shape (matches today’s render_compound_link_cell byte shape):

  • External URL (http(s)://...): <a href=URL class="moss-grid-card link-preview" target="_blank" rel="noopener">children</a>.
  • Internal URL: <a href=URL class="moss-grid-card" data-kind="link">children</a>.

Fields

§url: Url
§children: Vec<Block>
§

FootnoteDefinition

[^label]: body — a GFM footnote definition, wherever the author wrote it (pulldown-cmark nests one written inside a blockquote or a list item under that container). The renderer hoists it out to the document’s endnote section; see ADR-035.

Fields

§label: String
§children: Vec<Block>
§

Other(String)

Raw HTML passthrough: a Tag::HtmlBlock the author wrote, or a payload moss synthesized itself (the shortcode sentinel pass in dispatch_wikilink_embeds). Emitted verbatim. NOT a fallback for unmodeled pulldown constructs — see the module doc.

Trait Implementations§

Source§

impl Clone for Block

Source§

fn clone(&self) -> Block

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Block

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for Block

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Eq for Block

Source§

impl PartialEq for Block

Source§

fn eq(&self, other: &Block) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl Serialize for Block

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl StructuralPartialEq for Block

Auto Trait Implementations§

§

impl Freeze for Block

§

impl RefUnwindSafe for Block

§

impl Send for Block

§

impl Sync for Block

§

impl Unpin for Block

§

impl UnsafeUnpin for Block

§

impl UnwindSafe for Block

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.