Skip to content

Commit bd528d8

Browse files
committed
refactor: extract marked text location mapping into trait-based system
I really didn't like so much repeated code (still don't) but it is what it is. Overall the code needs a bunch of refactors as I optimised to get roughly to a minimal working version of the asciidoc documentation and specs.
1 parent 09f9c14 commit bd528d8

File tree

6 files changed

+215
-365
lines changed

6 files changed

+215
-365
lines changed

acdc-parser/src/grammar/document.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1832,7 +1832,7 @@ peg::parser! {
18321832
location,
18331833
})],
18341834
metadata,
1835-
title: Vec::new(), // TODO(nlopes): Handle paragraph titles
1835+
title: block_metadata.title.clone(),
18361836
location: initial_location,
18371837
}));
18381838
}

acdc-parser/src/grammar/inline_processing.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ pub(crate) fn parse_inlines(
5353
}
5454

5555
/// Process inlines
56+
///
57+
/// This function processes inline content by first preprocessing it and then parsing it
58+
/// into inline nodes. Then, it maps the locations of the parsed inline nodes back to their
59+
/// original positions in the source.
5660
#[tracing::instrument(skip_all, fields(?start, ?content_start, end, offset))]
5761
pub(crate) fn process_inlines(
5862
state: &ParserState,

acdc-parser/src/grammar/location_mapping.rs

Lines changed: 33 additions & 274 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::{
44
Monospace, Plain, ProcessedContent, StandaloneCurvedApostrophe, Subscript, Superscript,
55
};
66

7-
use super::document::ParserState;
7+
use super::{document::ParserState, marked_text::WithLocationMappingContext};
88

99
/// Context for location mapping operations
1010
pub(crate) struct LocationMappingContext<'a> {
@@ -13,197 +13,6 @@ pub(crate) struct LocationMappingContext<'a> {
1313
pub base_location: &'a Location,
1414
}
1515

