oak_markdown/builder/
mod.rs1use crate::{ast::*, language::MarkdownLanguage, parser::MarkdownParser};
2use oak_core::{Builder, BuilderCache, GreenNode, OakError, Parser, RedNode, RedTree, SourceText, TextEdit, source::Source};
3
4#[derive(Clone)]
6pub struct MarkdownBuilder<'config> {
7 config: &'config MarkdownLanguage,
9}
10
11impl<'config> MarkdownBuilder<'config> {
12 pub fn new(config: &'config MarkdownLanguage) -> Self {
14 Self { config }
15 }
16
17 fn build_root(&self, green_tree: &GreenNode<MarkdownLanguage>, source: &SourceText) -> Result<MarkdownRoot, OakError> {
19 let red_root = RedNode::new(green_tree, 0);
20
21 let mut blocks = Vec::new();
22 for child in red_root.children() {
23 if let RedTree::Node(node) = child {
24 if let Some(block) = self.build_block(node, source) {
25 blocks.push(block);
26 }
27 }
28 }
29
30 Ok(MarkdownRoot { blocks })
31 }
32
33 fn build_block(&self, node: RedNode<MarkdownLanguage>, source: &SourceText) -> Option<Block> {
35 use crate::kind::MarkdownSyntaxKind::*;
36
37 let kind = node.green.kind;
38 match kind {
39 Heading1 | Heading2 | Heading3 | Heading4 | Heading5 | Heading6 => {
40 let level = match kind {
41 Heading1 => 1,
42 Heading2 => 2,
43 Heading3 => 3,
44 Heading4 => 4,
45 Heading5 => 5,
46 Heading6 => 6,
47 _ => unreachable!(),
48 };
49 Some(Block::Heading(crate::ast::Heading { level, content: source.get_text_in(node.span()).to_string(), span: node.span() }))
50 }
51 Paragraph => Some(Block::Paragraph(crate::ast::Paragraph { content: source.get_text_in(node.span()).to_string(), span: node.span() })),
52 CodeBlock => Some(Block::CodeBlock(crate::ast::CodeBlock {
53 language: None, content: source.get_text_in(node.span()).to_string(),
55 span: node.span(),
56 })),
57 UnorderedList | OrderedList => {
58 let mut items = Vec::new();
59 for child in node.children() {
60 if let RedTree::Node(child_node) = child {
61 if child_node.green.kind == ListItem {
62 items.push(self.build_list_item(child_node, source));
63 }
64 }
65 }
66 Some(Block::List(crate::ast::List { is_ordered: kind == OrderedList, items, span: node.span() }))
67 }
68 Blockquote => Some(Block::Blockquote(crate::ast::Blockquote { content: node.children().filter_map(|child| if let RedTree::Node(child_node) = child { self.build_block(child_node, source) } else { None }).collect(), span: node.span() })),
69 HorizontalRule => Some(Block::HorizontalRule(crate::ast::HorizontalRule { span: node.span() })),
70 Table => {
71 None
73 }
74 HtmlTag => {
75 None
77 }
78 _ => None,
79 }
80 }
81
82 fn build_list_item(&self, node: RedNode<MarkdownLanguage>, source: &SourceText) -> crate::ast::ListItem {
83 let mut content = Vec::new();
84 for child in node.children() {
85 if let RedTree::Node(child_node) = child {
86 if let Some(block) = self.build_block(child_node, source) {
87 content.push(block);
88 }
89 }
90 }
91
92 crate::ast::ListItem {
93 content,
94 is_task: false, is_checked: None, span: node.span(),
97 }
98 }
99}
100
101impl<'config> Builder<MarkdownLanguage> for MarkdownBuilder<'config> {
102 fn build<'a, S: Source + ?Sized>(&self, source: &S, edits: &[TextEdit], _cache: &'a mut impl BuilderCache<MarkdownLanguage>) -> oak_core::builder::BuildOutput<MarkdownLanguage> {
103 let parser = MarkdownParser::new(self.config);
104 let mut parse_session = oak_core::parser::session::ParseSession::<MarkdownLanguage>::default();
105 let parse_result = parser.parse(source, edits, &mut parse_session);
106
107 match parse_result.result {
108 Ok(green_tree) => {
109 let source_text = SourceText::new(source.get_text_in((0..source.length()).into()));
110 match self.build_root(green_tree, &source_text) {
111 Ok(ast_root) => oak_core::OakDiagnostics { result: Ok(ast_root), diagnostics: parse_result.diagnostics },
112 Err(build_error) => {
113 let mut diagnostics = parse_result.diagnostics;
114 diagnostics.push(build_error.clone());
115 oak_core::OakDiagnostics { result: Err(build_error), diagnostics }
116 }
117 }
118 }
119 Err(parse_error) => oak_core::OakDiagnostics { result: Err(parse_error), diagnostics: parse_result.diagnostics },
120 }
121 }
122}