From eb8aee477db045a7449bc752975528263964b8ce Mon Sep 17 00:00:00 2001
From: John MacFarlane <jgm@berkeley.edu>
Date: Fri, 30 Oct 2015 12:37:08 -0700
Subject: [PATCH] Pipe tables with long lines now get relative cell widths.

If a pipe table contains a line longer than the column
width (as set by `--columns` or 80 by default), relative
widths are computed based on the widths of the separator lines
relative to the column width.

This should solve persistent problems with long pipe tables in
LaTeX/PDF output, and give more flexibility for determining
relative column widths in other formats, too.

For narrower pipe tables, column widths of 0 are used,
telling pandoc not to specify widths explicitly in output
formats that permit this.

Closes #2471.
---
 src/Text/Pandoc/Readers/Markdown.hs | 33 +++++++++++++++++------------
 tests/pipe-tables.native            | 13 +++++++++++-
 tests/pipe-tables.txt               |  7 ++++++
 3 files changed, 39 insertions(+), 14 deletions(-)

diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs
index e0b43d7f0..58878feb5 100644
--- a/src/Text/Pandoc/Readers/Markdown.hs
+++ b/src/Text/Pandoc/Readers/Markdown.hs
@@ -1320,7 +1320,7 @@ removeOneLeadingSpace xs =
 gridTableFooter :: MarkdownParser [Char]
 gridTableFooter = blanklines
 
-pipeBreak :: MarkdownParser [Alignment]
+pipeBreak :: MarkdownParser ([Alignment], [Int])
 pipeBreak = try $ do
   nonindentSpaces
   openPipe <- (True <$ char '|') <|> return False
@@ -1330,16 +1330,22 @@ pipeBreak = try $ do
   guard $ not (null rest && not openPipe)
   optional (char '|')
   blankline
-  return (first:rest)
+  return $ unzip (first:rest)
 
 pipeTable :: MarkdownParser ([Alignment], [Double], F [Blocks], F [[Blocks]])
 pipeTable = try $ do
   nonindentSpaces
   lookAhead nonspaceChar
-  (heads,aligns) <- (,) <$> pipeTableRow <*> pipeBreak
-  lines' <-  sequence <$> many pipeTableRow
-  let widths = replicate (length aligns) 0.0
-  return $ (aligns, widths, heads, lines')
+  (heads,(aligns, seplengths)) <- (,) <$> pipeTableRow <*> pipeBreak
+  (lines', rawRows) <- unzip <$> many (withRaw pipeTableRow)
+  let maxlength = maximum $ map length rawRows
+  numColumns <- getOption readerColumns
+  let widths = if maxlength > numColumns
+                  then map (\len ->
+                           fromIntegral (len + 1) / fromIntegral numColumns)
+                             seplengths
+                  else replicate (length aligns) 0.0
+  return $ (aligns, widths, heads, sequence lines')
 
 sepPipe :: MarkdownParser ()
 sepPipe = try $ do
@@ -1368,19 +1374,20 @@ pipeTableRow = do
                  ils' | B.isNull ils' -> mempty
                       | otherwise   -> B.plain $ ils') cells'
 
-pipeTableHeaderPart :: Parser [Char] st Alignment
+pipeTableHeaderPart :: Parser [Char] st (Alignment, Int)
 pipeTableHeaderPart = try $ do
   skipMany spaceChar
   left <- optionMaybe (char ':')
-  many1 (char '-')
+  pipe <- many1 (char '-')
   right <- optionMaybe (char ':')
   skipMany spaceChar
+  let len = length pipe + maybe 0 (const 1) left + maybe 0 (const 1) right
   return $
-    case (left,right) of
-      (Nothing,Nothing) -> AlignDefault
-      (Just _,Nothing)  -> AlignLeft
-      (Nothing,Just _)  -> AlignRight
-      (Just _,Just _)   -> AlignCenter
+    ((case (left,right) of
+       (Nothing,Nothing) -> AlignDefault
+       (Just _,Nothing)  -> AlignLeft
+       (Nothing,Just _)  -> AlignRight
+       (Just _,Just _)   -> AlignCenter), len)
 
 -- Succeed only if current line contains a pipe.
 scanForPipe :: Parser [Char] st ()
diff --git a/tests/pipe-tables.native b/tests/pipe-tables.native
index 9d499c9c2..f52175ff0 100644
--- a/tests/pipe-tables.native
+++ b/tests/pipe-tables.native
@@ -83,4 +83,15 @@
  [[[Plain [Str "3"]]
   ,[Plain [Str "33"]]]
  ,[[Plain [Str "4"]]
-  ,[Plain [Str "44"]]]]]
+  ,[Plain [Str "44"]]]]
+,Para [Str "Long",Space,Str "pipe",Space,Str "table",Space,Str "with",Space,Str "relative",Space,Str "widths:"]
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.125,0.1375,0.5]
+ [[Plain [Str "Default1"]]
+ ,[Plain [Str "Default2"]]
+ ,[Plain [Str "Default3"]]]
+ [[[Plain [Str "123"]]
+  ,[Plain [Str "this",Space,Str "is",Space,Str "a",Space,Str "table",Space,Str "cell"]]
+  ,[Plain [Str "and",Space,Str "this",Space,Str "is",Space,Str "a",Space,Str "really",Space,Str "long",Space,Str "table",Space,Str "cell",Space,Str "that",Space,Str "will",Space,Str "probably",Space,Str "need",Space,Str "wrapping"]]]
+ ,[[Plain [Str "123"]]
+  ,[Plain [Str "123"]]
+  ,[Plain [Str "123"]]]]]
diff --git a/tests/pipe-tables.txt b/tests/pipe-tables.txt
index a8803724a..a5984b99b 100644
--- a/tests/pipe-tables.txt
+++ b/tests/pipe-tables.txt
@@ -59,3 +59,10 @@ Number of siblings | Salary
 ------------------:|:------
                  3 | 33
                  4 | 44
+
+Long pipe table with relative widths:
+
+| Default1 | Default2 | Default3 |
+ |---------|----------|---------------------------------------|
+|123|this is a table cell|and this is a really long table cell that will probably need wrapping|
+|123|123|123|