@@ -20,7 +20,6 @@ module Text.Pandoc.Writers.LaTeX (
21import Control.Applicative ((<|>))
21import Control.Applicative ((<|>))
22import Control.Monad.State.Strict
22import Control.Monad.State.Strict
23−import Data.Monoid (Any(..))
24import Data.Char (isAlphaNum, isAscii, isDigit, isLetter, isSpace,
23import Data.Char (isAlphaNum, isAscii, isDigit, isLetter, isSpace,
25 isPunctuation, ord)
24 isPunctuation, ord)
26import Data.List (foldl', intersperse, nubBy, (\\), uncons)
25import Data.List (foldl', intersperse, nubBy, (\\), uncons)
@@ -42,69 +41,14 @@ import Text.Pandoc.Options
42import Text.DocLayout
41import Text.DocLayout
43import Text.Pandoc.Shared
42import Text.Pandoc.Shared
44import Text.Pandoc.Slides
43import Text.Pandoc.Slides
45−import Text.Pandoc.Walk
44+import Text.Pandoc.Walk (query, walk, walkM)
45+import Text.Pandoc.Writers.LaTeX.Caption (getCaption)
46+import Text.Pandoc.Writers.LaTeX.Table (tableToLaTeX)
47+import Text.Pandoc.Writers.LaTeX.Types (LW, WriterState (..), startingState)
46import Text.Pandoc.Writers.Shared
48import Text.Pandoc.Writers.Shared
47import Text.Printf (printf)
49import Text.Printf (printf)
48import qualified Data.Text.Normalize as Normalize
50import qualified Data.Text.Normalize as Normalize
51− WriterState { stInNote :: Bool -- true if we're in a note
52− , stInQuote :: Bool -- true if in a blockquote
53− , stExternalNotes :: Bool -- true if in context where
54− -- we need to store footnotes
55− , stInMinipage :: Bool -- true if in minipage
56− , stInHeading :: Bool -- true if in a section heading
57− , stInItem :: Bool -- true if in \item[..]
58− , stNotes :: [Doc Text] -- notes in a minipage
59− , stOLLevel :: Int -- level of ordered list nesting
60− , stOptions :: WriterOptions -- writer options, so they don't have to be parameter
61− , stVerbInNote :: Bool -- true if document has verbatim text in note
62− , stTable :: Bool -- true if document has a table
63− , stStrikeout :: Bool -- true if document has strikeout
64− , stUrl :: Bool -- true if document has visible URL link
65− , stGraphics :: Bool -- true if document contains images
66− , stLHS :: Bool -- true if document has literate haskell code
67− , stHasChapters :: Bool -- true if document has chapters
68− , stCsquotes :: Bool -- true if document uses csquotes
69− , stHighlighting :: Bool -- true if document has highlighted code
70− , stIncremental :: Bool -- true if beamer lists should be displayed bit by bit
71− , stInternalLinks :: [Text] -- list of internal link targets
72− , stBeamer :: Bool -- produce beamer
73− , stEmptyLine :: Bool -- true if no content on line
74− , stHasCslRefs :: Bool -- has a Div with class refs
75− , stIsFirstInDefinition :: Bool -- first block in a defn list
78−startingState :: WriterOptions -> WriterState
79−startingState options = WriterState {
82− , stExternalNotes = False
83− , stInHeading = False
84− , stInMinipage = False
88− , stOptions = options
89− , stVerbInNote = False
91− , stStrikeout = False
95− , stHasChapters = case writerTopLevelDivision options of
97− TopLevelChapter -> True
100− , stHighlighting = False
101− , stIncremental = writerIncremental options
102− , stInternalLinks = []
104− , stEmptyLine = True
105− , stHasCslRefs = False
106− , stIsFirstInDefinition = False }
108-- | Convert Pandoc to LaTeX.
52-- | Convert Pandoc to LaTeX.
109writeLaTeX :: PandocMonad m => WriterOptions -> Pandoc -> m Text
53writeLaTeX :: PandocMonad m => WriterOptions -> Pandoc -> m Text
110writeLaTeX options document =
54writeLaTeX options document =
@@ -117,8 +61,6 @@ writeBeamer options document =
117 evalStateT (pandocToLaTeX options document) $
61 evalStateT (pandocToLaTeX options document) $
118 (startingState options){ stBeamer = True }
62 (startingState options){ stBeamer = True }
120−type LW m = StateT WriterState m
122pandocToLaTeX :: PandocMonad m
64pandocToLaTeX :: PandocMonad m
123 => WriterOptions -> Pandoc -> LW m Text
65 => WriterOptions -> Pandoc -> LW m Text
124pandocToLaTeX options (Pandoc meta blocks) = do
66pandocToLaTeX options (Pandoc meta blocks) = do
@@ -573,7 +515,7 @@ blockToLaTeX (Plain lst) =
573blockToLaTeX (Para [Image attr@(ident, _, _) txt (src,tgt)])
515blockToLaTeX (Para [Image attr@(ident, _, _) txt (src,tgt)])
574 | Just tit <- T.stripPrefix "fig:" tgt
516 | Just tit <- T.stripPrefix "fig:" tgt
576− (capt, captForLof, footnotes) <- getCaption True txt
518+ (capt, captForLof, footnotes) <- getCaption inlineListToLaTeX True txt
577 lab <- labelFor ident
519 lab <- labelFor ident
578 let caption = "\\caption" <> captForLof <> braces capt <> lab
520 let caption = "\\caption" <> captForLof <> braces capt <> lab
579 img <- inlineToLaTeX (Image attr txt (src,tit))
521 img <- inlineToLaTeX (Image attr txt (src,tit))
@@ -774,181 +716,14 @@ blockToLaTeX (Header level (id',classes,_) lst) = do
774 hdr <- sectionHeader classes id' level lst
716 hdr <- sectionHeader classes id' level lst
775 modify $ \s -> s{stInHeading = False}
717 modify $ \s -> s{stInHeading = False}
776 return hdr
718 return hdr
777−blockToLaTeX (Table _ blkCapt specs thead tbody tfoot) = do
719+blockToLaTeX (Table _ blkCapt specs thead tbodies tfoot) =
720+ tableToLaTeX inlineListToLaTeX blockListToLaTeX
778− let (caption, aligns, widths, heads, rows) = toLegacyTable blkCapt specs thead tbody tfoot
721+ blkCapt specs thead tbodies tfoot
779− -- simple tables have to have simple cells:
780− let isSimple [Plain _] = True
781− isSimple [Para _] = True
784− let widths' = if all (== 0) widths && not (all (all isSimple) rows)
785− then replicate (length aligns)
786− (1 / fromIntegral (length aligns))
788− (captionText, captForLof, captNotes) <- getCaption False caption
789− let toHeaders hs = do contents <- tableRowToLaTeX True aligns hs
790− return ("\\toprule" $$ contents $$ "\\midrule")
791− let removeNote (Note _) = Span ("", [], []) []
793− firsthead <- if isEmpty captionText || all null heads
795− else ($$ text "\\endfirsthead") <$> toHeaders heads
796− head' <- if all null heads
797− then return "\\toprule"
798− -- avoid duplicate notes in head and firsthead:
799− else toHeaders (if isEmpty firsthead
801− else walk removeNote heads)
802− let capt = if isEmpty captionText
804− else "\\caption" <> captForLof <> braces captionText
805− <> "\\tabularnewline"
806− rows' <- mapM (tableRowToLaTeX False aligns) rows
807− let colDescriptors =
808− (if all (== 0) widths'
809− then hcat . map literal
810− else (\xs -> cr <> nest 2 (vcat $ map literal xs))) $
811− zipWith (toColDescriptor (length widths')) aligns widths'
812− modify $ \s -> s{ stTable = True }
813− notes <- notesToLaTeX <$> gets stNotes
814− return $ "\\begin{longtable}[]" <>
815− braces ("@{}" <> colDescriptors <> "@{}")
816− -- the @{} removes extra space at beginning and end
823− $$ "\\end{longtable}"
827−getCaption :: PandocMonad m
828− => Bool -> [Inline] -> LW m (Doc Text, Doc Text, Doc Text)
829−getCaption externalNotes txt = do
830− oldExternalNotes <- gets stExternalNotes
831− modify $ \st -> st{ stExternalNotes = externalNotes, stNotes = [] }
832− capt <- inlineListToLaTeX txt
833− footnotes <- if externalNotes
834− then notesToLaTeX <$> gets stNotes
836− modify $ \st -> st{ stExternalNotes = oldExternalNotes, stNotes = [] }
837− -- We can't have footnotes in the list of figures/tables, so remove them:
838− let getNote (Note _) = Any True
839− getNote _ = Any False
840− let hasNotes = getAny . query getNote
841− captForLof <- if hasNotes txt
842− then brackets <$> inlineListToLaTeX (walk deNote txt)
844− return (capt, captForLof, footnotes)
846−toColDescriptor :: Int -> Alignment -> Double -> Text
847−toColDescriptor _numcols align 0 =
853−toColDescriptor numcols align width =
855− ">{%s\\arraybackslash}p{(\\columnwidth - %d\\tabcolsep) * \\real{%0.2f}}"
861− align' = case align of
862− AlignLeft -> "\\raggedright"
863− AlignRight -> "\\raggedleft"
864− AlignCenter -> "\\centering"
865− AlignDefault -> "\\raggedright"
867blockListToLaTeX :: PandocMonad m => [Block] -> LW m (Doc Text)
723blockListToLaTeX :: PandocMonad m => [Block] -> LW m (Doc Text)
868blockListToLaTeX lst =
724blockListToLaTeX lst =
869 vsep `fmap` mapM (\b -> setEmptyLine True >> blockToLaTeX b) lst
725 vsep `fmap` mapM (\b -> setEmptyLine True >> blockToLaTeX b) lst
871−tableRowToLaTeX :: PandocMonad m
876−tableRowToLaTeX header aligns cols = do
877− cells <- mapM (tableCellToLaTeX header) $ zip aligns cols
878− return $ hsep (intersperse "&" cells) <> " \\\\ \\addlinespace"
880−-- For simple latex tables (without minipages or parboxes),
881−-- we need to go to some lengths to get line breaks working:
882−-- as LineBreak bs = \vtop{\hbox{\strut as}\hbox{\strut bs}}.
883−fixLineBreaks :: Block -> Block
884−fixLineBreaks (Para ils) = Para $ fixLineBreaks' ils
885−fixLineBreaks (Plain ils) = Plain $ fixLineBreaks' ils
888−fixLineBreaks' :: [Inline] -> [Inline]
889−fixLineBreaks' ils = case splitBy (== LineBreak) ils of
892− chunks -> RawInline "tex" "\\vtop{" :
893− concatMap tohbox chunks <>
894− [RawInline "tex" "}"]
895− where tohbox ys = RawInline "tex" "\\hbox{\\strut " : ys <>
896− [RawInline "tex" "}"]
898−-- We also change display math to inline math, since display
899−-- math breaks in simple tables.
900−displayMathToInline :: Inline -> Inline
901−displayMathToInline (Math DisplayMath x) = Math InlineMath x
902−displayMathToInline x = x
904−tableCellToLaTeX :: PandocMonad m
905− => Bool -> (Alignment, [Block])
907−tableCellToLaTeX header (align, blocks) = do
908− beamer <- gets stBeamer
909− externalNotes <- gets stExternalNotes
910− inMinipage <- gets stInMinipage
911− -- See #5367 -- footnotehyper/footnote don't work in beamer,
912− -- so we need to produce the notes outside the table...
913− modify $ \st -> st{ stExternalNotes = beamer }
914− let isPlainOrPara Para{} = True
915− isPlainOrPara Plain{} = True
916− isPlainOrPara _ = False
918− if all isPlainOrPara blocks
920− blockListToLaTeX $ walk fixLineBreaks $ walk displayMathToInline blocks
922− modify $ \st -> st{ stInMinipage = True }
923− cellContents <- blockListToLaTeX blocks
924− modify $ \st -> st{ stInMinipage = inMinipage }
925− let valign = text $ if header then "[b]" else "[t]"
926− let halign = case align of
927− AlignLeft -> "\\raggedright"
928− AlignRight -> "\\raggedleft"
929− AlignCenter -> "\\centering"
930− AlignDefault -> "\\raggedright"
931− return $ "\\begin{minipage}" <> valign <>
932− braces "\\linewidth" <> halign <> cr <>
933− cellContents <> cr <>
935− modify $ \st -> st{ stExternalNotes = externalNotes }
939−notesToLaTeX :: [Doc Text] -> Doc Text
940−notesToLaTeX [] = empty
941−notesToLaTeX ns = (case length ns of
942− n | n > 1 -> "\\addtocounter" <>
943− braces "footnote" <>
944− braces (text $ show $ 1 - n)
945− | otherwise -> empty)
948− ("\\addtocounter" <> braces "footnote" <> braces "1")
949− $ map (\x -> "\\footnotetext" <> braces x)
952listItemToLaTeX :: PandocMonad m => [Block] -> LW m (Doc Text)
727listItemToLaTeX :: PandocMonad m => [Block] -> LW m (Doc Text)
953listItemToLaTeX lst
728listItemToLaTeX lst
954 -- we need to put some text before a header if it's the first
729 -- we need to put some text before a header if it's the first
@@ -1081,7 +856,7 @@ mapAlignment a = case a of
1081 "top-baseline" -> "t"
856 "top-baseline" -> "t"
1082 "bottom" -> "b"
857 "bottom" -> "b"
1083 "center" -> "c"
858 "center" -> "c"
1086wrapDiv :: PandocMonad m => Attr -> Doc Text -> LW m (Doc Text)
861wrapDiv :: PandocMonad m => Attr -> Doc Text -> LW m (Doc Text)
1087wrapDiv (_,classes,kvs) t = do
862wrapDiv (_,classes,kvs) t = do
@@ -1095,7 +870,7 @@ wrapDiv (_,classes,kvs) t = do
1095 (lookup "totalwidth" kvs)
870 (lookup "totalwidth" kvs)
1096 onlytextwidth = filter ("onlytextwidth" ==) classes
871 onlytextwidth = filter ("onlytextwidth" ==) classes
1097 options = text $ T.unpack $ T.intercalate "," $
872 options = text $ T.unpack $ T.intercalate "," $
1098− valign : totalwidth ++ onlytextwidth
873+ valign : totalwidth ++ onlytextwidth
1099 in inCmd "begin" "columns" <> brackets options
874 in inCmd "begin" "columns" <> brackets options
1100 $$ contents
875 $$ contents
1101 $$ inCmd "end" "columns"
876 $$ inCmd "end" "columns"
@@ -1106,8 +881,8 @@ wrapDiv (_,classes,kvs) t = do
1106 maybe ""
881 maybe ""
1107 (brackets . text . T.unpack . mapAlignment)
882 (brackets . text . T.unpack . mapAlignment)
1108 (lookup "align" kvs)
883 (lookup "align" kvs)
1109− w = maybe "0.48" fromPct (lookup "width" kvs)
884+ w = maybe "0.48" fromPct (lookup "width" kvs)
1110− in inCmd "begin" "column" <>
885+ in inCmd "begin" "column" <>
1111 valign <>
886 valign <>
1112 braces (literal w <> "\\textwidth")
887 braces (literal w <> "\\textwidth")
1113 $$ contents
888 $$ contents