From bd7c9eb32be7c5499f4a50cb4b5f138f9eb919e8 Mon Sep 17 00:00:00 2001 From: John MacFarlane <jgm@berkeley.edu> Date: Thu, 29 Oct 2020 12:10:05 -0700 Subject: [PATCH] LaTeX writer: Improved calculation of table column widths. We now have LaTeX do the calculation, using `\tabcolsep`. So we should now have accurate relative column widths no matter what the text width. The default template has been modified to load the calc package if tables are used. --- data/templates/default.latex | 1 + src/Text/Pandoc/Writers/LaTeX.hs | 22 +++---- test/command/5367.md | 6 +- test/tables.latex | 99 ++++++++++++++++++++------------ 4 files changed, 79 insertions(+), 49 deletions(-) diff --git a/data/templates/default.latex b/data/templates/default.latex index 80f6a7feb..4cac0a7cc 100644 --- a/data/templates/default.latex +++ b/data/templates/default.latex @@ -257,6 +257,7 @@ $highlighting-macros$ $endif$ $if(tables)$ \usepackage{longtable,booktabs} +\usepackage{calc} % for calculating minipage widths $if(beamer)$ \usepackage{caption} % Make caption package work with longtable diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs index 28b4efca4..f7775318a 100644 --- a/src/Text/Pandoc/Writers/LaTeX.hs +++ b/src/Text/Pandoc/Writers/LaTeX.hs @@ -851,9 +851,6 @@ tableRowToLaTeX :: PandocMonad m -> [[Block]] -> LW m (Doc Text) tableRowToLaTeX header aligns widths cols = do - -- scale factor compensates for extra space between columns - -- so the whole table isn't larger than columnwidth - let scaleFactor = 0.97 ** fromIntegral (length aligns) let isSimple [Plain _] = True isSimple [Para _] = True isSimple [] = True @@ -861,9 +858,10 @@ tableRowToLaTeX header aligns widths cols = do -- simple tables have to have simple cells: let widths' = if all (== 0) widths && not (all isSimple cols) then replicate (length aligns) - (scaleFactor / fromIntegral (length aligns)) - else map (scaleFactor *) widths - cells <- mapM (tableCellToLaTeX header) $ zip3 widths' aligns cols + (1 / fromIntegral (length aligns)) + else widths + let numcols = length widths' + cells <- mapM (tableCellToLaTeX header numcols) $ zip3 widths' aligns cols return $ hsep (intersperse "&" cells) <> "\\tabularnewline" -- For simple latex tables (without minipages or parboxes), @@ -890,11 +888,12 @@ displayMathToInline :: Inline -> Inline displayMathToInline (Math DisplayMath x) = Math InlineMath x displayMathToInline x = x -tableCellToLaTeX :: PandocMonad m => Bool -> (Double, Alignment, [Block]) +tableCellToLaTeX :: PandocMonad m + => Bool -> Int -> (Double, Alignment, [Block]) -> LW m (Doc Text) -tableCellToLaTeX _ (0, _, blocks) = +tableCellToLaTeX _ _ (0, _, blocks) = blockListToLaTeX $ walk fixLineBreaks $ walk displayMathToInline blocks -tableCellToLaTeX header (width, align, blocks) = do +tableCellToLaTeX header numcols (width, align, blocks) = do beamer <- gets stBeamer externalNotes <- gets stExternalNotes inMinipage <- gets stInMinipage @@ -912,9 +911,12 @@ tableCellToLaTeX header (width, align, blocks) = do AlignCenter -> "\\centering" AlignDefault -> "\\raggedright" return $ "\\begin{minipage}" <> valign <> - braces (text (printf "%.2f\\columnwidth" width)) <> + braces (text (printf + "(\\columnwidth - %d\\tabcolsep) * \\real{%.2f}" + (numcols - 1) width)) <> halign <> cr <> cellContents <> "\\strut" <> cr <> "\\end{minipage}" +-- (\columnwidth - 8\tabcolsep) * \real{0.15} notesToLaTeX :: [Doc Text] -> Doc Text notesToLaTeX [] = empty diff --git a/test/command/5367.md b/test/command/5367.md index ae8744dd7..18ac764ab 100644 --- a/test/command/5367.md +++ b/test/command/5367.md @@ -23,18 +23,18 @@ hello\footnote{doc footnote} \begin{longtable}[]{@{}c@{}} \caption[Sample table.]{Sample table.\footnote{caption footnote}}\tabularnewline \toprule -\begin{minipage}[b]{0.16\columnwidth}\centering +\begin{minipage}[b]{(\columnwidth - 0\tabcolsep) * \real{0.17}}\centering Fruit\footnote{header footnote}\strut \end{minipage}\tabularnewline \midrule \endfirsthead \toprule -\begin{minipage}[b]{0.16\columnwidth}\centering +\begin{minipage}[b]{(\columnwidth - 0\tabcolsep) * \real{0.17}}\centering Fruit{}\strut \end{minipage}\tabularnewline \midrule \endhead -\begin{minipage}[t]{0.16\columnwidth}\centering +\begin{minipage}[t]{(\columnwidth - 0\tabcolsep) * \real{0.17}}\centering Bans\footnote{table cell footnote}\strut \end{minipage}\tabularnewline \bottomrule diff --git a/test/tables.latex b/test/tables.latex index 4616448a9..e0be7efdc 100644 --- a/test/tables.latex +++ b/test/tables.latex @@ -52,45 +52,57 @@ Multiline table with caption: \begin{longtable}[]{@{}clrl@{}} \caption{Here's the caption. It may span multiple lines.}\tabularnewline \toprule -\begin{minipage}[b]{0.13\columnwidth}\centering +\begin{minipage}[b]{(\columnwidth - 3\tabcolsep) * \real{0.15}}\centering Centered Header\strut -\end{minipage} & \begin{minipage}[b]{0.12\columnwidth}\raggedright +\end{minipage} & +\begin{minipage}[b]{(\columnwidth - 3\tabcolsep) * \real{0.14}}\raggedright Left Aligned\strut -\end{minipage} & \begin{minipage}[b]{0.14\columnwidth}\raggedleft +\end{minipage} & +\begin{minipage}[b]{(\columnwidth - 3\tabcolsep) * \real{0.16}}\raggedleft Right Aligned\strut -\end{minipage} & \begin{minipage}[b]{0.31\columnwidth}\raggedright +\end{minipage} & +\begin{minipage}[b]{(\columnwidth - 3\tabcolsep) * \real{0.35}}\raggedright Default aligned\strut \end{minipage}\tabularnewline \midrule \endfirsthead \toprule -\begin{minipage}[b]{0.13\columnwidth}\centering +\begin{minipage}[b]{(\columnwidth - 3\tabcolsep) * \real{0.15}}\centering Centered Header\strut -\end{minipage} & \begin{minipage}[b]{0.12\columnwidth}\raggedright +\end{minipage} & +\begin{minipage}[b]{(\columnwidth - 3\tabcolsep) * \real{0.14}}\raggedright Left Aligned\strut -\end{minipage} & \begin{minipage}[b]{0.14\columnwidth}\raggedleft +\end{minipage} & +\begin{minipage}[b]{(\columnwidth - 3\tabcolsep) * \real{0.16}}\raggedleft Right Aligned\strut -\end{minipage} & \begin{minipage}[b]{0.31\columnwidth}\raggedright +\end{minipage} & +\begin{minipage}[b]{(\columnwidth - 3\tabcolsep) * \real{0.35}}\raggedright Default aligned\strut \end{minipage}\tabularnewline \midrule \endhead -\begin{minipage}[t]{0.13\columnwidth}\centering +\begin{minipage}[t]{(\columnwidth - 3\tabcolsep) * \real{0.15}}\centering First\strut -\end{minipage} & \begin{minipage}[t]{0.12\columnwidth}\raggedright +\end{minipage} & +\begin{minipage}[t]{(\columnwidth - 3\tabcolsep) * \real{0.14}}\raggedright row\strut -\end{minipage} & \begin{minipage}[t]{0.14\columnwidth}\raggedleft +\end{minipage} & +\begin{minipage}[t]{(\columnwidth - 3\tabcolsep) * \real{0.16}}\raggedleft 12.0\strut -\end{minipage} & \begin{minipage}[t]{0.31\columnwidth}\raggedright +\end{minipage} & +\begin{minipage}[t]{(\columnwidth - 3\tabcolsep) * \real{0.35}}\raggedright Example of a row that spans multiple lines.\strut \end{minipage}\tabularnewline -\begin{minipage}[t]{0.13\columnwidth}\centering +\begin{minipage}[t]{(\columnwidth - 3\tabcolsep) * \real{0.15}}\centering Second\strut -\end{minipage} & \begin{minipage}[t]{0.12\columnwidth}\raggedright +\end{minipage} & +\begin{minipage}[t]{(\columnwidth - 3\tabcolsep) * \real{0.14}}\raggedright row\strut -\end{minipage} & \begin{minipage}[t]{0.14\columnwidth}\raggedleft +\end{minipage} & +\begin{minipage}[t]{(\columnwidth - 3\tabcolsep) * \real{0.16}}\raggedleft 5.0\strut -\end{minipage} & \begin{minipage}[t]{0.31\columnwidth}\raggedright +\end{minipage} & +\begin{minipage}[t]{(\columnwidth - 3\tabcolsep) * \real{0.35}}\raggedright Here's another one. Note the blank line between rows.\strut \end{minipage}\tabularnewline \bottomrule @@ -100,33 +112,42 @@ Multiline table without caption: \begin{longtable}[]{@{}clrl@{}} \toprule -\begin{minipage}[b]{0.13\columnwidth}\centering +\begin{minipage}[b]{(\columnwidth - 3\tabcolsep) * \real{0.15}}\centering Centered Header\strut -\end{minipage} & \begin{minipage}[b]{0.12\columnwidth}\raggedright +\end{minipage} & +\begin{minipage}[b]{(\columnwidth - 3\tabcolsep) * \real{0.14}}\raggedright Left Aligned\strut -\end{minipage} & \begin{minipage}[b]{0.14\columnwidth}\raggedleft +\end{minipage} & +\begin{minipage}[b]{(\columnwidth - 3\tabcolsep) * \real{0.16}}\raggedleft Right Aligned\strut -\end{minipage} & \begin{minipage}[b]{0.31\columnwidth}\raggedright +\end{minipage} & +\begin{minipage}[b]{(\columnwidth - 3\tabcolsep) * \real{0.35}}\raggedright Default aligned\strut \end{minipage}\tabularnewline \midrule \endhead -\begin{minipage}[t]{0.13\columnwidth}\centering +\begin{minipage}[t]{(\columnwidth - 3\tabcolsep) * \real{0.15}}\centering First\strut -\end{minipage} & \begin{minipage}[t]{0.12\columnwidth}\raggedright +\end{minipage} & +\begin{minipage}[t]{(\columnwidth - 3\tabcolsep) * \real{0.14}}\raggedright row\strut -\end{minipage} & \begin{minipage}[t]{0.14\columnwidth}\raggedleft +\end{minipage} & +\begin{minipage}[t]{(\columnwidth - 3\tabcolsep) * \real{0.16}}\raggedleft 12.0\strut -\end{minipage} & \begin{minipage}[t]{0.31\columnwidth}\raggedright +\end{minipage} & +\begin{minipage}[t]{(\columnwidth - 3\tabcolsep) * \real{0.35}}\raggedright Example of a row that spans multiple lines.\strut \end{minipage}\tabularnewline -\begin{minipage}[t]{0.13\columnwidth}\centering +\begin{minipage}[t]{(\columnwidth - 3\tabcolsep) * \real{0.15}}\centering Second\strut -\end{minipage} & \begin{minipage}[t]{0.12\columnwidth}\raggedright +\end{minipage} & +\begin{minipage}[t]{(\columnwidth - 3\tabcolsep) * \real{0.14}}\raggedright row\strut -\end{minipage} & \begin{minipage}[t]{0.14\columnwidth}\raggedleft +\end{minipage} & +\begin{minipage}[t]{(\columnwidth - 3\tabcolsep) * \real{0.16}}\raggedleft 5.0\strut -\end{minipage} & \begin{minipage}[t]{0.31\columnwidth}\raggedright +\end{minipage} & +\begin{minipage}[t]{(\columnwidth - 3\tabcolsep) * \real{0.35}}\raggedright Here's another one. Note the blank line between rows.\strut \end{minipage}\tabularnewline \bottomrule @@ -148,22 +169,28 @@ Multiline table without column headers: \begin{longtable}[]{@{}clrl@{}} \toprule \endhead -\begin{minipage}[t]{0.13\columnwidth}\centering +\begin{minipage}[t]{(\columnwidth - 3\tabcolsep) * \real{0.15}}\centering First\strut -\end{minipage} & \begin{minipage}[t]{0.12\columnwidth}\raggedright +\end{minipage} & +\begin{minipage}[t]{(\columnwidth - 3\tabcolsep) * \real{0.14}}\raggedright row\strut -\end{minipage} & \begin{minipage}[t]{0.14\columnwidth}\raggedleft +\end{minipage} & +\begin{minipage}[t]{(\columnwidth - 3\tabcolsep) * \real{0.16}}\raggedleft 12.0\strut -\end{minipage} & \begin{minipage}[t]{0.31\columnwidth}\raggedright +\end{minipage} & +\begin{minipage}[t]{(\columnwidth - 3\tabcolsep) * \real{0.35}}\raggedright Example of a row that spans multiple lines.\strut \end{minipage}\tabularnewline -\begin{minipage}[t]{0.13\columnwidth}\centering +\begin{minipage}[t]{(\columnwidth - 3\tabcolsep) * \real{0.15}}\centering Second\strut -\end{minipage} & \begin{minipage}[t]{0.12\columnwidth}\raggedright +\end{minipage} & +\begin{minipage}[t]{(\columnwidth - 3\tabcolsep) * \real{0.14}}\raggedright row\strut -\end{minipage} & \begin{minipage}[t]{0.14\columnwidth}\raggedleft +\end{minipage} & +\begin{minipage}[t]{(\columnwidth - 3\tabcolsep) * \real{0.16}}\raggedleft 5.0\strut -\end{minipage} & \begin{minipage}[t]{0.31\columnwidth}\raggedright +\end{minipage} & +\begin{minipage}[t]{(\columnwidth - 3\tabcolsep) * \real{0.35}}\raggedright Here's another one. Note the blank line between rows.\strut \end{minipage}\tabularnewline \bottomrule