git.iko.soy/typeable/pandoc
on master help sign in
RST writer: improve grid table output, fix bug with empty rows.

Uses the new gridTable in Writers.Shared, which is here improved to better handle 0-width cells. Closes #3516.

commitdaf8d1db18efcfbac31afd6a2323411b93ce1b62 authorJohn MacFarlane <jgm@berkeley.edu> dateTue 21 Mar 2017, 14:16 (10 years ago) parentd3798a0
5 files changed+91−85
src/Text/Pandoc/Writers/RST.hs+11−32 src/Text/Pandoc/Writers/Shared.hs+29−17 test/command/3516.md+15 test/tables-rstsubset.native+6−6 test/tables.rst+30−30
src/Text/Pandoc/Writers/RST.hs+11−32
@@ -33,7 +33,7 @@ reStructuredText: <http://docutils.sourceforge.net/rst.html>
3333module Text.Pandoc.Writers.RST ( writeRST ) where
3434import Control.Monad.State
3535import Data.Char (isSpace, toLower)
36−import Data.List (intersperse, isPrefixOf, stripPrefix, transpose)
36+import Data.List (isPrefixOf, stripPrefix)
3737import Data.Maybe (fromMaybe)
3838import Network.URI (isURI)
3939import qualified Text.Pandoc.Builder as B
@@ -269,39 +269,18 @@ blockToRST (BlockQuote blocks) = do
269269 tabstop <- gets $ writerTabStop . stOptions
270270 contents <- blockListToRST blocks
271271 return $ (nest tabstop contents) <> blankline
272−blockToRST (Table caption _ widths headers rows) = do
272+blockToRST (Table caption aligns widths headers rows) = do
273273 caption' <- inlineListToRST caption
274− headers' <- mapM blockListToRST headers
275− rawRows <- mapM (mapM blockListToRST) rows
276− -- let isSimpleCell [Plain _] = True
277− -- isSimpleCell [Para _] = True
278− -- isSimpleCell [] = True
279− -- isSimpleCell _ = False
280− -- let isSimple = all (==0) widths && all (all isSimpleCell) rows
281− let numChars = maximum . map offset
274+ let blocksToDoc opts bs = do
275+ oldOpts <- gets stOptions
276+ modify $ \st -> st{ stOptions = opts }
277+ result <- blockListToRST bs
278+ modify $ \st -> st{ stOptions = oldOpts }
279+ return result
282280 opts <- gets stOptions
283− let widthsInChars =
284− if all (== 0) widths
285− then map ((+2) . numChars) $ transpose (headers' : rawRows)
286− else map (floor . (fromIntegral (writerColumns opts) *)) widths
287− let hpipeBlocks blocks = hcat [beg, middle, end]
288− where h = height (hcat blocks)
289− sep' = lblock 3 $ vcat (map text $ replicate h " | ")
290− beg = lblock 2 $ vcat (map text $ replicate h "| ")
291− end = lblock 2 $ vcat (map text $ replicate h " |")
292− middle = hcat $ intersperse sep' blocks
293− let makeRow = hpipeBlocks . zipWith lblock widthsInChars
294− let head' = makeRow headers'
295− let rows' = map makeRow rawRows
296− let border ch = char '+' <> char ch <>
297− (hcat $ intersperse (char ch <> char '+' <> char ch) $
298− map (\l -> text $ replicate l ch) widthsInChars) <>
299− char ch <> char '+'
300− let body = vcat $ intersperse (border '-') rows'
301− let head'' = if all null headers
302− then empty
303− else head' $$ border '='
304− let tbl = border '-' $$ head'' $$ body $$ border '-'
281+ tbl <- gridTable opts blocksToDoc (all null headers)
282+ (map (const AlignDefault) aligns) widths
283+ headers rows
305284 return $ if null caption
306285 then tbl $$ blankline
307286 else (".. table:: " <> caption') $$ blankline $$ nest 3 tbl $$
src/Text/Pandoc/Writers/Shared.hs+29−17
@@ -46,7 +46,7 @@ import Control.Monad (liftM, zipWithM)
4646import Data.Aeson (FromJSON (..), Result (..), ToJSON (..), Value (Object),
4747 encode, fromJSON)
4848import qualified Data.HashMap.Strict as H
49−import Data.List (groupBy, intersperse)
49+import Data.List (groupBy, intersperse, transpose)
5050import qualified Data.Map as M
5151import Data.Maybe (isJust)
5252import qualified Data.Text as T
@@ -229,22 +229,34 @@ gridTable :: Monad m
229229gridTable opts blocksToDoc headless aligns widths headers rows = do
230230 let numcols = maximum (length aligns : length widths :
231231 map length (headers:rows))
232− let widths' = if all (==0) widths
233− then replicate numcols
234− (1.0 / fromIntegral numcols)
235− else widths
236− let widthsInChars = map ((\x -> x - 3) . floor .
237− (fromIntegral (writerColumns opts) *)) widths'
238− rawHeaders <- zipWithM blocksToDoc
239− (map (\w -> opts{writerColumns =
240− min (w - 2) (writerColumns opts)}) widthsInChars)
241− headers
242− rawRows <- mapM
243− (\cs -> zipWithM blocksToDoc
244− (map (\w -> opts{writerColumns =
245− min (w - 2) (writerColumns opts)}) widthsInChars)
246− cs)
247− rows
232+ let handleGivenWidths widths' = do
233+ let widthsInChars' = map ((\x -> x - 3) . floor .
234+ (fromIntegral (writerColumns opts) *)) widths'
235+ rawHeaders' <- zipWithM blocksToDoc
236+ (map (\w -> opts{writerColumns =
237+ min (w - 2) (writerColumns opts)}) widthsInChars')
238+ headers
239+ rawRows' <- mapM
240+ (\cs -> zipWithM blocksToDoc
241+ (map (\w -> opts{writerColumns =
242+ min (w - 2) (writerColumns opts)}) widthsInChars')
243+ cs)
244+ rows
245+ return (widthsInChars', rawHeaders', rawRows')
246+ let handleZeroWidths = do
247+ rawHeaders' <- mapM (blocksToDoc opts) headers
248+ rawRows' <- mapM (mapM (blocksToDoc opts)) rows
249+ let numChars = maximum . map offset
250+ let widthsInChars' =
251+ map ((+2) . numChars) $ transpose (rawHeaders' : rawRows')
252+ if sum widthsInChars' > writerColumns opts
253+ then -- use even widths
254+ handleGivenWidths
255+ (replicate numcols (1.0 / fromIntegral numcols) :: [Double])
256+ else return (widthsInChars', rawHeaders', rawRows')
257+ (widthsInChars, rawHeaders, rawRows) <- if all (== 0) widths
258+ then handleZeroWidths
259+ else handleGivenWidths widths
248260 let hpipeBlocks blocks = hcat [beg, middle, end]
249261 where h = maximum (1 : map height blocks)
250262 sep' = lblock 3 $ vcat (map text $ replicate h " | ")
test/command/3516.mdnew file+15
@@ -0,0 +1,15 @@
1+Correctly handle empty row:
2+```
3+% pandoc -f markdown -t rst
4++---+---+
5+| 1 | 2 |
6++---+---+
7+| | |
8++---+---+
9+^D
10++---+---+
11+| 1 | 2 |
12++---+---+
13+| | |
14++---+---+
15+```
test/tables-rstsubset.native+6−6
@@ -53,7 +53,7 @@
5353 ,[Plain [Str "1"]]
5454 ,[Plain [Str "1"]]]]
5555,Para [Str "Multiline",Space,Str "table",Space,Str "with",Space,Str "caption:"]
56−,Table [Str "Here\8217s",Space,Str "the",Space,Str "caption.",Space,Str "It",Space,Str "may",Space,Str "span",Space,Str "multiple",Space,Str "lines."] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.175,0.1625,0.1875,0.3625]
56+,Table [Str "Here\8217s",Space,Str "the",Space,Str "caption.",Space,Str "It",Space,Str "may",Space,Str "span",Space,Str "multiple",Space,Str "lines."] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.1375,0.125,0.15,0.325]
5757 [[Plain [Str "Centered",Space,Str "Header"]]
5858 ,[Plain [Str "Left",Space,Str "Aligned"]]
5959 ,[Plain [Str "Right",Space,Str "Aligned"]]
@@ -65,9 +65,9 @@
6565 ,[[Plain [Str "Second"]]
6666 ,[Plain [Str "row"]]
6767 ,[Plain [Str "5.0"]]
68− ,[Plain [Str "Here\8217s",Space,Str "another",Space,Str "one.",Space,Str "Note",SoftBreak,Str "the",Space,Str "blank",Space,Str "line",Space,Str "between",SoftBreak,Str "rows."]]]]
68+ ,[Plain [Str "Here\8217s",Space,Str "another",Space,Str "one.",SoftBreak,Str "Note",Space,Str "the",Space,Str "blank",Space,Str "line",SoftBreak,Str "between",Space,Str "rows."]]]]
6969,Para [Str "Multiline",Space,Str "table",Space,Str "without",Space,Str "caption:"]
70−,Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.175,0.1625,0.1875,0.3625]
70+,Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.1375,0.125,0.15,0.325]
7171 [[Plain [Str "Centered",Space,Str "Header"]]
7272 ,[Plain [Str "Left",Space,Str "Aligned"]]
7373 ,[Plain [Str "Right",Space,Str "Aligned"]]
@@ -79,7 +79,7 @@
7979 ,[[Plain [Str "Second"]]
8080 ,[Plain [Str "row"]]
8181 ,[Plain [Str "5.0"]]
82− ,[Plain [Str "Here\8217s",Space,Str "another",Space,Str "one.",Space,Str "Note",SoftBreak,Str "the",Space,Str "blank",Space,Str "line",Space,Str "between",SoftBreak,Str "rows."]]]]
82+ ,[Plain [Str "Here\8217s",Space,Str "another",Space,Str "one.",SoftBreak,Str "Note",Space,Str "the",Space,Str "blank",Space,Str "line",SoftBreak,Str "between",Space,Str "rows."]]]]
8383,Para [Str "Table",Space,Str "without",Space,Str "column",Space,Str "headers:"]
8484,Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.1,0.1,0.1,0.1]
8585 [[]
@@ -99,7 +99,7 @@
9999 ,[Plain [Str "1"]]
100100 ,[Plain [Str "1"]]]]
101101,Para [Str "Multiline",Space,Str "table",Space,Str "without",Space,Str "column",Space,Str "headers:"]
102−,Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.175,0.1625,0.1875,0.3625]
102+,Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.1375,0.125,0.15,0.325]
103103 [[]
104104 ,[]
105105 ,[]
@@ -111,4 +111,4 @@
111111 ,[[Plain [Str "Second"]]
112112 ,[Plain [Str "row"]]
113113 ,[Plain [Str "5.0"]]
114− ,[Plain [Str "Here\8217s",Space,Str "another",Space,Str "one.",Space,Str "Note",SoftBreak,Str "the",Space,Str "blank",Space,Str "line",Space,Str "between",SoftBreak,Str "rows."]]]]]
114+ ,[Plain [Str "Here\8217s",Space,Str "another",Space,Str "one.",SoftBreak,Str "Note",Space,Str "the",Space,Str "blank",Space,Str "line",SoftBreak,Str "between",Space,Str "rows."]]]]]
test/tables.rst+30−30
@@ -42,31 +42,31 @@ Multiline table with caption:
4242
4343.. table:: Here’s the caption. It may span multiple lines.
4444
45− +-------------+------------+--------------+----------------------------+
46− | Centered | Left | Right | Default aligned |
47− | Header | Aligned | Aligned | |
48− +=============+============+==============+============================+
49− | First | row | 12.0 | Example of a row that |
50− | | | | spans multiple lines. |
51− +-------------+------------+--------------+----------------------------+
52− | Second | row | 5.0 | Here’s another one. Note |
53− | | | | the blank line between |
54− | | | | rows. |
55− +-------------+------------+--------------+----------------------------+
45+ +----------+---------+-----------+-------------------------+
46+ | Centered | Left | Right | Default aligned |
47+ | Header | Aligned | Aligned | |
48+ +==========+=========+===========+=========================+
49+ | First | row | 12.0 | Example of a row that |
50+ | | | | spans multiple lines. |
51+ +----------+---------+-----------+-------------------------+
52+ | Second | row | 5.0 | Here’s another one. |
53+ | | | | Note the blank line |
54+ | | | | between rows. |
55+ +----------+---------+-----------+-------------------------+
5656
5757Multiline table without caption:
5858
59−+-------------+------------+--------------+----------------------------+
60−| Centered | Left | Right | Default aligned |
61−| Header | Aligned | Aligned | |
62−+=============+============+==============+============================+
63−| First | row | 12.0 | Example of a row that |
64−| | | | spans multiple lines. |
65−+-------------+------------+--------------+----------------------------+
66−| Second | row | 5.0 | Here’s another one. Note |
67−| | | | the blank line between |
68−| | | | rows. |
69−+-------------+------------+--------------+----------------------------+
59++----------+---------+-----------+-------------------------+
60+| Centered | Left | Right | Default aligned |
61+| Header | Aligned | Aligned | |
62++==========+=========+===========+=========================+
63+| First | row | 12.0 | Example of a row that |
64+| | | | spans multiple lines. |
65++----------+---------+-----------+-------------------------+
66+| Second | row | 5.0 | Here’s another one. |
67+| | | | Note the blank line |
68+| | | | between rows. |
69++----------+---------+-----------+-------------------------+
7070
7171Table without column headers:
7272
@@ -80,11 +80,11 @@ Table without column headers:
8080
8181Multiline table without column headers:
8282
83−+-------------+------------+--------------+----------------------------+
84−| First | row | 12.0 | Example of a row that |
85−| | | | spans multiple lines. |
86−+-------------+------------+--------------+----------------------------+
87−| Second | row | 5.0 | Here’s another one. Note |
88−| | | | the blank line between |
89−| | | | rows. |
90−+-------------+------------+--------------+----------------------------+
83++----------+---------+-----------+-------------------------+
84+| First | row | 12.0 | Example of a row that |
85+| | | | spans multiple lines. |
86++----------+---------+-----------+-------------------------+
87+| Second | row | 5.0 | Here’s another one. |
88+| | | | Note the blank line |
89+| | | | between rows. |
90++----------+---------+-----------+-------------------------+