diff options
-rw-r--r-- | src/Text/Pandoc/Parsing.hs | 69 | ||||
-rw-r--r-- | src/Text/Pandoc/Readers/Markdown.hs | 84 | ||||
-rw-r--r-- | test/command/3516.md | 4 | ||||
-rw-r--r-- | test/markdown-reader-more.native | 68 | ||||
-rw-r--r-- | test/tables-rstsubset.native | 12 |
5 files changed, 94 insertions, 143 deletions
diff --git a/src/Text/Pandoc/Parsing.hs b/src/Text/Pandoc/Parsing.hs index e0c0e36d6..fa3ff898e 100644 --- a/src/Text/Pandoc/Parsing.hs +++ b/src/Text/Pandoc/Parsing.hs @@ -66,6 +66,7 @@ module Text.Pandoc.Parsing ( anyLine, tableWith, widthsFromIndices, gridTableWith, + gridTableWith', readWith, readWithM, testStringWith, @@ -770,6 +771,20 @@ tableWith :: (Stream s m Char, HasReaderOptions st, -> ParserT s st m end -> ParserT s st m (mf Blocks) tableWith headerParser rowParser lineParser footerParser = try $ do + (aligns, widths, heads, rows) <- tableWith' headerParser rowParser + lineParser footerParser + return $ B.table mempty (zip aligns widths) <$> heads <*> rows + +type TableComponents mf = ([Alignment], [Double], mf [Blocks], mf [[Blocks]]) + +tableWith' :: (Stream s m Char, HasReaderOptions st, + Functor mf, Applicative mf, Monad mf) + => ParserT s st m (mf [Blocks], [Alignment], [Int]) + -> ([Int] -> ParserT s st m (mf [Blocks])) + -> ParserT s st m sep + -> ParserT s st m end + -> ParserT s st m (TableComponents mf) +tableWith' headerParser rowParser lineParser footerParser = try $ do (heads, aligns, indices) <- headerParser lines' <- sequence <$> rowParser indices `sepEndBy1` lineParser footerParser @@ -777,7 +792,7 @@ tableWith headerParser rowParser lineParser footerParser = try $ do let widths = if (indices == []) then replicate (length aligns) 0.0 else widthsFromIndices numColumns indices - return $ B.table mempty (zip aligns widths) <$> heads <*> lines' + return $ (aligns, widths, heads, lines') -- Calculate relative widths of table columns, based on indices widthsFromIndices :: Int -- Number of columns on terminal @@ -812,24 +827,42 @@ widthsFromIndices numColumns' indices = -- ending with a footer (dashed line followed by blank line). gridTableWith :: (Stream [Char] m Char, HasReaderOptions st, Functor mf, Applicative mf, Monad mf) - => ParserT [Char] st m (mf Blocks) -- ^ Block list parser + => ParserT [Char] st m (mf Blocks) -- ^ Block list parser -> Bool -- ^ Headerless table -> ParserT [Char] st m (mf Blocks) gridTableWith blocks headless = tableWith (gridTableHeader headless blocks) (gridTableRow blocks) (gridTableSep '-') gridTableFooter +gridTableWith' :: (Stream [Char] m Char, HasReaderOptions st, + Functor mf, Applicative mf, Monad mf) + => ParserT [Char] st m (mf Blocks) -- ^ Block list parser + -> Bool -- ^ Headerless table + -> ParserT [Char] st m (TableComponents mf) +gridTableWith' blocks headless = + tableWith' (gridTableHeader headless blocks) (gridTableRow blocks) + (gridTableSep '-') gridTableFooter + gridTableSplitLine :: [Int] -> String -> [String] gridTableSplitLine indices line = map removeFinalBar $ tail $ splitStringByIndices (init indices) $ trimr line -gridPart :: Stream s m Char => Char -> ParserT s st m (Int, Int) +gridPart :: Stream s m Char => Char -> ParserT s st m ((Int, Int), Alignment) gridPart ch = do + leftColon <- option False (True <$ char ':') dashes <- many1 (char ch) + rightColon <- option False (True <$ char ':') char '+' - return (length dashes, length dashes + 1) - -gridDashedLines :: Stream s m Char => Char -> ParserT s st m [(Int,Int)] + let lengthDashes = length dashes + (if leftColon then 1 else 0) + + (if rightColon then 1 else 0) + let alignment = case (leftColon, rightColon) of + (True, True) -> AlignCenter + (True, False) -> AlignLeft + (False, True) -> AlignRight + (False, False) -> AlignDefault + return ((lengthDashes, lengthDashes + 1), alignment) + +gridDashedLines :: Stream s m Char => Char -> ParserT s st m [((Int, Int), Alignment)] gridDashedLines ch = try $ char '+' >> many1 (gridPart ch) <* blankline removeFinalBar :: String -> String @@ -853,18 +886,18 @@ gridTableHeader headless blocks = try $ do else many1 (notFollowedBy (gridTableSep '=') >> char '|' >> many1Till anyChar newline) - if headless - then return () - else gridTableSep '=' >> return () - let lines' = map snd dashes + underDashes <- if headless + then return dashes + else gridDashedLines '=' + guard $ length dashes == length underDashes + let lines' = map (snd . fst) underDashes let indices = scanl (+) 0 lines' - let aligns = replicate (length lines') AlignDefault - -- RST does not have a notion of alignments + let aligns = map snd underDashes let rawHeads = if headless - then replicate (length dashes) "" - else map (intercalate " ") $ transpose + then replicate (length underDashes) "" + else map (unlines . map trim) $ transpose $ map (gridTableSplitLine indices) rawContent - heads <- fmap sequence . mapM (parseFromString blocks) $ map trim rawHeads + heads <- fmap sequence $ mapM (parseFromString blocks . trim) rawHeads return (heads, aligns, indices) gridTableRawLine :: Stream s m Char => [Int] -> ParserT s st m [String] @@ -882,6 +915,9 @@ gridTableRow blocks indices = do colLines <- many1 (gridTableRawLine indices) let cols = map ((++ "\n") . unlines . removeOneLeadingSpace) $ transpose colLines + compactifyCell bs = case compactify [bs] of + [] -> mempty + x:_ -> x cells <- sequence <$> mapM (parseFromString blocks) cols return $ fmap (map compactifyCell) cells @@ -893,9 +929,6 @@ removeOneLeadingSpace xs = where startsWithSpace "" = True startsWithSpace (y:_) = y == ' ' -compactifyCell :: Blocks -> Blocks -compactifyCell bs = head $ compactify [bs] - -- | Parse footer for a grid table. gridTableFooter :: Stream s m Char => ParserT s st m [Char] gridTableFooter = blanklines diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs index 691d4d5cf..4ff5a1845 100644 --- a/src/Text/Pandoc/Readers/Markdown.hs +++ b/src/Text/Pandoc/Readers/Markdown.hs @@ -1291,89 +1291,7 @@ multilineTableHeader headless = try $ do -- ending with a footer (dashed line followed by blank line). gridTable :: PandocMonad m => Bool -- ^ Headerless table -> MarkdownParser m ([Alignment], [Double], F [Blocks], F [[Blocks]]) -gridTable headless = - tableWith (gridTableHeader headless) gridTableRow - (gridTableSep '-') gridTableFooter - -gridTableSplitLine :: [Int] -> String -> [String] -gridTableSplitLine indices line = map removeFinalBar $ tail $ - splitStringByIndices (init indices) $ trimr line - -gridPart :: PandocMonad m => Char -> ParserT [Char] st m ((Int, Int), Alignment) -gridPart ch = do - leftColon <- option False (True <$ char ':') - dashes <- many1 (char ch) - rightColon <- option False (True <$ char ':') - char '+' - let lengthDashes = length dashes + (if leftColon then 1 else 0) + - (if rightColon then 1 else 0) - let alignment = case (leftColon, rightColon) of - (True, True) -> AlignCenter - (True, False) -> AlignLeft - (False, True) -> AlignRight - (False, False) -> AlignDefault - return ((lengthDashes, lengthDashes + 1), alignment) - -gridDashedLines :: PandocMonad m => Char -> ParserT [Char] st m [((Int, Int), Alignment)] -gridDashedLines ch = try $ char '+' >> many1 (gridPart ch) <* blankline - -removeFinalBar :: String -> String -removeFinalBar = - reverse . dropWhile (`elem` " \t") . dropWhile (=='|') . reverse - --- | Separator between rows of grid table. -gridTableSep :: PandocMonad m => Char -> MarkdownParser m Char -gridTableSep ch = try $ gridDashedLines ch >> return '\n' - --- | Parse header for a grid table. -gridTableHeader :: PandocMonad m => Bool -- ^ Headerless table - -> MarkdownParser m (F [Blocks], [Alignment], [Int]) -gridTableHeader headless = try $ do - optional blanklines - dashes <- gridDashedLines '-' - rawContent <- if headless - then return [] - else many1 (try (char '|' >> anyLine)) - underDashes <- if headless - then return dashes - else gridDashedLines '=' - guard $ length dashes == length underDashes - let lines' = map (snd . fst) underDashes - let indices = scanl (+) 0 lines' - let aligns = map snd underDashes - let rawHeads = if headless - then replicate (length underDashes) "" - else map (unlines . map trim) $ transpose - $ map (gridTableSplitLine indices) rawContent - heads <- fmap sequence $ mapM (parseFromString parseBlocks . trim) rawHeads - return (heads, aligns, indices) - -gridTableRawLine :: PandocMonad m => [Int] -> MarkdownParser m [String] -gridTableRawLine indices = do - char '|' - line <- anyLine - return (gridTableSplitLine indices line) - --- | Parse row of grid table. -gridTableRow :: PandocMonad m => [Int] - -> MarkdownParser m (F [Blocks]) -gridTableRow indices = do - colLines <- many1 (gridTableRawLine indices) - let cols = map ((++ "\n") . unlines . removeOneLeadingSpace) $ - transpose colLines - fmap compactify <$> fmap sequence (mapM (parseFromString parseBlocks) cols) - -removeOneLeadingSpace :: [String] -> [String] -removeOneLeadingSpace xs = - if all startsWithSpace xs - then map (drop 1) xs - else xs - where startsWithSpace "" = True - startsWithSpace (y:_) = y == ' ' - --- | Parse footer for a grid table. -gridTableFooter :: PandocMonad m => MarkdownParser m [Char] -gridTableFooter = blanklines +gridTable headless = gridTableWith' parseBlocks headless pipeBreak :: PandocMonad m => MarkdownParser m ([Alignment], [Int]) pipeBreak = try $ do diff --git a/test/command/3516.md b/test/command/3516.md index 982043874..8c7e478d3 100644 --- a/test/command/3516.md +++ b/test/command/3516.md @@ -27,8 +27,8 @@ on Windows builds. [Table [] [AlignDefault,AlignDefault] [5.555555555555555e-2,5.555555555555555e-2] [[] ,[]] - [[[Para [Str "1"]] - ,[Para [Str "2"]]] + [[[Plain [Str "1"]] + ,[Plain [Str "2"]]] ,[[] ,[]]]] ``` diff --git a/test/markdown-reader-more.native b/test/markdown-reader-more.native index baafb5334..1007dbac7 100644 --- a/test/markdown-reader-more.native +++ b/test/markdown-reader-more.native @@ -99,74 +99,74 @@ Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "Author",S [[Plain [Str "col",Space,Str "1"]] ,[Plain [Str "col",Space,Str "2"]] ,[Plain [Str "col",Space,Str "3"]]] - [[[Para [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]] - ,[Para [Str "b",SoftBreak,Str "b",Space,Str "2"]] - ,[Para [Str "c",SoftBreak,Str "c",Space,Str "2"]]] - ,[[Para [Str "r2",Space,Str "d"]] - ,[Para [Str "e"]] - ,[Para [Str "f"]]]] + [[[Plain [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]] + ,[Plain [Str "b",SoftBreak,Str "b",Space,Str "2"]] + ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2"]]] + ,[[Plain [Str "r2",Space,Str "d"]] + ,[Plain [Str "e"]] + ,[Plain [Str "f"]]]] ,Para [Str "Headless"] ,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.2638888888888889,0.16666666666666666,0.18055555555555555] [[] ,[] ,[]] - [[[Para [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]] - ,[Para [Str "b",SoftBreak,Str "b",Space,Str "2"]] - ,[Para [Str "c",SoftBreak,Str "c",Space,Str "2"]]] - ,[[Para [Str "r2",Space,Str "d"]] - ,[Para [Str "e"]] - ,[Para [Str "f"]]]] + [[[Plain [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]] + ,[Plain [Str "b",SoftBreak,Str "b",Space,Str "2"]] + ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2"]]] + ,[[Plain [Str "r2",Space,Str "d"]] + ,[Plain [Str "e"]] + ,[Plain [Str "f"]]]] ,Para [Str "With",Space,Str "alignments"] ,Table [] [AlignRight,AlignLeft,AlignCenter] [0.2638888888888889,0.16666666666666666,0.18055555555555555] [[Plain [Str "col",Space,Str "1"]] ,[Plain [Str "col",Space,Str "2"]] ,[Plain [Str "col",Space,Str "3"]]] - [[[Para [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]] - ,[Para [Str "b",SoftBreak,Str "b",Space,Str "2"]] - ,[Para [Str "c",SoftBreak,Str "c",Space,Str "2"]]] - ,[[Para [Str "r2",Space,Str "d"]] - ,[Para [Str "e"]] - ,[Para [Str "f"]]]] + [[[Plain [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]] + ,[Plain [Str "b",SoftBreak,Str "b",Space,Str "2"]] + ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2"]]] + ,[[Plain [Str "r2",Space,Str "d"]] + ,[Plain [Str "e"]] + ,[Plain [Str "f"]]]] ,Para [Str "Headless",Space,Str "with",Space,Str "alignments"] ,Table [] [AlignRight,AlignLeft,AlignCenter] [0.2638888888888889,0.16666666666666666,0.18055555555555555] [[] ,[] ,[]] - [[[Para [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]] - ,[Para [Str "b",SoftBreak,Str "b",Space,Str "2"]] - ,[Para [Str "c",SoftBreak,Str "c",Space,Str "2"]]] - ,[[Para [Str "r2",Space,Str "d"]] - ,[Para [Str "e"]] - ,[Para [Str "f"]]]] + [[[Plain [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]] + ,[Plain [Str "b",SoftBreak,Str "b",Space,Str "2"]] + ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2"]]] + ,[[Plain [Str "r2",Space,Str "d"]] + ,[Plain [Str "e"]] + ,[Plain [Str "f"]]]] ,Para [Str "Spaces",Space,Str "at",Space,Str "ends",Space,Str "of",Space,Str "lines"] ,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.2638888888888889,0.16666666666666666,0.18055555555555555] [[] ,[] ,[]] - [[[Para [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]] - ,[Para [Str "b",SoftBreak,Str "b",Space,Str "2"]] - ,[Para [Str "c",SoftBreak,Str "c",Space,Str "2"]]] - ,[[Para [Str "r2",Space,Str "d"]] - ,[Para [Str "e"]] - ,[Para [Str "f"]]]] + [[[Plain [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]] + ,[Plain [Str "b",SoftBreak,Str "b",Space,Str "2"]] + ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2"]]] + ,[[Plain [Str "r2",Space,Str "d"]] + ,[Plain [Str "e"]] + ,[Plain [Str "f"]]]] ,Para [Str "Multiple",Space,Str "blocks",Space,Str "in",Space,Str "a",Space,Str "cell"] ,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.2638888888888889,0.16666666666666666,0.18055555555555555] [[] ,[] ,[]] [[[Header 1 ("col-1",[],[]) [Str "col",Space,Str "1"] - ,Para [Str "col",Space,Str "1"]] + ,Plain [Str "col",Space,Str "1"]] ,[Header 1 ("col-2",[],[]) [Str "col",Space,Str "2"] - ,Para [Str "col",Space,Str "2"]] + ,Plain [Str "col",Space,Str "2"]] ,[Header 1 ("col-3",[],[]) [Str "col",Space,Str "3"] - ,Para [Str "col",Space,Str "3"]]] + ,Plain [Str "col",Space,Str "3"]]] ,[[Para [Str "r1",Space,Str "a"] ,Para [Str "r1",Space,Str "bis"]] ,[BulletList [[Plain [Str "b"]] ,[Plain [Str "b",Space,Str "2"]] ,[Plain [Str "b",Space,Str "2"]]]] - ,[Para [Str "c",SoftBreak,Str "c",Space,Str "2",SoftBreak,Str "c",Space,Str "2"]]]] + ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2",SoftBreak,Str "c",Space,Str "2"]]]] ,Para [Str "Empty",Space,Str "cells"] ,Table [] [AlignDefault,AlignDefault] [5.555555555555555e-2,5.555555555555555e-2] [[] diff --git a/test/tables-rstsubset.native b/test/tables-rstsubset.native index d9bb9f2fb..8b7ccdf76 100644 --- a/test/tables-rstsubset.native +++ b/test/tables-rstsubset.native @@ -54,9 +54,9 @@ ,[Plain [Str "1"]]]] ,Para [Str "Multiline",Space,Str "table",Space,Str "with",Space,Str "caption:"] ,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] - [[Plain [Str "Centered",Space,Str "Header"]] - ,[Plain [Str "Left",Space,Str "Aligned"]] - ,[Plain [Str "Right",Space,Str "Aligned"]] + [[Plain [Str "Centered",SoftBreak,Str "Header"]] + ,[Plain [Str "Left",SoftBreak,Str "Aligned"]] + ,[Plain [Str "Right",SoftBreak,Str "Aligned"]] ,[Plain [Str "Default",Space,Str "aligned"]]] [[[Plain [Str "First"]] ,[Plain [Str "row"]] @@ -68,9 +68,9 @@ ,[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."]]]] ,Para [Str "Multiline",Space,Str "table",Space,Str "without",Space,Str "caption:"] ,Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.1375,0.125,0.15,0.325] - [[Plain [Str "Centered",Space,Str "Header"]] - ,[Plain [Str "Left",Space,Str "Aligned"]] - ,[Plain [Str "Right",Space,Str "Aligned"]] + [[Plain [Str "Centered",SoftBreak,Str "Header"]] + ,[Plain [Str "Left",SoftBreak,Str "Aligned"]] + ,[Plain [Str "Right",SoftBreak,Str "Aligned"]] ,[Plain [Str "Default",Space,Str "aligned"]]] [[[Plain [Str "First"]] ,[Plain [Str "row"]] |