use crate::model::FreeSectionKind;
use crate::model::SectionKind;
use crate::parse::Style;
use crate::parse::google::kind::GoogleSectionKind;
use crate::parse::numpy::kind::NumPySectionKind;
use crate::parse::text_block::TextBlock;
use crate::parse::text_block::find_text_block;
use crate::parse::token_ref::TokenRef;
use crate::syntax::Parsed;
use crate::syntax::SyntaxKind;
use crate::syntax::SyntaxNode;
use crate::text::TextRange;
#[derive(Debug, Clone, Copy)]
pub struct Document<'a> {
parsed: &'a Parsed,
}
impl<'a> Document<'a> {
pub fn new(parsed: &'a Parsed) -> Self {
debug_assert_eq!(parsed.root().kind(), SyntaxKind::DOCUMENT);
Self { parsed }
}
pub fn style(&self) -> Style {
self.parsed.style()
}
pub fn syntax(&self) -> &'a SyntaxNode {
self.parsed.root()
}
pub fn summary(&self) -> Option<TextBlock<'a>> {
find_text_block(self.parsed, self.parsed.root(), SyntaxKind::SUMMARY)
}
pub fn extended_summary(&self) -> Option<TextBlock<'a>> {
find_text_block(self.parsed, self.parsed.root(), SyntaxKind::EXTENDED_SUMMARY)
}
pub fn directives(&self) -> impl Iterator<Item = Directive<'a>> {
let parsed = self.parsed;
self.parsed
.root()
.nodes(SyntaxKind::DIRECTIVE)
.map(move |node| Directive { parsed, node })
}
pub fn sections(&self) -> impl Iterator<Item = Section<'a>> {
let parsed = self.parsed;
self.parsed
.root()
.nodes(SyntaxKind::SECTION)
.map(move |node| Section { parsed, node })
}
pub fn paragraphs(&self) -> impl Iterator<Item = TextBlock<'a>> {
let parsed = self.parsed;
self.parsed
.root()
.nodes(SyntaxKind::PARAGRAPH)
.filter_map(move |node| TextBlock::cast(parsed, node))
}
}
#[derive(Debug, Clone, Copy)]
pub struct Section<'a> {
parsed: &'a Parsed,
node: &'a SyntaxNode,
}
impl<'a> Section<'a> {
pub fn cast(parsed: &'a Parsed, node: &'a SyntaxNode) -> Option<Self> {
(node.kind() == SyntaxKind::SECTION).then_some(Self { parsed, node })
}
pub fn syntax(&self) -> &'a SyntaxNode {
self.node
}
pub fn range(&self) -> &'a TextRange {
self.node.range()
}
pub fn header_name(&self) -> &'a str {
self.node
.find_node(SyntaxKind::SECTION_HEADER)
.expect("SECTION must have a SECTION_HEADER child")
.required_token(SyntaxKind::NAME)
.text(self.parsed.source())
}
pub fn kind(&self) -> SectionKind {
let name = self.header_name();
let lower = name.to_ascii_lowercase();
match self.parsed.style() {
Style::Google => GoogleSectionKind::from_name(&lower).to_section_kind(name),
Style::NumPy => NumPySectionKind::from_name(&lower).to_section_kind(name),
_ => SectionKind::FreeText(FreeSectionKind::Unknown(name.to_owned())),
}
}
pub fn entries(&self) -> impl Iterator<Item = Entry<'a>> {
let parsed = self.parsed;
self.node
.nodes(SyntaxKind::ENTRY)
.map(move |node| Entry { parsed, node })
}
pub fn body(&self) -> Option<TextBlock<'a>> {
find_text_block(self.parsed, self.node, SyntaxKind::DESCRIPTION)
}
pub fn citations(&self) -> impl Iterator<Item = Citation<'a>> {
let parsed = self.parsed;
self.node
.nodes(SyntaxKind::CITATION)
.map(move |node| Citation { parsed, node })
}
}
#[derive(Debug, Clone, Copy)]
pub struct Entry<'a> {
parsed: &'a Parsed,
node: &'a SyntaxNode,
}
impl<'a> Entry<'a> {
pub fn cast(parsed: &'a Parsed, node: &'a SyntaxNode) -> Option<Self> {
(node.kind() == SyntaxKind::ENTRY).then_some(Self { parsed, node })
}
pub fn syntax(&self) -> &'a SyntaxNode {
self.node
}
pub fn range(&self) -> &'a TextRange {
self.node.range()
}
pub fn names(&self) -> impl Iterator<Item = TokenRef<'a>> {
let parsed = self.parsed;
self.node
.tokens(SyntaxKind::NAME)
.map(move |t| TokenRef::new(parsed, t))
}
pub fn name(&self) -> Option<TokenRef<'a>> {
self.names().next()
}
pub fn type_annotation(&self) -> Option<TokenRef<'a>> {
self.node
.find_token(SyntaxKind::TYPE)
.map(|t| TokenRef::new(self.parsed, t))
}
pub fn description(&self) -> Option<TextBlock<'a>> {
find_text_block(self.parsed, self.node, SyntaxKind::DESCRIPTION)
}
pub fn is_optional(&self) -> bool {
self.optionals().next().is_some()
}
pub fn optionals(&self) -> impl Iterator<Item = TokenRef<'a>> {
let parsed = self.parsed;
self.node
.tokens(SyntaxKind::OPTIONAL)
.map(move |t| TokenRef::new(parsed, t))
}
pub fn defaults(&self) -> impl Iterator<Item = DefaultMarker<'a>> {
let parsed = self.parsed;
self.node
.nodes(SyntaxKind::DEFAULT)
.map(move |node| DefaultMarker { parsed, node })
}
pub fn default_value(&self) -> Option<TokenRef<'a>> {
self.defaults().next().and_then(|d| d.value())
}
}
#[derive(Debug, Clone, Copy)]
pub struct DefaultMarker<'a> {
pub(crate) parsed: &'a Parsed,
pub(crate) node: &'a SyntaxNode,
}
impl<'a> DefaultMarker<'a> {
pub fn cast(parsed: &'a Parsed, node: &'a SyntaxNode) -> Option<Self> {
(node.kind() == SyntaxKind::DEFAULT).then_some(Self { parsed, node })
}
pub fn syntax(&self) -> &'a SyntaxNode {
self.node
}
pub fn range(&self) -> &'a TextRange {
self.node.range()
}
pub fn keyword(&self) -> TokenRef<'a> {
TokenRef::new(self.parsed, self.node.required_token(SyntaxKind::DEFAULT_KEYWORD))
}
pub fn separator(&self) -> Option<TokenRef<'a>> {
self.node
.find_token(SyntaxKind::DEFAULT_SEPARATOR)
.map(|t| TokenRef::new(self.parsed, t))
}
pub fn value(&self) -> Option<TokenRef<'a>> {
self.node
.find_token(SyntaxKind::DEFAULT_VALUE)
.map(|t| TokenRef::new(self.parsed, t))
}
}
#[derive(Debug, Clone, Copy)]
pub struct Directive<'a> {
pub(crate) parsed: &'a Parsed,
pub(crate) node: &'a SyntaxNode,
}
impl<'a> Directive<'a> {
pub fn cast(parsed: &'a Parsed, node: &'a SyntaxNode) -> Option<Self> {
(node.kind() == SyntaxKind::DIRECTIVE).then_some(Self { parsed, node })
}
pub fn syntax(&self) -> &'a SyntaxNode {
self.node
}
pub fn range(&self) -> &'a TextRange {
self.node.range()
}
pub fn name(&self) -> TokenRef<'a> {
TokenRef::new(self.parsed, self.node.required_token(SyntaxKind::DIRECTIVE_NAME))
}
pub fn argument(&self) -> Option<TokenRef<'a>> {
self.node
.find_token(SyntaxKind::ARGUMENT)
.map(|t| TokenRef::new(self.parsed, t))
}
pub fn description(&self) -> Option<TextBlock<'a>> {
find_text_block(self.parsed, self.node, SyntaxKind::DESCRIPTION)
}
}
#[derive(Debug, Clone, Copy)]
pub struct Citation<'a> {
pub(crate) parsed: &'a Parsed,
pub(crate) node: &'a SyntaxNode,
}
impl<'a> Citation<'a> {
pub fn cast(parsed: &'a Parsed, node: &'a SyntaxNode) -> Option<Self> {
(node.kind() == SyntaxKind::CITATION).then_some(Self { parsed, node })
}
pub fn syntax(&self) -> &'a SyntaxNode {
self.node
}
pub fn range(&self) -> &'a TextRange {
self.node.range()
}
pub fn label(&self) -> Option<TokenRef<'a>> {
self.node
.find_token(SyntaxKind::LABEL)
.map(|t| TokenRef::new(self.parsed, t))
}
pub fn description(&self) -> Option<TextBlock<'a>> {
find_text_block(self.parsed, self.node, SyntaxKind::DESCRIPTION)
}
}