git.iko.soy/typeable/pandoc
on 1.15.0.5 help sign in
typeable/pandoc/pandoc.hs
1384 lines 61 kB history raw
1{-# LANGUAGE CPP, TupleSections #-}
2{-
3Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
5This program is free software; you can redistribute it and/or modify
6it under the terms of the GNU General Public License as published by
7the Free Software Foundation; either version 2 of the License, or
8(at your option) any later version.
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18-}
20{- |
21 Module : Main
22 Copyright : Copyright (C) 2006-2015 John MacFarlane
23 License : GNU GPL, version 2 or above
25 Maintainer : John MacFarlane <jgm@berkeley@edu>
26 Stability : alpha
27 Portability : portable
29Parses command-line options and calls the appropriate readers and
30writers.
31-}
32module Main where
33import Text.Pandoc
34import Text.Pandoc.Builder (setMeta)
35import Text.Pandoc.PDF (makePDF)
36import Text.Pandoc.Walk (walk)
37import Text.Pandoc.Readers.LaTeX (handleIncludes)
38import Text.Pandoc.Shared ( tabFilter, readDataFileUTF8, readDataFile,
39 safeRead, headerShift, normalize, err, warn,
40 openURL )
41import Text.Pandoc.MediaBag ( mediaDirectory, extractMediaBag, MediaBag )
42import Text.Pandoc.XML ( toEntities )
43import Text.Pandoc.SelfContained ( makeSelfContained )
44import Text.Pandoc.Process (pipeProcess)
45import Text.Highlighting.Kate ( languages, Style, tango, pygments,
46 espresso, zenburn, kate, haddock, monochrome )
47import System.Environment ( getArgs, getProgName )
48import System.Exit ( exitWith, ExitCode (..) )
49import System.FilePath
50import System.Console.GetOpt
51import Data.Char ( toLower )
52import Data.List ( delete, intercalate, isPrefixOf, isSuffixOf, sort )
53import System.Directory ( getAppUserDataDirectory, findExecutable,
54 doesFileExist, Permissions(..), getPermissions )
55import System.IO ( stdout, stderr )
56import System.IO.Error ( isDoesNotExistError )
57import qualified Control.Exception as E
58import Control.Exception.Extensible ( throwIO )
59import qualified Text.Pandoc.UTF8 as UTF8
60import Control.Monad (when, unless, (>=>))
61import Data.Maybe (fromMaybe, isNothing)
62import Data.Foldable (foldrM)
63import Network.URI (parseURI, isURI, URI(..))
64import qualified Data.ByteString.Lazy as B
65import qualified Data.ByteString as BS
66import Data.Aeson (eitherDecode', encode)
67import qualified Data.Map as M
68import Data.Yaml (decode)
69import qualified Data.Yaml as Yaml
70import qualified Data.Text as T
71import Control.Applicative ((<$>), (<|>))
72import Text.Pandoc.Readers.Txt2Tags (getT2TMeta)
73import Data.Monoid
75import Text.Pandoc.Error
77type Transform = Pandoc -> Pandoc
79copyrightMessage :: String
80copyrightMessage = intercalate "\n" [
81 "",
82 "Copyright (C) 2006-2015 John MacFarlane",
83 "Web: http://pandoc.org",
84 "This is free software; see the source for copying conditions.",
85 "There is no warranty, not even for merchantability or fitness",
86 "for a particular purpose." ]
88compileInfo :: String
89compileInfo =
90 "\nCompiled with texmath " ++
91 VERSION_texmath ++ ", highlighting-kate " ++ VERSION_highlighting_kate ++
92 ".\nSyntax highlighting is supported for the following languages:\n " ++
93 wrapWords 4 78
94 [map toLower l | l <- languages, l /= "Alert" && l /= "Alert_indent"]
96-- | Converts a list of strings into a single string with the items printed as
97-- comma separated words in lines with a maximum line length.
98wrapWords :: Int -> Int -> [String] -> String
99wrapWords indent c = wrap' (c - indent) (c - indent)
100 where
101 wrap' _ _ [] = ""
102 wrap' cols remaining (x:xs)
103 | remaining == cols =
104 x ++ wrap' cols (remaining - length x) xs
105 | (length x + 1) > remaining =
106 ",\n" ++ replicate indent ' ' ++ x ++
107 wrap' cols (cols - length x) xs
108 | otherwise =
109 ", " ++ x ++
110 wrap' cols (remaining - length x - 2) xs
112isTextFormat :: String -> Bool
113isTextFormat s = takeWhile (`notElem` "+-") s `notElem` binaries
114 where binaries = ["odt","docx","epub","epub3"]
116externalFilter :: FilePath -> [String] -> Pandoc -> IO Pandoc
117externalFilter f args' d = do
118 mbexe <- if '/' `elem` f
119 -- don't check PATH if filter name has a path
120 then return Nothing
121 -- we catch isDoesNotExistError because this will
122 -- be triggered if PATH not set:
123 else E.catch (findExecutable f)
124 (\e -> if isDoesNotExistError e
125 then return Nothing
126 else throwIO e)
127 (f', args'') <- case mbexe of
128 Just x -> return (x, args')
129 Nothing -> do
130 exists <- doesFileExist f
131 if exists
132 then do
133 isExecutable <- executable `fmap`
134 getPermissions f
135 return $
136 case map toLower $ takeExtension f of
137 _ | isExecutable -> (f, args')
138 ".py" -> ("python", f:args')
139 ".hs" -> ("runhaskell", f:args')
140 ".pl" -> ("perl", f:args')
141 ".rb" -> ("ruby", f:args')
142 ".php" -> ("php", f:args')
143 _ -> (f, args')
144 else err 85 $ "Filter " ++ f ++ " not found"
145 when (f' /= f) $ do
146 mbExe <- findExecutable f'
147 when (isNothing mbExe) $
148 err 83 $ "Error running filter " ++ f ++ "\n" ++
149 show f' ++ " not found in path."
150 (exitcode, outbs, errbs) <- E.handle filterException $
151 pipeProcess Nothing f' args'' $ encode d
152 when (not $ B.null errbs) $ B.hPutStr stderr errbs
153 case exitcode of
154 ExitSuccess -> return $ either error id $ eitherDecode' outbs
155 ExitFailure ec -> err 83 $ "Error running filter " ++ f ++ "\n" ++
156 "Filter returned error status " ++ show ec
157 where filterException :: E.SomeException -> IO a
158 filterException e = err 83 $ "Error running filter " ++ f ++ "\n" ++
159 show e
161-- | Data structure for command line options.
162data Opt = Opt
163 { optTabStop :: Int -- ^ Number of spaces per tab
164 , optPreserveTabs :: Bool -- ^ Preserve tabs instead of converting to spaces
165 , optStandalone :: Bool -- ^ Include header, footer
166 , optReader :: String -- ^ Reader format
167 , optWriter :: String -- ^ Writer format
168 , optParseRaw :: Bool -- ^ Parse unconvertable HTML and TeX
169 , optTableOfContents :: Bool -- ^ Include table of contents
170 , optTransforms :: [Transform] -- ^ Doc transforms to apply
171 , optTemplate :: Maybe FilePath -- ^ Custom template
172 , optVariables :: [(String,String)] -- ^ Template variables to set
173 , optMetadata :: M.Map String MetaValue -- ^ Metadata fields to set
174 , optOutputFile :: String -- ^ Name of output file
175 , optNumberSections :: Bool -- ^ Number sections in LaTeX
176 , optNumberOffset :: [Int] -- ^ Starting number for sections
177 , optSectionDivs :: Bool -- ^ Put sections in div tags in HTML
178 , optIncremental :: Bool -- ^ Use incremental lists in Slidy/Slideous/S5
179 , optSelfContained :: Bool -- ^ Make HTML accessible offline
180 , optSmart :: Bool -- ^ Use smart typography
181 , optOldDashes :: Bool -- ^ Parse dashes like pandoc <=1.8.2.1
182 , optHtml5 :: Bool -- ^ Produce HTML5 in HTML
183 , optHtmlQTags :: Bool -- ^ Use <q> tags in HTML
184 , optHighlight :: Bool -- ^ Highlight source code
185 , optHighlightStyle :: Style -- ^ Style to use for highlighted code
186 , optChapters :: Bool -- ^ Use chapter for top-level sects
187 , optHTMLMathMethod :: HTMLMathMethod -- ^ Method to print HTML math
188 , optReferenceODT :: Maybe FilePath -- ^ Path of reference.odt
189 , optReferenceDocx :: Maybe FilePath -- ^ Path of reference.docx
190 , optEpubStylesheet :: Maybe String -- ^ EPUB stylesheet
191 , optEpubMetadata :: String -- ^ EPUB metadata
192 , optEpubFonts :: [FilePath] -- ^ EPUB fonts to embed
193 , optEpubChapterLevel :: Int -- ^ Header level at which to split chapters
194 , optTOCDepth :: Int -- ^ Number of levels to include in TOC
195 , optDumpArgs :: Bool -- ^ Output command-line arguments
196 , optIgnoreArgs :: Bool -- ^ Ignore command-line arguments
197 , optVerbose :: Bool -- ^ Verbose diagnostic output
198 , optReferenceLinks :: Bool -- ^ Use reference links in writing markdown, rst
199 , optWrapText :: Bool -- ^ Wrap text
200 , optColumns :: Int -- ^ Line length in characters
201 , optFilters :: [FilePath] -- ^ Filters to apply
202 , optEmailObfuscation :: ObfuscationMethod
203 , optIdentifierPrefix :: String
204 , optIndentedCodeClasses :: [String] -- ^ Default classes for indented code blocks
205 , optDataDir :: Maybe FilePath
206 , optCiteMethod :: CiteMethod -- ^ Method to output cites
207 , optListings :: Bool -- ^ Use listings package for code blocks
208 , optLaTeXEngine :: String -- ^ Program to use for latex -> pdf
209 , optLaTeXEngineArgs :: [String] -- ^ Flags to pass to the latex-engine
210 , optSlideLevel :: Maybe Int -- ^ Header level that creates slides
211 , optSetextHeaders :: Bool -- ^ Use atx headers for markdown level 1-2
212 , optAscii :: Bool -- ^ Use ascii characters only in html
213 , optTeXLigatures :: Bool -- ^ Use TeX ligatures for quotes/dashes
214 , optDefaultImageExtension :: String -- ^ Default image extension
215 , optExtractMedia :: Maybe FilePath -- ^ Path to extract embedded media
216 , optTrace :: Bool -- ^ Print debug information
217 , optTrackChanges :: TrackChanges -- ^ Accept or reject MS Word track-changes.
218 , optKaTeXStylesheet :: Maybe String -- ^ Path to stylesheet for KaTeX
219 , optKaTeXJS :: Maybe String -- ^ Path to js file for KaTeX
220 }
222-- | Defaults for command-line options.
223defaultOpts :: Opt
224defaultOpts = Opt
225 { optTabStop = 4
226 , optPreserveTabs = False
227 , optStandalone = False
228 , optReader = "" -- null for default reader
229 , optWriter = "" -- null for default writer
230 , optParseRaw = False
231 , optTableOfContents = False
232 , optTransforms = []
233 , optTemplate = Nothing
234 , optVariables = []
235 , optMetadata = M.empty
236 , optOutputFile = "-" -- "-" means stdout
237 , optNumberSections = False
238 , optNumberOffset = [0,0,0,0,0,0]
239 , optSectionDivs = False
240 , optIncremental = False
241 , optSelfContained = False
242 , optSmart = False
243 , optOldDashes = False
244 , optHtml5 = False
245 , optHtmlQTags = False
246 , optHighlight = True
247 , optHighlightStyle = pygments
248 , optChapters = False
249 , optHTMLMathMethod = PlainMath
250 , optReferenceODT = Nothing
251 , optReferenceDocx = Nothing
252 , optEpubStylesheet = Nothing
253 , optEpubMetadata = ""
254 , optEpubFonts = []
255 , optEpubChapterLevel = 1
256 , optTOCDepth = 3
257 , optDumpArgs = False
258 , optIgnoreArgs = False
259 , optVerbose = False
260 , optReferenceLinks = False
261 , optWrapText = True
262 , optColumns = 72
263 , optFilters = []
264 , optEmailObfuscation = JavascriptObfuscation
265 , optIdentifierPrefix = ""
266 , optIndentedCodeClasses = []
267 , optDataDir = Nothing
268 , optCiteMethod = Citeproc
269 , optListings = False
270 , optLaTeXEngine = "pdflatex"
271 , optLaTeXEngineArgs = []
272 , optSlideLevel = Nothing
273 , optSetextHeaders = True
274 , optAscii = False
275 , optTeXLigatures = True
276 , optDefaultImageExtension = ""
277 , optExtractMedia = Nothing
278 , optTrace = False
279 , optTrackChanges = AcceptChanges
280 , optKaTeXStylesheet = Nothing
281 , optKaTeXJS = Nothing
282 }
284-- | A list of functions, each transforming the options data structure
285-- in response to a command-line option.
286options :: [OptDescr (Opt -> IO Opt)]
287options =
288 [ Option "fr" ["from","read"]
289 (ReqArg
290 (\arg opt -> return opt { optReader = arg })
291 "FORMAT")
292 ""
294 , Option "tw" ["to","write"]
295 (ReqArg
296 (\arg opt -> return opt { optWriter = arg })
297 "FORMAT")
298 ""
300 , Option "o" ["output"]
301 (ReqArg
302 (\arg opt -> return opt { optOutputFile = arg })
303 "FILENAME")
304 "" -- "Name of output file"
306 , Option "" ["data-dir"]
307 (ReqArg
308 (\arg opt -> return opt { optDataDir = Just arg })
309 "DIRECTORY") -- "Directory containing pandoc data files."
310 ""
312 , Option "" ["strict"]
313 (NoArg
314 (\opt -> do
315 err 59 $ "The --strict option has been removed.\n" ++
316 "Use `markdown_strict' input or output format instead."
317 return opt ))
318 "" -- "Disable markdown syntax extensions"
320 , Option "R" ["parse-raw"]
321 (NoArg
322 (\opt -> return opt { optParseRaw = True }))
323 "" -- "Parse untranslatable HTML codes and LaTeX environments as raw"
325 , Option "S" ["smart"]
326 (NoArg
327 (\opt -> return opt { optSmart = True }))
328 "" -- "Use smart quotes, dashes, and ellipses"
330 , Option "" ["old-dashes"]
331 (NoArg
332 (\opt -> return opt { optSmart = True
333 , optOldDashes = True }))
334 "" -- "Use smart quotes, dashes, and ellipses"
336 , Option "" ["base-header-level"]
337 (ReqArg
338 (\arg opt ->
339 case safeRead arg of
340 Just t | t > 0 -> do
341 let oldTransforms = optTransforms opt
342 let shift = t - 1
343 return opt{ optTransforms =
344 headerShift shift : oldTransforms }
345 _ -> err 19
346 "base-header-level must be a number > 0")
347 "NUMBER")
348 "" -- "Headers base level"
350 , Option "" ["indented-code-classes"]
351 (ReqArg
352 (\arg opt -> return opt { optIndentedCodeClasses = words $
353 map (\c -> if c == ',' then ' ' else c) arg })
354 "STRING")
355 "" -- "Classes (whitespace- or comma-separated) to use for indented code-blocks"
357 , Option "F" ["filter"]
358 (ReqArg
359 (\arg opt -> return opt { optFilters = arg : optFilters opt })
360 "PROGRAM")
361 "" -- "External JSON filter"
363 , Option "" ["normalize"]
364 (NoArg
365 (\opt -> return opt { optTransforms =
366 normalize : optTransforms opt } ))
367 "" -- "Normalize the Pandoc AST"
369 , Option "p" ["preserve-tabs"]
370 (NoArg
371 (\opt -> return opt { optPreserveTabs = True }))
372 "" -- "Preserve tabs instead of converting to spaces"
374 , Option "" ["tab-stop"]
375 (ReqArg
376 (\arg opt ->
377 case safeRead arg of
378 Just t | t > 0 -> return opt { optTabStop = t }
379 _ -> err 31
380 "tab-stop must be a number greater than 0")
381 "NUMBER")
382 "" -- "Tab stop (default 4)"
384 , Option "" ["track-changes"]
385 (ReqArg
386 (\arg opt -> do
387 action <- case arg of
388 "accept" -> return AcceptChanges
389 "reject" -> return RejectChanges
390 "all" -> return AllChanges
391 _ -> err 6
392 ("Unknown option for track-changes: " ++ arg)
393 return opt { optTrackChanges = action })
394 "accept|reject|all")
395 "" -- "Accepting or reject MS Word track-changes.""
397 , Option "" ["extract-media"]
398 (ReqArg
399 (\arg opt -> do
400 return opt { optExtractMedia = Just arg })
401 "PATH")
402 "" -- "Directory to which to extract embedded media"
404 , Option "s" ["standalone"]
405 (NoArg
406 (\opt -> return opt { optStandalone = True }))
407 "" -- "Include needed header and footer on output"
409 , Option "" ["template"]
410 (ReqArg
411 (\arg opt -> do
412 return opt{ optTemplate = Just arg,
413 optStandalone = True })
414 "FILENAME")
415 "" -- "Use custom template"
417 , Option "M" ["metadata"]
418 (ReqArg
419 (\arg opt -> do
420 let (key,val) = case break (`elem` ":=") arg of
421 (k,_:v) -> (k, readMetaValue v)
422 (k,_) -> (k, MetaBool True)
423 return opt{ optMetadata = addMetadata key val
424 $ optMetadata opt })
425 "KEY[:VALUE]")
426 ""
428 , Option "V" ["variable"]
429 (ReqArg
430 (\arg opt -> do
431 let (key,val) = case break (`elem` ":=") arg of
432 (k,_:v) -> (k,v)
433 (k,_) -> (k,"true")
434 return opt{ optVariables = (key,val) : optVariables opt })
435 "KEY[:VALUE]")
436 ""
438 , Option "D" ["print-default-template"]
439 (ReqArg
440 (\arg _ -> do
441 templ <- getDefaultTemplate Nothing arg
442 case templ of
443 Right t -> UTF8.hPutStr stdout t
444 Left e -> error $ show e
445 exitWith ExitSuccess)
446 "FORMAT")
447 "" -- "Print default template for FORMAT"
449 , Option "" ["print-default-data-file"]
450 (ReqArg
451 (\arg _ -> do
452 readDataFile Nothing arg >>= BS.hPutStr stdout
453 exitWith ExitSuccess)
454 "FILE")
455 "" -- "Print default data file"
457 , Option "" ["no-wrap"]
458 (NoArg
459 (\opt -> return opt { optWrapText = False }))
460 "" -- "Do not wrap text in output"
462 , Option "" ["columns"]
463 (ReqArg
464 (\arg opt ->
465 case safeRead arg of
466 Just t | t > 0 -> return opt { optColumns = t }
467 _ -> err 33 $
468 "columns must be a number greater than 0")
469 "NUMBER")
470 "" -- "Length of line in characters"
472 , Option "" ["toc", "table-of-contents"]
473 (NoArg
474 (\opt -> return opt { optTableOfContents = True }))
475 "" -- "Include table of contents"
477 , Option "" ["toc-depth"]
478 (ReqArg
479 (\arg opt -> do
480 case safeRead arg of
481 Just t | t >= 1 && t <= 6 ->
482 return opt { optTOCDepth = t }
483 _ -> err 57 $
484 "TOC level must be a number between 1 and 6")
485 "NUMBER")
486 "" -- "Number of levels to include in TOC"
488 , Option "" ["no-highlight"]
489 (NoArg
490 (\opt -> return opt { optHighlight = False }))
491 "" -- "Don't highlight source code"
493 , Option "" ["highlight-style"]
494 (ReqArg
495 (\arg opt -> do
496 newStyle <- case map toLower arg of
497 "pygments" -> return pygments
498 "tango" -> return tango
499 "espresso" -> return espresso
500 "zenburn" -> return zenburn
501 "kate" -> return kate
502 "monochrome" -> return monochrome
503 "haddock" -> return haddock
504 _ -> err 39 $
505 "Unknown style :" ++ arg
506 return opt{ optHighlightStyle = newStyle })
507 "STYLE")
508 "" -- "Style for highlighted code"
510 , Option "H" ["include-in-header"]
511 (ReqArg
512 (\arg opt -> do
513 text <- UTF8.readFile arg
514 -- add new ones to end, so they're included in order specified
515 let newvars = optVariables opt ++ [("header-includes",text)]
516 return opt { optVariables = newvars,
517 optStandalone = True })
518 "FILENAME")
519 "" -- "File to include at end of header (implies -s)"
521 , Option "B" ["include-before-body"]
522 (ReqArg
523 (\arg opt -> do
524 text <- UTF8.readFile arg
525 -- add new ones to end, so they're included in order specified
526 let newvars = optVariables opt ++ [("include-before",text)]
527 return opt { optVariables = newvars,
528 optStandalone = True })
529 "FILENAME")
530 "" -- "File to include before document body"
532 , Option "A" ["include-after-body"]
533 (ReqArg
534 (\arg opt -> do
535 text <- UTF8.readFile arg
536 -- add new ones to end, so they're included in order specified
537 let newvars = optVariables opt ++ [("include-after",text)]
538 return opt { optVariables = newvars,
539 optStandalone = True })
540 "FILENAME")
541 "" -- "File to include after document body"
543 , Option "" ["self-contained"]
544 (NoArg
545 (\opt -> return opt { optSelfContained = True,
546 optStandalone = True }))
547 "" -- "Make slide shows include all the needed js and css"
549 , Option "" ["offline"]
550 (NoArg
551 (\opt -> do warn $ "--offline is deprecated. Use --self-contained instead."
552 return opt { optSelfContained = True,
553 optStandalone = True }))
554 "" -- "Make slide shows include all the needed js and css"
555 -- deprecated synonym for --self-contained
557 , Option "5" ["html5"]
558 (NoArg
559 (\opt -> do
560 warn $ "--html5 is deprecated. "
561 ++ "Use the html5 output format instead."
562 return opt { optHtml5 = True }))
563 "" -- "Produce HTML5 in HTML output"
565 , Option "" ["html-q-tags"]
566 (NoArg
567 (\opt -> do
568 return opt { optHtmlQTags = True }))
569 "" -- "Use <q> tags for quotes in HTML"
571 , Option "" ["ascii"]
572 (NoArg
573 (\opt -> return opt { optAscii = True }))
574 "" -- "Use ascii characters only in HTML output"
576 , Option "" ["reference-links"]
577 (NoArg
578 (\opt -> return opt { optReferenceLinks = True } ))
579 "" -- "Use reference links in parsing HTML"
581 , Option "" ["atx-headers"]
582 (NoArg
583 (\opt -> return opt { optSetextHeaders = False } ))
584 "" -- "Use atx-style headers for markdown"
586 , Option "" ["chapters"]
587 (NoArg
588 (\opt -> return opt { optChapters = True }))
589 "" -- "Use chapter for top-level sections in LaTeX, DocBook"
591 , Option "N" ["number-sections"]
592 (NoArg
593 (\opt -> return opt { optNumberSections = True }))
594 "" -- "Number sections in LaTeX"
596 , Option "" ["number-offset"]
597 (ReqArg
598 (\arg opt ->
599 case safeRead ('[':arg ++ "]") of
600 Just ns -> return opt { optNumberOffset = ns,
601 optNumberSections = True }
602 _ -> err 57 "could not parse number-offset")
603 "NUMBERS")
604 "" -- "Starting number for sections, subsections, etc."
606 , Option "" ["no-tex-ligatures"]
607 (NoArg
608 (\opt -> return opt { optTeXLigatures = False }))
609 "" -- "Don't use tex ligatures for quotes, dashes"
611 , Option "" ["listings"]
612 (NoArg
613 (\opt -> return opt { optListings = True }))
614 "" -- "Use listings package for LaTeX code blocks"
616 , Option "i" ["incremental"]
617 (NoArg
618 (\opt -> return opt { optIncremental = True }))
619 "" -- "Make list items display incrementally in Slidy/Slideous/S5"
621 , Option "" ["slide-level"]
622 (ReqArg
623 (\arg opt -> do
624 case safeRead arg of
625 Just t | t >= 1 && t <= 6 ->
626 return opt { optSlideLevel = Just t }
627 _ -> err 39 $
628 "slide level must be a number between 1 and 6")
629 "NUMBER")
630 "" -- "Force header level for slides"
632 , Option "" ["section-divs"]
633 (NoArg
634 (\opt -> return opt { optSectionDivs = True }))
635 "" -- "Put sections in div tags in HTML"
637 , Option "" ["default-image-extension"]
638 (ReqArg
639 (\arg opt -> return opt { optDefaultImageExtension = arg })
640 "extension")
641 "" -- "Default extension for extensionless images"
643 , Option "" ["email-obfuscation"]
644 (ReqArg
645 (\arg opt -> do
646 method <- case arg of
647 "references" -> return ReferenceObfuscation
648 "javascript" -> return JavascriptObfuscation
649 "none" -> return NoObfuscation
650 _ -> err 6
651 ("Unknown obfuscation method: " ++ arg)
652 return opt { optEmailObfuscation = method })
653 "none|javascript|references")
654 "" -- "Method for obfuscating email in HTML"
656 , Option "" ["id-prefix"]
657 (ReqArg
658 (\arg opt -> return opt { optIdentifierPrefix = arg })
659 "STRING")
660 "" -- "Prefix to add to automatically generated HTML identifiers"
662 , Option "T" ["title-prefix"]
663 (ReqArg
664 (\arg opt -> do
665 let newvars = ("title-prefix", arg) : optVariables opt
666 return opt { optVariables = newvars,
667 optStandalone = True })
668 "STRING")
669 "" -- "String to prefix to HTML window title"
671 , Option "c" ["css"]
672 (ReqArg
673 (\arg opt -> do
674 -- add new link to end, so it is included in proper order
675 let newvars = optVariables opt ++ [("css",arg)]
676 return opt { optVariables = newvars,
677 optStandalone = True })
678 "URL")
679 "" -- "Link to CSS style sheet"
681 , Option "" ["reference-odt"]
682 (ReqArg
683 (\arg opt -> do
684 return opt { optReferenceODT = Just arg })
685 "FILENAME")
686 "" -- "Path of custom reference.odt"
688 , Option "" ["reference-docx"]
689 (ReqArg
690 (\arg opt -> do
691 return opt { optReferenceDocx = Just arg })
692 "FILENAME")
693 "" -- "Path of custom reference.docx"
695 , Option "" ["epub-stylesheet"]
696 (ReqArg
697 (\arg opt -> do
698 text <- UTF8.readFile arg
699 return opt { optEpubStylesheet = Just text })
700 "FILENAME")
701 "" -- "Path of epub.css"
703 , Option "" ["epub-cover-image"]
704 (ReqArg
705 (\arg opt ->
706 return opt { optVariables =
707 ("epub-cover-image", arg) : optVariables opt })
708 "FILENAME")
709 "" -- "Path of epub cover image"
711 , Option "" ["epub-metadata"]
712 (ReqArg
713 (\arg opt -> do
714 text <- UTF8.readFile arg
715 return opt { optEpubMetadata = text })
716 "FILENAME")
717 "" -- "Path of epub metadata file"
719 , Option "" ["epub-embed-font"]
720 (ReqArg
721 (\arg opt -> do
722 return opt{ optEpubFonts = arg : optEpubFonts opt })
723 "FILE")
724 "" -- "Directory of fonts to embed"
726 , Option "" ["epub-chapter-level"]
727 (ReqArg
728 (\arg opt -> do
729 case safeRead arg of
730 Just t | t >= 1 && t <= 6 ->
731 return opt { optEpubChapterLevel = t }
732 _ -> err 59 $
733 "chapter level must be a number between 1 and 6")
734 "NUMBER")
735 "" -- "Header level at which to split chapters in EPUB"
737 , Option "" ["latex-engine"]
738 (ReqArg
739 (\arg opt -> do
740 let b = takeBaseName arg
741 if b `elem` ["pdflatex", "lualatex", "xelatex"]
742 then return opt { optLaTeXEngine = arg }
743 else err 45 "latex-engine must be pdflatex, lualatex, or xelatex.")
744 "PROGRAM")
745 "" -- "Name of latex program to use in generating PDF"
747 , Option "" ["latex-engine-opt"]
748 (ReqArg
749 (\arg opt -> do
750 let oldArgs = optLaTeXEngineArgs opt
751 return opt { optLaTeXEngineArgs = arg : oldArgs })
752 "STRING")
753 "" -- "Flags to pass to the LaTeX engine, all instances of this option are accumulated and used"
755 , Option "" ["bibliography"]
756 (ReqArg
757 (\arg opt -> return opt{ optMetadata = addMetadata
758 "bibliography" (readMetaValue arg)
759 $ optMetadata opt
760 })
761 "FILE")
762 ""
764 , Option "" ["csl"]
765 (ReqArg
766 (\arg opt ->
767 return opt{ optMetadata = addMetadata "csl"
768 (readMetaValue arg)
769 $ optMetadata opt })
770 "FILE")
771 ""
773 , Option "" ["citation-abbreviations"]
774 (ReqArg
775 (\arg opt ->
776 return opt{ optMetadata = addMetadata
777 "citation-abbreviations"
778 (readMetaValue arg)
779 $ optMetadata opt })
780 "FILE")
781 ""
783 , Option "" ["natbib"]
784 (NoArg
785 (\opt -> return opt { optCiteMethod = Natbib }))
786 "" -- "Use natbib cite commands in LaTeX output"
788 , Option "" ["biblatex"]
789 (NoArg
790 (\opt -> return opt { optCiteMethod = Biblatex }))
791 "" -- "Use biblatex cite commands in LaTeX output"
793 , Option "m" ["latexmathml", "asciimathml"]
794 (OptArg
795 (\arg opt ->
796 return opt { optHTMLMathMethod = LaTeXMathML arg })
797 "URL")
798 "" -- "Use LaTeXMathML script in html output"
800 , Option "" ["mathml"]
801 (OptArg
802 (\arg opt ->
803 return opt { optHTMLMathMethod = MathML arg })
804 "URL")
805 "" -- "Use mathml for HTML math"
807 , Option "" ["mimetex"]
808 (OptArg
809 (\arg opt -> do
810 let url' = case arg of
811 Just u -> u ++ "?"
812 Nothing -> "/cgi-bin/mimetex.cgi?"
813 return opt { optHTMLMathMethod = WebTeX url' })
814 "URL")
815 "" -- "Use mimetex for HTML math"
817 , Option "" ["webtex"]
818 (OptArg
819 (\arg opt -> do
820 let url' = case arg of
821 Just u -> u
822 Nothing -> "http://chart.apis.google.com/chart?cht=tx&chl="
823 return opt { optHTMLMathMethod = WebTeX url' })
824 "URL")
825 "" -- "Use web service for HTML math"
827 , Option "" ["jsmath"]
828 (OptArg
829 (\arg opt -> return opt { optHTMLMathMethod = JsMath arg})
830 "URL")
831 "" -- "Use jsMath for HTML math"
833 , Option "" ["mathjax"]
834 (OptArg
835 (\arg opt -> do
836 let url' = case arg of
837 Just u -> u
838 Nothing -> "https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"
839 return opt { optHTMLMathMethod = MathJax url'})
840 "URL")
841 "" -- "Use MathJax for HTML math"
842 , Option "" ["katex"]
843 (OptArg
844 (\arg opt ->
845 return opt
846 { optKaTeXJS =
847 arg <|> Just "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.1.0/katex.min.js"})
848 "URL")
849 "" -- Use KaTeX for HTML Math
851 , Option "" ["katex-stylesheet"]
852 (ReqArg
853 (\arg opt ->
854 return opt { optKaTeXStylesheet = Just arg })
855 "URL")
856 "" -- Set the KaTeX Stylesheet location
858 , Option "" ["gladtex"]
859 (NoArg
860 (\opt -> return opt { optHTMLMathMethod = GladTeX }))
861 "" -- "Use gladtex for HTML math"
863 , Option "" ["trace"]
864 (NoArg
865 (\opt -> return opt { optTrace = True }))
866 "" -- "Turn on diagnostic tracing in readers."
868 , Option "" ["dump-args"]
869 (NoArg
870 (\opt -> return opt { optDumpArgs = True }))
871 "" -- "Print output filename and arguments to stdout."
873 , Option "" ["ignore-args"]
874 (NoArg
875 (\opt -> return opt { optIgnoreArgs = True }))
876 "" -- "Ignore command-line arguments."
878 , Option "" ["verbose"]
879 (NoArg
880 (\opt -> return opt { optVerbose = True }))
881 "" -- "Verbose diagnostic output."
883 , Option "v" ["version"]
884 (NoArg
885 (\_ -> do
886 prg <- getProgName
887 defaultDatadir <- getAppUserDataDirectory "pandoc"
888 UTF8.hPutStrLn stdout (prg ++ " " ++ pandocVersion ++
889 compileInfo ++ "\nDefault user data directory: " ++
890 defaultDatadir ++ copyrightMessage)
891 exitWith ExitSuccess ))
892 "" -- "Print version"
894 , Option "h" ["help"]
895 (NoArg
896 (\_ -> do
897 prg <- getProgName
898 UTF8.hPutStr stdout (usageMessage prg options)
899 exitWith ExitSuccess ))
900 "" -- "Show help"
902 ]
905addMetadata :: String -> MetaValue -> M.Map String MetaValue
906 -> M.Map String MetaValue
907addMetadata k v m = case M.lookup k m of
908 Nothing -> M.insert k v m
909 Just (MetaList xs) -> M.insert k
910 (MetaList (xs ++ [v])) m
911 Just x -> M.insert k (MetaList [v, x]) m
913readMetaValue :: String -> MetaValue
914readMetaValue s = case decode (UTF8.fromString s) of
915 Just (Yaml.String t) -> MetaString $ T.unpack t
916 Just (Yaml.Bool b) -> MetaBool b
917 _ -> MetaString s
919-- Returns usage message
920usageMessage :: String -> [OptDescr (Opt -> IO Opt)] -> String
921usageMessage programName = usageInfo
922 (programName ++ " [OPTIONS] [FILES]" ++ "\nInput formats: " ++
923 (wrapWords 16 78 $ readers'names) ++
924 '\n' : replicate 16 ' ' ++
925 "[ *only Pandoc's JSON version of native AST]" ++ "\nOutput formats: " ++
926 (wrapWords 16 78 $ writers'names) ++
927 '\n' : replicate 16 ' ' ++
928 "[**for pdf output, use latex or beamer and -o FILENAME.pdf]\nOptions:")
929 where
930 writers'names = sort $ "json*" : "pdf**" : delete "json" (map fst writers)
931 readers'names = sort $ "json*" : delete "json" (map fst readers)
933-- Determine default reader based on source file extensions
934defaultReaderName :: String -> [FilePath] -> String
935defaultReaderName fallback [] = fallback
936defaultReaderName fallback (x:xs) =
937 case takeExtension (map toLower x) of
938 ".xhtml" -> "html"
939 ".html" -> "html"
940 ".htm" -> "html"
941 ".tex" -> "latex"
942 ".latex" -> "latex"
943 ".ltx" -> "latex"
944 ".rst" -> "rst"
945 ".org" -> "org"
946 ".lhs" -> "markdown+lhs"
947 ".db" -> "docbook"
948 ".opml" -> "opml"
949 ".wiki" -> "mediawiki"
950 ".dokuwiki" -> "dokuwiki"
951 ".textile" -> "textile"
952 ".native" -> "native"
953 ".json" -> "json"
954 ".docx" -> "docx"
955 ".t2t" -> "t2t"
956 ".epub" -> "epub"
957 ".odt" -> "odt" -- so we get an "unknown reader" error
958 ".pdf" -> "pdf" -- so we get an "unknown reader" error
959 ".doc" -> "doc" -- so we get an "unknown reader" error
960 _ -> defaultReaderName fallback xs
962-- Returns True if extension of first source is .lhs
963lhsExtension :: [FilePath] -> Bool
964lhsExtension (x:_) = takeExtension x == ".lhs"
965lhsExtension _ = False
967-- Determine default writer based on output file extension
968defaultWriterName :: FilePath -> String
969defaultWriterName "-" = "html" -- no output file
970defaultWriterName x =
971 case takeExtension (map toLower x) of
972 "" -> "markdown" -- empty extension
973 ".tex" -> "latex"
974 ".latex" -> "latex"
975 ".ltx" -> "latex"
976 ".context" -> "context"
977 ".ctx" -> "context"
978 ".rtf" -> "rtf"
979 ".rst" -> "rst"
980 ".s5" -> "s5"
981 ".native" -> "native"
982 ".json" -> "json"
983 ".txt" -> "markdown"
984 ".text" -> "markdown"
985 ".md" -> "markdown"
986 ".markdown" -> "markdown"
987 ".textile" -> "textile"
988 ".lhs" -> "markdown+lhs"
989 ".texi" -> "texinfo"
990 ".texinfo" -> "texinfo"
991 ".db" -> "docbook"
992 ".odt" -> "odt"
993 ".docx" -> "docx"
994 ".epub" -> "epub"
995 ".org" -> "org"
996 ".asciidoc" -> "asciidoc"
997 ".pdf" -> "latex"
998 ".fb2" -> "fb2"
999 ".opml" -> "opml"
1000 ".icml" -> "icml"
1001 ['.',y] | y `elem` ['1'..'9'] -> "man"
1002 _ -> "html"
1004-- Transformations of a Pandoc document post-parsing:
1006extractMedia :: MediaBag -> FilePath -> Pandoc -> IO Pandoc
1007extractMedia media dir d =
1008 case [fp | (fp, _, _) <- mediaDirectory media] of
1009 [] -> return d
1010 fps -> do
1011 extractMediaBag True dir media
1012 return $ walk (adjustImagePath dir fps) d
1014adjustImagePath :: FilePath -> [FilePath] -> Inline -> Inline
1015adjustImagePath dir paths (Image lab (src, tit))
1016 | src `elem` paths = Image lab (dir ++ "/" ++ src, tit)
1017adjustImagePath _ _ x = x
1019adjustMetadata :: M.Map String MetaValue -> Pandoc -> IO Pandoc
1020adjustMetadata metadata d = return $ M.foldWithKey setMeta d metadata
1022applyTransforms :: [Transform] -> Pandoc -> IO Pandoc
1023applyTransforms transforms d = return $ foldr ($) d transforms
1025applyFilters :: [FilePath] -> [String] -> Pandoc -> IO Pandoc
1026applyFilters filters args d =
1027 foldrM ($) d $ map (flip externalFilter args) filters
1029main :: IO ()
1030main = do
1032 rawArgs <- map UTF8.decodeArg <$> getArgs
1033 prg <- getProgName
1034 let compatMode = (prg == "hsmarkdown")
1036 let (actions, args, errors) = if compatMode
1037 then ([], rawArgs, [])
1038 else getOpt Permute options rawArgs
1040 unless (null errors) $
1041 err 2 $ concat $ errors ++
1042 ["Try " ++ prg ++ " --help for more information."]
1044 let defaultOpts' = if compatMode
1045 then defaultOpts { optReader = "markdown_strict"
1046 , optWriter = "html"
1047 , optEmailObfuscation =
1048 ReferenceObfuscation }
1049 else defaultOpts
1051 -- thread option data structure through all supplied option actions
1052 opts <- foldl (>>=) (return defaultOpts') actions
1054 let Opt { optTabStop = tabStop
1055 , optPreserveTabs = preserveTabs
1056 , optStandalone = standalone
1057 , optReader = readerName
1058 , optWriter = writerName
1059 , optParseRaw = parseRaw
1060 , optVariables = variables
1061 , optMetadata = metadata
1062 , optTableOfContents = toc
1063 , optTransforms = transforms
1064 , optTemplate = templatePath
1065 , optOutputFile = outputFile
1066 , optNumberSections = numberSections
1067 , optNumberOffset = numberFrom
1068 , optSectionDivs = sectionDivs
1069 , optIncremental = incremental
1070 , optSelfContained = selfContained
1071 , optSmart = smart
1072 , optOldDashes = oldDashes
1073 , optHtml5 = html5
1074 , optHtmlQTags = htmlQTags
1075 , optHighlight = highlight
1076 , optHighlightStyle = highlightStyle
1077 , optChapters = chapters
1078 , optHTMLMathMethod = mathMethod'
1079 , optReferenceODT = referenceODT
1080 , optReferenceDocx = referenceDocx
1081 , optEpubStylesheet = epubStylesheet
1082 , optEpubMetadata = epubMetadata
1083 , optEpubFonts = epubFonts
1084 , optEpubChapterLevel = epubChapterLevel
1085 , optTOCDepth = epubTOCDepth
1086 , optDumpArgs = dumpArgs
1087 , optIgnoreArgs = ignoreArgs
1088 , optVerbose = verbose
1089 , optReferenceLinks = referenceLinks
1090 , optWrapText = wrap
1091 , optColumns = columns
1092 , optFilters = filters
1093 , optEmailObfuscation = obfuscationMethod
1094 , optIdentifierPrefix = idPrefix
1095 , optIndentedCodeClasses = codeBlockClasses
1096 , optDataDir = mbDataDir
1097 , optCiteMethod = citeMethod
1098 , optListings = listings
1099 , optLaTeXEngine = latexEngine
1100 , optLaTeXEngineArgs = latexEngineArgs
1101 , optSlideLevel = slideLevel
1102 , optSetextHeaders = setextHeaders
1103 , optAscii = ascii
1104 , optTeXLigatures = texLigatures
1105 , optDefaultImageExtension = defaultImageExtension
1106 , optExtractMedia = mbExtractMedia
1107 , optTrace = trace
1108 , optTrackChanges = trackChanges
1109 , optKaTeXStylesheet = katexStylesheet
1110 , optKaTeXJS = katexJS
1111 } = opts
1113 when dumpArgs $
1114 do UTF8.hPutStrLn stdout outputFile
1115 mapM_ (\arg -> UTF8.hPutStrLn stdout arg) args
1116 exitWith ExitSuccess
1118 let csscdn = "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.1.0/katex.min.css"
1119 let mathMethod =
1120 case (katexJS, katexStylesheet) of
1121 (Nothing, _) -> mathMethod'
1122 (Just js, ss) -> KaTeX js (fromMaybe csscdn ss)
1125 -- --bibliography implies -F pandoc-citeproc for backwards compatibility:
1126 let needsCiteproc = any ("--bibliography" `isPrefixOf`) rawArgs &&
1127 optCiteMethod opts `notElem` [Natbib, Biblatex] &&
1128 "pandoc-citeproc" `notElem` map takeBaseName filters
1129 let filters' = if needsCiteproc then "pandoc-citeproc" : filters
1130 else filters
1132 let sources = if ignoreArgs then [] else args
1134 datadir <- case mbDataDir of
1135 Nothing -> E.catch
1136 (Just <$> getAppUserDataDirectory "pandoc")
1137 (\e -> let _ = (e :: E.SomeException)
1138 in return Nothing)
1139 Just _ -> return mbDataDir
1141 -- assign reader and writer based on options and filenames
1142 let readerName' = case map toLower readerName of
1143 [] -> defaultReaderName
1144 (if any isURI sources
1145 then "html"
1146 else "markdown") sources
1147 "html4" -> "html"
1148 x -> x
1150 let writerName' = case map toLower writerName of
1151 [] -> defaultWriterName outputFile
1152 "epub2" -> "epub"
1153 "html4" -> "html"
1154 x -> x
1156 let pdfOutput = map toLower (takeExtension outputFile) == ".pdf"
1158 let laTeXOutput = "latex" `isPrefixOf` writerName' ||
1159 "beamer" `isPrefixOf` writerName'
1161 writer <- if ".lua" `isSuffixOf` writerName'
1162 -- note: use non-lowercased version writerName
1163 then return $ IOStringWriter $ writeCustom writerName
1164 else case getWriter writerName' of
1165 Left e -> err 9 $
1166 if writerName' == "pdf"
1167 then e ++
1168 "\nTo create a pdf with pandoc, use " ++
1169 "the latex or beamer writer and specify\n" ++
1170 "an output file with .pdf extension " ++
1171 "(pandoc -t latex -o filename.pdf)."
1172 else e
1173 Right w -> return w
1175 reader <- if "t2t" == readerName'
1176 then (mkStringReader .
1177 readTxt2Tags) <$>
1178 (getT2TMeta sources outputFile)
1179 else case getReader readerName' of
1180 Right r -> return r
1181 Left e -> err 7 e'
1182 where e' = case readerName' of
1183 "odt" -> e ++
1184 "\nPandoc can convert to ODT, but not from ODT.\nTry using LibreOffice to export as HTML, and convert that with pandoc."
1185 "pdf" -> e ++
1186 "\nPandoc can convert to PDF, but not from PDF."
1187 "doc" -> e ++
1188 "\nPandoc can convert from DOCX, but not from DOC.\nTry using Word to save your DOC file as DOCX, and convert that with pandoc."
1189 _ -> e
1191 let standalone' = standalone || not (isTextFormat writerName') || pdfOutput
1193 templ <- case templatePath of
1194 _ | not standalone' -> return ""
1195 Nothing -> do
1196 deftemp <- getDefaultTemplate datadir writerName'
1197 case deftemp of
1198 Left e -> throwIO e
1199 Right t -> return t
1200 Just tp -> do
1201 -- strip off extensions
1202 let format = takeWhile (`notElem` "+-") writerName'
1203 let tp' = case takeExtension tp of
1204 "" -> tp <.> format
1205 _ -> tp
1206 E.catch (UTF8.readFile tp')
1207 (\e -> if isDoesNotExistError e
1208 then E.catch
1209 (readDataFileUTF8 datadir
1210 ("templates" </> tp'))
1211 (\e' -> let _ = (e' :: E.SomeException)
1212 in throwIO e')
1213 else throwIO e)
1215 variables' <- case mathMethod of
1216 LaTeXMathML Nothing -> do
1217 s <- readDataFileUTF8 datadir "LaTeXMathML.js"
1218 return $ ("mathml-script", s) : variables
1219 MathML Nothing -> do
1220 s <- readDataFileUTF8 datadir "MathMLinHTML.js"
1221 return $ ("mathml-script", s) : variables
1222 _ -> return variables
1224 variables'' <- if "dzslides" `isPrefixOf` writerName'
1225 then do
1226 dztempl <- readDataFileUTF8 datadir
1227 ("dzslides" </> "template.html")
1228 let dzline = "<!-- {{{{ dzslides core"
1229 let dzcore = unlines
1230 $ dropWhile (not . (dzline `isPrefixOf`))
1231 $ lines dztempl
1232 return $ ("dzslides-core", dzcore) : variables'
1233 else return variables'
1235 let sourceURL = case sources of
1236 [] -> Nothing
1237 (x:_) -> case parseURI x of
1238 Just u
1239 | uriScheme u `elem` ["http:","https:"] ->
1240 Just $ show u{ uriQuery = "",
1241 uriFragment = "" }
1242 _ -> Nothing
1244 let readerOpts = def{ readerSmart = smart || (texLigatures &&
1245 (laTeXOutput || "context" `isPrefixOf` writerName'))
1246 , readerStandalone = standalone'
1247 , readerParseRaw = parseRaw
1248 , readerColumns = columns
1249 , readerTabStop = tabStop
1250 , readerOldDashes = oldDashes
1251 , readerIndentedCodeClasses = codeBlockClasses
1252 , readerApplyMacros = not laTeXOutput
1253 , readerDefaultImageExtension = defaultImageExtension
1254 , readerTrace = trace
1255 , readerTrackChanges = trackChanges
1258 when (not (isTextFormat writerName') && outputFile == "-") $
1259 err 5 $ "Cannot write " ++ writerName' ++ " output to stdout.\n" ++
1260 "Specify an output file using the -o option."
1262 let readSources [] = mapM readSource ["-"]
1263 readSources srcs = mapM readSource srcs
1264 readSource "-" = UTF8.getContents
1265 readSource src = case parseURI src of
1266 Just u | uriScheme u `elem` ["http:","https:"] ->
1267 readURI src
1268 _ -> UTF8.readFile src
1269 readURI src = do
1270 res <- openURL src
1271 case res of
1272 Left e -> throwIO e
1273 Right (bs,_) -> return $ UTF8.toString bs
1275 let readFiles [] = error "Cannot read archive from stdin"
1276 readFiles [x] = B.readFile x
1277 readFiles (x:xs) = mapM (warn . ("Ignoring: " ++)) xs >> B.readFile x
1279 let convertTabs = tabFilter (if preserveTabs || readerName' == "t2t"
1280 then 0
1281 else tabStop)
1283 let handleIncludes' :: String -> IO (Either PandocError String)
1284 handleIncludes' = if readerName' `elem` ["latex", "latex+lhs"]
1285 then handleIncludes
1286 else return . Right
1288 (doc, media) <- fmap handleError $
1289 case reader of
1290 StringReader r-> do
1291 srcs <- convertTabs . intercalate "\n" <$> readSources sources
1292 doc <- handleIncludes' srcs
1293 either (return . Left) (\s -> fmap (,mempty) <$> r readerOpts s) doc
1294 ByteStringReader r -> readFiles sources >>= r readerOpts
1296 let writerOptions = def { writerStandalone = standalone',
1297 writerTemplate = templ,
1298 writerVariables = variables'',
1299 writerTabStop = tabStop,
1300 writerTableOfContents = toc,
1301 writerHTMLMathMethod = mathMethod,
1302 writerIncremental = incremental,
1303 writerCiteMethod = citeMethod,
1304 writerIgnoreNotes = False,
1305 writerNumberSections = numberSections,
1306 writerNumberOffset = numberFrom,
1307 writerSectionDivs = sectionDivs,
1308 writerReferenceLinks = referenceLinks,
1309 writerWrapText = wrap,
1310 writerColumns = columns,
1311 writerEmailObfuscation = obfuscationMethod,
1312 writerIdentifierPrefix = idPrefix,
1313 writerSourceURL = sourceURL,
1314 writerUserDataDir = datadir,
1315 writerHtml5 = html5,
1316 writerHtmlQTags = htmlQTags,
1317 writerChapters = chapters,
1318 writerListings = listings,
1319 writerBeamer = False,
1320 writerSlideLevel = slideLevel,
1321 writerHighlight = highlight,
1322 writerHighlightStyle = highlightStyle,
1323 writerSetextHeaders = setextHeaders,
1324 writerTeXLigatures = texLigatures,
1325 writerEpubMetadata = epubMetadata,
1326 writerEpubStylesheet = epubStylesheet,
1327 writerEpubFonts = epubFonts,
1328 writerEpubChapterLevel = epubChapterLevel,
1329 writerTOCDepth = epubTOCDepth,
1330 writerReferenceODT = referenceODT,
1331 writerReferenceDocx = referenceDocx,
1332 writerMediaBag = media,
1333 writerVerbose = verbose,
1334 writerLaTeXArgs = latexEngineArgs
1338 doc' <- (maybe return (extractMedia media) mbExtractMedia >=>
1339 adjustMetadata metadata >=>
1340 applyTransforms transforms >=>
1341 applyFilters filters' [writerName']) doc
1343 let writeBinary :: B.ByteString -> IO ()
1344 writeBinary = B.writeFile (UTF8.encodePath outputFile)
1346 let writerFn :: FilePath -> String -> IO ()
1347 writerFn "-" = UTF8.putStr
1348 writerFn f = UTF8.writeFile f
1350 case writer of
1351 IOStringWriter f -> f writerOptions doc' >>= writerFn outputFile
1352 IOByteStringWriter f -> f writerOptions doc' >>= writeBinary
1353 PureStringWriter f
1354 | pdfOutput -> do
1355 -- make sure writer is latex or beamer
1356 unless laTeXOutput $
1357 err 47 $ "cannot produce pdf output with " ++ writerName' ++
1358 " writer"
1360 -- check for latex program
1361 mbLatex <- findExecutable latexEngine
1362 when (mbLatex == Nothing) $
1363 err 41 $ latexEngine ++ " not found. " ++
1364 latexEngine ++ " is needed for pdf output."
1366 res <- makePDF latexEngine f writerOptions doc'
1367 case res of
1368 Right pdf -> writeBinary pdf
1369 Left err' -> do
1370 B.hPutStr stderr $ err'
1371 B.hPut stderr $ B.pack [10]
1372 err 43 "Error producing PDF from TeX source"
1373 | otherwise -> selfcontain (f writerOptions doc' ++
1374 ['\n' | not standalone'])
1375 >>= writerFn outputFile . handleEntities
1376 where htmlFormat = writerName' `elem`
1377 ["html","html+lhs","html5","html5+lhs",
1378 "s5","slidy","slideous","dzslides","revealjs"]
1379 selfcontain = if selfContained && htmlFormat
1380 then makeSelfContained writerOptions
1381 else return
1382 handleEntities = if htmlFormat && ascii
1383 then toEntities
1384 else id