Skip to content

Commit 1624587

Browse files
committed
feat(parser): parse callout references in grammar
Move callout reference parsing (`<1>`, `<.>`) from post-processing in converters into the grammar itself. This produces `CalloutRef` inline nodes with proper source locations and distinguishes between explicit and auto-numbered callouts. Closes #207.
1 parent ecec097 commit 1624587

28 files changed

+1622
-363
lines changed

CHANGELOG.md

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased acdc-converters-core]
99

10+
### Added
11+
12+
- `#[non_exhaustive]` attribute on `Options`, `GeneratorMetadata`, `toc::Config`,
13+
`Doctype`, and `IconMode` for semver-safe future additions
14+
- Comprehensive module-level documentation
15+
- `acdc-converters-dev` crate for test utilities (not published to crates.io)
16+
- Visitor method `visit_callout_ref` for processing callout references
17+
1018
### Changed
1119

1220
- **BREAKING**: Renamed crate from `acdc-converters-common` to `acdc-converters-core`
@@ -15,13 +23,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1523
- **BREAKING**: `toc::Config` fields are now private - use accessor methods
1624
(`placement()`, `title()`, `levels()`, `toc_class()`)
1725

18-
### Added
19-
20-
- `#[non_exhaustive]` attribute on `Options`, `GeneratorMetadata`, `toc::Config`,
21-
`Doctype`, and `IconMode` for semver-safe future additions
22-
- Comprehensive module-level documentation
23-
- `acdc-converters-dev` crate for test utilities (not published to crates.io)
24-
2526
## [Unreleased acdc-cli]
2627

2728
### Added
@@ -45,6 +46,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
4546

4647
## [Unreleased acdc-parser]
4748

49+
### Added
50+
51+
- Callout references (`<1>`, `<.>`) in source/listing blocks now have source locations in
52+
the AST
53+
- New `CalloutRef` inline node type for programmatic access to callout markers
54+
55+
### Changed
56+
57+
- Auto-numbered callouts (`<.>`) are now resolved during parsing, not rendering
58+
- JSON serialization for Callout references uses `"name": "callout_reference"`
59+
4860
### Fixed
4961

5062
- List continuations with blank line before `+` now correctly attach to ancestor list

