From 668596cc89f8f6bddafd35fd031638bc0c416183 Mon Sep 17 00:00:00 2001
From: timo-a <timo-a@gmx.ch>
Date: Mon, 28 Dec 2020 03:42:28 +0100
Subject: [PATCH] Add support for writing nested tables to asciidoc (#6972)

Added field to WriterState that denotes the current nesting level for traversing tables.
Depending on the value of that field nested tables are recognized and written.
Asciidoc supports one level of nesting. If deeper tables are to be written, they are
omitted and a warning is issued.
---
 src/Text/Pandoc/Writers/AsciiDoc.hs           | 39 +++++++--
 test/command/nested-table-to-asciidoc-6942.md | 82 +++++++++++++++++++
 2 files changed, 114 insertions(+), 7 deletions(-)
 create mode 100644 test/command/nested-table-to-asciidoc-6942.md

diff --git a/src/Text/Pandoc/Writers/AsciiDoc.hs b/src/Text/Pandoc/Writers/AsciiDoc.hs
index e742577b6..0a312d1d1 100644
--- a/src/Text/Pandoc/Writers/AsciiDoc.hs
+++ b/src/Text/Pandoc/Writers/AsciiDoc.hs
@@ -37,6 +37,7 @@ import Text.Pandoc.Shared
 import Text.Pandoc.Templates (renderTemplate)
 import Text.Pandoc.Writers.Shared
 
+
 data WriterState = WriterState { defListMarker       :: Text
                                , orderedListLevel    :: Int
                                , bulletListLevel     :: Int
@@ -45,6 +46,10 @@ data WriterState = WriterState { defListMarker       :: Text
                                , asciidoctorVariant  :: Bool
                                , inList              :: Bool
                                , hasMath             :: Bool
+                               -- |0 is no table
+                               -- 1 is top level table
+                               -- 2 is a table in a table
+                               , tableNestingLevel   :: Int
                                }
 
 defaultWriterState :: WriterState
@@ -56,6 +61,7 @@ defaultWriterState = WriterState { defListMarker      = "::"
                                  , asciidoctorVariant = False
                                  , inList             = False
                                  , hasMath            = False
+                                 , tableNestingLevel  = 0
                                  }
 
 -- | Convert Pandoc to AsciiDoc.
@@ -194,7 +200,7 @@ blockToAsciiDoc opts (BlockQuote blocks) = do
                      else contents
   let bar = text "____"
   return $ bar $$ chomp contents' $$ bar <> blankline
-blockToAsciiDoc opts (Table _ blkCapt specs thead tbody tfoot) = do
+blockToAsciiDoc opts block@(Table _ blkCapt specs thead tbody tfoot) = do
   let (caption, aligns, widths, headers, rows) =
         toLegacyTable blkCapt specs thead tbody tfoot
   caption' <- inlineListToAsciiDoc opts caption
@@ -236,23 +242,42 @@ blockToAsciiDoc opts (Table _ blkCapt specs thead tbody tfoot) = do
              $ zipWith colspec aligns widths')
          <> text ","
          <> headerspec <> text "]"
+         
+  -- construct cells and recurse in case of nested tables
+  parentTableLevel <- gets tableNestingLevel
+  let currentNestingLevel = parentTableLevel + 1
+  
+  modify $ \st -> st{ tableNestingLevel = currentNestingLevel }
+  
+  let separator = text (if parentTableLevel == 0
+                          then "|"  -- top level separator
+                          else "!") -- nested separator
+
   let makeCell [Plain x] = do d <- blockListToAsciiDoc opts [Plain x]
-                              return $ text "|" <> chomp d
+                              return $ separator <> chomp d
       makeCell [Para x]  = makeCell [Plain x]
-      makeCell []        = return $ text "|"
-      makeCell bs        = do d <- blockListToAsciiDoc opts bs
-                              return $ text "a|" $$ d
+      makeCell []        = return separator
+      makeCell bs        = if currentNestingLevel == 2
+                             then do
+                               --asciidoc only supports nesting once
+                               report $ BlockNotRendered block
+                               return separator
+                             else do
+                               d <- blockListToAsciiDoc opts bs
+                               return $ (text "a" <> separator) $$ d
+
   let makeRow cells = hsep `fmap` mapM makeCell cells
   rows' <- mapM makeRow rows
   head' <- makeRow headers
+  modify $ \st -> st{ tableNestingLevel = parentTableLevel }
   let head'' = if all null headers then empty else head'
   let colwidth = if writerWrapText opts == WrapAuto
                     then writerColumns opts
                     else 100000
   let maxwidth = maximum $ map offset (head':rows')
   let body = if maxwidth > colwidth then vsep rows' else vcat rows'
-  let border = text "|==="
-  return $
+  let border = separator <> text "==="
+  return $ 
     caption'' $$ tablespec $$ border $$ head'' $$ body $$ border $$ blankline
 blockToAsciiDoc opts (BulletList items) = do
   inlist <- gets inList
diff --git a/test/command/nested-table-to-asciidoc-6942.md b/test/command/nested-table-to-asciidoc-6942.md
new file mode 100644
index 000000000..baf11fdf7
--- /dev/null
+++ b/test/command/nested-table-to-asciidoc-6942.md
@@ -0,0 +1,82 @@
+A table within a table should be convertet into a table within table
+
+```
+% pandoc -f html -t asciidoc
+<!doctype html>
+<html>
+<head>
+<meta charset="utf-8">
+<title> NestedTables </title>
+</head>
+<body>
+<table>
+ <tr>
+  <td >
+   <table>  <tr> <td> a1 </td> <td> a2 </td> </tr>  </table>
+  </td>
+  <td>b</td>
+ </tr>
+ <tr>
+   <td>c</td> <td>d </td>
+ </tr>
+</table>
+</body>
+</html>
+^D
+[width="100%",cols="50%,50%",]
+|===
+a|
+[cols=",",]
+!===
+!a1 !a2
+!===
+
+|b
+|c |d
+|===
+```
+
+A table within a table within a table cannot be converted because asciidoc only
+supports two levels of tables.
+The table on level 3 is thus converted to level 2 and a warning is produced
+```
+% pandoc -f html -t asciidoc --verbose
+<!doctype html>
+<html>
+<head>
+<meta charset="utf-8">
+<title> NestedTables </title>
+</head>
+<body>
+<table>
+ <tr>
+  <td>
+    <table>  <tr>
+	<td> a1 </td>
+	<td>
+	  <table>  <tr> <td> 1 </td> <td> 2 </td> </tr>  </table>
+	</td>
+    </tr>  </table>
+  </td>
+  <td>b</td>
+ </tr>
+ <tr>
+   <td>c</td> <td>d </td>
+ </tr>
+</table>
+</body>
+</html>
+^D
+[INFO] Not rendering Table ("",[],[]) (Caption Nothing []) [(AlignDefault,ColWidth 0.5),(AlignDefault,ColWidth 0.5)] (TableHead ("",[],[]) []) [TableBody ("",[],[]) (RowHeadColumns 0) [] [Row ("",[],[]) [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "a1"]],Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Table ("",[],[]) (Caption Nothing []) [(AlignDefault,ColWidthDefault),(AlignDefault,ColWidthDefault)] (TableHead ("",[],[]) []) [TableBody ("",[],[]) (RowHeadColumns 0) [] [Row ("",[],[]) [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "1"]],Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "2"]]]]] (TableFoot ("",[],[]) [])]]]] (TableFoot ("",[],[]) [])
+[width="100%",cols="50%,50%",]
+|===
+a|
+[width="100%",cols="50%,50%",]
+!===
+!a1 !
+!===
+
+|b
+|c |d
+|===
+```