@@ -62,7 +62,7 @@ import Text.Pandoc.Shared (trim)
6262import Text.Pandoc.Readers.LaTeX ( rawLaTeXInline, rawLaTeXBlock )
6363import Text.HTML.TagSoup (parseTags, innerText, fromAttrib, Tag(..))
6464import Text.HTML.TagSoup.Match
65−import Data.List ( intercalate )
65+import Data.List ( intercalate, transpose )
6666import Data.Char ( digitToInt, isUpper )
6767import Control.Monad ( guard, liftM, when )
6868import Text.Pandoc.Compat.Monoid ((<>))
@@ -134,7 +134,7 @@ blockParsers = [ codeBlock
134134 , anyList
135135 , rawHtmlBlock
136136 , rawLaTeXBlock'
137− , maybeExplicitBlock "table" table
137+ , table
138138 , maybeExplicitBlock "p" para
139139 , mempty <$ blanklines
140140 ]
@@ -328,38 +328,78 @@ para = B.para . trimInlines . mconcat <$> many1 inline
328328
329329-- Tables
330330
331+toAlignment :: Char -> Alignment
332+toAlignment '<' = AlignLeft
333+toAlignment '>' = AlignRight
334+toAlignment '=' = AlignCenter
335+toAlignment _ = AlignDefault
336+
337+cellAttributes :: Parser [Char] ParserState (Bool, Alignment)
338+cellAttributes = try $ do
339+ isHeader <- option False (True <$ char '_')
340+ -- we just ignore colspan and rowspan markers:
341+ optional $ try $ oneOf "/\\" >> many1 digit
342+ -- we pay attention to alignments:
343+ alignment <- option AlignDefault $ toAlignment <$> oneOf "<>="
344+ -- ignore other attributes for now:
345+ _ <- attributes
346+ char '.'
347+ return (isHeader, alignment)
348+
331349-- | A table cell spans until a pipe |
332−tableCell :: Bool -> Parser [Char] ParserState Blocks
333−tableCell headerCell = try $ do
350+tableCell :: Parser [Char] ParserState ((Bool, Alignment), Blocks)
351+tableCell = try $ do
334352 char '|'
335− when headerCell $ () <$ string "_."
353+ (isHeader, alignment) <- option (False, AlignDefault) $ cellAttributes
336354 notFollowedBy blankline
337355 raw <- trim <$>
338356 many (noneOf "|\n" <|> try (char '\n' <* notFollowedBy blankline))
339357 content <- mconcat <$> parseFromString (many inline) raw
340− return $ B.plain content
358+ return ((isHeader, alignment), B.plain content)
341359
342360-- | A table row is made of many table cells
343−tableRow :: Parser [Char] ParserState [Blocks]
344−tableRow = many1 (tableCell False) <* char '|' <* newline
345−
346−tableHeader :: Parser [Char] ParserState [Blocks]
347−tableHeader = many1 (tableCell True) <* char '|' <* newline
348−
349−-- | A table with an optional header. Current implementation can
350−-- handle tables with and without header, but will parse cells
351−-- alignment attributes as content.
361+tableRow :: Parser [Char] ParserState [((Bool, Alignment), Blocks)]
362+tableRow = try $ do
363+ -- skip optional row attributes
364+ optional $ try $ do
365+ _ <- attributes
366+ char '.'
367+ many1 spaceChar
368+ many1 tableCell <* char '|' <* blankline
369+
370+-- | A table with an optional header.
352371table :: Parser [Char] ParserState Blocks
353372table = try $ do
354− headers <- option mempty $ tableHeader
355− rows <- many1 tableRow
373+ -- ignore table attributes
374+ caption <- option mempty $ try $ do
375+ string "table"
376+ _ <- attributes
377+ char '.'
378+ rawcapt <- trim <$> anyLine
379+ parseFromString (mconcat <$> many inline) rawcapt
380+ rawrows <- many1 $ (skipMany ignorableRow) >> tableRow
381+ skipMany ignorableRow
356382 blanklines
383+ let (headers, rows) = case rawrows of
384+ (toprow:rest) | any (fst . fst) toprow ->
385+ (toprow, rest)
386+ _ -> (mempty, rawrows)
357387 let nbOfCols = max (length headers) (length $ head rows)
358− return $ B.table mempty
359− (zip (replicate nbOfCols AlignDefault) (replicate nbOfCols 0.0))
360− headers
361− rows
362−
388+ let aligns = map minimum $ transpose $ map (map (snd . fst)) (headers:rows)
389+ return $ B.table caption
390+ (zip aligns (replicate nbOfCols 0.0))
391+ (map snd headers)
392+ (map (map snd) rows)
393+
394+-- | Ignore markers for cols, thead, tfoot.
395+ignorableRow :: Parser [Char] ParserState ()
396+ignorableRow = try $ do
397+ char '|'
398+ oneOf ":^-~"
399+ _ <- attributes
400+ char '.'
401+ _ <- anyLine
402+ return ()
363403
364404-- | Blocks like 'p' and 'table' do not need explicit block tag.
365405-- However, they can be used to set HTML/CSS attributes when needed.