@@ -20,10 +20,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 Module : Text.Pandoc.Writers.LaTeX
21 Module : Text.Pandoc.Writers.LaTeX
22 Copyright : Copyright (C) 2006-2010 John MacFarlane
22 Copyright : Copyright (C) 2006-2010 John MacFarlane
23− License : GNU GPL, version 2 or above
23+ License : GNU GPL, version 2 or above
25 Maintainer : John MacFarlane <jgm@berkeley.edu>
25 Maintainer : John MacFarlane <jgm@berkeley.edu>
26− Stability : alpha
26+ Stability : alpha
27 Portability : portable
27 Portability : portable
29Conversion of 'Pandoc' format into LaTeX.
29Conversion of 'Pandoc' format into LaTeX.
@@ -41,37 +41,39 @@ import Data.Char ( toLower, isPunctuation )
41import Control.Monad.State
41import Control.Monad.State
42import Text.Pandoc.Pretty
42import Text.Pandoc.Pretty
43import System.FilePath (dropExtension)
43import System.FilePath (dropExtension)
44+import Text.Pandoc.Highlighting (highlightLaTeX, defaultLaTeXMacros)
45−data WriterState =
46+data WriterState =
46− WriterState { stInNote :: Bool -- @True@ if we're in a note
47+ WriterState { stInNote :: Bool -- true if we're in a note
47− , stInTable :: Bool -- @True@ if we're in a table
48+ , stInTable :: Bool -- true if we're in a table
48− , stTableNotes :: [(Char, Doc)] -- List of markers, notes
49+ , stTableNotes :: [(Char, Doc)] -- List of markers, notes
49− -- in current table
50+ -- in current table
50− , stOLLevel :: Int -- level of ordered list nesting
51+ , stOLLevel :: Int -- level of ordered list nesting
51− , stOptions :: WriterOptions -- writer options, so they don't have to be parameter
52+ , stOptions :: WriterOptions -- writer options, so they don't have to be parameter
52− , stVerbInNote :: Bool -- true if document has verbatim text in note
53+ , stVerbInNote :: Bool -- true if document has verbatim text in note
53− , stEnumerate :: Bool -- true if document needs fancy enumerated lists
54+ , stEnumerate :: Bool -- true if document needs fancy enumerated lists
54− , stTable :: Bool -- true if document has a table
55+ , stTable :: Bool -- true if document has a table
55− , stStrikeout :: Bool -- true if document has strikeout
56+ , stStrikeout :: Bool -- true if document has strikeout
56− , stSubscript :: Bool -- true if document has subscript
57+ , stSubscript :: Bool -- true if document has subscript
57− , stUrl :: Bool -- true if document has visible URL link
58+ , stUrl :: Bool -- true if document has visible URL link
58− , stGraphics :: Bool -- true if document contains images
59+ , stGraphics :: Bool -- true if document contains images
59− , stLHS :: Bool -- true if document has literate haskell code
60+ , stLHS :: Bool -- true if document has literate haskell code
60− , stBook :: Bool -- true if document uses book or memoir class
61+ , stBook :: Bool -- true if document uses book or memoir class
61− , stCsquotes :: Bool -- true if document uses csquotes
62+ , stCsquotes :: Bool -- true if document uses csquotes
63+ , stHighlighting :: Bool -- true if document has highlighted code
64-- | Convert Pandoc to LaTeX.
66-- | Convert Pandoc to LaTeX.
65writeLaTeX :: WriterOptions -> Pandoc -> String
67writeLaTeX :: WriterOptions -> Pandoc -> String
66−writeLaTeX options document =
68+writeLaTeX options document =
67− evalState (pandocToLaTeX options document) $
69+ evalState (pandocToLaTeX options document) $
68 WriterState { stInNote = False, stInTable = False,
70 WriterState { stInNote = False, stInTable = False,
69 stTableNotes = [], stOLLevel = 1, stOptions = options,
71 stTableNotes = [], stOLLevel = 1, stOptions = options,
70 stVerbInNote = False, stEnumerate = False,
72 stVerbInNote = False, stEnumerate = False,
71 stTable = False, stStrikeout = False, stSubscript = False,
73 stTable = False, stStrikeout = False, stSubscript = False,
72 stUrl = False, stGraphics = False,
74 stUrl = False, stGraphics = False,
73 stLHS = False, stBook = writerChapters options,
75 stLHS = False, stBook = writerChapters options,
74− stCsquotes = False }
76+ stCsquotes = False, stHighlighting = False }
76pandocToLaTeX :: WriterOptions -> Pandoc -> State WriterState String
78pandocToLaTeX :: WriterOptions -> Pandoc -> State WriterState String
77pandocToLaTeX options (Pandoc (Meta title authors date) blocks) = do
79pandocToLaTeX options (Pandoc (Meta title authors date) blocks) = do
@@ -129,6 +131,7 @@ pandocToLaTeX options (Pandoc (Meta title authors date) blocks) = do
129 [ ("graphics", "yes") | stGraphics st ] ++
131 [ ("graphics", "yes") | stGraphics st ] ++
130 [ ("book-class", "yes") | stBook st] ++
132 [ ("book-class", "yes") | stBook st] ++
131 [ ("listings", "yes") | writerListings options ] ++
133 [ ("listings", "yes") | writerListings options ] ++
134+ [ ("highlighting-macros", defaultLaTeXMacros) | stHighlighting st ] ++
132 citecontext
135 citecontext
133 return $ if writerStandalone options
136 return $ if writerStandalone options
134 then renderTemplate context template
137 then renderTemplate context template
@@ -180,48 +183,58 @@ blockToLaTeX (BlockQuote lst) = do
180 contents <- blockListToLaTeX lst
183 contents <- blockListToLaTeX lst
181 return $ "\\begin{quote}" $$ contents $$ "\\end{quote}"
184 return $ "\\begin{quote}" $$ contents $$ "\\end{quote}"
182blockToLaTeX (CodeBlock (_,classes,keyvalAttr) str) = do
185blockToLaTeX (CodeBlock (_,classes,keyvalAttr) str) = do
183− st <- get
186+ opts <- gets stOptions
184− env <- if writerLiterateHaskell (stOptions st) && "haskell" `elem` classes &&
188+ _ | writerLiterateHaskell opts && "haskell" `elem` classes &&
185− "literate" `elem` classes
189+ "literate" `elem` classes -> lhsCodeBlock
186− then do
190+ | writerListings opts -> listingsCodeBlock
191+ | writerHighlight opts && not (null classes) -> highlightedCodeBlock
192+ | otherwise -> rawCodeBlock
193+ where lhsCodeBlock = do
187− modify $ \s -> s{ stLHS = True }
194+ modify $ \s -> s{ stLHS = True }
188− return "code"
195+ return $ flush ("\\begin{code}" $$ text str $$ "\\end{code}") $$ cr
189− else if writerListings (stOptions st)
196+ rawCodeBlock = do
190− then return "lstlisting"
197+ st <- get
191− else if stInNote st
198+ env <- if stInNote st
193− modify $ \s -> s{ stVerbInNote = True }
199+ then modify (\s -> s{ stVerbInNote = True }) >>
194− return "Verbatim"
200+ return "Verbatim"
195− else return "verbatim"
201+ else return "verbatim"
202+ return $ flush (text $ "\\begin{" ++ env ++ "}") $$ text str $$
203+ text ("\\end{" ++ env ++ "}") $$ cr -- final cr because of notes
204+ listingsCodeBlock = do
196− let params = if writerListings (stOptions st)
206+ let params = if writerListings (stOptions st)
197− then take 1
207+ then take 1
198− [ "language=" ++ lang | lang <- classes
208+ [ "language=" ++ lang | lang <- classes
199− , lang `elem` ["ABAP","IDL","Plasm","ACSL","inform"
209+ , lang `elem` ["ABAP","IDL","Plasm","ACSL","inform"
200− ,"POV","Ada","Java","Prolog","Algol"
210+ ,"POV","Ada","Java","Prolog","Algol"
201− ,"JVMIS","Promela","Ant","ksh","Python"
211+ ,"JVMIS","Promela","Ant","ksh","Python"
202− ,"Assembler","Lisp","R","Awk","Logo"
212+ ,"Assembler","Lisp","R","Awk","Logo"
203− ,"Reduce","bash","make","Rexx","Basic"
213+ ,"Reduce","bash","make","Rexx","Basic"
204− ,"Mathematica","RSL","C","Matlab","Ruby"
214+ ,"Mathematica","RSL","C","Matlab","Ruby"
205− ,"C++","Mercury","S","Caml","MetaPost"
215+ ,"C++","Mercury","S","Caml","MetaPost"
206− ,"SAS","Clean","Miranda","Scilab","Cobol"
216+ ,"SAS","Clean","Miranda","Scilab","Cobol"
207− ,"Mizar","sh","Comal","ML","SHELXL","csh"
217+ ,"Mizar","sh","Comal","ML","SHELXL","csh"
208− ,"Modula-2","Simula","Delphi","MuPAD"
218+ ,"Modula-2","Simula","Delphi","MuPAD"
209− ,"SQL","Eiffel","NASTRAN","tcl","Elan"
219+ ,"SQL","Eiffel","NASTRAN","tcl","Elan"
210− ,"Oberon-2","TeX","erlang","OCL"
220+ ,"Oberon-2","TeX","erlang","OCL"
211− ,"VBScript","Euphoria","Octave","Verilog"
221+ ,"VBScript","Euphoria","Octave","Verilog"
212− ,"Fortran","Oz","VHDL","GCL","Pascal"
222+ ,"Fortran","Oz","VHDL","GCL","Pascal"
213− ,"VRML","Gnuplot","Perl","XML","Haskell"
223+ ,"VRML","Gnuplot","Perl","XML","Haskell"
214− ,"PHP","XSLT","HTML","PL/I"]
224+ ,"PHP","XSLT","HTML","PL/I"]
216− [ key ++ "=" ++ attr | (key,attr) <- keyvalAttr ]
226+ [ key ++ "=" ++ attr | (key,attr) <- keyvalAttr ]
218− printParams
228+ printParams
219− | null params = empty
229+ | null params = empty
220− | otherwise = "[" <> hsep (intersperse "," (map text params)) <>
230+ | otherwise = brackets $ hsep (intersperse "," (map text params))
222− return $ flush ("\\begin{" <> text env <> "}" <> printParams $$ text str $$
231+ return $ flush ("\\begin{lstlisting}" <> printParams $$ text str $$
223− "\\end{" <> text env <> "}") $$ cr
232+ "\\end{lstlisting}") $$ cr
224− -- final cr needed because of footnotes
233+ highlightedCodeBlock =
234+ case highlightLaTeX False ("",classes,keyvalAttr) str of
235+ Nothing -> rawCodeBlock
236+ Just h -> modify (\st -> st{ stHighlighting = True }) >>
225blockToLaTeX (RawBlock "latex" x) = return $ text x <> blankline
238blockToLaTeX (RawBlock "latex" x) = return $ text x <> blankline
226blockToLaTeX (RawBlock _ _) = return empty
239blockToLaTeX (RawBlock _ _) = return empty
227blockToLaTeX (BulletList lst) = do
240blockToLaTeX (BulletList lst) = do
@@ -236,15 +249,15 @@ blockToLaTeX (OrderedList (start, numstyle, numdelim) lst) = do
236 exemplar <- if numstyle /= DefaultStyle || numdelim /= DefaultDelim
249 exemplar <- if numstyle /= DefaultStyle || numdelim /= DefaultDelim
238 modify $ \s -> s{ stEnumerate = True }
251 modify $ \s -> s{ stEnumerate = True }
239− return $ char '[' <>
252+ return $ char '[' <>
240 text (head (orderedListMarkers (1, numstyle,
253 text (head (orderedListMarkers (1, numstyle,
241 numdelim))) <> char ']'
254 numdelim))) <> char ']'
242 else return empty
255 else return empty
243 let resetcounter = if start /= 1 && oldlevel <= 4
256 let resetcounter = if start /= 1 && oldlevel <= 4
244− then text $ "\\setcounter{enum" ++
257+ then text $ "\\setcounter{enum" ++
245 map toLower (toRomanNumeral oldlevel) ++
258 map toLower (toRomanNumeral oldlevel) ++
246 "}{" ++ show (start - 1) ++ "}"
259 "}{" ++ show (start - 1) ++ "}"
247− else empty
260+ else empty
248 return $ "\\begin{enumerate}" <> exemplar $$ resetcounter $$
261 return $ "\\begin{enumerate}" <> exemplar $$ resetcounter $$
249 vcat items $$ "\\end{enumerate}"
262 vcat items $$ "\\end{enumerate}"
250blockToLaTeX (DefinitionList lst) = do
263blockToLaTeX (DefinitionList lst) = do
@@ -358,8 +371,8 @@ inlineToLaTeX :: Inline -- ^ Inline to convert
358 -> State WriterState Doc
371 -> State WriterState Doc
359inlineToLaTeX (Emph lst) =
372inlineToLaTeX (Emph lst) =
360 inlineListToLaTeX lst >>= return . inCmd "emph"
373 inlineListToLaTeX lst >>= return . inCmd "emph"
361−inlineToLaTeX (Strong lst) =
374+inlineToLaTeX (Strong lst) =
362− inlineListToLaTeX lst >>= return . inCmd "textbf"
375+ inlineListToLaTeX lst >>= return . inCmd "textbf"
363inlineToLaTeX (Strikeout lst) = do
376inlineToLaTeX (Strikeout lst) = do
364 contents <- inlineListToLaTeX lst
377 contents <- inlineListToLaTeX lst
365 modify $ \s -> s{ stStrikeout = True }
378 modify $ \s -> s{ stStrikeout = True }