git.iko.soy/typeable/pandoc
on master help sign in
[Latex Reader] Fixing issues with \multirow and \multicolumn table cells (#6608)

* Added test to replicate (#6596) * Table cell reader not consuming spaces correctly (#6596) * Prevented wrong nesting of \multicolumn and \multirow table cells (#6603) * Parse empty table cells (#6603) * Support full prototype for multirow macro (#6603) Closes #6603

commit482a2e50798481f484267bdcfb7b305ea7bd7971 authorLaurent P. René de Cotret <LaurentRDC@users.noreply.github.com> dateSat 15 Aug 2020, 14:40 (6 years ago) parent3766e03
2 files changed+61−32
src/Text/Pandoc/Readers/LaTeX.hs+48−28 test/Tests/Readers/LaTeX.hs+13−4
src/Text/Pandoc/Readers/LaTeX.hs+48−28
@@ -2383,16 +2383,26 @@ parseTableRow envname prefsufs = do
23832383 cells <- mapM (\ts -> setInput ts >> parseTableCell) rawcells
23842384 setInput oldInput
23852385 spaces
2386− return $ Row nullAttr cells
2386+ -- Because of table normalization performed by Text.Pandoc.Builder.table,
2387+ -- we need to remove empty cells
2388+ return $ Row nullAttr $ filter (\c -> c /= emptyCell) cells
23872389
23882390parseTableCell :: PandocMonad m => LP m Cell
23892391parseTableCell = do
23902392 spaces
23912393 updateState $ \st -> st{ sInTableCell = True }
2392− cell' <- parseMultiCell <|> parseSimpleCell
2394+ cell' <- ( multicolumnCell
2395+ <|> multirowCell
2396+ <|> parseSimpleCell
2397+ <|> parseEmptyCell
2398+ )
23932399 updateState $ \st -> st{ sInTableCell = False }
23942400 spaces
23952401 return cell'
2402+ where
2403+ -- The parsing of empty cells is important in LaTeX, especially when dealing
2404+ -- with multirow/multicolumn. See #6603.
2405+ parseEmptyCell = optional spaces >> return emptyCell <* optional spaces
23962406
23972407cellAlignment :: PandocMonad m => LP m Alignment
23982408cellAlignment = skipMany (symbol '|') *> alignment <* skipMany (symbol '|')
@@ -2411,32 +2421,42 @@ plainify bs = case toList bs of
24112421 [Para ils] -> plain (fromList ils)
24122422 _ -> bs
24132423
2414−parseMultiCell :: PandocMonad m => LP m Cell
2415−parseMultiCell = (controlSeq "multirow" >> parseMultirowCell)
2416− <|> (controlSeq "multicolumn" >> parseMulticolCell)
2417− where
2418− parseMultirowCell = parseMultiXCell RowSpan (const $ ColSpan 1)
2419− parseMulticolCell = parseMultiXCell (const $ RowSpan 1) ColSpan
2420−
2421− parseMultiXCell rowspanf colspanf = do
2422− span' <- fmap (fromMaybe 1 . safeRead . untokenize) braced
2423− alignment <- symbol '{' *> cellAlignment <* symbol '}'
2424−
2425− -- Two possible contents: either a nested \multirow/\multicol, or content.
2426− -- E.g. \multirow{1}{c}{\multicol{1}{c}{content}}
2427− let singleCell = do
2428− content <- plainify <$> blocks
2429− return $ cell alignment (rowspanf span') (colspanf span') content
2430−
2431− let nestedCell = do
2432− (Cell _ _ (RowSpan rs) (ColSpan cs) bs) <- parseMultiCell
2433− return $ cell
2434− alignment
2435− (RowSpan $ max span' rs)
2436− (ColSpan $ max span' cs)
2437− (fromList bs)
2438−
2439− symbol '{' *> (nestedCell <|> singleCell) <* symbol '}'
2424+multirowCell :: PandocMonad m => LP m Cell
2425+multirowCell = controlSeq "multirow" >> do
2426+ -- Full prototype for \multirow macro is:
2427+ -- \multirow[vpos]{nrows}[bigstruts]{width}[vmove]{text}
2428+ -- However, everything except `nrows` and `text` make
2429+ -- sense in the context of the Pandoc AST
2430+ _ <- optional $ symbol '[' *> cellAlignment <* symbol ']' -- vertical position
2431+ nrows <- fmap (fromMaybe 1 . safeRead . untokenize) braced
2432+ _ <- optional $ symbol '[' *> manyTill anyTok (symbol ']') -- bigstrut-related
2433+ _ <- symbol '{' *> manyTill anyTok (symbol '}') -- Cell width
2434+ _ <- optional $ symbol '[' *> manyTill anyTok (symbol ']') -- Length used for fine-tuning
2435+ content <- symbol '{' *> (plainify <$> blocks) <* symbol '}'
2436+ return $ cell AlignDefault (RowSpan nrows) (ColSpan 1) content
2437+
2438+multicolumnCell :: PandocMonad m => LP m Cell
2439+multicolumnCell = controlSeq "multicolumn" >> do
2440+ span' <- fmap (fromMaybe 1 . safeRead . untokenize) braced
2441+ alignment <- symbol '{' *> cellAlignment <* symbol '}'
2442+
2443+ let singleCell = do
2444+ content <- plainify <$> blocks
2445+ return $ cell alignment (RowSpan 1) (ColSpan span') content
2446+
2447+ -- Two possible contents: either a \multirow cell, or content.
2448+ -- E.g. \multicol{1}{c}{\multirow{2}{1em}{content}}
2449+ -- Note that a \multirow cell can be nested in a \multicolumn,
2450+ -- but not the other way around. See #6603
2451+ let nestedCell = do
2452+ (Cell _ _ (RowSpan rs) _ bs) <- multirowCell
2453+ return $ cell
2454+ alignment
2455+ (RowSpan $ rs)
2456+ (ColSpan $ span')
2457+ (fromList bs)
2458+
2459+ symbol '{' *> (nestedCell <|> singleCell) <* symbol '}'
24402460
24412461-- Parse a simple cell, i.e. not multirow/multicol
24422462parseSimpleCell :: PandocMonad m => LP m Cell
test/Tests/Readers/LaTeX.hs+13−4
@@ -157,17 +157,26 @@ tests = [ testGroup "tokenization"
157157 ]
158158 , "Table with multirow item" =:
159159 T.unlines ["\\begin{tabular}{c}"
160− ,"\\multirow{2}{c}{One}\\\\Two\\\\"
160+ ,"\\multirow{2}{5em}{One}\\\\Two\\\\"
161161 ,"\\end{tabular}"
162162 ] =?>
163163 table' [AlignCenter]
164− [ Row nullAttr [ cell AlignCenter (RowSpan 2) (ColSpan 1) (plain "One") ]
164+ [ Row nullAttr [ cell AlignDefault (RowSpan 2) (ColSpan 1) (plain "One") ]
165+ , Row nullAttr [ simpleCell (plain "Two") ]
166+ ]
167+ , "Table with multirow item using full prototype" =:
168+ T.unlines ["\\begin{tabular}{c}"
169+ ,"\\multirow[c]{2}[3]{5em}[1in]{One}\\\\Two\\\\"
170+ ,"\\end{tabular}"
171+ ] =?>
172+ table' [AlignCenter]
173+ [ Row nullAttr [ cell AlignDefault (RowSpan 2) (ColSpan 1) (plain "One") ]
165174 , Row nullAttr [ simpleCell (plain "Two") ]
166175 ]
167176 , "Table with nested multirow/multicolumn item" =:
168177 T.unlines [ "\\begin{tabular}{c c c}"
169− , "\\multirow{2}{c}{\\multicolumn{2}{c}{One}}&Two\\\\"
170− , "Three\\\\"
178+ , "\\multicolumn{2}{c}{\\multirow{2}{5em}{One}}&Two\\\\"
179+ , "& & Three\\\\"
171180 , "Four&Five&Six\\\\"
172181 , "\\end{tabular}"
173182 ] =?>