acdc-cli/src/subcommands/inspect.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ fn inlines_to_string(inlines: &[InlineNode]) -> String {
3939
.as_deref()
4040
.map_or(String::new(), |l| format!("|{l}"))
4141
),
42+
InlineNode::CalloutRef(callout) => format!("<{}>", callout.number),
4243
InlineNode::Macro(macro_node) => match macro_node {
4344
InlineMacro::Link(link) => {
4445
link.text.clone().unwrap_or_else(|| link.target.to_string())

acdc-parser/fixtures/tests/callout_list_auto_numbering.json

Lines changed: 127 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,85 @@
4242
{
4343
"name": "text",
4444
"type": "string",
45-
"value": "Line one <1>\nLine two <2>\nLine three <3>",
45+
"value": "Line one ",
46+
"location": [
47+
{
48+
"line": 4,
49+
"col": 1
50+
},
51+
{
52+
"line": 6,
53+
"col": 14
54+
}
55+
]
56+
},
57+
{
58+
"name": "callout_reference",
59+
"type": "inline",
60+
"variant": "auto",
61+
"number": 1,
62+
"location": [
63+
{
64+
"line": 4,
65+
"col": 1
66+
},
67+
{
68+
"line": 6,
69+
"col": 14
70+
}
71+
]
72+
},
73+
{
74+
"name": "text",
75+
"type": "string",
76+
"value": "\nLine two ",
77+
"location": [
78+
{
79+
"line": 4,
80+
"col": 1
81+
},
82+
{
83+
"line": 6,
84+
"col": 14
85+
}
86+
]
87+
},
88+
{
89+
"name": "callout_reference",
90+
"type": "inline",
91+
"variant": "auto",
92+
"number": 2,
93+
"location": [
94+
{
95+
"line": 4,
96+
"col": 1
97+
},
98+
{
99+
"line": 6,
100+
"col": 14
101+
}
102+
]
103+
},
104+
{
105+
"name": "text",
106+
"type": "string",
107+
"value": "\nLine three ",
108+
"location": [
109+
{
110+
"line": 4,
111+
"col": 1
112+
},
113+
{
114+
"line": 6,
115+
"col": 14
116+
}
117+
]
118+
},
119+
{
120+
"name": "callout_reference",
121+
"type": "inline",
122+
"variant": "auto",
123+
"number": 3,
46124
"location": [
47125
{
48126
"line": 4,
@@ -74,7 +152,22 @@
74152
{
75153
"name": "listItem",
76154
"type": "block",
77-
"marker": "<1>",
155+
"callout": {
156+
"name": "callout_reference",
157+
"type": "inline",
158+
"variant": "auto",
159+
"number": 1,
160+
"location": [
161+
{
162+
"line": 8,
163+
"col": 1
164+
},
165+
{
166+
"line": 8,
167+
"col": 17
168+
}
169+
]
170+
},
78171
"principal": [
79172
{
80173
"name": "text",
@@ -106,7 +199,22 @@
106199
{
107200
"name": "listItem",
108201
"type": "block",
109-
"marker": "<2>",
202+
"callout": {
203+
"name": "callout_reference",
204+
"type": "inline",
205+
"variant": "auto",
206+
"number": 2,
207+
"location": [
208+
{
209+
"line": 9,
210+
"col": 1
211+
},
212+
{
213+
"line": 9,
214+
"col": 18
215+
}
216+
]
217+
},
110218
"principal": [
111219
{
112220
"name": "text",
@@ -138,7 +246,22 @@
138246
{
139247
"name": "listItem",
140248
"type": "block",
141-
"marker": "<3>",
249+
"callout": {
250+
"name": "callout_reference",
251+
"type": "inline",
252+
"variant": "auto",
253+
"number": 3,
254+
"location": [
255+
{
256+
"line": 10,
257+
"col": 1
258+
},
259+
{
260+
"line": 10,
261+
"col": 17
262+
}
263+
]
264+
},
142265
"principal": [
143266
{
144267
"name": "text",

acdc-parser/fixtures/tests/callout_list_basic.json

Lines changed: 127 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,85 @@
4242
{
4343
"name": "text",
4444
"type": "string",
45-
"value": "Line one <1>\nLine two <2>\nLine three <3>",
45+
"value": "Line one ",
46+
"location": [
47+
{
48+
"line": 4,
49+
"col": 1
50+
},
51+
{
52+
"line": 6,
53+
"col": 14
54+
}
55+
]
56+
},
57+
{
58+
"name": "callout_reference",
59+
"type": "inline",
60+
"variant": "explicit",
61+
"number": 1,
62+
"location": [
63+
{
64+
"line": 4,
65+
"col": 1
66+
},
67+
{
68+
"line": 6,
69+
"col": 14
70+
}
71+
]
72+
},
73+
{
74+
"name": "text",
75+
"type": "string",
76+
"value": "\nLine two ",
77+
"location": [
78+
{
79+
"line": 4,
80+
"col": 1
81+
},
82+
{
83+
"line": 6,
84+
"col": 14
85+
}
86+
]
87+
},
88+
{
89+
"name": "callout_reference",
90+
"type": "inline",
91+
"variant": "explicit",
92+
"number": 2,
93+
"location": [
94+
{
95+
"line": 4,
96+
"col": 1
97+
},
98+
{
99+
"line": 6,
100+
"col": 14
101+
}
102+
]
103+
},
104+
{
105+
"name": "text",
106+
"type": "string",
107+
"value": "\nLine three ",
108+
"location": [
109+
{
110+
"line": 4,
111+
"col": 1
112+
},
113+
{
114+
"line": 6,
115+
"col": 14
116+
}
117+
]
118+
},
119+
{
120+
"name": "callout_reference",
121+
"type": "inline",
122+
"variant": "explicit",
123+
"number": 3,
46124
"location": [
47125
{
48126
"line": 4,
@@ -74,7 +152,22 @@
74152
{
75153
"name": "listItem",
76154
"type": "block",
77-
"marker": "<1>",
155+
"callout": {
156+
"name": "callout_reference",
157+
"type": "inline",
158+
"variant": "explicit",
159+
"number": 1,
160+
"location": [
161+
{
162+
"line": 8,
163+
"col": 1
164+
},
165+
{
166+
"line": 8,
167+
"col": 17
168+
}
169+
]
170+
},
78171
"principal": [
79172
{
80173
"name": "text",
@@ -106,7 +199,22 @@
106199
{
107200
"name": "listItem",
108201
"type": "block",
109-
"marker": "<2>",
202+
"callout": {
203+
"name": "callout_reference",
204+
"type": "inline",
205+
"variant": "explicit",
206+
"number": 2,
207+
"location": [
208+
{
209+
"line": 9,
210+
"col": 1
211+
},
212+
{
213+
"line": 9,
214+
"col": 18
215+
}
216+
]
217+
},
110218
"principal": [
111219
{
112220
"name": "text",
@@ -138,7 +246,22 @@
138246
{
139247
"name": "listItem",
140248
"type": "block",
141-
"marker": "<3>",
249+
"callout": {
250+
"name": "callout_reference",
251+
"type": "inline",
252+
"variant": "explicit",
253+
"number": 3,
254+
"location": [
255+
{
256+
"line": 10,
257+
"col": 1
258+
},
259+
{
260+
"line": 10,
261+
"col": 17
262+
}
263+
]
264+
},
142265
"principal": [
143266
{
144267
"name": "text",

0 commit comments

Comments
 (0)