Skip to main content

mos_eval/
inline.rs

1//! Lower inline parser nodes into semantic document children.
2
3use std::collections::BTreeMap;
4
5use mos_core::{AttrMap, AttrValue, Document, NodeId, NodeKind, NodeSpec};
6use mos_parse::{Inline, InlineKind};
7
8use crate::insert_label_attributes;
9
10pub(super) fn lower_inlines(doc: &mut Document, parent: NodeId, inlines: &[Inline]) {
11    for inline in inlines {
12        let kind = match inline.kind {
13            InlineKind::Text => NodeKind::Text,
14            InlineKind::Emphasis => NodeKind::Emphasis,
15            InlineKind::Strong => NodeKind::Strong,
16            InlineKind::BoldItalic => NodeKind::BoldItalic,
17            InlineKind::Code => NodeKind::Raw,
18            InlineKind::Reference => NodeKind::Reference,
19            InlineKind::PageReference => NodeKind::PageReference,
20            InlineKind::Citation => NodeKind::Citation,
21            InlineKind::HardBreak => NodeKind::HardBreak,
22        };
23        let mut attributes: AttrMap = BTreeMap::new();
24        match inline.kind {
25            InlineKind::Reference => {
26                // Stamp the label and its identifier `label_span` (issue #116)
27                // exactly as declarations are, so rename reads the editable
28                // identifier range directly instead of re-deriving it from the
29                // reference node's span geometry. Pre-resolve placeholder text:
30                // the resolver overwrites it on success; unresolved refs still
31                // render visible `?label?` text.
32                insert_label_attributes(&mut attributes, &inline.text, inline.label_span.as_ref());
33                attributes.insert(
34                    "text".to_owned(),
35                    AttrValue::Str(format!("?{}?", inline.text)),
36                );
37            }
38            InlineKind::PageReference => {
39                // Same label + identifier-span stamp as a cross-reference
40                // (issue #116). The `?label?` placeholder stays visible until
41                // the resolve↔layout fixpoint (issue #72) rewrites it to the
42                // target's page number; this slice models the node only.
43                insert_label_attributes(&mut attributes, &inline.text, inline.label_span.as_ref());
44                attributes.insert(
45                    "text".to_owned(),
46                    AttrValue::Str(format!("?{}?", inline.text)),
47                );
48            }
49            InlineKind::Citation => {
50                // Record the bare key and a visible `[?key?]` fallback.
51                // `resolve_citations` rewrites this to a numeric label
52                // (`[1]`, ...) for keys found in a declared bibliography;
53                // unresolved keys keep `[?key?]` so the citation stays
54                // visible the same way unresolved refs are.
55                attributes.insert("key".to_owned(), AttrValue::Str(inline.text.clone()));
56                attributes.insert(
57                    "text".to_owned(),
58                    AttrValue::Str(format!("[?{}?]", inline.text)),
59                );
60            }
61            // Hard breaks are pure structural markers -- no text payload
62            // to lower, no attributes. Layout's `collect_words` matches
63            // on `NodeKind::HardBreak` directly.
64            InlineKind::HardBreak => {}
65            _ => {
66                attributes.insert("text".to_owned(), AttrValue::Str(inline.text.clone()));
67            }
68        }
69        doc.alloc_child(
70            parent,
71            NodeSpec::new(kind, inline.span.clone()).with_attributes(attributes),
72        );
73    }
74}