use crate::{Form, InlineNode, Location, grammar::ProcessedContent};
use super::{
ParserState,
location_mapping::{LocationMapper, LocationMappingContext},
};
pub(crate) trait MarkedText: Sized {
type Content: LocationMappable;
fn location(&self) -> &Location;
fn location_mut(&mut self) -> &mut Location;
fn content_mut(&mut self) -> &mut Self::Content;
fn form(&self) -> &Form;
fn map_locations(mut self, mapping_ctx: &LocationMappingContext) -> Result<Self, crate::Error> {
let form = self.form().clone();
let location = self.location().clone();
let map_loc = super::location_mapping::create_location_mapper(
mapping_ctx.state,
mapping_ctx.processed,
mapping_ctx.base_location,
Some(&form),
);
let mapped_outer = map_loc(&location)?;
let extended_location = super::location_mapping::extend_attribute_location_if_needed(
mapping_ctx.state,
mapping_ctx.processed,
mapped_outer,
);
*self.location_mut() = extended_location;
self.content_mut().map_locations_with(
&map_loc,
mapping_ctx.state,
mapping_ctx.processed,
mapping_ctx.base_location,
)?;
Ok(self)
}
}
pub trait LocationMappable: Clone {
fn map_locations_with(
&mut self,
map_loc: &LocationMapper<'_>,
state: &ParserState,
processed: &ProcessedContent,
base_location: &Location,
) -> Result<(), crate::Error>;
}
impl LocationMappable for Vec<InlineNode> {
fn map_locations_with(
&mut self,
map_loc: &LocationMapper<'_>,
state: &ParserState,
processed: &ProcessedContent,
base_location: &Location,
) -> Result<(), crate::Error> {
*self = super::location_mapping::map_inner_content_locations(
std::mem::take(self),
map_loc,
state,
processed,
base_location,
)?;
Ok(())
}
}
macro_rules! impl_marked_text {
($($type:ty),+ $(,)?) => {
$(
impl MarkedText for $type {
type Content = Vec<InlineNode>;
fn location(&self) -> &Location {
&self.location
}
fn location_mut(&mut self) -> &mut Location {
&mut self.location
}
fn content_mut(&mut self) -> &mut Self::Content {
&mut self.content
}
fn form(&self) -> &Form {
&self.form
}
}
)+
};
}
impl_marked_text!(
crate::Bold,
crate::Italic,
crate::Monospace,
crate::Highlight,
crate::Subscript,
crate::Superscript,
crate::CurvedQuotation,
crate::CurvedApostrophe,
);
pub trait WithLocationMappingContext {
fn with_location_mapping_context(
self,
mapping_ctx: &LocationMappingContext,
) -> Result<Self, crate::Error>
where
Self: Sized;
}
impl WithLocationMappingContext for InlineNode {
fn with_location_mapping_context(
self,
mapping_ctx: &LocationMappingContext,
) -> Result<InlineNode, crate::Error> {
Ok(match self {
InlineNode::BoldText(node) => InlineNode::BoldText(node.map_locations(mapping_ctx)?),
InlineNode::ItalicText(node) => {
InlineNode::ItalicText(node.map_locations(mapping_ctx)?)
}
InlineNode::MonospaceText(node) => {
InlineNode::MonospaceText(node.map_locations(mapping_ctx)?)
}
InlineNode::HighlightText(node) => {
InlineNode::HighlightText(node.map_locations(mapping_ctx)?)
}
InlineNode::SubscriptText(node) => {
InlineNode::SubscriptText(node.map_locations(mapping_ctx)?)
}
InlineNode::SuperscriptText(node) => {
InlineNode::SuperscriptText(node.map_locations(mapping_ctx)?)
}
InlineNode::CurvedQuotationText(node) => {
InlineNode::CurvedQuotationText(node.map_locations(mapping_ctx)?)
}
InlineNode::CurvedApostropheText(node) => {
InlineNode::CurvedApostropheText(node.map_locations(mapping_ctx)?)
}
InlineNode::RawText(_)
| InlineNode::PlainText(_)
| InlineNode::VerbatimText(_)
| InlineNode::LineBreak(_)
| InlineNode::InlineAnchor(_)
| InlineNode::CalloutRef(_)
| InlineNode::Macro(_)
| InlineNode::StandaloneCurvedApostrophe(_) => self,
})
}
}