16-
/// Trait for formatted inline elements that have form, content, and location
17-
pub(crate) trait FormattedInline {
18-
fn location(&self) -> &Location;
19-
fn location_mut(&mut self) -> &mut Location;
20-
fn content(&self) -> &Vec<InlineNode>;
21-
fn content_mut(&mut self) -> &mut Vec<InlineNode>;
22-
fn form(&self) -> &Form;
23-
}
24-
25-
// Implementations for all formatted inline types
26-
impl FormattedInline for Bold {
27-
fn location(&self) -> &Location {
28-
&self.location
29-
}
30-
fn location_mut(&mut self) -> &mut Location {
31-
&mut self.location
32-
}
33-
fn content(&self) -> &Vec<InlineNode> {
34-
&self.content
35-
}
36-
fn content_mut(&mut self) -> &mut Vec<InlineNode> {
37-
&mut self.content
38-
}
39-
fn form(&self) -> &Form {
40-
&self.form
41-
}
42-
}
43-
44-
impl FormattedInline for Italic {
45-
fn location(&self) -> &Location {
46-
&self.location
47-
}
48-
fn location_mut(&mut self) -> &mut Location {
49-
&mut self.location
50-
}
51-
fn content(&self) -> &Vec<InlineNode> {
52-
&self.content
53-
}
54-
fn content_mut(&mut self) -> &mut Vec<InlineNode> {
55-
&mut self.content
56-
}
57-
fn form(&self) -> &Form {
58-
&self.form
59-
}
60-
}
61-
62-
impl FormattedInline for Monospace {
63-
fn location(&self) -> &Location {
64-
&self.location
65-
}
66-
fn location_mut(&mut self) -> &mut Location {
67-
&mut self.location
68-
}
69-
fn content(&self) -> &Vec<InlineNode> {
70-
&self.content
71-
}
72-
fn content_mut(&mut self) -> &mut Vec<InlineNode> {
73-
&mut self.content
74-
}
75-
fn form(&self) -> &Form {
76-
&self.form
77-
}
78-
}
79-
80-
impl FormattedInline for Highlight {
81-
fn location(&self) -> &Location {
82-
&self.location
83-
}
84-
fn location_mut(&mut self) -> &mut Location {
85-
&mut self.location
86-
}
87-
fn content(&self) -> &Vec<InlineNode> {
88-
&self.content
89-
}
90-
fn content_mut(&mut self) -> &mut Vec<InlineNode> {
91-
&mut self.content
92-
}
93-
fn form(&self) -> &Form {
94-
&self.form
95-
}
96-
}
97-
98-
impl FormattedInline for Subscript {
99-
fn location(&self) -> &Location {
100-
&self.location
101-
}
102-
fn location_mut(&mut self) -> &mut Location {
103-
&mut self.location
104-
}
105-
fn content(&self) -> &Vec<InlineNode> {
106-
&self.content
107-
}
108-
fn content_mut(&mut self) -> &mut Vec<InlineNode> {
109-
&mut self.content
110-
}
111-
fn form(&self) -> &Form {
112-
&self.form
113-
}
114-
}
115-
116-
impl FormattedInline for Superscript {
117-
fn location(&self) -> &Location {
118-
&self.location
119-
}
120-
fn location_mut(&mut self) -> &mut Location {
121-
&mut self.location
122-
}
123-
fn content(&self) -> &Vec<InlineNode> {
124-
&self.content
125-
}
126-
fn content_mut(&mut self) -> &mut Vec<InlineNode> {
127-
&mut self.content
128-
}
129-
fn form(&self) -> &Form {
130-
&self.form
131-
}
132-
}
133-
134-
impl FormattedInline for CurvedQuotation {
135-
fn location(&self) -> &Location {
136-
&self.location
137-
}
138-
fn location_mut(&mut self) -> &mut Location {
139-
&mut self.location
140-
}
141-
fn content(&self) -> &Vec<InlineNode> {
142-
&self.content
143-
}
144-
fn content_mut(&mut self) -> &mut Vec<InlineNode> {
145-
&mut self.content
146-
}
147-
fn form(&self) -> &Form {
148-
&self.form
149-
}
150-
}
151-
152-
impl FormattedInline for CurvedApostrophe {
153-
fn location(&self) -> &Location {
154-
&self.location
155-
}
156-
fn location_mut(&mut self) -> &mut Location {
157-
&mut self.location
158-
}
159-
fn content(&self) -> &Vec<InlineNode> {
160-
&self.content
161-
}
162-
fn content_mut(&mut self) -> &mut Vec<InlineNode> {
163-
&mut self.content
164-
}
165-
fn form(&self) -> &Form {
166-
&self.form
167-
}
168-
}
169-
170-
/// Generic function for mapping formatted inline locations with form-awareness
171-
pub(crate) fn map_formatted_inline_locations<T: FormattedInline>(
172-
mut inline: T,
173-
mapping_ctx: &LocationMappingContext,
174-
) -> T {
175-
// Get the form first to avoid borrowing issues
176-
let form = inline.form().clone();
177-
let content = inline.content().clone();
178-
let location = inline.location().clone();
179-
180-
// Create a form-aware location mapper - this provides more accurate location mapping!
181-
let map_loc = create_location_mapper(
182-
mapping_ctx.state,
183-
mapping_ctx.processed,
184-
mapping_ctx.base_location,
185-
Some(&form), // Pass the form information for precise mapping
186-
);
187-
188-
// Map outer location with attribute extension
189-
let mapped_outer = map_loc(&location);
190-
let extended_location =
191-
extend_attribute_location_if_needed(mapping_ctx.state, mapping_ctx.processed, mapped_outer);
192-
*inline.location_mut() = extended_location;
193-
194-
// Map inner content locations
195-
let mapped_content = map_inner_content_locations(
196-
content,
197-
map_loc.as_ref(),
198-
mapping_ctx.state,
199-
mapping_ctx.processed,
200-
mapping_ctx.base_location,
201-
);
202-
*inline.content_mut() = mapped_content;
203-
204-
inline
205-
}
206-
20716
/// Location mapping coordinate transformations during inline processing.
20817
///
20918
/// # Location Mapping Overview
@@ -410,102 +219,52 @@ pub(crate) fn map_inner_content_locations(
410219
processed,
411220
base_location,
412221
};
413-
marked_text.map_formatted_inline_locations(&mapping_ctx)
222+
marked_text.with_location_mapping_context(&mapping_ctx)
414223
}
415224
other => other,
416225
})
417226
.collect()
418227
}
419228

