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