]> git.lizzy.rs Git - rust.git/commitdiff
Correct complex list item support in AsciiDoc-to-Markdown conversion
authorNoritada Kobayashi <noritada.kobayashi@gmail.com>
Mon, 12 Dec 2022 04:09:18 +0000 (13:09 +0900)
committerNoritada Kobayashi <noritada.kobayashi@gmail.com>
Mon, 12 Dec 2022 04:09:18 +0000 (13:09 +0900)
Support for following cases are added:

- newlines between list items
- list item with multiline principal text with or without indent
- list item immediately after a list continuation paragraph without
  empty lines in between

xtask/src/publish/notes.rs

index 6968ae77e41b7453ca51964ccafb2e14774a3d7f..3ff0f5a28078ec8a260d0f7b7623caca6e9fd569 100644 (file)
@@ -42,7 +42,7 @@ fn process(&mut self) -> anyhow::Result<()> {
             } else if line.starts_with(VIDEO_BLOCK_PREFIX) {
                 self.process_video_block(None, 0)?;
             } else {
-                self.process_paragraph(0)?;
+                self.process_paragraph(0, |line| line.is_empty())?;
             }
 
             self.skip_blank_lines()?;
@@ -84,16 +84,19 @@ fn process_document_title(&mut self) -> anyhow::Result<()> {
 
     fn process_list(&mut self) -> anyhow::Result<()> {
         let mut nesting = ListNesting::new();
-        while let Some(line) = self.iter.next() {
-            let line = line?;
-            if line.is_empty() {
-                break;
-            }
+        while let Some(line) = self.iter.peek() {
+            let line = line.as_deref().map_err(|e| anyhow!("{e}"))?;
 
-            if let Some((marker, item)) = get_list_item(&line) {
+            if get_list_item(&line).is_some() {
+                let line = self.iter.next().unwrap()?;
+                let (marker, item) = get_list_item(&line).unwrap();
                 nesting.set_current(marker);
                 self.write_list_item(item, &nesting);
+                self.process_paragraph(nesting.indent(), |line| {
+                    line.is_empty() || get_list_item(line).is_some() || line == "+"
+                })?;
             } else if line == "+" {
+                let _ = self.iter.next().unwrap()?;
                 let line = self
                     .iter
                     .peek()
@@ -118,11 +121,17 @@ fn process_list(&mut self) -> anyhow::Result<()> {
                     self.process_video_block(None, indent)?;
                 } else {
                     self.write_line("", 0);
-                    self.process_paragraph(indent)?;
+                    let current = nesting.current().unwrap();
+                    self.process_paragraph(indent, |line| {
+                        line.is_empty()
+                            || get_list_item(line).filter(|(m, _)| m == current).is_some()
+                            || line == "+"
+                    })?;
                 }
             } else {
-                bail!("not a list block")
+                break;
             }
+            self.skip_blank_lines()?;
         }
 
         Ok(())
@@ -235,15 +244,19 @@ fn process_video_block(&mut self, caption: Option<&str>, level: usize) -> anyhow
         bail!("not a video block")
     }
 
-    fn process_paragraph(&mut self, level: usize) -> anyhow::Result<()> {
+    fn process_paragraph<P>(&mut self, level: usize, predicate: P) -> anyhow::Result<()>
+    where
+        P: Fn(&str) -> bool,
+    {
         while let Some(line) = self.iter.peek() {
             let line = line.as_deref().map_err(|e| anyhow!("{e}"))?;
-            if line.is_empty() || (level > 0 && line == "+") {
+            if predicate(&line) {
                 break;
             }
 
             self.write_indent(level);
             let line = self.iter.next().unwrap()?;
+            let line = line.trim_start();
             if line.ends_with('+') {
                 let line = &line[..(line.len() - 1)];
                 self.output.push_str(line);
@@ -373,6 +386,10 @@ fn new() -> Self {
         Self(Vec::<ListMarker>::with_capacity(6))
     }
 
+    fn current(&mut self) -> Option<&ListMarker> {
+        self.0.last()
+    }
+
     fn set_current(&mut self, marker: ListMarker) {
         let Self(markers) = self;
         if let Some(index) = markers.iter().position(|m| *m == marker) {
@@ -469,6 +486,22 @@ fn test_asciidoc_to_markdown_conversion() {
 ----
 This is a plain listing.
 ----
+* single line item followed by empty lines
+
+* multiline list
+item followed by empty lines
+
+* multiline list
+  item with indent
+
+* multiline list
+item not followed by empty lines
+* multiline list
+item followed by different marker
+** foo
+** bar
+* multiline list
+item followed by list continuation
 +
 paragraph
 paragraph
@@ -539,6 +572,19 @@ fn test_asciidoc_to_markdown_conversion() {
   ```
   This is a plain listing.
   ```
+- single line item followed by empty lines
+- multiline list
+  item followed by empty lines
+- multiline list
+  item with indent
+- multiline list
+  item not followed by empty lines
+- multiline list
+  item followed by different marker
+  - foo
+  - bar
+- multiline list
+  item followed by list continuation
 
   paragraph
   paragraph