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