Skip to content

Commit

Permalink
fix: inlines are now properly calculated
Browse files Browse the repository at this point in the history
  • Loading branch information
nlopes committed Feb 6, 2025
1 parent d12c9f0 commit 4b5c073
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 42 deletions.
2 changes: 1 addition & 1 deletion acdc-parser/fixtures/tests/dots_in_link_text.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"name": "text",
"type": "string",
"value": ".",
"location": [{"line": 3, "col": 146},{"line": 3, "col": 146}]
"location": [{"line": 3, "col": 116},{"line": 3, "col": 116}]
}
],
"location": [{"line": 3, "col": 1},{"line": 3, "col": 116}]
Expand Down
4 changes: 2 additions & 2 deletions acdc-parser/fixtures/tests/inline_line_break.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@
"col": 16
},
{
"line": 2,
"col": 0
"line": 1,
"col": 17
}
]
},
Expand Down
4 changes: 2 additions & 2 deletions acdc-parser/fixtures/tests/simple_attribute_substitution.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@
"name": "text",
"type": "string",
"value": "1.0",
"location": [{"line": 3,"col": 12},{"line": 3,"col": 14}]
"location": [{"line": 3,"col": 12},{"line": 3,"col": 21}]
}
],
"location": [{"line": 3,"col": 12},{"line": 3,"col": 18}]
"location": [{"line": 3,"col": 12},{"line": 3,"col": 21}]
},
{
"name": "text",
Expand Down
5 changes: 3 additions & 2 deletions acdc-parser/grammar/inlines.pest
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ italic_text = { PUSH("_") ~ (!"_" ~ ANY)+ ~ (!"__" ~ POP) }
monospace_text = { PUSH("`") ~ (!"`" ~ ANY)+ ~ (!"``" ~ POP) }
highlight_text = { PUSH("#") ~ (!"#" ~ ANY)+ ~ (!"##" ~ POP) }

inline_line_break = { " +" ~ NEWLINE }
inline_line_break_token = _{ inline_line_break ~ NEWLINE }
inline_line_break = { " +" }

image_inline = { "image:" ~ (url | path) ~ attrlist }
icon_inline = { "icon:" ~ path ~ attrlist }
Expand Down Expand Up @@ -100,7 +101,7 @@ non_plain_text = {
placeholder |
(attrlist? ~ (
footnote |
inline_line_break |
inline_line_break ~ NEWLINE |
bold_text_unconstrained |
italic_text_unconstrained |
monospace_text_unconstrained |
Expand Down
2 changes: 0 additions & 2 deletions acdc-parser/src/blocks/paragraph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,9 @@ impl Paragraph {
tracing::error!("error processing paragraph inlines: {}", e);
Error::Parse(e.to_string())
})?;

// Now parse the processed text
let mut pairs = InnerPestParser::parse(Rule::inlines, &processed.text)
.map_err(|e| Error::Parse(e.to_string()))?;

// We need to shift the location of the inlines so that they are
// correct.
location.shift(parent_location);
Expand Down
2 changes: 0 additions & 2 deletions acdc-parser/src/blocks/section.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,8 @@ impl Section {
tracing::error!("error processing section title: {}", e);
Error::Parse(e.to_string())
})?;

let mut pairs = InnerPestParser::parse(Rule::inlines, &processed.text)
.map_err(|e| Error::Parse(e.to_string()))?;

title = parse_inlines(
pairs.next().ok_or_else(|| {
tracing::error!("error parsing section title");
Expand Down
143 changes: 112 additions & 31 deletions acdc-parser/src/inlines/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ use tracing::instrument;
use crate::{
error::Error, AttributeValue, Autolink, Bold, Button, DocumentAttributes, ElementAttributes,
Highlight, Icon, Image, InlineMacro, InlineNode, Italic, Keyboard, LineBreak, Link, Location,
Menu, Monospace, Pass, PassthroughKind, Plain, ProcessedContent, ProcessedKind, Raw, Rule,
Subscript, Superscript, Url,
Menu, Monospace, Pass, PassthroughKind, Plain, Position, ProcessedContent, ProcessedKind, Raw,
Rule, Subscript, Superscript, Url,
};

impl InlineNode {
Expand All @@ -44,7 +44,7 @@ impl InlineNode {
index = Some(inner.as_str().parse::<usize>().unwrap_or_default());
*last_index_seen = index;
}
let mapped_location = map_inline_location(&location, processed, index, last_index_seen)
let mapped_location = map_inline_location(&location, processed)
.unwrap_or((Some(pair.as_str().to_string()), location.clone()));
match rule {
Rule::plain_text | Rule::one_line_plain_text => {
Expand Down Expand Up @@ -177,7 +177,7 @@ impl InlineNode {
}));
}
return Ok(InlineNode::RawText(Raw {
content: pair.as_str().to_string(),
content: mapped_location.0.unwrap_or_default(),
location: mapped_location.1,
}));
}
Expand Down Expand Up @@ -360,38 +360,119 @@ pub(crate) fn get_content(
fn map_inline_location(
location: &Location,
processed: Option<&ProcessedContent>,
index: Option<usize>,
last_index_seen: &mut Option<usize>,
) -> Option<(Option<String>, Location)> {
if let Some(processed) = processed {
// First, if this location is inside an attribute replacement, collapse it.
if let Some(rep) = processed.source_map.replacements.iter().find(|rep| {
rep.kind == ProcessedKind::Attribute
&& location.absolute_start >= rep.absolute_start
&& location.absolute_start < rep.absolute_end
}) {
let processed = processed?;
let mut adjustment = 0;
let mut passthrough_index = 0;
let location_absolute_start = i32::try_from(location.absolute_start).unwrap();

let mut previously_seen_rep_processed_end = 0;

for rep in &processed.source_map.replacements {
let rep_absolute_start = i32::try_from(rep.absolute_start).unwrap();
let rep_processed_end = i32::try_from(rep.processed_end).unwrap();

let adjusted_absolute_start = location_absolute_start + adjustment;

// if this adjusted absolute start is negative, we are no longer in a valid
// situation, we can stop going through the replacements.
if adjusted_absolute_start < 0 {
break;
}

// if the adjusted absolute start is greater than the processed end of the last
// replacement, we can stop and calculate the new location for this location.
if previously_seen_rep_processed_end >= adjusted_absolute_start {
break;
}

if rep.kind == ProcessedKind::Passthrough {
// if we find a passthrough in this index, we need to adjust the location
let Some(passthrough) = processed.passthroughs.get(passthrough_index) else {
continue;
};
passthrough_index += 1;

// We do this because pest parses \u{FFFD} as a 3-byte character and we
// need to adjust the location accordingly. We use 3*\u{FFFD} on each side
// of a passthrough, therefore (3-1)*3*2 = 18.
if passthrough.kind != PassthroughKind::Macro {
adjustment -= 12;
}

let adjusted_absolute_start_mapped = processed
.source_map
.map_position(usize::try_from(adjusted_absolute_start).unwrap());

// If this is true, we went too far and need to adjust the adjustment back.
if adjusted_absolute_start_mapped < rep.absolute_start {
adjustment += 12;
}

// This means we are inside a passthrough, so we need to adjust the location
if adjusted_absolute_start_mapped >= rep.absolute_start
&& adjusted_absolute_start_mapped < rep.absolute_end
{
let new_location = Location {
start: Position {
line: location.start.line,
column: processed.source_map.map_position(location.start.column),
},
end: Position {
line: location.end.line,
column: processed.source_map.map_position(
location.start.column + rep.absolute_end - rep.absolute_start,
),
},
absolute_start: rep.absolute_start,
absolute_end: rep.absolute_end,
};
return Some((passthrough.text.clone(), new_location));
}
} else if adjusted_absolute_start >= rep_absolute_start
&& adjusted_absolute_start < rep_processed_end
{
let new_location = Location {
// The start and end positions (line/column) might be left unchanged,
// or you might adjust them if you have a way to recalculate from the new offsets.
start: location.start.clone(),
end: location.end.clone(),
absolute_start: processed.source_map.map_position(location.absolute_start),
absolute_end: processed.source_map.map_position(location.absolute_end),
start: Position {
line: location.start.line,
column: processed.source_map.map_position(location.start.column),
},
end: Position {
line: location.end.line,
column: processed.source_map.map_position(
location.start.column + rep.absolute_end - rep.absolute_start,
),
},
absolute_start: rep.absolute_start,
absolute_end: rep.absolute_end,
};
return Some((None, new_location));
}

// Otherwise, if this location is not inside an attribute replacement,
// adjust its absolute_start and absolute_end using map_position.
let adjusted_start = processed.source_map.map_position(location.absolute_start);
let adjusted_end = processed.source_map.map_position(location.absolute_end);
let new_location = Location {
start: location.start.clone(),
end: location.end.clone(),
absolute_start: adjusted_start,
absolute_end: adjusted_end,
};
return Some((None, new_location));
// We need to keep track of the processed end of the last replacement we saw
// to know when to stop going through the replacements.
previously_seen_rep_processed_end = rep_processed_end;
}
None

// Otherwise, if this location is not inside an attribute replacement,
// adjust its absolute_start and absolute_end using map_position.
let adjusted_absolute_start = location_absolute_start + adjustment;
let adjusted_absolute_start_mapped = processed
.source_map
.map_position(usize::try_from(adjusted_absolute_start).unwrap());
let location_start_column_mapped = processed.source_map.map_position(location.start.column);
let new_location = Location {
start: Position {
line: location.start.line,
column: location_start_column_mapped,
},
end: Position {
line: location.end.line,
column: location_start_column_mapped + (location.end.column - location.start.column),
},
absolute_start: adjusted_absolute_start_mapped,
absolute_end: adjusted_absolute_start_mapped
+ (location.absolute_end - location.absolute_start),
};
Some((None, new_location))
}

0 comments on commit 4b5c073

Please sign in to comment.