use crate::parse::utils::convert_multiline_with_indentation;
use crate::syntax::SyntaxKind;
use crate::syntax::SyntaxNode;
use crate::syntax::SyntaxToken;
use crate::text::TextRange;
#[derive(Debug)]
pub struct TextBlock<'a>(pub(crate) &'a SyntaxNode);
impl<'a> TextBlock<'a> {
pub const fn can_cast(kind: SyntaxKind) -> bool {
matches!(
kind,
SyntaxKind::SUMMARY
| SyntaxKind::EXTENDED_SUMMARY
| SyntaxKind::DESCRIPTION
| SyntaxKind::BODY_TEXT
| SyntaxKind::CONTENT
)
}
pub fn cast(node: &'a SyntaxNode) -> Option<Self> {
Self::can_cast(node.kind()).then_some(Self(node))
}
pub fn syntax(&self) -> &'a SyntaxNode {
self.0
}
pub fn range(&self) -> &'a TextRange {
self.0.range()
}
pub fn is_missing(&self) -> bool {
self.0.range().is_empty()
}
pub fn lines(&self) -> impl Iterator<Item = &'a SyntaxToken> {
self.0.tokens(SyntaxKind::TEXT_LINE)
}
pub fn text(&self, source: &'a str) -> &'a str {
self.0.range().source_text(source)
}
pub fn logical_text(&self, source: &str) -> String {
convert_multiline_with_indentation(self.text(source))
}
}
pub(crate) fn find_text_block<'a>(node: &'a SyntaxNode, kind: SyntaxKind) -> Option<TextBlock<'a>> {
node.nodes(kind)
.find(|n| !n.range().is_empty())
.and_then(TextBlock::cast)
}