git.iko.soy/typeable/pandoc
on master help sign in
Revised LaTeX writer to use templates.
2033da8fiddlosopher
data/headers/LaTeX.header+42
@@ -4,5 +4,47 @@
4\usepackage[utf8x]{inputenc}
4\usepackage[utf8x]{inputenc}
5\usepackage{listings}
5\usepackage{listings}
6\lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small\ttfamily}}{}
6\lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small\ttfamily}}{}
7+\usepackage{fancyvrb}
8+\usepackage{enumerate}
9+\usepackage{array}
10+% This is needed because raggedright in table elements redefines \\:
11+\newcommand{\PreserveBackslash}[1]{\let\temp=\\#1\let\\=\temp}
12+\let\PBS=\PreserveBackslash
13+\usepackage[normalem]{ulem}
14+\newcommand{\textsubscr}[1]{\ensuremath{_{\scriptsize\textrm{#1}}}}
15+\usepackage[breaklinks=true]{hyperref}
16+\usepackage{url}
17+\usepackage{graphicx}
18+
7\setlength{\parindent}{0pt}
19\setlength{\parindent}{0pt}
8\setlength{\parskip}{6pt plus 2pt minus 1pt}
20\setlength{\parskip}{6pt plus 2pt minus 1pt}
21+\VerbatimFootnotes % allows verbatim text in footnotes
22+$if(numbersections)$
23+$else$
24+\setcounter{secnumdepth}{0}
25+$endif$
26+
27+$if(title)$
28+\title{$title$}
29+$endif$
30+$if(authors)$
31+\author{$authors$}
32+$endif$
33+$if(date)$
34+\date{$date$}
35+$endif$
36+
37+\begin{document}
38+\maketitle
39+
40+$if(toc)$
41+\tableofcontents
42+$endif$
43+$if(before)$
44+$before$
45+$endif$
46+$body$
47+$if(after)$
48+$after$
49+$endif$
50+\end{document}
src/Text/Pandoc/Writers/LaTeX.hs+34−85
@@ -30,81 +30,45 @@ Conversion of 'Pandoc' format into LaTeX.
30module Text.Pandoc.Writers.LaTeX ( writeLaTeX ) where
30module Text.Pandoc.Writers.LaTeX ( writeLaTeX ) where
31import Text.Pandoc.Definition
31import Text.Pandoc.Definition
32import Text.Pandoc.Shared
32import Text.Pandoc.Shared
33+import Text.Pandoc.Templates
33import Text.Printf ( printf )
34import Text.Printf ( printf )
34import Data.List ( (\\), isSuffixOf, intercalate, intersperse )
35import Data.List ( (\\), isSuffixOf, intercalate, intersperse )
35import Data.Char ( toLower )
36import Data.Char ( toLower )
36−import qualified Data.Set as S
37import Control.Monad.State
37import Control.Monad.State
38import Control.Monad (liftM)
38import Control.Monad (liftM)
39import Text.PrettyPrint.HughesPJ hiding ( Str )
39import Text.PrettyPrint.HughesPJ hiding ( Str )
40
40
41data WriterState =
41data 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
44 , stOLLevel :: Int -- level of ordered list nesting
43 , stOLLevel :: Int -- level of ordered list nesting
45 , stOptions :: WriterOptions -- writer options, so they don't have to be parameter
44 , stOptions :: WriterOptions -- writer options, so they don't have to be parameter
46 }
45 }
47
46
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−
55-- | Convert Pandoc to LaTeX.
47-- | Convert Pandoc to LaTeX.
56writeLaTeX :: WriterOptions -> Pandoc -> String
48writeLaTeX :: WriterOptions -> Pandoc -> String
57writeLaTeX options document =
49writeLaTeX options document =
58− render $ evalState (pandocToLaTeX options document) $
50+ evalState (pandocToLaTeX options document) $
59− WriterState { stIncludes = S.empty, stInNote = False, stOLLevel = 1, stOptions = options }
51+ WriterState { stInNote = False, stOLLevel = 1, stOptions = options }
60
52
61−pandocToLaTeX :: WriterOptions -> Pandoc -> State WriterState Doc
53+pandocToLaTeX :: WriterOptions -> Pandoc -> State WriterState String
62−pandocToLaTeX options (Pandoc meta blocks) = do
54+pandocToLaTeX options (Pandoc (Meta title authors date) blocks) = do
63− main <- blockListToLaTeX blocks
55+ main <- liftM render $ 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
87 titletext <- if null title
56 titletext <- if null title
88− then return empty
57+ then return ""
89− else inlineListToLaTeX title >>= return . inCmd "title"
58+ else liftM render $ inlineListToLaTeX title
90− headerIncludes <- get >>= return . S.toList . stIncludes
59+ let context = [ ("before", writerIncludeBefore options)
91− let extras = text $ unlines headerIncludes
60+ , ("after", writerIncludeAfter options)
92− let verbatim = if "\\usepackage{fancyvrb}" `elem` headerIncludes
61+ , ("toc", if writerTableOfContents options then "yes" else "")
93− then text "\\VerbatimFootnotes % allows verbatim text in footnotes"
62+ , ("body", main)
94− else empty
63+ , ("title", titletext)
95− let authorstext = text $ "\\author{" ++
96− intercalate "\\\\" (map stringToLaTeX authors) ++ "}"
64+ , ("authors", intercalate "\\\\" $ map stringToLaTeX authors)
97− let datetext = if date == ""
98− then empty
99− else text $ "\\date{" ++ stringToLaTeX date ++ "}"
65+ , ("date", stringToLaTeX date) ]
100− let maketitle = if null title then empty else text "\\maketitle"
66+ let templ = if writerStandalone options
101− let secnumline = if (writerNumberSections options)
102− then empty
103− else text "\\setcounter{secnumdepth}{0}"
104− let baseHeader = text $ writerHeader options
67+ then writerHeader options
105− let header = baseHeader $$ extras
68+ else "$if(toc)$\\tableofcontents\n$endif$" ++
106− return $ header $$ secnumline $$ verbatim $$ titletext $$ authorstext $$
69+ "$if(before)$$before$\n$endif$" ++
107− datetext $$ text "\\begin{document}" $$ maketitle $$ text ""
70+ "$body$$if(after)$$after$\n$endif$"
71+ return $ renderTemplate context templ
108
72
109-- escape things as needed for LaTeX
73-- escape things as needed for LaTeX
110
74
@@ -150,13 +114,12 @@ blockToLaTeX (BlockQuote lst) = do
150 return $ text "\\begin{quote}" $$ contents $$ text "\\end{quote}"
114 return $ text "\\begin{quote}" $$ contents $$ text "\\end{quote}"
151blockToLaTeX (CodeBlock (_,classes,_) str) = do
115blockToLaTeX (CodeBlock (_,classes,_) str) = do
152 st <- get
116 st <- get
153− env <- if writerLiterateHaskell (stOptions st) && "haskell" `elem` classes &&
117+ let env = if writerLiterateHaskell (stOptions st) && "haskell" `elem` classes &&
154 "literate" `elem` classes
118 "literate" `elem` classes
155− then return "code"
119+ then "code"
156− else if stInNote st
120+ else if stInNote st
157− then do addToHeader "\\usepackage{fancyvrb}"
158− return "Verbatim"
121+ then "Verbatim"
159− else return "verbatim"
122+ else "verbatim"
160 return $ text ("\\begin{" ++ env ++ "}\n") <> text str <>
123 return $ text ("\\begin{" ++ env ++ "}\n") <> text str <>
161 text ("\n\\end{" ++ env ++ "}")
124 text ("\n\\end{" ++ env ++ "}")
162blockToLaTeX (RawHtml _) = return empty
125blockToLaTeX (RawHtml _) = return empty
@@ -169,12 +132,11 @@ blockToLaTeX (OrderedList (start, numstyle, numdelim) lst) = do
169 put $ st {stOLLevel = oldlevel + 1}
132 put $ st {stOLLevel = oldlevel + 1}
170 items <- mapM listItemToLaTeX lst
133 items <- mapM listItemToLaTeX lst
171 modify (\s -> s {stOLLevel = oldlevel})
134 modify (\s -> s {stOLLevel = oldlevel})
172− exemplar <- if numstyle /= DefaultStyle || numdelim /= DefaultDelim
135+ let exemplar = if numstyle /= DefaultStyle || numdelim /= DefaultDelim
173− then do addToHeader "\\usepackage{enumerate}"
174− return $ char '[' <>
136+ then char '[' <>
175− text (head (orderedListMarkers (1, numstyle,
137+ text (head (orderedListMarkers (1, numstyle,
176− numdelim))) <> char ']'
138+ numdelim))) <> char ']'
177− else return empty
139+ else empty
178 let resetcounter = if start /= 1 && oldlevel <= 4
140 let resetcounter = if start /= 1 && oldlevel <= 4
179 then text $ "\\setcounter{enum" ++
141 then text $ "\\setcounter{enum" ++
180 map toLower (toRomanNumeral oldlevel) ++
142 map toLower (toRomanNumeral oldlevel) ++
@@ -214,10 +176,6 @@ blockToLaTeX (Table caption aligns widths heads rows) = do
214 headers $$ text "\\hline" $$ vcat rows' $$
176 headers $$ text "\\hline" $$ vcat rows' $$
215 text "\\end{tabular}"
177 text "\\end{tabular}"
216 let centered txt = text "\\begin{center}" $$ txt $$ text "\\end{center}"
178 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"
221 return $ if isEmpty captionText
179 return $ if isEmpty captionText
222 then centered tableBody <> char '\n'
180 then centered tableBody <> char '\n'
223 else text "\\begin{table}[h]" $$ centered tableBody $$
181 else text "\\begin{table}[h]" $$ centered tableBody $$
@@ -276,7 +234,6 @@ inlineToLaTeX (Strong lst) =
276 inlineListToLaTeX (deVerb lst) >>= return . inCmd "textbf"
234 inlineListToLaTeX (deVerb lst) >>= return . inCmd "textbf"
277inlineToLaTeX (Strikeout lst) = do
235inlineToLaTeX (Strikeout lst) = do
278 contents <- inlineListToLaTeX $ deVerb lst
236 contents <- inlineListToLaTeX $ deVerb lst
279− addToHeader "\\usepackage[normalem]{ulem}"
280 return $ inCmd "sout" contents
237 return $ inCmd "sout" contents
281inlineToLaTeX (Superscript lst) =
238inlineToLaTeX (Superscript lst) =
282 inlineListToLaTeX (deVerb lst) >>= return . inCmd "textsuperscript"
239 inlineListToLaTeX (deVerb lst) >>= return . inCmd "textsuperscript"
@@ -284,17 +241,12 @@ inlineToLaTeX (Subscript lst) = do
284 contents <- inlineListToLaTeX $ deVerb lst
241 contents <- inlineListToLaTeX $ deVerb lst
285 -- oddly, latex includes \textsuperscript but not \textsubscript
242 -- oddly, latex includes \textsuperscript but not \textsubscript
286 -- so we have to define it (using a different name so as not to conflict with memoir class):
243 -- 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}}}}"
288 return $ inCmd "textsubscr" contents
244 return $ inCmd "textsubscr" contents
289inlineToLaTeX (SmallCaps lst) =
245inlineToLaTeX (SmallCaps lst) =
290 inlineListToLaTeX (deVerb lst) >>= return . inCmd "textsc"
246 inlineListToLaTeX (deVerb lst) >>= return . inCmd "textsc"
291inlineToLaTeX (Cite _ lst) =
247inlineToLaTeX (Cite _ lst) =
292 inlineListToLaTeX lst
248 inlineListToLaTeX lst
293inlineToLaTeX (Code str) = do
249inlineToLaTeX (Code str) = do
294− st <- get
295− if stInNote st
296− then do addToHeader "\\usepackage{fancyvrb}"
297− else return ()
298 let chr = ((enumFromTo '!' '~') \\ str) !! 0
250 let chr = ((enumFromTo '!' '~') \\ str) !! 0
299 return $ text $ "\\verb" ++ [chr] ++ str ++ [chr]
251 return $ text $ "\\verb" ++ [chr] ++ str ++ [chr]
300inlineToLaTeX (Quoted SingleQuote lst) = do
252inlineToLaTeX (Quoted SingleQuote lst) = do
@@ -327,16 +279,13 @@ inlineToLaTeX (HtmlInline _) = return empty
327inlineToLaTeX (LineBreak) = return $ text "\\\\"
279inlineToLaTeX (LineBreak) = return $ text "\\\\"
328inlineToLaTeX Space = return $ char ' '
280inlineToLaTeX Space = return $ char ' '
329inlineToLaTeX (Link txt (src, _)) = do
281inlineToLaTeX (Link txt (src, _)) = do
330− addToHeader "\\usepackage[breaklinks=true]{hyperref}"
331 case txt of
282 case txt of
332 [Code x] | x == src -> -- autolink
283 [Code x] | x == src -> -- autolink
333− do addToHeader "\\usepackage{url}"
334− return $ text $ "\\url{" ++ x ++ "}"
284+ do return $ text $ "\\url{" ++ x ++ "}"
335 _ -> do contents <- inlineListToLaTeX $ deVerb txt
285 _ -> do contents <- inlineListToLaTeX $ deVerb txt
336 return $ text ("\\href{" ++ src ++ "}{") <> contents <>
286 return $ text ("\\href{" ++ src ++ "}{") <> contents <>
337 char '}'
287 char '}'
338−inlineToLaTeX (Image _ (source, _)) = do
288+inlineToLaTeX (Image _ (source, _)) =
339− addToHeader "\\usepackage{graphicx}"
340 return $ text $ "\\includegraphics{" ++ source ++ "}"
289 return $ text $ "\\includegraphics{" ++ source ++ "}"
341inlineToLaTeX (Note contents) = do
290inlineToLaTeX (Note contents) = do
342 st <- get
291 st <- get
tests/writer.latex+14−8
@@ -4,22 +4,27 @@
4\usepackage[utf8x]{inputenc}
4\usepackage[utf8x]{inputenc}
5\usepackage{listings}
5\usepackage{listings}
6\lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small\ttfamily}}{}
6\lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small\ttfamily}}{}
7−\setlength{\parindent}{0pt}
7+\usepackage{fancyvrb}
8−\setlength{\parskip}{6pt plus 2pt minus 1pt}
8+\usepackage{enumerate}
9−
9+\usepackage{array}
10+% This is needed because raggedright in table elements redefines \\:
11+\newcommand{\PreserveBackslash}[1]{\let\temp=\\#1\let\\=\temp}
12+\let\PBS=\PreserveBackslash
13+\usepackage[normalem]{ulem}
10\newcommand{\textsubscr}[1]{\ensuremath{_{\scriptsize\textrm{#1}}}}
14\newcommand{\textsubscr}[1]{\ensuremath{_{\scriptsize\textrm{#1}}}}
11\usepackage[breaklinks=true]{hyperref}
15\usepackage[breaklinks=true]{hyperref}
12−\usepackage[normalem]{ulem}
13−\usepackage{enumerate}
14−\usepackage{fancyvrb}
15−\usepackage{graphicx}
16\usepackage{url}
16\usepackage{url}
17+\usepackage{graphicx}
17
18
18−\setcounter{secnumdepth}{0}
19+\setlength{\parindent}{0pt}
20+\setlength{\parskip}{6pt plus 2pt minus 1pt}
19\VerbatimFootnotes % allows verbatim text in footnotes
21\VerbatimFootnotes % allows verbatim text in footnotes
22+\setcounter{secnumdepth}{0}
23+
20\title{Pandoc Test Suite}
24\title{Pandoc Test Suite}
21\author{John MacFarlane\\Anonymous}
25\author{John MacFarlane\\Anonymous}
22\date{July 17, 2006}
26\date{July 17, 2006}
27+
23\begin{document}
28\begin{document}
24\maketitle
29\maketitle
25
30
@@ -847,3 +852,4 @@ This paragraph should not be part of the note, as it is not
847indented.
852indented.
848
853
849\end{document}
854\end{document}
855+