use crate::{Form, InlineNode, Location, grammar::ProcessedContent};
use super::{
ParserState,
location_mapping::{LocationMapper, LocationMappingContext},
};
pub(crate) trait MarkedText<'a>: Sized {
type Content: LocationMappable<'a>;
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<'_, 'a>,
) -> 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<'a>: Clone {
fn map_locations_with(
&mut self,
map_loc: &LocationMapper<'_>,
state: &ParserState<'a>,
processed: &ProcessedContent<'a>,
base_location: &Location,
) -> Result<(), crate::Error>;
}
impl<'a> LocationMappable<'a> for Vec<InlineNode<'a>> {
fn map_locations_with(
&mut self,
map_loc: &LocationMapper<'_>,
state: &ParserState<'a>,
processed: &ProcessedContent<'a>,
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:ident),+ $(,)?) => {
$(
impl<'a> MarkedText<'a> for crate::$type<'a> {
type Content = Vec<InlineNode<'a>>;
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!(
Bold,
Italic,
Monospace,
Highlight,
Subscript,
Superscript,
CurvedQuotation,
CurvedApostrophe,
);
pub trait WithLocationMappingContext<'a> {
fn with_location_mapping_context(
self,
mapping_ctx: &LocationMappingContext<'_, 'a>,
) -> Result<Self, crate::Error>
where
Self: Sized;
}
impl<'a> WithLocationMappingContext<'a> for InlineNode<'a> {
fn with_location_mapping_context(
self,
mapping_ctx: &LocationMappingContext<'_, 'a>,
) -> Result<InlineNode<'a>, 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,
})
}
}