git.iko.soy/typeable/pandoc
on 1.17.1 help sign in
typeable/pandoc/pandoc.hs
1426 lines 62 kB history raw
1{-# LANGUAGE CPP, TupleSections, ScopedTypeVariables #-}
2{-
3Copyright (C) 2006-2016 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-2016 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 ( ExitCode (..), exitSuccess )
49import System.FilePath
50import System.Console.GetOpt
51import Data.Char ( toLower, toUpper )
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, isJust)
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 Paths_pandoc (getDataDir)
74import Text.Printf (printf)
75import Text.Pandoc.Error
77type Transform = Pandoc -> Pandoc
79copyrightMessage :: String
80copyrightMessage = intercalate "\n" [
81 "",
82 "Copyright (C) 2006-2016 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 = s `notElem` ["odt","docx","epub","epub3"]
115externalFilter :: FilePath -> [String] -> Pandoc -> IO Pandoc
116externalFilter f args' d = do
117 mbexe <- if '/' `elem` f
118 -- don't check PATH if filter name has a path
119 then return Nothing
120 -- we catch isDoesNotExistError because this will
121 -- be triggered if PATH not set:
122 else E.catch (findExecutable f)
123 (\e -> if isDoesNotExistError e
124 then return Nothing
125 else throwIO e)
126 (f', args'') <- case mbexe of
127 Just x -> return (x, args')
128 Nothing -> do
129 exists <- doesFileExist f
130 if exists
131 then do
132 isExecutable <- executable `fmap`
133 getPermissions f
134 return $
135 case map toLower $ takeExtension f of
136 _ | isExecutable -> (f, args')
137 ".py" -> ("python", f:args')
138 ".hs" -> ("runhaskell", f:args')
139 ".pl" -> ("perl", f:args')
140 ".rb" -> ("ruby", f:args')
141 ".php" -> ("php", f:args')
142 _ -> (f, args')
143 else err 85 $ "Filter " ++ f ++ " not found"
144 when (f' /= f) $ do
145 mbExe <- findExecutable f'
146 when (isNothing mbExe) $
147 err 83 $ "Error running filter " ++ f ++ "\n" ++
148 show f' ++ " not found in path."
149 (exitcode, outbs, errbs) <- E.handle filterException $
150 pipeProcess Nothing f' args'' $ encode d
151 unless (B.null errbs) $ B.hPutStr stderr errbs
152 case exitcode of
153 ExitSuccess -> return $ either error id $ eitherDecode' outbs
154 ExitFailure ec -> err 83 $ "Error running filter " ++ f ++ "\n" ++
155 "Filter returned error status " ++ show ec
156 where filterException :: E.SomeException -> IO a
157 filterException e = err 83 $ "Error running filter " ++ f ++ "\n" ++
158 show e
160-- | Data structure for command line options.
161data Opt = Opt
162 { optTabStop :: Int -- ^ Number of spaces per tab
163 , optPreserveTabs :: Bool -- ^ Preserve tabs instead of converting to spaces
164 , optStandalone :: Bool -- ^ Include header, footer
165 , optReader :: String -- ^ Reader format
166 , optWriter :: String -- ^ Writer format
167 , optParseRaw :: Bool -- ^ Parse unconvertable HTML and TeX
168 , optTableOfContents :: Bool -- ^ Include table of contents
169 , optTransforms :: [Transform] -- ^ Doc transforms to apply
170 , optTemplate :: Maybe FilePath -- ^ Custom template
171 , optVariables :: [(String,String)] -- ^ Template variables to set
172 , optMetadata :: M.Map String MetaValue -- ^ Metadata fields to set
173 , optOutputFile :: String -- ^ Name of output file
174 , optNumberSections :: Bool -- ^ Number sections in LaTeX
175 , optNumberOffset :: [Int] -- ^ Starting number for sections
176 , optSectionDivs :: Bool -- ^ Put sections in div tags in HTML
177 , optIncremental :: Bool -- ^ Use incremental lists in Slidy/Slideous/S5
178 , optSelfContained :: Bool -- ^ Make HTML accessible offline
179 , optSmart :: Bool -- ^ Use smart typography
180 , optOldDashes :: Bool -- ^ Parse dashes like pandoc <=1.8.2.1
181 , optHtml5 :: Bool -- ^ Produce HTML5 in HTML
182 , optHtmlQTags :: Bool -- ^ Use <q> tags in HTML
183 , optHighlight :: Bool -- ^ Highlight source code
184 , optHighlightStyle :: Style -- ^ Style to use for highlighted code
185 , optChapters :: Bool -- ^ Use chapter for top-level sects
186 , optHTMLMathMethod :: HTMLMathMethod -- ^ Method to print HTML math
187 , optReferenceODT :: Maybe FilePath -- ^ Path of reference.odt
188 , optReferenceDocx :: Maybe FilePath -- ^ Path of reference.docx
189 , optEpubStylesheet :: Maybe String -- ^ EPUB stylesheet
190 , optEpubMetadata :: String -- ^ EPUB metadata
191 , optEpubFonts :: [FilePath] -- ^ EPUB fonts to embed
192 , optEpubChapterLevel :: Int -- ^ Header level at which to split chapters
193 , optTOCDepth :: Int -- ^ Number of levels to include in TOC
194 , optDumpArgs :: Bool -- ^ Output command-line arguments
195 , optIgnoreArgs :: Bool -- ^ Ignore command-line arguments
196 , optVerbose :: Bool -- ^ Verbose diagnostic output
197 , optReferenceLinks :: Bool -- ^ Use reference links in writing markdown, rst
198 , optDpi :: Int -- ^ Dpi
199 , optWrapText :: WrapOption -- ^ Options for wrapping 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 , optFileScope :: Bool -- ^ Parse input files before combining
219 , optKaTeXStylesheet :: Maybe String -- ^ Path to stylesheet for KaTeX
220 , optKaTeXJS :: Maybe String -- ^ Path to js file for KaTeX
221 }
223-- | Defaults for command-line options.
224defaultOpts :: Opt
225defaultOpts = Opt
226 { optTabStop = 4
227 , optPreserveTabs = False
228 , optStandalone = False
229 , optReader = "" -- null for default reader
230 , optWriter = "" -- null for default writer
231 , optParseRaw = False
232 , optTableOfContents = False
233 , optTransforms = []
234 , optTemplate = Nothing
235 , optVariables = []
236 , optMetadata = M.empty
237 , optOutputFile = "-" -- "-" means stdout
238 , optNumberSections = False
239 , optNumberOffset = [0,0,0,0,0,0]
240 , optSectionDivs = False
241 , optIncremental = False
242 , optSelfContained = False
243 , optSmart = False
244 , optOldDashes = False
245 , optHtml5 = False
246 , optHtmlQTags = False
247 , optHighlight = True
248 , optHighlightStyle = pygments
249 , optChapters = False
250 , optHTMLMathMethod = PlainMath
251 , optReferenceODT = Nothing
252 , optReferenceDocx = Nothing
253 , optEpubStylesheet = Nothing
254 , optEpubMetadata = ""
255 , optEpubFonts = []
256 , optEpubChapterLevel = 1
257 , optTOCDepth = 3
258 , optDumpArgs = False
259 , optIgnoreArgs = False
260 , optVerbose = False
261 , optReferenceLinks = False
262 , optDpi = 96
263 , optWrapText = WrapAuto
264 , optColumns = 72
265 , optFilters = []
266 , optEmailObfuscation = JavascriptObfuscation
267 , optIdentifierPrefix = ""
268 , optIndentedCodeClasses = []
269 , optDataDir = Nothing
270 , optCiteMethod = Citeproc
271 , optListings = False
272 , optLaTeXEngine = "pdflatex"
273 , optLaTeXEngineArgs = []
274 , optSlideLevel = Nothing
275 , optSetextHeaders = True
276 , optAscii = False
277 , optTeXLigatures = True
278 , optDefaultImageExtension = ""
279 , optExtractMedia = Nothing
280 , optTrace = False
281 , optTrackChanges = AcceptChanges
282 , optFileScope = False
283 , optKaTeXStylesheet = Nothing
284 , optKaTeXJS = Nothing
285 }
287-- | A list of functions, each transforming the options data structure
288-- in response to a command-line option.
289options :: [OptDescr (Opt -> IO Opt)]
290options =
291 [ Option "fr" ["from","read"]
292 (ReqArg
293 (\arg opt -> return opt { optReader = arg })
294 "FORMAT")
295 ""
297 , Option "tw" ["to","write"]
298 (ReqArg
299 (\arg opt -> return opt { optWriter = arg })
300 "FORMAT")
301 ""
303 , Option "o" ["output"]
304 (ReqArg
305 (\arg opt -> return opt { optOutputFile = arg })
306 "FILENAME")
307 "" -- "Name of output file"
309 , Option "" ["data-dir"]
310 (ReqArg
311 (\arg opt -> return opt { optDataDir = Just arg })
312 "DIRECTORY") -- "Directory containing pandoc data files."
313 ""
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 "" ["file-scope"]
393 (NoArg
394 (\opt -> return opt { optFileScope = True }))
395 "" -- "Parse input files before combining"
397 , Option "" ["extract-media"]
398 (ReqArg
399 (\arg opt ->
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 ->
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 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 exitSuccess)
454 "FILE")
455 "" -- "Print default data file"
457 , Option "" ["dpi"]
458 (ReqArg
459 (\arg opt ->
460 case safeRead arg of
461 Just t | t > 0 -> return opt { optDpi = t }
462 _ -> err 31
463 "dpi must be a number greater than 0")
464 "NUMBER")
465 "" -- "Dpi (default 96)"
467 , Option "" ["no-wrap"]
468 (NoArg
469 (\opt -> do warn $ "--no-wrap is deprecated. " ++
470 "Use --wrap=none or --wrap=preserve instead."
471 return opt { optWrapText = WrapNone }))
472 ""
474 , Option "" ["wrap"]
475 (ReqArg
476 (\arg opt ->
477 case safeRead ("Wrap" ++ uppercaseFirstLetter arg) of
478 Just o -> return opt { optWrapText = o }
479 Nothing -> err 77 "--wrap must be auto, none, or preserve")
480 "[auto|none|preserve]")
481 "" -- "Option for wrapping text in output"
483 , Option "" ["columns"]
484 (ReqArg
485 (\arg opt ->
486 case safeRead arg of
487 Just t | t > 0 -> return opt { optColumns = t }
488 _ -> err 33
489 "columns must be a number greater than 0")
490 "NUMBER")
491 "" -- "Length of line in characters"
493 , Option "" ["toc", "table-of-contents"]
494 (NoArg
495 (\opt -> return opt { optTableOfContents = True }))
496 "" -- "Include table of contents"
498 , Option "" ["toc-depth"]
499 (ReqArg
500 (\arg opt ->
501 case safeRead arg of
502 Just t | t >= 1 && t <= 6 ->
503 return opt { optTOCDepth = t }
504 _ -> err 57
505 "TOC level must be a number between 1 and 6")
506 "NUMBER")
507 "" -- "Number of levels to include in TOC"
509 , Option "" ["no-highlight"]
510 (NoArg
511 (\opt -> return opt { optHighlight = False }))
512 "" -- "Don't highlight source code"
514 , Option "" ["highlight-style"]
515 (ReqArg
516 (\arg opt -> do
517 newStyle <- case map toLower arg of
518 "pygments" -> return pygments
519 "tango" -> return tango
520 "espresso" -> return espresso
521 "zenburn" -> return zenburn
522 "kate" -> return kate
523 "monochrome" -> return monochrome
524 "haddock" -> return haddock
525 _ -> err 39 $
526 "Unknown style :" ++ arg
527 return opt{ optHighlightStyle = newStyle })
528 "STYLE")
529 "" -- "Style for highlighted code"
531 , Option "H" ["include-in-header"]
532 (ReqArg
533 (\arg opt -> do
534 text <- UTF8.readFile arg
535 -- add new ones to end, so they're included in order specified
536 let newvars = optVariables opt ++ [("header-includes",text)]
537 return opt { optVariables = newvars,
538 optStandalone = True })
539 "FILENAME")
540 "" -- "File to include at end of header (implies -s)"
542 , Option "B" ["include-before-body"]
543 (ReqArg
544 (\arg opt -> do
545 text <- UTF8.readFile arg
546 -- add new ones to end, so they're included in order specified
547 let newvars = optVariables opt ++ [("include-before",text)]
548 return opt { optVariables = newvars,
549 optStandalone = True })
550 "FILENAME")
551 "" -- "File to include before document body"
553 , Option "A" ["include-after-body"]
554 (ReqArg
555 (\arg opt -> do
556 text <- UTF8.readFile arg
557 -- add new ones to end, so they're included in order specified
558 let newvars = optVariables opt ++ [("include-after",text)]
559 return opt { optVariables = newvars,
560 optStandalone = True })
561 "FILENAME")
562 "" -- "File to include after document body"
564 , Option "" ["self-contained"]
565 (NoArg
566 (\opt -> return opt { optSelfContained = True,
567 optStandalone = True }))
568 "" -- "Make slide shows include all the needed js and css"
570 , Option "" ["html-q-tags"]
571 (NoArg
572 (\opt ->
573 return opt { optHtmlQTags = True }))
574 "" -- "Use <q> tags for quotes in HTML"
576 , Option "" ["ascii"]
577 (NoArg
578 (\opt -> return opt { optAscii = True }))
579 "" -- "Use ascii characters only in HTML output"
581 , Option "" ["reference-links"]
582 (NoArg
583 (\opt -> return opt { optReferenceLinks = True } ))
584 "" -- "Use reference links in parsing HTML"
586 , Option "" ["atx-headers"]
587 (NoArg
588 (\opt -> return opt { optSetextHeaders = False } ))
589 "" -- "Use atx-style headers for markdown"
591 , Option "" ["chapters"]
592 (NoArg
593 (\opt -> return opt { optChapters = True }))
594 "" -- "Use chapter for top-level sections in LaTeX, DocBook"
596 , Option "N" ["number-sections"]
597 (NoArg
598 (\opt -> return opt { optNumberSections = True }))
599 "" -- "Number sections in LaTeX"
601 , Option "" ["number-offset"]
602 (ReqArg
603 (\arg opt ->
604 case safeRead ('[':arg ++ "]") of
605 Just ns -> return opt { optNumberOffset = ns,
606 optNumberSections = True }
607 _ -> err 57 "could not parse number-offset")
608 "NUMBERS")
609 "" -- "Starting number for sections, subsections, etc."
611 , Option "" ["no-tex-ligatures"]
612 (NoArg
613 (\opt -> return opt { optTeXLigatures = False }))
614 "" -- "Don't use tex ligatures for quotes, dashes"
616 , Option "" ["listings"]
617 (NoArg
618 (\opt -> return opt { optListings = True }))
619 "" -- "Use listings package for LaTeX code blocks"
621 , Option "i" ["incremental"]
622 (NoArg
623 (\opt -> return opt { optIncremental = True }))
624 "" -- "Make list items display incrementally in Slidy/Slideous/S5"
626 , Option "" ["slide-level"]
627 (ReqArg
628 (\arg opt ->
629 case safeRead arg of
630 Just t | t >= 1 && t <= 6 ->
631 return opt { optSlideLevel = Just t }
632 _ -> err 39
633 "slide level must be a number between 1 and 6")
634 "NUMBER")
635 "" -- "Force header level for slides"
637 , Option "" ["section-divs"]
638 (NoArg
639 (\opt -> return opt { optSectionDivs = True }))
640 "" -- "Put sections in div tags in HTML"
642 , Option "" ["default-image-extension"]
643 (ReqArg
644 (\arg opt -> return opt { optDefaultImageExtension = arg })
645 "extension")
646 "" -- "Default extension for extensionless images"
648 , Option "" ["email-obfuscation"]
649 (ReqArg
650 (\arg opt -> do
651 method <- case arg of
652 "references" -> return ReferenceObfuscation
653 "javascript" -> return JavascriptObfuscation
654 "none" -> return NoObfuscation
655 _ -> err 6
656 ("Unknown obfuscation method: " ++ arg)
657 return opt { optEmailObfuscation = method })
658 "none|javascript|references")
659 "" -- "Method for obfuscating email in HTML"
661 , Option "" ["id-prefix"]
662 (ReqArg
663 (\arg opt -> return opt { optIdentifierPrefix = arg })
664 "STRING")
665 "" -- "Prefix to add to automatically generated HTML identifiers"
667 , Option "T" ["title-prefix"]
668 (ReqArg
669 (\arg opt -> do
670 let newvars = ("title-prefix", arg) : optVariables opt
671 return opt { optVariables = newvars,
672 optStandalone = True })
673 "STRING")
674 "" -- "String to prefix to HTML window title"
676 , Option "c" ["css"]
677 (ReqArg
678 (\arg opt -> do
679 -- add new link to end, so it is included in proper order
680 let newvars = optVariables opt ++ [("css",arg)]
681 return opt { optVariables = newvars,
682 optStandalone = True })
683 "URL")
684 "" -- "Link to CSS style sheet"
686 , Option "" ["reference-odt"]
687 (ReqArg
688 (\arg opt ->
689 return opt { optReferenceODT = Just arg })
690 "FILENAME")
691 "" -- "Path of custom reference.odt"
693 , Option "" ["reference-docx"]
694 (ReqArg
695 (\arg opt ->
696 return opt { optReferenceDocx = Just arg })
697 "FILENAME")
698 "" -- "Path of custom reference.docx"
700 , Option "" ["epub-stylesheet"]
701 (ReqArg
702 (\arg opt -> do
703 text <- UTF8.readFile arg
704 return opt { optEpubStylesheet = Just text })
705 "FILENAME")
706 "" -- "Path of epub.css"
708 , Option "" ["epub-cover-image"]
709 (ReqArg
710 (\arg opt ->
711 return opt { optVariables =
712 ("epub-cover-image", arg) : optVariables opt })
713 "FILENAME")
714 "" -- "Path of epub cover image"
716 , Option "" ["epub-metadata"]
717 (ReqArg
718 (\arg opt -> do
719 text <- UTF8.readFile arg
720 return opt { optEpubMetadata = text })
721 "FILENAME")
722 "" -- "Path of epub metadata file"
724 , Option "" ["epub-embed-font"]
725 (ReqArg
726 (\arg opt ->
727 return opt{ optEpubFonts = arg : optEpubFonts opt })
728 "FILE")
729 "" -- "Directory of fonts to embed"
731 , Option "" ["epub-chapter-level"]
732 (ReqArg
733 (\arg opt ->
734 case safeRead arg of
735 Just t | t >= 1 && t <= 6 ->
736 return opt { optEpubChapterLevel = t }
737 _ -> err 59
738 "chapter level must be a number between 1 and 6")
739 "NUMBER")
740 "" -- "Header level at which to split chapters in EPUB"
742 , Option "" ["latex-engine"]
743 (ReqArg
744 (\arg opt -> do
745 let b = takeBaseName arg
746 if b `elem` ["pdflatex", "lualatex", "xelatex"]
747 then return opt { optLaTeXEngine = arg }
748 else err 45 "latex-engine must be pdflatex, lualatex, or xelatex.")
749 "PROGRAM")
750 "" -- "Name of latex program to use in generating PDF"
752 , Option "" ["latex-engine-opt"]
753 (ReqArg
754 (\arg opt -> do
755 let oldArgs = optLaTeXEngineArgs opt
756 return opt { optLaTeXEngineArgs = arg : oldArgs })
757 "STRING")
758 "" -- "Flags to pass to the LaTeX engine, all instances of this option are accumulated and used"
760 , Option "" ["bibliography"]
761 (ReqArg
762 (\arg opt -> return opt{ optMetadata = addMetadata
763 "bibliography" (readMetaValue arg)
764 $ optMetadata opt
765 })
766 "FILE")
767 ""
769 , Option "" ["csl"]
770 (ReqArg
771 (\arg opt ->
772 return opt{ optMetadata = addMetadata "csl"
773 (readMetaValue arg)
774 $ optMetadata opt })
775 "FILE")
776 ""
778 , Option "" ["citation-abbreviations"]
779 (ReqArg
780 (\arg opt ->
781 return opt{ optMetadata = addMetadata
782 "citation-abbreviations"
783 (readMetaValue arg)
784 $ optMetadata opt })
785 "FILE")
786 ""
788 , Option "" ["natbib"]
789 (NoArg
790 (\opt -> return opt { optCiteMethod = Natbib }))
791 "" -- "Use natbib cite commands in LaTeX output"
793 , Option "" ["biblatex"]
794 (NoArg
795 (\opt -> return opt { optCiteMethod = Biblatex }))
796 "" -- "Use biblatex cite commands in LaTeX output"
798 , Option "m" ["latexmathml", "asciimathml"]
799 (OptArg
800 (\arg opt ->
801 return opt { optHTMLMathMethod = LaTeXMathML arg })
802 "URL")
803 "" -- "Use LaTeXMathML script in html output"
805 , Option "" ["mathml"]
806 (OptArg
807 (\arg opt ->
808 return opt { optHTMLMathMethod = MathML arg })
809 "URL")
810 "" -- "Use mathml for HTML math"
812 , Option "" ["mimetex"]
813 (OptArg
814 (\arg opt -> do
815 let url' = case arg of
816 Just u -> u ++ "?"
817 Nothing -> "/cgi-bin/mimetex.cgi?"
818 return opt { optHTMLMathMethod = WebTeX url' })
819 "URL")
820 "" -- "Use mimetex for HTML math"
822 , Option "" ["webtex"]
823 (OptArg
824 (\arg opt -> do
825 let url' = fromMaybe "http://chart.apis.google.com/chart?cht=tx&chl=" arg
826 return opt { optHTMLMathMethod = WebTeX url' })
827 "URL")
828 "" -- "Use web service for HTML math"
830 , Option "" ["jsmath"]
831 (OptArg
832 (\arg opt -> return opt { optHTMLMathMethod = JsMath arg})
833 "URL")
834 "" -- "Use jsMath for HTML math"
836 , Option "" ["mathjax"]
837 (OptArg
838 (\arg opt -> do
839 let url' = fromMaybe "https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_CHTML-full" arg
840 return opt { optHTMLMathMethod = MathJax url'})
841 "URL")
842 "" -- "Use MathJax for HTML math"
843 , Option "" ["katex"]
844 (OptArg
845 (\arg opt ->
846 return opt
847 { optKaTeXJS =
848 arg <|> Just "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.5.1/katex.min.js"})
849 "URL")
850 "" -- Use KaTeX for HTML Math
852 , Option "" ["katex-stylesheet"]
853 (ReqArg
854 (\arg opt ->
855 return opt { optKaTeXStylesheet = Just arg })
856 "URL")
857 "" -- Set the KaTeX Stylesheet location
859 , Option "" ["gladtex"]
860 (NoArg
861 (\opt -> return opt { optHTMLMathMethod = GladTeX }))
862 "" -- "Use gladtex for HTML math"
864 , Option "" ["trace"]
865 (NoArg
866 (\opt -> return opt { optTrace = True }))
867 "" -- "Turn on diagnostic tracing in readers."
869 , Option "" ["dump-args"]
870 (NoArg
871 (\opt -> return opt { optDumpArgs = True }))
872 "" -- "Print output filename and arguments to stdout."
874 , Option "" ["ignore-args"]
875 (NoArg
876 (\opt -> return opt { optIgnoreArgs = True }))
877 "" -- "Ignore command-line arguments."
879 , Option "" ["verbose"]
880 (NoArg
881 (\opt -> return opt { optVerbose = True }))
882 "" -- "Verbose diagnostic output."
884 , Option "" ["bash-completion"]
885 (NoArg
886 (\_ -> do
887 ddir <- getDataDir
888 tpl <- readDataFileUTF8 Nothing "bash_completion.tpl"
889 let optnames (Option shorts longs _ _) =
890 map (\c -> ['-',c]) shorts ++
891 map ("--" ++) longs
892 let allopts = unwords (concatMap optnames options)
893 UTF8.hPutStrLn stdout $ printf tpl allopts
894 (unwords (map fst readers))
895 (unwords ("pdf": map fst writers))
896 ddir
897 exitSuccess ))
898 "" -- "Print bash completion script"
900 , Option "v" ["version"]
901 (NoArg
902 (\_ -> do
903 prg <- getProgName
904 defaultDatadir <- getAppUserDataDirectory "pandoc"
905 UTF8.hPutStrLn stdout (prg ++ " " ++ pandocVersion ++
906 compileInfo ++ "\nDefault user data directory: " ++
907 defaultDatadir ++ copyrightMessage)
908 exitSuccess ))
909 "" -- "Print version"
911 , Option "h" ["help"]
912 (NoArg
913 (\_ -> do
914 prg <- getProgName
915 UTF8.hPutStr stdout (usageMessage prg options)
916 exitSuccess ))
917 "" -- "Show help"
919 ]
922addMetadata :: String -> MetaValue -> M.Map String MetaValue
923 -> M.Map String MetaValue
924addMetadata k v m = case M.lookup k m of
925 Nothing -> M.insert k v m
926 Just (MetaList xs) -> M.insert k
927 (MetaList (xs ++ [v])) m
928 Just x -> M.insert k (MetaList [v, x]) m
930readMetaValue :: String -> MetaValue
931readMetaValue s = case decode (UTF8.fromString s) of
932 Just (Yaml.String t) -> MetaString $ T.unpack t
933 Just (Yaml.Bool b) -> MetaBool b
934 _ -> MetaString s
936-- Returns usage message
937usageMessage :: String -> [OptDescr (Opt -> IO Opt)] -> String
938usageMessage programName = usageInfo
939 (programName ++ " [OPTIONS] [FILES]" ++ "\nInput formats: " ++
940 wrapWords 16 78 readers'names ++
941 '\n' : replicate 16 ' ' ++
942 "[ *only Pandoc's JSON version of native AST]" ++ "\nOutput formats: " ++
943 wrapWords 16 78 writers'names ++
944 '\n' : replicate 16 ' ' ++
945 "[**for pdf output, use latex or beamer and -o FILENAME.pdf]\nOptions:")
946 where
947 writers'names = sort $ "json*" : "pdf**" : delete "json" (map fst writers)
948 readers'names = sort $ "json*" : delete "json" (map fst readers)
950-- Determine default reader based on source file extensions
951defaultReaderName :: String -> [FilePath] -> String
952defaultReaderName fallback [] = fallback
953defaultReaderName fallback (x:xs) =
954 case takeExtension (map toLower x) of
955 ".xhtml" -> "html"
956 ".html" -> "html"
957 ".htm" -> "html"
958 ".tex" -> "latex"
959 ".latex" -> "latex"
960 ".ltx" -> "latex"
961 ".rst" -> "rst"
962 ".org" -> "org"
963 ".lhs" -> "markdown+lhs"
964 ".db" -> "docbook"
965 ".opml" -> "opml"
966 ".wiki" -> "mediawiki"
967 ".dokuwiki" -> "dokuwiki"
968 ".textile" -> "textile"
969 ".native" -> "native"
970 ".json" -> "json"
971 ".docx" -> "docx"
972 ".t2t" -> "t2t"
973 ".epub" -> "epub"
974 ".odt" -> "odt"
975 ".pdf" -> "pdf" -- so we get an "unknown reader" error
976 ".doc" -> "doc" -- so we get an "unknown reader" error
977 _ -> defaultReaderName fallback xs
979-- Returns True if extension of first source is .lhs
980lhsExtension :: [FilePath] -> Bool
981lhsExtension (x:_) = takeExtension x == ".lhs"
982lhsExtension _ = False
984-- Determine default writer based on output file extension
985defaultWriterName :: FilePath -> String
986defaultWriterName "-" = "html" -- no output file
987defaultWriterName x =
988 case takeExtension (map toLower x) of
989 "" -> "markdown" -- empty extension
990 ".tex" -> "latex"
991 ".latex" -> "latex"
992 ".ltx" -> "latex"
993 ".context" -> "context"
994 ".ctx" -> "context"
995 ".rtf" -> "rtf"
996 ".rst" -> "rst"
997 ".s5" -> "s5"
998 ".native" -> "native"
999 ".json" -> "json"
1000 ".txt" -> "markdown"
1001 ".text" -> "markdown"
1002 ".md" -> "markdown"
1003 ".markdown" -> "markdown"
1004 ".textile" -> "textile"
1005 ".lhs" -> "markdown+lhs"
1006 ".texi" -> "texinfo"
1007 ".texinfo" -> "texinfo"
1008 ".db" -> "docbook"
1009 ".odt" -> "odt"
1010 ".docx" -> "docx"
1011 ".epub" -> "epub"
1012 ".org" -> "org"
1013 ".asciidoc" -> "asciidoc"
1014 ".adoc" -> "asciidoc"
1015 ".pdf" -> "latex"
1016 ".fb2" -> "fb2"
1017 ".opml" -> "opml"
1018 ".icml" -> "icml"
1019 ".tei.xml" -> "tei"
1020 ".tei" -> "tei"
1021 ['.',y] | y `elem` ['1'..'9'] -> "man"
1022 _ -> "html"
1024-- Transformations of a Pandoc document post-parsing:
1026extractMedia :: MediaBag -> FilePath -> Pandoc -> IO Pandoc
1027extractMedia media dir d =
1028 case [fp | (fp, _, _) <- mediaDirectory media] of
1029 [] -> return d
1030 fps -> do
1031 extractMediaBag True dir media
1032 return $ walk (adjustImagePath dir fps) d
1034adjustImagePath :: FilePath -> [FilePath] -> Inline -> Inline
1035adjustImagePath dir paths (Image attr lab (src, tit))
1036 | src `elem` paths = Image attr lab (dir ++ "/" ++ src, tit)
1037adjustImagePath _ _ x = x
1039adjustMetadata :: M.Map String MetaValue -> Pandoc -> IO Pandoc
1040adjustMetadata metadata d = return $ M.foldWithKey setMeta d metadata
1042applyTransforms :: [Transform] -> Pandoc -> IO Pandoc
1043applyTransforms transforms d = return $ foldr ($) d transforms
1045applyFilters :: [FilePath] -> [String] -> Pandoc -> IO Pandoc
1046applyFilters filters args d =
1047 foldrM ($) d $ map (flip externalFilter args) filters
1049uppercaseFirstLetter :: String -> String
1050uppercaseFirstLetter (c:cs) = toUpper c : cs
1051uppercaseFirstLetter [] = []
1053main :: IO ()
1054main = do
1056 rawArgs <- map UTF8.decodeArg <$> getArgs
1057 prg <- getProgName
1059 let (actions, args, errors) = getOpt Permute options rawArgs
1061 unless (null errors) $
1062 err 2 $ concat $ errors ++
1063 ["Try " ++ prg ++ " --help for more information."]
1065 -- thread option data structure through all supplied option actions
1066 opts <- foldl (>>=) (return defaultOpts) actions
1067 convertWithOpts opts args
1069convertWithOpts :: Opt -> [FilePath] -> IO ()
1070convertWithOpts opts args = do
1071 let Opt { optTabStop = tabStop
1072 , optPreserveTabs = preserveTabs
1073 , optStandalone = standalone
1074 , optReader = readerName
1075 , optWriter = writerName
1076 , optParseRaw = parseRaw
1077 , optVariables = variables
1078 , optMetadata = metadata
1079 , optTableOfContents = toc
1080 , optTransforms = transforms
1081 , optTemplate = templatePath
1082 , optOutputFile = outputFile
1083 , optNumberSections = numberSections
1084 , optNumberOffset = numberFrom
1085 , optSectionDivs = sectionDivs
1086 , optIncremental = incremental
1087 , optSelfContained = selfContained
1088 , optSmart = smart
1089 , optOldDashes = oldDashes
1090 , optHtml5 = html5
1091 , optHtmlQTags = htmlQTags
1092 , optHighlight = highlight
1093 , optHighlightStyle = highlightStyle
1094 , optChapters = chapters
1095 , optHTMLMathMethod = mathMethod'
1096 , optReferenceODT = referenceODT
1097 , optReferenceDocx = referenceDocx
1098 , optEpubStylesheet = epubStylesheet
1099 , optEpubMetadata = epubMetadata
1100 , optEpubFonts = epubFonts
1101 , optEpubChapterLevel = epubChapterLevel
1102 , optTOCDepth = epubTOCDepth
1103 , optDumpArgs = dumpArgs
1104 , optIgnoreArgs = ignoreArgs
1105 , optVerbose = verbose
1106 , optReferenceLinks = referenceLinks
1107 , optDpi = dpi
1108 , optWrapText = wrap
1109 , optColumns = columns
1110 , optFilters = filters
1111 , optEmailObfuscation = obfuscationMethod
1112 , optIdentifierPrefix = idPrefix
1113 , optIndentedCodeClasses = codeBlockClasses
1114 , optDataDir = mbDataDir
1115 , optCiteMethod = citeMethod
1116 , optListings = listings
1117 , optLaTeXEngine = latexEngine
1118 , optLaTeXEngineArgs = latexEngineArgs
1119 , optSlideLevel = slideLevel
1120 , optSetextHeaders = setextHeaders
1121 , optAscii = ascii
1122 , optTeXLigatures = texLigatures
1123 , optDefaultImageExtension = defaultImageExtension
1124 , optExtractMedia = mbExtractMedia
1125 , optTrace = trace
1126 , optTrackChanges = trackChanges
1127 , optFileScope = fileScope
1128 , optKaTeXStylesheet = katexStylesheet
1129 , optKaTeXJS = katexJS
1130 } = opts
1132 when dumpArgs $
1133 do UTF8.hPutStrLn stdout outputFile
1134 mapM_ (UTF8.hPutStrLn stdout) args
1135 exitSuccess
1137 let csscdn = "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.5.1/katex.min.css"
1138 let mathMethod =
1139 case (katexJS, katexStylesheet) of
1140 (Nothing, _) -> mathMethod'
1141 (Just js, ss) -> KaTeX js (fromMaybe csscdn ss)
1144 -- --bibliography implies -F pandoc-citeproc for backwards compatibility:
1145 let needsCiteproc = isJust (M.lookup "bibliography" (optMetadata opts)) &&
1146 optCiteMethod opts `notElem` [Natbib, Biblatex] &&
1147 "pandoc-citeproc" `notElem` map takeBaseName filters
1148 let filters' = if needsCiteproc then "pandoc-citeproc" : filters
1149 else filters
1151 let sources = if ignoreArgs then [] else args
1153 datadir <- case mbDataDir of
1154 Nothing -> E.catch
1155 (Just <$> getAppUserDataDirectory "pandoc")
1156 (\e -> let _ = (e :: E.SomeException)
1157 in return Nothing)
1158 Just _ -> return mbDataDir
1160 -- assign reader and writer based on options and filenames
1161 let readerName' = case map toLower readerName of
1162 [] -> defaultReaderName
1163 (if any isURI sources
1164 then "html"
1165 else "markdown") sources
1166 "html4" -> "html"
1167 x -> x
1169 let writerName' = case map toLower writerName of
1170 [] -> defaultWriterName outputFile
1171 "epub2" -> "epub"
1172 "html4" -> "html"
1173 x -> x
1174 let format = takeWhile (`notElem` ['+','-'])
1175 $ takeFileName writerName' -- in case path to lua script
1177 let pdfOutput = map toLower (takeExtension outputFile) == ".pdf"
1179 let laTeXOutput = format `elem` ["latex", "beamer"]
1180 let conTeXtOutput = format == "context"
1181 let html5Output = format == "html5"
1183 let laTeXInput = "latex" `isPrefixOf` readerName' ||
1184 "beamer" `isPrefixOf` readerName'
1186 writer <- if ".lua" `isSuffixOf` format
1187 -- note: use non-lowercased version writerName
1188 then return $ IOStringWriter $ writeCustom writerName
1189 else case getWriter writerName' of
1190 Left e -> err 9 $
1191 if format == "pdf"
1192 then e ++
1193 "\nTo create a pdf with pandoc, use " ++
1194 "the latex or beamer writer and specify\n" ++
1195 "an output file with .pdf extension " ++
1196 "(pandoc -t latex -o filename.pdf)."
1197 else e
1198 Right w -> return w
1200 reader <- if "t2t" == readerName'
1201 then (mkStringReader .
1202 readTxt2Tags) <$>
1203 getT2TMeta sources outputFile
1204 else case getReader readerName' of
1205 Right r -> return r
1206 Left e -> err 7 e'
1207 where e' = case readerName' of
1208 "pdf" -> e ++
1209 "\nPandoc can convert to PDF, but not from PDF."
1210 "doc" -> e ++
1211 "\nPandoc can convert from DOCX, but not from DOC.\nTry using Word to save your DOC file as DOCX, and convert that with pandoc."
1212 _ -> e
1214 let standalone' = standalone || not (isTextFormat format) || pdfOutput
1216 templ <- case templatePath of
1217 _ | not standalone' -> return ""
1218 Nothing -> do
1219 deftemp <- getDefaultTemplate datadir format
1220 case deftemp of
1221 Left e -> throwIO e
1222 Right t -> return t
1223 Just tp -> do
1224 -- strip off extensions
1225 let tp' = case takeExtension tp of
1226 "" -> tp <.> format
1227 _ -> tp
1228 E.catch (UTF8.readFile tp')
1229 (\e -> if isDoesNotExistError e
1230 then E.catch
1231 (readDataFileUTF8 datadir
1232 ("templates" </> tp'))
1233 (\e' -> let _ = (e' :: E.SomeException)
1234 in throwIO e')
1235 else throwIO e)
1237 variables' <- case mathMethod of
1238 LaTeXMathML Nothing -> do
1239 s <- readDataFileUTF8 datadir "LaTeXMathML.js"
1240 return $ ("mathml-script", s) : variables
1241 MathML Nothing -> do
1242 s <- readDataFileUTF8 datadir "MathMLinHTML.js"
1243 return $ ("mathml-script", s) : variables
1244 _ -> return variables
1246 variables'' <- if format == "dzslides"
1247 then do
1248 dztempl <- readDataFileUTF8 datadir
1249 ("dzslides" </> "template.html")
1250 let dzline = "<!-- {{{{ dzslides core"
1251 let dzcore = unlines
1252 $ dropWhile (not . (dzline `isPrefixOf`))
1253 $ lines dztempl
1254 return $ ("dzslides-core", dzcore) : variables'
1255 else return variables'
1257 let sourceURL = case sources of
1258 [] -> Nothing
1259 (x:_) -> case parseURI x of
1260 Just u
1261 | uriScheme u `elem` ["http:","https:"] ->
1262 Just $ show u{ uriQuery = "",
1263 uriFragment = "" }
1264 _ -> Nothing
1266 let readerOpts = def{ readerSmart = if laTeXInput
1267 then texLigatures
1268 else smart || (texLigatures &&
1269 (laTeXOutput || conTeXtOutput))
1270 , readerStandalone = standalone'
1271 , readerParseRaw = parseRaw
1272 , readerColumns = columns
1273 , readerTabStop = tabStop
1274 , readerOldDashes = oldDashes
1275 , readerIndentedCodeClasses = codeBlockClasses
1276 , readerApplyMacros = not laTeXOutput
1277 , readerDefaultImageExtension = defaultImageExtension
1278 , readerTrace = trace
1279 , readerTrackChanges = trackChanges
1280 , readerFileScope = fileScope
1283 when (not (isTextFormat format) && outputFile == "-") $
1284 err 5 $ "Cannot write " ++ format ++ " output to stdout.\n" ++
1285 "Specify an output file using the -o option."
1287 let readSources [] = mapM readSource ["-"]
1288 readSources srcs = mapM readSource srcs
1289 readSource "-" = UTF8.getContents
1290 readSource src = case parseURI src of
1291 Just u | uriScheme u `elem` ["http:","https:"] ->
1292 readURI src
1293 _ -> UTF8.readFile src
1294 readURI src = do
1295 res <- openURL src
1296 case res of
1297 Left e -> throwIO e
1298 Right (bs,_) -> return $ UTF8.toString bs
1300 let readFiles [] = error "Cannot read archive from stdin"
1301 readFiles [x] = B.readFile x
1302 readFiles (x:xs) = mapM_ (warn . ("Ignoring: " ++)) xs >> B.readFile x
1304 let convertTabs = tabFilter (if preserveTabs || readerName' == "t2t"
1305 then 0
1306 else tabStop)
1308 let handleIncludes' :: String -> IO (Either PandocError String)
1309 handleIncludes' = if readerName' `elem` ["latex", "latex+lhs"]
1310 then handleIncludes
1311 else return . Right
1313 let sourceToDoc :: [FilePath] -> IO (Pandoc, MediaBag)
1314 sourceToDoc sources' = fmap handleError $
1315 case reader of
1316 StringReader r-> do
1317 srcs <- convertTabs . intercalate "\n" <$> readSources sources'
1318 doc <- handleIncludes' srcs
1319 either (return . Left) (\s -> fmap (,mempty) <$> r readerOpts s) doc
1320 ByteStringReader r -> readFiles sources' >>= r readerOpts
1322 -- We parse first if (1) fileScope is set, (2), it's a binary
1323 -- reader, or (3) we're reading JSON. This is easier to do of an AND
1324 -- of negatives as opposed to an OR of positives, so we do default
1325 -- parsing if it's a StringReader AND (fileScope is set AND it's not
1326 -- a JSON reader).
1327 (doc, media) <- case reader of
1328 (StringReader _) | not fileScope && readerName' /= "json" ->
1329 sourceToDoc sources
1330 _ | null sources -> sourceToDoc sources
1331 _ -> do pairs <- mapM (\s -> sourceToDoc [s]) sources
1332 return (mconcat $ map fst pairs, mconcat $ map snd pairs)
1334 let writerOptions = def { writerStandalone = standalone',
1335 writerTemplate = templ,
1336 writerVariables = variables'',
1337 writerTabStop = tabStop,
1338 writerTableOfContents = toc,
1339 writerHTMLMathMethod = mathMethod,
1340 writerIncremental = incremental,
1341 writerCiteMethod = citeMethod,
1342 writerIgnoreNotes = False,
1343 writerNumberSections = numberSections,
1344 writerNumberOffset = numberFrom,
1345 writerSectionDivs = sectionDivs,
1346 writerReferenceLinks = referenceLinks,
1347 writerDpi = dpi,
1348 writerWrapText = wrap,
1349 writerColumns = columns,
1350 writerEmailObfuscation = obfuscationMethod,
1351 writerIdentifierPrefix = idPrefix,
1352 writerSourceURL = sourceURL,
1353 writerUserDataDir = datadir,
1354 writerHtml5 = html5,
1355 writerHtmlQTags = htmlQTags,
1356 writerChapters = chapters,
1357 writerListings = listings,
1358 writerBeamer = False,
1359 writerSlideLevel = slideLevel,
1360 writerHighlight = highlight,
1361 writerHighlightStyle = highlightStyle,
1362 writerSetextHeaders = setextHeaders,
1363 writerTeXLigatures = texLigatures,
1364 writerEpubMetadata = epubMetadata,
1365 writerEpubStylesheet = epubStylesheet,
1366 writerEpubFonts = epubFonts,
1367 writerEpubChapterLevel = epubChapterLevel,
1368 writerTOCDepth = epubTOCDepth,
1369 writerReferenceODT = referenceODT,
1370 writerReferenceDocx = referenceDocx,
1371 writerMediaBag = media,
1372 writerVerbose = verbose,
1373 writerLaTeXArgs = latexEngineArgs
1377 doc' <- (maybe return (extractMedia media) mbExtractMedia >=>
1378 adjustMetadata metadata >=>
1379 applyTransforms transforms >=>
1380 applyFilters filters' [format]) doc
1382 let writeBinary :: B.ByteString -> IO ()
1383 writeBinary = B.writeFile (UTF8.encodePath outputFile)
1385 let writerFn :: FilePath -> String -> IO ()
1386 writerFn "-" = UTF8.putStr
1387 writerFn f = UTF8.writeFile f
1389 case writer of
1390 IOStringWriter f -> f writerOptions doc' >>= writerFn outputFile
1391 IOByteStringWriter f -> f writerOptions doc' >>= writeBinary
1392 PureStringWriter f
1393 | pdfOutput -> do
1394 -- make sure writer is latex or beamer or context or html5
1395 unless (laTeXOutput || conTeXtOutput || html5Output) $
1396 err 47 $ "cannot produce pdf output with " ++ format ++
1397 " writer"
1399 let pdfprog = case () of
1400 _ | conTeXtOutput -> "context"
1401 _ | html5Output -> "wkhtmltopdf"
1402 _ -> latexEngine
1403 -- check for pdf creating program
1404 mbPdfProg <- findExecutable pdfprog
1405 when (isNothing mbPdfProg) $
1406 err 41 $ pdfprog ++ " not found. " ++
1407 pdfprog ++ " is needed for pdf output."
1409 res <- makePDF pdfprog f writerOptions doc'
1410 case res of
1411 Right pdf -> writeBinary pdf
1412 Left err' -> do
1413 B.hPutStr stderr err'
1414 B.hPut stderr $ B.pack [10]
1415 err 43 "Error producing PDF"
1416 | otherwise -> selfcontain (f writerOptions doc' ++
1417 ['\n' | not standalone'])
1418 >>= writerFn outputFile . handleEntities
1419 where htmlFormat = format `elem`
1420 ["html","html5","s5","slidy","slideous","dzslides","revealjs"]
1421 selfcontain = if selfContained && htmlFormat
1422 then makeSelfContained writerOptions
1423 else return
1424 handleEntities = if htmlFormat && ascii
1425 then toEntities
1426 else id