use super::ast::{AstChildren, support};
use super::{AstNode, PanacheLanguage, SyntaxKind, SyntaxNode};
pub struct BlockQuote(SyntaxNode);
impl AstNode for BlockQuote {
type Language = PanacheLanguage;
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::BLOCK_QUOTE
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(Self(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
impl BlockQuote {
pub fn blocks(&self) -> impl Iterator<Item = SyntaxNode> {
self.0.children().filter(|child| {
!matches!(
child.kind(),
SyntaxKind::BLOCK_QUOTE_MARKER | SyntaxKind::WHITESPACE
)
})
}
pub fn nested_blockquotes(&self) -> AstChildren<BlockQuote> {
support::children(&self.0)
}
pub fn contains_node(node: &SyntaxNode) -> bool {
node.ancestors()
.any(|ancestor| Self::can_cast(ancestor.kind()))
}
pub fn depth(&self) -> usize {
self.0
.ancestors()
.filter(|ancestor| Self::can_cast(ancestor.kind()))
.count()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::parse;
#[test]
fn blockquote_cast_and_blocks() {
let tree = parse("> Intro\n>\n> - Item\n>\n> Outro\n", None);
let bq = tree
.descendants()
.find_map(BlockQuote::cast)
.expect("blockquote");
let kinds: Vec<_> = bq.blocks().map(|n| n.kind()).collect();
assert!(kinds.contains(&SyntaxKind::PARAGRAPH));
assert!(kinds.contains(&SyntaxKind::LIST));
}
#[test]
fn blockquote_nested_blockquotes_iterator() {
let tree = parse("> outer\n>\n> > inner\n", None);
let outer = tree
.descendants()
.find_map(BlockQuote::cast)
.expect("outer blockquote");
assert!(outer.nested_blockquotes().next().is_some());
assert_eq!(outer.depth(), 1);
}
#[test]
fn blockquote_contains_node_detects_membership() {
let tree = parse("> quote\n", None);
let blockquote = tree
.descendants()
.find_map(BlockQuote::cast)
.expect("blockquote");
assert!(BlockQuote::contains_node(blockquote.syntax()));
}
}