summaryrefslogtreecommitdiff
path: root/src/md/visitor/structure.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/md/visitor/structure.rs')
-rw-r--r--src/md/visitor/structure.rs100
1 files changed, 100 insertions, 0 deletions
diff --git a/src/md/visitor/structure.rs b/src/md/visitor/structure.rs
new file mode 100644
index 0000000..d8faef6
--- /dev/null
+++ b/src/md/visitor/structure.rs
@@ -0,0 +1,100 @@
+use crate::md::panhelper;
+
+use pandoc_ast::{Block, Inline, MutVisitor};
+
+// A structure element in the document: a heading or a scenario snippet.
+#[derive(Debug)]
+pub enum Element {
+ // Headings consist of the text and the level of the heading.
+ Heading(String, i64),
+
+ // Scenario snippets consist just of the unparsed text.
+ Snippet(String),
+}
+
+impl Element {
+ pub fn heading(text: &str, level: i64) -> Element {
+ Element::Heading(text.to_string(), level)
+ }
+
+ pub fn snippet(text: &str) -> Element {
+ Element::Snippet(text.to_string())
+ }
+}
+
+// A MutVisitor for extracting document structure.
+pub struct StructureVisitor {
+ pub elements: Vec<Element>,
+}
+
+impl StructureVisitor {
+ pub fn new() -> Self {
+ Self { elements: vec![] }
+ }
+}
+
+impl MutVisitor for StructureVisitor {
+ fn visit_vec_block(&mut self, vec_block: &mut Vec<Block>) {
+ use panhelper::is_class;
+ for block in vec_block {
+ match block {
+ Block::Header(level, _attr, inlines) => {
+ let text = join(inlines);
+ let heading = Element::heading(&text, *level);
+ self.elements.push(heading);
+ }
+ Block::CodeBlock(attr, s) => {
+ if is_class(attr, "scenario") {
+ let snippet = Element::snippet(s);
+ self.elements.push(snippet);
+ }
+ }
+ _ => {
+ self.visit_block(block);
+ }
+ }
+ }
+ }
+}
+
+fn join(vec: &[Inline]) -> String {
+ let mut buf = String::new();
+ join_into_buffer(vec, &mut buf);
+ buf
+}
+
+fn join_into_buffer(vec: &[Inline], buf: &mut String) {
+ for item in vec {
+ match item {
+ Inline::Str(s) => buf.push_str(s),
+ Inline::Emph(v) => join_into_buffer(v, buf),
+ Inline::Strong(v) => join_into_buffer(v, buf),
+ Inline::Strikeout(v) => join_into_buffer(v, buf),
+ Inline::Superscript(v) => join_into_buffer(v, buf),
+ Inline::Subscript(v) => join_into_buffer(v, buf),
+ Inline::SmallCaps(v) => join_into_buffer(v, buf),
+ Inline::Quoted(qt, v) => {
+ let q = match qt {
+ pandoc_ast::QuoteType::SingleQuote => "'",
+ pandoc_ast::QuoteType::DoubleQuote => "\"",
+ };
+ buf.push_str(q);
+ join_into_buffer(v, buf);
+ buf.push_str(q);
+ }
+ Inline::Cite(_, v) => join_into_buffer(v, buf),
+ Inline::Code(_attr, s) => buf.push_str(s),
+ Inline::Space => buf.push(' '),
+ Inline::SoftBreak => buf.push(' '),
+ Inline::LineBreak => buf.push(' '),
+ Inline::Math(_, s) => buf.push_str(s),
+ Inline::RawInline(_, s) => buf.push_str(s),
+ Inline::Link(_, v, _) => join_into_buffer(v, buf),
+ Inline::Image(_, v, _) => join_into_buffer(v, buf),
+ Inline::Note(_) => buf.push_str(""),
+ Inline::Span(_attr, v) => join_into_buffer(v, buf),
+ #[cfg(feature = "pandoc_ast_08")]
+ Inline::Underline(v) => join_into_buffer(v, buf),
+ }
+ }
+}