Skip to main content

acdc_parser/model/
anchor.rs

1//! Anchor and reference types for `AsciiDoc` documents.
2
3use serde::{
4    Serialize,
5    ser::{SerializeMap, Serializer},
6};
7
8use super::location::Location;
9use super::title::Title;
10
11/// Section styles that should not receive automatic numbering.
12///
13/// When `sectnums` is enabled, sections with these styles are excluded from
14/// the numbering scheme. Appendix uses letter numbering (A, B, C) which is
15/// handled separately.
16pub const UNNUMBERED_SECTION_STYLES: &[&str] = &[
17    "preface",
18    "abstract",
19    "dedication",
20    "colophon",
21    "bibliography",
22    "glossary",
23    "index",
24    "appendix",
25];
26
27/// An `Anchor` represents an anchor in a document.
28///
29/// An anchor is a reference point in a document that can be linked to.
30#[derive(Clone, Debug, Default, PartialEq, Serialize)]
31#[non_exhaustive]
32pub struct Anchor {
33    pub id: String,
34    #[serde(default, skip_serializing_if = "Option::is_none")]
35    pub xreflabel: Option<String>,
36    pub location: Location,
37}
38
39impl Anchor {
40    /// Create a new anchor with the given ID and location.
41    #[must_use]
42    pub fn new(id: String, location: Location) -> Self {
43        Self {
44            id,
45            xreflabel: None,
46            location,
47        }
48    }
49
50    /// Set the cross-reference label.
51    #[must_use]
52    pub fn with_xreflabel(mut self, xreflabel: Option<String>) -> Self {
53        self.xreflabel = xreflabel;
54        self
55    }
56}
57
58/// A `TocEntry` represents a table of contents entry.
59///
60/// This is collected during parsing from Section.
61#[derive(Clone, Debug, PartialEq)]
62#[non_exhaustive]
63pub struct TocEntry {
64    /// Unique identifier for this section (used for anchor links)
65    pub id: String,
66    /// Title of the section
67    pub title: Title,
68    /// Section level (1 for top-level, 2 for subsection, etc.)
69    pub level: u8,
70    /// Optional cross-reference label (from `[[id,xreflabel]]` syntax)
71    pub xreflabel: Option<String>,
72    /// Whether this section should be numbered when `sectnums` is enabled.
73    ///
74    /// False for special section styles like `[bibliography]`, `[glossary]`, etc.
75    pub numbered: bool,
76    /// Optional style from block metadata (e.g., "appendix", "bibliography").
77    pub style: Option<String>,
78}
79
80impl Serialize for TocEntry {
81    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
82    where
83        S: Serializer,
84    {
85        let mut state = serializer.serialize_map(None)?;
86        state.serialize_entry("id", &self.id)?;
87        state.serialize_entry("title", &self.title)?;
88        state.serialize_entry("level", &self.level)?;
89        if self.xreflabel.is_some() {
90            state.serialize_entry("xreflabel", &self.xreflabel)?;
91        }
92        if self.style.is_some() {
93            state.serialize_entry("style", &self.style)?;
94        }
95        state.end()
96    }
97}