#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Span {
pub start: usize,
pub end: usize,
}
impl Span {
#[must_use]
pub fn new(start: usize, end: usize) -> Self {
Self { start, end }
}
}
pub struct TemplatedDocument<'src> {
pub(crate) source: &'src str,
pub(crate) roots: Vec<Node>,
pub(crate) document_spans: Vec<Span>,
}
impl<'src> TemplatedDocument<'src> {
#[must_use]
pub fn parse(source: &'src str) -> Self {
match crate::actions::parse_go_template(source) {
Some(tree) => Self::parse_with_root(source, tree.root_node()),
None => crate::parse::parse_document(source, Vec::new()),
}
}
#[must_use]
pub fn parse_with_root(source: &'src str, root: tree_sitter::Node<'_>) -> Self {
let tokens = crate::actions::collect_action_tokens(root);
crate::parse::parse_document(source, tokens)
}
#[must_use]
pub fn source(&self) -> &'src str {
self.source
}
#[must_use]
pub fn roots(&self) -> &[Node] {
&self.roots
}
#[must_use]
pub fn document_spans(&self) -> &[Span] {
&self.document_spans
}
}
#[derive(Debug)]
pub enum Node {
Mapping(MappingEntry),
Sequence(SequenceItem),
Control(ControlRegion),
Output(OutputAction),
Comment(CommentLine),
Scalar(ScalarLine),
Opaque(OpaqueNode),
}
#[derive(Debug)]
pub struct ScalarParts {
pub span: Span,
pub parts: Vec<ScalarPart>,
}
#[derive(Debug)]
pub enum ScalarPart {
Text(Span),
Hole(Span),
}
#[derive(Debug)]
pub struct MappingEntry {
pub span: Span,
pub indent: usize,
pub key: ScalarParts,
pub value: Option<ScalarParts>,
pub block: Option<BlockScalar>,
pub opens_scope: bool,
pub children: Vec<Node>,
}
impl MappingEntry {
#[must_use]
pub fn sequence_items(&self) -> Vec<&SequenceItem> {
let mut items = Vec::new();
collect_sequence_items(&self.children, &mut items);
items.sort_by_key(|item| item.span.start);
items
}
}
fn collect_sequence_items<'nodes>(nodes: &'nodes [Node], items: &mut Vec<&'nodes SequenceItem>) {
for node in nodes {
match node {
Node::Sequence(item) => items.push(item),
Node::Control(region) => {
for branch in ®ion.branches {
collect_sequence_items(&branch.body, items);
}
}
_ => {}
}
}
}
#[derive(Debug)]
pub struct SequenceItem {
pub span: Span,
pub indent: usize,
pub value: Option<ScalarParts>,
pub block: Option<BlockScalar>,
pub children: Vec<Node>,
}
impl SequenceItem {
#[must_use]
pub fn content_span(&self) -> Span {
let start = if let Some(value) = &self.value {
value.span.start
} else if let Some(block) = &self.block {
block.header.start
} else if let Some(first) = self.children.first() {
first.span_start()
} else {
self.span.start
};
let end = subtree_end(
self.span.end,
self.value.as_ref(),
self.block.as_ref(),
&self.children,
);
Span::new(start, end.max(start))
}
}
impl Node {
#[must_use]
pub fn span_start(&self) -> usize {
match self {
Node::Mapping(entry) => entry.span.start,
Node::Sequence(item) => item.span.start,
Node::Control(region) => region.span.start,
Node::Output(action) => action.span.start,
Node::Comment(comment) => comment.span.start,
Node::Scalar(line) => line.span.start,
Node::Opaque(opaque) => opaque.span.start,
}
}
#[must_use]
pub fn subtree_end(&self) -> usize {
match self {
Node::Mapping(entry) => subtree_end(
entry.span.end,
entry.value.as_ref(),
entry.block.as_ref(),
&entry.children,
),
Node::Sequence(item) => subtree_end(
item.span.end,
item.value.as_ref(),
item.block.as_ref(),
&item.children,
),
Node::Control(region) => region
.branches
.iter()
.flat_map(|branch| &branch.body)
.map(Node::subtree_end)
.fold(region.span.end, usize::max),
Node::Output(action) => action.span.end,
Node::Comment(comment) => comment.span.end,
Node::Scalar(line) => scalar_parts_end(&line.content).max(line.span.end),
Node::Opaque(opaque) => opaque.span.end,
}
}
}
fn subtree_end(
own_end: usize,
value: Option<&ScalarParts>,
block: Option<&BlockScalar>,
children: &[Node],
) -> usize {
let mut end = own_end;
if let Some(value) = value {
end = end.max(scalar_parts_end(value));
}
if let Some(block) = block {
end = end.max(block.header.end).max(block.body.end);
}
for child in children {
end = end.max(child.subtree_end());
}
end
}
fn scalar_parts_end(parts: &ScalarParts) -> usize {
let mut end = parts.span.end;
for part in &parts.parts {
let (ScalarPart::Text(span) | ScalarPart::Hole(span)) = part;
end = end.max(span.end);
}
end
}
#[derive(Debug)]
pub struct BlockScalar {
pub header: Span,
pub body: Span,
pub holes: Vec<Span>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ControlKind {
If,
With,
Range,
Define,
Block,
}
#[derive(Debug)]
pub struct ControlRegion {
pub kind: ControlKind,
pub span: Span,
pub branches: Vec<ControlBranch>,
pub well_nested: bool,
}
#[derive(Debug)]
pub struct ControlBranch {
pub header: Span,
pub body: Vec<Node>,
}
#[derive(Debug)]
pub struct OutputAction {
pub span: Span,
pub expr_span: Span,
}
#[derive(Debug)]
pub struct CommentLine {
pub span: Span,
pub content: ScalarParts,
}
#[derive(Debug)]
pub struct ScalarLine {
pub span: Span,
pub indent: usize,
pub content: ScalarParts,
}
#[derive(Debug)]
pub struct OpaqueNode {
pub span: Span,
pub kind: OpaqueKind,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum OpaqueKind {
TemplateComment,
Assignment,
Break,
Continue,
InlineRegion,
ActionLineText,
ParseError,
}