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