use super::{DescriptorObservation, Selection};
use vize_l0::{SourceBlock, SourceRoot, Span};
#[derive(Debug)]
pub(super) struct TemplateNamePair {
pub(super) opening: Span,
pub(super) closing: Span,
}
#[derive(Debug)]
pub(super) struct TemplateSelection<'a> {
pub(super) selection: Selection<'a>,
pub(super) names: Option<TemplateNamePair>,
}
#[derive(Debug, Clone, Copy)]
pub struct TemplateView<'o, 'a> {
pub(super) owner: &'o DescriptorObservation<'a>,
pub(super) selected: &'o TemplateSelection<'a>,
}
impl<'o, 'a> TemplateView<'o, 'a> {
pub fn source(&self) -> &'a str {
self.owner.source()
}
pub fn container_index(&self) -> usize {
self.selected.selection.index
}
pub fn block(&self) -> SourceBlock<'a> {
self.selected.selection.block
}
pub fn frame_names(
self,
) -> Result<NativeTemplateFrameNames<'o, 'a>, NativeTemplateFrameNameRefusal> {
use NativeTemplateFrameNameRefusal::{IncompleteBoundary, SourceMismatch};
let selected = self.owner.template.as_ref().ok_or(IncompleteBoundary)?;
if !core::ptr::eq(selected, self.selected) {
return Err(SourceMismatch);
}
let root = self.owner.root.ok_or(SourceMismatch)?;
let names = selected.names.as_ref().ok_or(IncompleteBoundary)?;
let block = self
.owner
.container
.blocks
.get(self.container_index())
.ok_or(SourceMismatch)?;
if root.whole_block().span_of(block.name) != Some(names.opening)
|| !root.contains_span(names.opening)
|| !root.contains_span(names.closing)
|| names.opening.start >= names.opening.end
|| names.closing.start >= names.closing.end
|| block.open_tag.start > names.opening.start
|| names.opening.end > block.open_tag.end
|| names.opening.end > block.content.start
|| block.content.end > names.closing.start
|| !block.close_tag.is_some_and(|close| {
close.start <= names.closing.start && names.closing.end <= close.end
})
{
return Err(SourceMismatch);
}
Ok(NativeTemplateFrameNames {
owner: self.owner,
selected,
root,
names,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NativeTemplateFrameNameRefusal {
IncompleteBoundary,
SourceMismatch,
}
pub struct NativeTemplateFrameNames<'o, 'a> {
owner: &'o DescriptorObservation<'a>,
selected: &'o TemplateSelection<'a>,
root: SourceRoot<'a>,
names: &'o TemplateNamePair,
}
impl core::fmt::Debug for NativeTemplateFrameNames<'_, '_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("NativeTemplateFrameNames")
.field("container_index", &self.container_index())
.field("opening", &self.opening())
.field("closing", &self.closing())
.finish_non_exhaustive()
}
}
impl<'o, 'a> NativeTemplateFrameNames<'o, 'a> {
#[must_use]
pub fn template(&self) -> TemplateView<'o, 'a> {
TemplateView {
owner: self.owner,
selected: self.selected,
}
}
#[must_use]
pub fn source_block(&self) -> SourceBlock<'a> {
self.root.whole_block()
}
#[must_use]
pub fn container_index(&self) -> usize {
self.selected.selection.index
}
#[must_use]
pub fn opening(&self) -> Span {
self.names.opening
}
#[must_use]
pub fn closing(&self) -> Span {
self.names.closing
}
#[must_use]
pub fn accepts(&self, view: &TemplateView<'_, 'a>) -> bool {
core::ptr::eq(self.owner, view.owner) && core::ptr::eq(self.selected, view.selected)
}
}
#[cfg(test)]
mod tests;