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