diff options
-rw-r--r-- | src/Text/Pandoc/Writers/LaTeX.hs | 89 | ||||
-rw-r--r-- | templates/latex.template | 6 | ||||
-rw-r--r-- | tests/tables.latex | 255 |
3 files changed, 213 insertions, 137 deletions
diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs index f5003de0d..cf008bf6a 100644 --- a/src/Text/Pandoc/Writers/LaTeX.hs +++ b/src/Text/Pandoc/Writers/LaTeX.hs @@ -42,6 +42,9 @@ import System.FilePath (dropExtension) data WriterState = WriterState { stInNote :: Bool -- @True@ if we're in a note + , stInTable :: Bool -- @True@ if we're in a table + , stTableNotes :: [(Char, Doc)] -- List of markers, notes + -- in current table , stOLLevel :: Int -- level of ordered list nesting , stOptions :: WriterOptions -- writer options, so they don't have to be parameter , stVerbInNote :: Bool -- true if document has verbatim text in note @@ -59,7 +62,8 @@ data WriterState = writeLaTeX :: WriterOptions -> Pandoc -> String writeLaTeX options document = evalState (pandocToLaTeX options document) $ - WriterState { stInNote = False, stOLLevel = 1, stOptions = options, + WriterState { stInNote = False, stInTable = False, + stTableNotes = [], stOLLevel = 1, stOptions = options, stVerbInNote = False, stEnumerate = False, stTable = False, stStrikeout = False, stSubscript = False, stUrl = False, stGraphics = False, @@ -269,48 +273,61 @@ blockToLaTeX (Header level lst) = do 5 -> headerWith "\\subparagraph" stuffing _ -> txt $$ blankline blockToLaTeX (Table caption aligns widths heads rows) = do + modify $ \s -> s{ stInTable = True, stTableNotes = [] } headers <- if all null heads then return empty - else liftM ($$ "\\hline\\noalign{\\smallskip}") - $ (tableRowToLaTeX widths) heads + else liftM ($$ "\\ML") + $ (tableRowToLaTeX True aligns widths) heads captionText <- inlineListToLaTeX $ deVerb caption - rows' <- mapM (tableRowToLaTeX widths) rows - let colDescriptors = concat $ zipWith toColDescriptor widths aligns - let tableBody = text ("\\begin{tabular}{" ++ colDescriptors ++ "}") $$ - headers $$ vcat rows' $$ "\\end{tabular}" - let centered txt = "\\begin{center}" $$ txt $$ "\\end{center}" - modify $ \s -> s{ stTable = True } - return $ if isEmpty captionText - then centered tableBody $$ blankline - else "\\begin{table}[h]" $$ centered tableBody $$ - inCmd "caption" captionText $$ "\\end{table}" $$ blankline - -toColDescriptor :: Double -> Alignment -> String -toColDescriptor 0 align = + let capt = if isEmpty captionText + then empty + else text "caption = " <> captionText <> "," <> space + rows' <- mapM (tableRowToLaTeX False aligns widths) rows + let rows'' = intersperse ("\\\\\\noalign{\\medskip}") rows' + tableNotes <- liftM (reverse . stTableNotes) get + let toNote (marker, x) = "\\tnote" <> brackets (char marker) <> + braces (nest 2 x) + let notes = vcat $ map toNote tableNotes + let colDescriptors = text $ concat $ map toColDescriptor aligns + let tableBody = + ("\\ctable" <> brackets (capt <> text "pos = H, center, botcap")) + <> braces colDescriptors + $$ braces ("% notes" <> cr <> notes <> cr) + $$ braces (text "% rows" $$ "\\FL" $$ + vcat (headers : rows'') $$ "\\LL" <> cr) + modify $ \s -> s{ stTable = True, stInTable = False, stTableNotes = [] } + return $ tableBody $$ blankline + +toColDescriptor :: Alignment -> String +toColDescriptor align = case align of AlignLeft -> "l" AlignRight -> "r" AlignCenter -> "c" AlignDefault -> "l" -toColDescriptor width align = ">{\\PBS" ++ - (case align of - AlignLeft -> "\\raggedright" - AlignRight -> "\\raggedleft" - AlignCenter -> "\\centering" - AlignDefault -> "\\raggedright") ++ - "\\hspace{0pt}}p{" ++ printf "%.2f" width ++ "\\columnwidth}" blockListToLaTeX :: [Block] -> State WriterState Doc blockListToLaTeX lst = mapM blockToLaTeX lst >>= return . vcat -tableRowToLaTeX :: [Double] -> [[Block]] -> State WriterState Doc -tableRowToLaTeX widths cols = do +tableRowToLaTeX :: Bool + -> [Alignment] + -> [Double] + -> [[Block]] + -> State WriterState Doc +tableRowToLaTeX header aligns widths cols = do renderedCells <- mapM blockListToLaTeX cols - let toCell 0 c = c - toCell w c = "\\parbox[t]{" <> text (printf "%.2f" w) <> - "\\columnwidth}{" <> c <> cr <> "}" - let cells = zipWith toCell widths renderedCells - return $ (hcat $ intersperse (" & ") cells) <> "\\\\\\noalign{\\medskip}" + let valign = text $ if header then "[b]" else "[t]" + let halign x = case x of + AlignLeft -> "\\raggedright" + AlignRight -> "\\raggedleft" + AlignCenter -> "\\centering" + AlignDefault -> "\\raggedright" + let toCell 0 _ c = c + toCell w a c = "\\parbox" <> valign <> + braces (text (printf "%.2f\\columnwidth" w)) <> + braces (halign a <> cr <> c <> cr) + let cells = zipWith3 toCell widths aligns renderedCells + return $ hcat $ intersperse (" & ") cells listItemToLaTeX :: [Block] -> State WriterState Doc listItemToLaTeX lst = blockListToLaTeX lst >>= return . (text "\\item" $$) . @@ -413,9 +430,15 @@ inlineToLaTeX (Note contents) = do modify (\s -> s{stInNote = True}) contents' <- blockListToLaTeX contents modify (\s -> s {stInNote = False}) - -- note: a \n before } is needed when note ends with a Verbatim environment - return $ "\\footnote" <> braces (nest 2 contents') - + inTable <- liftM stInTable get + if inTable + then do + curnotes <- liftM stTableNotes get + let marker = cycle ['a'..'z'] !! length curnotes + modify $ \s -> s{ stTableNotes = (marker, contents') : curnotes } + return $ "\\tmark" <> brackets (char marker) <> space + else return $ "\\footnote" <> braces (nest 2 contents') + -- note: a \n before } needed when note ends with a Verbatim environment citationsToNatbib :: [Citation] -> State WriterState Doc citationsToNatbib (one:[]) diff --git a/templates/latex.template b/templates/latex.template index 40de32109..8142fb986 100644 --- a/templates/latex.template +++ b/templates/latex.template @@ -40,10 +40,8 @@ $if(fancy-enums)$ \usepackage{enumerate} $endif$ $if(tables)$ -\usepackage{array} -% This is needed because raggedright in table elements redefines \\: -\newcommand{\PreserveBackslash}[1]{\let\temp=\\#1\let\\=\temp} -\let\PBS=\PreserveBackslash +\usepackage{ctable} +\usepackage{float} % provides the H option for float placement $endif$ $if(strikeout)$ \usepackage[normalem]{ulem} diff --git a/tests/tables.latex b/tests/tables.latex index 89bcf9d9f..21ad73b0a 100644 --- a/tests/tables.latex +++ b/tests/tables.latex @@ -1,121 +1,176 @@ Simple table with caption: -\begin{table}[h] -\begin{center} -\begin{tabular}{rlcl} -Right & Left & Center & Default\\ -\hline -12 & 12 & 12 & 12\\ -123 & 123 & 123 & 123\\ -1 & 1 & 1 & 1\\ -\end{tabular} -\end{center} -\caption{Demonstration of simple table syntax.} -\end{table} +\ctable[caption = Demonstration of simple table syntax., +pos = H, center, botcap]{rlcl} +{% notes +} +{% rows +\FL +Right & Left & Center & Default +\ML +12 & 12 & 12 & 12 +\\\noalign{\medskip} +123 & 123 & 123 & 123 +\\\noalign{\medskip} +1 & 1 & 1 & 1 +\LL +} Simple table without caption: -\begin{center} -\begin{tabular}{rlcl} -Right & Left & Center & Default\\ -\hline -12 & 12 & 12 & 12\\ -123 & 123 & 123 & 123\\ -1 & 1 & 1 & 1\\ -\end{tabular} -\end{center} +\ctable[pos = H, center, botcap]{rlcl} +{% notes +} +{% rows +\FL +Right & Left & Center & Default +\ML +12 & 12 & 12 & 12 +\\\noalign{\medskip} +123 & 123 & 123 & 123 +\\\noalign{\medskip} +1 & 1 & 1 & 1 +\LL +} Simple table indented two spaces: -\begin{table}[h] -\begin{center} -\begin{tabular}{rlcl} -Right & Left & Center & Default\\ -\hline -12 & 12 & 12 & 12\\ -123 & 123 & 123 & 123\\ -1 & 1 & 1 & 1\\ -\end{tabular} -\end{center} -\caption{Demonstration of simple table syntax.} -\end{table} +\ctable[caption = Demonstration of simple table syntax., +pos = H, center, botcap]{rlcl} +{% notes +} +{% rows +\FL +Right & Left & Center & Default +\ML +12 & 12 & 12 & 12 +\\\noalign{\medskip} +123 & 123 & 123 & 123 +\\\noalign{\medskip} +1 & 1 & 1 & 1 +\LL +} Multiline table with caption: -\begin{table}[h] -\begin{center} -\begin{tabular}{>{\PBS\centering\hspace{0pt}}p{0.15\columnwidth}>{\PBS\raggedright\hspace{0pt}}p{0.14\columnwidth}>{\PBS\raggedleft\hspace{0pt}}p{0.16\columnwidth}>{\PBS\raggedright\hspace{0pt}}p{0.34\columnwidth}} -\parbox{0.15\columnwidth}{Centered Header -} & \parbox{0.14\columnwidth}{Left Aligned -} & \parbox{0.16\columnwidth}{Right Aligned -} & \parbox{0.34\columnwidth}{Default aligned -}\\ -\hline -\parbox{0.15\columnwidth}{First -} & \parbox{0.14\columnwidth}{row -} & \parbox{0.16\columnwidth}{12.0 -} & \parbox{0.34\columnwidth}{Example of a row that spans multiple lines. -}\\ -\parbox{0.15\columnwidth}{Second -} & \parbox{0.14\columnwidth}{row -} & \parbox{0.16\columnwidth}{5.0 -} & \parbox{0.34\columnwidth}{Here's another one. Note the blank line between -rows. -}\\ -\end{tabular} -\end{center} -\caption{Here's the caption. It may span multiple lines.} -\end{table} +\ctable[caption = Here's the caption. It may span multiple lines., +pos = H, center, botcap]{clrl} +{% notes +} +{% rows +\FL +\parbox[b]{0.15\columnwidth}{\centering +Centered Header +} & \parbox[b]{0.14\columnwidth}{\raggedright +Left Aligned +} & \parbox[b]{0.16\columnwidth}{\raggedleft +Right Aligned +} & \parbox[b]{0.34\columnwidth}{\raggedright +Default aligned +} +\ML +\parbox[t]{0.15\columnwidth}{\centering +First +} & \parbox[t]{0.14\columnwidth}{\raggedright +row +} & \parbox[t]{0.16\columnwidth}{\raggedleft +12.0 +} & \parbox[t]{0.34\columnwidth}{\raggedright +Example of a row that spans multiple lines. +} +\\\noalign{\medskip} +\parbox[t]{0.15\columnwidth}{\centering +Second +} & \parbox[t]{0.14\columnwidth}{\raggedright +row +} & \parbox[t]{0.16\columnwidth}{\raggedleft +5.0 +} & \parbox[t]{0.34\columnwidth}{\raggedright +Here's another one. Note the blank line between rows. +} +\LL +} Multiline table without caption: -\begin{center} -\begin{tabular}{>{\PBS\centering\hspace{0pt}}p{0.15\columnwidth}>{\PBS\raggedright\hspace{0pt}}p{0.14\columnwidth}>{\PBS\raggedleft\hspace{0pt}}p{0.16\columnwidth}>{\PBS\raggedright\hspace{0pt}}p{0.34\columnwidth}} -\parbox{0.15\columnwidth}{Centered Header -} & \parbox{0.14\columnwidth}{Left Aligned -} & \parbox{0.16\columnwidth}{Right Aligned -} & \parbox{0.34\columnwidth}{Default aligned -}\\ -\hline -\parbox{0.15\columnwidth}{First -} & \parbox{0.14\columnwidth}{row -} & \parbox{0.16\columnwidth}{12.0 -} & \parbox{0.34\columnwidth}{Example of a row that spans multiple lines. -}\\ -\parbox{0.15\columnwidth}{Second -} & \parbox{0.14\columnwidth}{row -} & \parbox{0.16\columnwidth}{5.0 -} & \parbox{0.34\columnwidth}{Here's another one. Note the blank line between -rows. -}\\ -\end{tabular} -\end{center} +\ctable[pos = H, center, botcap]{clrl} +{% notes +} +{% rows +\FL +\parbox[b]{0.15\columnwidth}{\centering +Centered Header +} & \parbox[b]{0.14\columnwidth}{\raggedright +Left Aligned +} & \parbox[b]{0.16\columnwidth}{\raggedleft +Right Aligned +} & \parbox[b]{0.34\columnwidth}{\raggedright +Default aligned +} +\ML +\parbox[t]{0.15\columnwidth}{\centering +First +} & \parbox[t]{0.14\columnwidth}{\raggedright +row +} & \parbox[t]{0.16\columnwidth}{\raggedleft +12.0 +} & \parbox[t]{0.34\columnwidth}{\raggedright +Example of a row that spans multiple lines. +} +\\\noalign{\medskip} +\parbox[t]{0.15\columnwidth}{\centering +Second +} & \parbox[t]{0.14\columnwidth}{\raggedright +row +} & \parbox[t]{0.16\columnwidth}{\raggedleft +5.0 +} & \parbox[t]{0.34\columnwidth}{\raggedright +Here's another one. Note the blank line between rows. +} +\LL +} Table without column headers: -\begin{center} -\begin{tabular}{rlcr} -12 & 12 & 12 & 12\\ -123 & 123 & 123 & 123\\ -1 & 1 & 1 & 1\\ -\end{tabular} -\end{center} +\ctable[pos = H, center, botcap]{rlcr} +{% notes +} +{% rows +\FL +12 & 12 & 12 & 12 +\\\noalign{\medskip} +123 & 123 & 123 & 123 +\\\noalign{\medskip} +1 & 1 & 1 & 1 +\LL +} Multiline table without column headers: -\begin{center} -\begin{tabular}{>{\PBS\centering\hspace{0pt}}p{0.15\columnwidth}>{\PBS\raggedright\hspace{0pt}}p{0.14\columnwidth}>{\PBS\raggedleft\hspace{0pt}}p{0.16\columnwidth}>{\PBS\raggedright\hspace{0pt}}p{0.34\columnwidth}} -\parbox{0.15\columnwidth}{First -} & \parbox{0.14\columnwidth}{row -} & \parbox{0.16\columnwidth}{12.0 -} & \parbox{0.34\columnwidth}{Example of a row that spans multiple lines. -}\\ -\parbox{0.15\columnwidth}{Second -} & \parbox{0.14\columnwidth}{row -} & \parbox{0.16\columnwidth}{5.0 -} & \parbox{0.34\columnwidth}{Here's another one. Note the blank line between -rows. -}\\ -\end{tabular} -\end{center} +\ctable[pos = H, center, botcap]{clrl} +{% notes +} +{% rows +\FL +\parbox[t]{0.15\columnwidth}{\centering +First +} & \parbox[t]{0.14\columnwidth}{\raggedright +row +} & \parbox[t]{0.16\columnwidth}{\raggedleft +12.0 +} & \parbox[t]{0.34\columnwidth}{\raggedright +Example of a row that spans multiple lines. +} +\\\noalign{\medskip} +\parbox[t]{0.15\columnwidth}{\centering +Second +} & \parbox[t]{0.14\columnwidth}{\raggedright +row +} & \parbox[t]{0.16\columnwidth}{\raggedleft +5.0 +} & \parbox[t]{0.34\columnwidth}{\raggedright +Here's another one. Note the blank line between rows. +} +\LL +} |