229+
/// Helper macro to remap locations for simple nodes (`PlainText`, etc.)
230+
macro_rules! remap_simple_location {
231+
($node:expr, $base_offset:expr) => {{
232+
$node.location.absolute_start += $base_offset;
233+
$node.location.absolute_end += $base_offset;
234+
$node.location.start.column += $base_offset;
235+
$node.location.end.column += $base_offset;
236+
}};
237+
}
238+
239+
/// Helper macro to remap locations for formatted nodes with content
240+
macro_rules! remap_formatted_location {
241+
($node:expr, $base_offset:expr) => {{
242+
remap_simple_location!($node, $base_offset);
243+
// Recursively remap nested content
244+
for nested_node in &mut $node.content {
245+
remap_inline_node_location(nested_node, $base_offset);
246+
}
247+
}};
248+
}
249+
420250
/// Remap the location of an inline node to final document coordinates
421251
pub(crate) fn remap_inline_node_location(node: &mut InlineNode, base_offset: usize) {
422252
match node {
423-
InlineNode::PlainText(plain) => {
424-
plain.location.absolute_start += base_offset;
425-
plain.location.absolute_end += base_offset;
426-
plain.location.start.column += base_offset;
427-
plain.location.end.column += base_offset;
428-
}
429-
InlineNode::BoldText(bold) => {
430-
bold.location.absolute_start += base_offset;
431-
bold.location.absolute_end += base_offset;
432-
bold.location.start.column += base_offset;
433-
bold.location.end.column += base_offset;
434-
// Recursively remap nested content
435-
for nested_node in &mut bold.content {
436-
remap_inline_node_location(nested_node, base_offset);
437-
}
438-
}
439-
InlineNode::ItalicText(italic) => {
440-
italic.location.absolute_start += base_offset;
441-
italic.location.absolute_end += base_offset;
442-
italic.location.start.column += base_offset;
443-
italic.location.end.column += base_offset;
444-
// Recursively remap nested content
445-
for nested_node in &mut italic.content {
446-
remap_inline_node_location(nested_node, base_offset);
447-
}
448-
}
253+
InlineNode::PlainText(plain) => remap_simple_location!(plain, base_offset),
254+
InlineNode::BoldText(bold) => remap_formatted_location!(bold, base_offset),
255+
InlineNode::ItalicText(italic) => remap_formatted_location!(italic, base_offset),
449256
InlineNode::SuperscriptText(superscript) => {
450-
superscript.location.absolute_start += base_offset;
451-
superscript.location.absolute_end += base_offset;
452-
superscript.location.start.column += base_offset;
453-
superscript.location.end.column += base_offset;
454-
// Recursively remap nested content
455-
for nested_node in &mut superscript.content {
456-
remap_inline_node_location(nested_node, base_offset);
457-
}
458-
}
459-
InlineNode::SubscriptText(subscript) => {
460-
subscript.location.absolute_start += base_offset;
461-
subscript.location.absolute_end += base_offset;
462-
subscript.location.start.column += base_offset;
463-
subscript.location.end.column += base_offset;
464-
// Recursively remap nested content
465-
for nested_node in &mut subscript.content {
466-
remap_inline_node_location(nested_node, base_offset);
467-
}
257+
remap_formatted_location!(superscript, base_offset);
468258
}
259+
InlineNode::SubscriptText(subscript) => remap_formatted_location!(subscript, base_offset),
469260
InlineNode::CurvedQuotationText(curved_quotation) => {
470-
curved_quotation.location.absolute_start += base_offset;
471-
curved_quotation.location.absolute_end += base_offset;
472-
curved_quotation.location.start.column += base_offset;
473-
curved_quotation.location.end.column += base_offset;
474-
// Recursively remap nested content
475-
for nested_node in &mut curved_quotation.content {
476-
remap_inline_node_location(nested_node, base_offset);
477-
}
261+
remap_formatted_location!(curved_quotation, base_offset);
478262
}
479263
InlineNode::CurvedApostropheText(curved_apostrophe) => {
480-
curved_apostrophe.location.absolute_start += base_offset;
481-
curved_apostrophe.location.absolute_end += base_offset;
482-
curved_apostrophe.location.start.column += base_offset;
483-
curved_apostrophe.location.end.column += base_offset;
484-
// Recursively remap nested content
485-
for nested_node in &mut curved_apostrophe.content {
486-
remap_inline_node_location(nested_node, base_offset);
487-
}
488-
}
489-
InlineNode::MonospaceText(monospace) => {
490-
monospace.location.absolute_start += base_offset;
491-
monospace.location.absolute_end += base_offset;
492-
monospace.location.start.column += base_offset;
493-
monospace.location.end.column += base_offset;
494-
// Recursively remap nested content
495-
for nested_node in &mut monospace.content {
496-
remap_inline_node_location(nested_node, base_offset);
497-
}
498-
}
499-
InlineNode::HighlightText(highlight) => {
500-
highlight.location.absolute_start += base_offset;
501-
highlight.location.absolute_end += base_offset;
502-
highlight.location.start.column += base_offset;
503-
highlight.location.end.column += base_offset;
504-
// Recursively remap nested content
505-
for nested_node in &mut highlight.content {
506-
remap_inline_node_location(nested_node, base_offset);
507-
}
264+
remap_formatted_location!(curved_apostrophe, base_offset);
508265
}
266+
InlineNode::MonospaceText(monospace) => remap_formatted_location!(monospace, base_offset),
267+
InlineNode::HighlightText(highlight) => remap_formatted_location!(highlight, base_offset),
509268
// Add other inline node types as needed
510269
_ => {}
511270
}
@@ -616,7 +375,7 @@ pub(crate) fn map_inline_locations(
616375
processed,
617376
base_location: location,
618377
};
619-
vec![marked_text.clone().map_formatted_inline_locations(&mapping_ctx)]
378+
vec![marked_text.clone().with_location_mapping_context(&mapping_ctx)]
620379
}
621380
InlineNode::StandaloneCurvedApostrophe(standalone) => {
622381
let mut mapped_standalone = standalone.clone();

0 commit comments

Comments
 (0)