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