use super::style::{self, *};
#[allow(unused_imports)]
use style::TextAlign as _TableAlignUse;
#[derive(Debug, Clone)]
pub struct Node {
pub kind: NodeKind,
pub style: Style,
pub splittable: bool,
}
impl Node {
pub fn new(kind: NodeKind, style: Style, splittable: bool) -> Self {
Self {
kind,
style,
splittable,
}
}
pub fn text_content(&self) -> String {
self.kind.text_content()
}
}
#[derive(Debug, Clone)]
pub enum NodeKind {
Document { children: Vec<Node> },
Heading { level: u8, children: Vec<Node> },
Paragraph { children: Vec<Node> },
List {
ordered: bool,
start: Option<u32>,
children: Vec<Node>,
},
ListItem { children: Vec<Node> },
TaskListItem { checked: bool, children: Vec<Node> },
Image {
src: String,
alt: String,
title: Option<String>,
},
CodeBlock { code: String, lang: Option<String> },
Blockquote { children: Vec<Node> },
ThematicBreak,
Table {
children: Vec<Node>,
align: Vec<TextAlign>,
},
TableRow { children: Vec<Node> },
Text { text: String },
Strong { children: Vec<Node> },
Emphasis { children: Vec<Node> },
InlineCode { code: String },
Link {
url: String,
title: Option<String>,
children: Vec<Node>,
},
Delete { children: Vec<Node> },
Subscript { children: Vec<Node> },
Superscript { children: Vec<Node> },
Span { children: Vec<Node> },
Center { children: Vec<Node> },
Container { children: Vec<Node> },
LineBreak,
}
impl NodeKind {
pub fn text_content(&self) -> String {
match self {
NodeKind::Text { text } => text.clone(),
NodeKind::LineBreak => "\n".to_string(),
NodeKind::Strong { children }
| NodeKind::Emphasis { children }
| NodeKind::Link { children, .. }
| NodeKind::Delete { children }
| NodeKind::Subscript { children }
| NodeKind::Superscript { children } => {
let mut s = String::new();
for child in children {
s.push_str(&child.text_content());
}
s
}
NodeKind::InlineCode { code } => code.clone(),
NodeKind::Heading { children, .. }
| NodeKind::Paragraph { children }
| NodeKind::ListItem { children }
| NodeKind::TaskListItem { children, .. }
| NodeKind::Blockquote { children }
| NodeKind::TableRow { children }
| NodeKind::Span { children }
| NodeKind::Center { children }
| NodeKind::Container { children } => {
let mut s = String::new();
for child in children {
s.push_str(&child.text_content());
}
s
}
_ => String::new(),
}
}
}
pub fn walk<F>(node: &Node, callback: &mut F)
where
F: FnMut(&Node),
{
callback(node);
match &node.kind {
NodeKind::Document { children }
| NodeKind::Heading { children, .. }
| NodeKind::Paragraph { children }
| NodeKind::List { children, .. }
| NodeKind::ListItem { children }
| NodeKind::TaskListItem { children, .. }
| NodeKind::Blockquote { children }
| NodeKind::Table { children, .. }
| NodeKind::TableRow { children }
| NodeKind::Strong { children }
| NodeKind::Emphasis { children }
| NodeKind::Link { children, .. }
| NodeKind::Delete { children }
| NodeKind::Span { children }
| NodeKind::Center { children }
| NodeKind::Container { children }
| NodeKind::Subscript { children }
| NodeKind::Superscript { children } => {
for child in children {
walk(child, callback);
}
}
_ => {}
}
}
pub fn collect_text(node: &Node) -> String {
let mut result = String::new();
walk(node, &mut |n| match &n.kind {
NodeKind::Text { text } => result.push_str(text),
NodeKind::LineBreak => result.push('\n'),
_ => {}
});
result
}