diff --git a/src/html.rs b/src/html.rs index 8a3cc5c1..6edf7215 100644 --- a/src/html.rs +++ b/src/html.rs @@ -26,7 +26,7 @@ use std::io::{self, ErrorKind, Write}; use crate::escape::{escape_href, escape_html}; use crate::parse::Event::*; -use crate::parse::{Alignment, Event, LinkType, Tag}; +use crate::parse::{Alignment, CodeBlockKind, Event, LinkType, Tag}; use crate::strings::CowStr; enum TableState { @@ -254,13 +254,18 @@ where if !self.end_newline { self.write_newline()?; } - let lang = info.split(' ').next().unwrap(); - if lang.is_empty() { - self.write("
")
-                } else {
-                    self.write("
")
+                match info {
+                    CodeBlockKind::Fenced(info) => {
+                        let lang = info.split(' ').next().unwrap();
+                        if lang.is_empty() {
+                            self.write("
")
+                        } else {
+                            self.write("
")
+                        }
+                    }
+                    CodeBlockKind::Indented => self.write("
"),
                 }
             }
             Tag::List(Some(1)) => {
diff --git a/src/lib.rs b/src/lib.rs
index 18b8d85d..229e1f03 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -70,5 +70,5 @@ mod tree;
 #[cfg(all(target_arch = "x86_64", feature = "simd"))]
 mod simd;
 
-pub use crate::parse::{Alignment, Event, LinkType, OffsetIter, Options, Parser, Tag};
+pub use crate::parse::{Alignment, CodeBlockKind, Event, LinkType, OffsetIter, Options, Parser, Tag};
 pub use crate::strings::{CowStr, InlineStr};
diff --git a/src/parse.rs b/src/parse.rs
index 9801b536..83a81dc8 100644
--- a/src/parse.rs
+++ b/src/parse.rs
@@ -38,6 +38,30 @@ use crate::tree::{Tree, TreeIndex, TreePointer};
 // https://spec.commonmark.org/0.29/#link-destination
 const LINK_MAX_NESTED_PARENS: usize = 5;
 
+/// Codeblock kind.
+#[derive(Clone, Debug, PartialEq)]
+pub enum CodeBlockKind<'a> {
+    Indented,
+    /// The value contained in the tag describes the language of the code, which may be empty.
+    Fenced(CowStr<'a>),
+}
+
+impl<'a> CodeBlockKind<'a> {
+    pub fn is_indented(&self) -> bool {
+        match *self {
+            CodeBlockKind::Indented => true,
+            _ => false,
+        }
+    }
+
+    pub fn is_fenced(&self) -> bool {
+        match *self {
+            CodeBlockKind::Fenced(_) => true,
+            _ => false,
+        }
+    }
+}
+
 /// Tags for elements that can contain other elements.
 #[derive(Clone, Debug, PartialEq)]
 pub enum Tag<'a> {
@@ -48,9 +72,8 @@ pub enum Tag<'a> {
     Heading(u32),
 
     BlockQuote,
-    /// A code block. The value contained in the tag describes the language of the code,
-    /// which may be empty.
-    CodeBlock(CowStr<'a>),
+    /// A code block.
+    CodeBlock(CodeBlockKind<'a>),
 
     /// A list. If the list is ordered the field indicates the number of the first item.
     /// Contains only list items.
@@ -1015,7 +1038,9 @@ impl<'a> FirstPass<'a> {
         self.tree.append(Item {
             start: start_ix,
             end: 0, // will get set later
-            body: ItemBody::FencedCodeBlock(self.allocs.allocate_cow(info_string)),
+            body: ItemBody::FencedCodeBlock(
+                self.allocs.allocate_cow(info_string),
+            ),
         });
         self.tree.push();
         loop {
@@ -2676,8 +2701,10 @@ fn item_to_tag<'a>(item: &Item, allocs: &Allocations<'a>) -> Tag<'a> {
             Tag::Image(*link_type, url.clone(), title.clone())
         }
         ItemBody::Heading(level) => Tag::Heading(level),
-        ItemBody::FencedCodeBlock(cow_ix) => Tag::CodeBlock(allocs[cow_ix].clone()),
-        ItemBody::IndentCodeBlock => Tag::CodeBlock("".into()),
+        ItemBody::FencedCodeBlock(cow_ix) => {
+            Tag::CodeBlock(CodeBlockKind::Fenced(allocs[cow_ix].clone()))
+        }
+        ItemBody::IndentCodeBlock => Tag::CodeBlock(CodeBlockKind::Indented),
         ItemBody::BlockQuote => Tag::BlockQuote,
         ItemBody::List(_, c, listitem_start) => {
             if c == b'.' || c == b')' {
@@ -2723,8 +2750,10 @@ fn item_to_event<'a>(item: Item, text: &'a str, allocs: &Allocations<'a>) -> Eve
             Tag::Image(*link_type, url.clone(), title.clone())
         }
         ItemBody::Heading(level) => Tag::Heading(level),
-        ItemBody::FencedCodeBlock(cow_ix) => Tag::CodeBlock(allocs[cow_ix].clone()),
-        ItemBody::IndentCodeBlock => Tag::CodeBlock("".into()),
+        ItemBody::FencedCodeBlock(cow_ix) => {
+            Tag::CodeBlock(CodeBlockKind::Fenced(allocs[cow_ix].clone()))
+        }
+        ItemBody::IndentCodeBlock => Tag::CodeBlock(CodeBlockKind::Indented),
         ItemBody::BlockQuote => Tag::BlockQuote,
         ItemBody::List(_, c, listitem_start) => {
             if c == b'.' || c == b')' {
@@ -3031,4 +3060,35 @@ mod test {
         }
         assert!(link_tag_count > 0);
     }
+
+    #[test]
+    fn code_block_kind_check_fenced() {
+        let parser = Parser::new("hello\n```test\ntadam\n```");
+        let mut found = 0;
+        for (ev, _range) in parser.into_offset_iter() {
+            match ev {
+                Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(syntax))) => {
+                    assert_eq!(syntax.as_ref(), "test");
+                    found += 1;
+                }
+                _ => {}
+            }
+        }
+        assert_eq!(found, 1);
+    }
+
+    #[test]
+    fn code_block_kind_check_indented() {
+        let parser = Parser::new("hello\n\n    ```test\n    tadam\nhello");
+        let mut found = 0;
+        for (ev, _range) in parser.into_offset_iter() {
+            match ev {
+                Event::Start(Tag::CodeBlock(CodeBlockKind::Indented)) => {
+                    found += 1;
+                }
+                _ => {}
+            }
+        }
+        assert_eq!(found, 1);
+    }
 }