summaryrefslogtreecommitdiff
path: root/src/parse_heirarchical.rs
diff options
context:
space:
mode:
authorBen Bridle <bridle.benjamin@gmail.com>2022-08-25 21:09:25 +1200
committerBen Bridle <bridle.benjamin@gmail.com>2022-08-25 21:09:25 +1200
commit54f5e9fd883e207931baa9c87b6181ca724d6bab (patch)
tree17111a1da036dbc061ae4062ea0716373e16e23d /src/parse_heirarchical.rs
downloadmarkdown-54f5e9fd883e207931baa9c87b6181ca724d6bab.zip
Initial commit
Diffstat (limited to 'src/parse_heirarchical.rs')
-rw-r--r--src/parse_heirarchical.rs137
1 files changed, 137 insertions, 0 deletions
diff --git a/src/parse_heirarchical.rs b/src/parse_heirarchical.rs
new file mode 100644
index 0000000..75c2bec
--- /dev/null
+++ b/src/parse_heirarchical.rs
@@ -0,0 +1,137 @@
+use crate::*;
+
+macro_rules! get_subsection {
+ ($t:ident) => {
+ pub fn get_subsection(&self, name: &str) -> Option<&$t> {
+ for section in &self.sections {
+ if line_to_string(&section.title) == name {
+ return Some(section);
+ }
+ }
+ return None;
+ }
+ };
+}
+
+#[derive(Default)]
+pub struct Document {
+ pub preamble: Vec<Block>,
+ pub sections: Vec<TopLevelSection>,
+}
+impl Document {
+ get_subsection! {TopLevelSection}
+}
+
+#[derive(Default)]
+pub struct TopLevelSection {
+ pub title: Line,
+ pub content: Vec<Block>,
+ pub sections: Vec<MidLevelSection>,
+}
+impl TopLevelSection {
+ get_subsection! {MidLevelSection}
+}
+
+#[derive(Default)]
+pub struct MidLevelSection {
+ pub title: Line,
+ pub content: Vec<Block>,
+ pub sections: Vec<LowLevelSection>,
+}
+impl MidLevelSection {
+ get_subsection! {LowLevelSection}
+}
+
+#[derive(Default)]
+pub struct LowLevelSection {
+ pub title: Line,
+ pub content: Vec<Block>,
+}
+
+pub fn parse_heirarchical(markdown: &str) -> Result<Document, ()> {
+ macro_rules! push_section {
+ ($from:ident => $to:ident) => {
+ $to.sections.push(std::mem::take(&mut $from))
+ };
+ }
+ let mut document = Document::default();
+ let mut h1_buffer = TopLevelSection::default();
+ let mut h2_buffer = MidLevelSection::default();
+ let mut h3_buffer = LowLevelSection::default();
+ let mut level = 0;
+
+ let blocks = parse(markdown);
+ for block in blocks {
+ match (level, block) {
+ (0, Block::Heading1(title)) => {
+ h1_buffer.title = title;
+ level = 1;
+ }
+ (0, Block::Heading2(_)) => return Err(()),
+ (0, Block::Heading3(_)) => return Err(()),
+ (0, block) => document.preamble.push(block),
+ (1, Block::Heading1(title)) => {
+ push_section!(h1_buffer => document);
+ h1_buffer.title = title;
+ }
+ (1, Block::Heading2(title)) => {
+ h2_buffer.title = title;
+ level = 2;
+ }
+ (1, Block::Heading3(_)) => return Err(()),
+ (1, block) => h1_buffer.content.push(block),
+ (2, Block::Heading1(title)) => {
+ push_section!(h2_buffer => h1_buffer);
+ push_section!(h1_buffer => document);
+ h1_buffer.title = title;
+ level = 1;
+ }
+ (2, Block::Heading2(title)) => {
+ push_section!(h2_buffer => h1_buffer);
+ h2_buffer.title = title;
+ }
+ (2, Block::Heading3(title)) => {
+ h3_buffer.title = title;
+ level = 3;
+ }
+ (2, block) => h2_buffer.content.push(block),
+ (3, Block::Heading1(title)) => {
+ push_section!(h3_buffer => h2_buffer);
+ push_section!(h2_buffer => h1_buffer);
+ push_section!(h1_buffer => document);
+ h1_buffer.title = title;
+ level = 1;
+ }
+ (3, Block::Heading2(title)) => {
+ push_section!(h3_buffer => h2_buffer);
+ push_section!(h2_buffer => h1_buffer);
+ h2_buffer.title = title;
+ level = 2;
+ }
+ (3, Block::Heading3(title)) => {
+ push_section!(h3_buffer => h2_buffer);
+ h3_buffer.title = title;
+ }
+ (3, block) => h3_buffer.content.push(block),
+ _ => unreachable!(),
+ }
+ }
+
+ // Push all in-progress sections
+ match level {
+ 3 => {
+ push_section!(h3_buffer => h2_buffer);
+ push_section!(h2_buffer => h1_buffer);
+ push_section!(h1_buffer => document);
+ }
+ 2 => {
+ push_section!(h2_buffer => h1_buffer);
+ push_section!(h1_buffer => document);
+ }
+ 1 => {
+ push_section!(h1_buffer => document);
+ }
+ _ => (),
+ }
+ Ok(document)
+}