@@ -30,81 +30,45 @@ Conversion of 'Pandoc' format into LaTeX.
3030module Text.Pandoc.Writers.LaTeX ( writeLaTeX ) where
3131import Text.Pandoc.Definition
3232import Text.Pandoc.Shared
33+import Text.Pandoc.Templates
3334import Text.Printf ( printf )
3435import Data.List ( (\\), isSuffixOf, intercalate, intersperse )
3536import Data.Char ( toLower )
36−import qualified Data.Set as S
3737import Control.Monad.State
3838import Control.Monad (liftM)
3939import Text.PrettyPrint.HughesPJ hiding ( Str )
4040
4141data WriterState =
42− WriterState { stIncludes :: S.Set String -- strings to include in header
43− , stInNote :: Bool -- @True@ if we're in a note
42+ WriterState { stInNote :: Bool -- @True@ if we're in a note
4443 , stOLLevel :: Int -- level of ordered list nesting
4544 , stOptions :: WriterOptions -- writer options, so they don't have to be parameter
4645 }
4746
48−-- | Add line to header.
49−addToHeader :: String -> State WriterState ()
50−addToHeader str = do
51− st <- get
52− let includes = stIncludes st
53− put st {stIncludes = S.insert str includes}
54−
5547-- | Convert Pandoc to LaTeX.
5648writeLaTeX :: WriterOptions -> Pandoc -> String
5749writeLaTeX options document =
58− render $ evalState (pandocToLaTeX options document) $
59− WriterState { stIncludes = S.empty, stInNote = False, stOLLevel = 1, stOptions = options }
50+ evalState (pandocToLaTeX options document) $
51+ WriterState { stInNote = False, stOLLevel = 1, stOptions = options }
6052
61−pandocToLaTeX :: WriterOptions -> Pandoc -> State WriterState Doc
62−pandocToLaTeX options (Pandoc meta blocks) = do
63− main <- blockListToLaTeX blocks
64− head' <- if writerStandalone options
65− then latexHeader options meta
66− else return empty
67− let before = if null (writerIncludeBefore options)
68− then empty
69− else text (writerIncludeBefore options)
70− let after = if null (writerIncludeAfter options)
71− then empty
72− else text (writerIncludeAfter options)
73− let body = before $$ main $$ after
74− let toc = if writerTableOfContents options
75− then text "\\tableofcontents\n"
76− else empty
77− let foot = if writerStandalone options
78− then text "\\end{document}"
79− else empty
80− return $ head' $$ toc $$ body $$ foot
81−
82−-- | Insert bibliographic information into LaTeX header.
83−latexHeader :: WriterOptions -- ^ Options, including LaTeX header
84− -> Meta -- ^ Meta with bibliographic information
85− -> State WriterState Doc
86−latexHeader options (Meta title authors date) = do
53+pandocToLaTeX :: WriterOptions -> Pandoc -> State WriterState String
54+pandocToLaTeX options (Pandoc (Meta title authors date) blocks) = do
55+ main <- liftM render $ blockListToLaTeX blocks
8756 titletext <- if null title
88− then return empty
89− else inlineListToLaTeX title >>= return . inCmd "title"
90− headerIncludes <- get >>= return . S.toList . stIncludes
91− let extras = text $ unlines headerIncludes
92− let verbatim = if "\\usepackage{fancyvrb}" `elem` headerIncludes
93− then text "\\VerbatimFootnotes % allows verbatim text in footnotes"
94− else empty
95− let authorstext = text $ "\\author{" ++
96− intercalate "\\\\" (map stringToLaTeX authors) ++ "}"
97− let datetext = if date == ""
98− then empty
99− else text $ "\\date{" ++ stringToLaTeX date ++ "}"
100− let maketitle = if null title then empty else text "\\maketitle"
101− let secnumline = if (writerNumberSections options)
102− then empty
103− else text "\\setcounter{secnumdepth}{0}"
104− let baseHeader = text $ writerHeader options
105− let header = baseHeader $$ extras
106− return $ header $$ secnumline $$ verbatim $$ titletext $$ authorstext $$
107− datetext $$ text "\\begin{document}" $$ maketitle $$ text ""
57+ then return ""
58+ else liftM render $ inlineListToLaTeX title
59+ let context = [ ("before", writerIncludeBefore options)
60+ , ("after", writerIncludeAfter options)
61+ , ("toc", if writerTableOfContents options then "yes" else "")
62+ , ("body", main)
63+ , ("title", titletext)
64+ , ("authors", intercalate "\\\\" $ map stringToLaTeX authors)
65+ , ("date", stringToLaTeX date) ]
66+ let templ = if writerStandalone options
67+ then writerHeader options
68+ else "$if(toc)$\\tableofcontents\n$endif$" ++
69+ "$if(before)$$before$\n$endif$" ++
70+ "$body$$if(after)$$after$\n$endif$"
71+ return $ renderTemplate context templ
10872
10973-- escape things as needed for LaTeX
11074
@@ -150,13 +114,12 @@ blockToLaTeX (BlockQuote lst) = do
150114 return $ text "\\begin{quote}" $$ contents $$ text "\\end{quote}"
151115blockToLaTeX (CodeBlock (_,classes,_) str) = do
152116 st <- get
153− env <- if writerLiterateHaskell (stOptions st) && "haskell" `elem` classes &&
117+ let env = if writerLiterateHaskell (stOptions st) && "haskell" `elem` classes &&
154118 "literate" `elem` classes
155− then return "code"
156− else if stInNote st
157− then do addToHeader "\\usepackage{fancyvrb}"
158− return "Verbatim"
159− else return "verbatim"
119+ then "code"
120+ else if stInNote st
121+ then "Verbatim"
122+ else "verbatim"
160123 return $ text ("\\begin{" ++ env ++ "}\n") <> text str <>
161124 text ("\n\\end{" ++ env ++ "}")
162125blockToLaTeX (RawHtml _) = return empty
@@ -169,12 +132,11 @@ blockToLaTeX (OrderedList (start, numstyle, numdelim) lst) = do
169132 put $ st {stOLLevel = oldlevel + 1}
170133 items <- mapM listItemToLaTeX lst
171134 modify (\s -> s {stOLLevel = oldlevel})
172− exemplar <- if numstyle /= DefaultStyle || numdelim /= DefaultDelim
173− then do addToHeader "\\usepackage{enumerate}"
174− return $ char '[' <>
175− text (head (orderedListMarkers (1, numstyle,
176− numdelim))) <> char ']'
177− else return empty
135+ let exemplar = if numstyle /= DefaultStyle || numdelim /= DefaultDelim
136+ then char '[' <>
137+ text (head (orderedListMarkers (1, numstyle,
138+ numdelim))) <> char ']'
139+ else empty
178140 let resetcounter = if start /= 1 && oldlevel <= 4
179141 then text $ "\\setcounter{enum" ++
180142 map toLower (toRomanNumeral oldlevel) ++
@@ -214,10 +176,6 @@ blockToLaTeX (Table caption aligns widths heads rows) = do
214176 headers $$ text "\\hline" $$ vcat rows' $$
215177 text "\\end{tabular}"
216178 let centered txt = text "\\begin{center}" $$ txt $$ text "\\end{center}"
217− addToHeader $ "\\usepackage{array}\n" ++
218− "% This is needed because raggedright in table elements redefines \\\\:\n" ++
219− "\\newcommand{\\PreserveBackslash}[1]{\\let\\temp=\\\\#1\\let\\\\=\\temp}\n" ++
220− "\\let\\PBS=\\PreserveBackslash"
221179 return $ if isEmpty captionText
222180 then centered tableBody <> char '\n'
223181 else text "\\begin{table}[h]" $$ centered tableBody $$
@@ -276,7 +234,6 @@ inlineToLaTeX (Strong lst) =
276234 inlineListToLaTeX (deVerb lst) >>= return . inCmd "textbf"
277235inlineToLaTeX (Strikeout lst) = do
278236 contents <- inlineListToLaTeX $ deVerb lst
279− addToHeader "\\usepackage[normalem]{ulem}"
280237 return $ inCmd "sout" contents
281238inlineToLaTeX (Superscript lst) =
282239 inlineListToLaTeX (deVerb lst) >>= return . inCmd "textsuperscript"
@@ -284,17 +241,12 @@ inlineToLaTeX (Subscript lst) = do
284241 contents <- inlineListToLaTeX $ deVerb lst
285242 -- oddly, latex includes \textsuperscript but not \textsubscript
286243 -- so we have to define it (using a different name so as not to conflict with memoir class):
287− addToHeader "\\newcommand{\\textsubscr}[1]{\\ensuremath{_{\\scriptsize\\textrm{#1}}}}"
288244 return $ inCmd "textsubscr" contents
289245inlineToLaTeX (SmallCaps lst) =
290246 inlineListToLaTeX (deVerb lst) >>= return . inCmd "textsc"
291247inlineToLaTeX (Cite _ lst) =
292248 inlineListToLaTeX lst
293249inlineToLaTeX (Code str) = do
294− st <- get
295− if stInNote st
296− then do addToHeader "\\usepackage{fancyvrb}"
297− else return ()
298250 let chr = ((enumFromTo '!' '~') \\ str) !! 0
299251 return $ text $ "\\verb" ++ [chr] ++ str ++ [chr]
300252inlineToLaTeX (Quoted SingleQuote lst) = do
@@ -327,16 +279,13 @@ inlineToLaTeX (HtmlInline _) = return empty
327279inlineToLaTeX (LineBreak) = return $ text "\\\\"
328280inlineToLaTeX Space = return $ char ' '
329281inlineToLaTeX (Link txt (src, _)) = do
330− addToHeader "\\usepackage[breaklinks=true]{hyperref}"
331282 case txt of
332283 [Code x] | x == src -> -- autolink
333− do addToHeader "\\usepackage{url}"
334− return $ text $ "\\url{" ++ x ++ "}"
284+ do return $ text $ "\\url{" ++ x ++ "}"
335285 _ -> do contents <- inlineListToLaTeX $ deVerb txt
336286 return $ text ("\\href{" ++ src ++ "}{") <> contents <>
337287 char '}'
338−inlineToLaTeX (Image _ (source, _)) = do
339− addToHeader "\\usepackage{graphicx}"
288+inlineToLaTeX (Image _ (source, _)) =
340289 return $ text $ "\\includegraphics{" ++ source ++ "}"
341290inlineToLaTeX (Note contents) = do
342291 st <- get