1{-# LANGUAGE CPP, TupleSections #-}
3Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
5This program is free software; you can redistribute it and/or modify
6it under the terms of the GNU General Public License as published by
7the Free Software Foundation; either version 2 of the License, or
8(at your option) any later version.
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 Copyright : Copyright (C) 2006-2015 John MacFarlane
23 License : GNU GPL, version 2 or above
25 Maintainer : John MacFarlane <jgm@berkeley@edu>
27 Portability : portable
29Parses command-line options and calls the appropriate readers and
34import Text.Pandoc.Builder (setMeta)
35import Text.Pandoc.PDF (makePDF)
36import Text.Pandoc.Walk (walk)
37import Text.Pandoc.Readers.LaTeX (handleIncludes)
38import Text.Pandoc.Shared ( tabFilter, readDataFileUTF8, readDataFile,
39 safeRead, headerShift, normalize, err, warn,
41import Text.Pandoc.MediaBag ( mediaDirectory, extractMediaBag, MediaBag )
42import Text.Pandoc.ManPages ( manPandoc1, manPandocMarkdown5 )
43import Text.Pandoc.XML ( toEntities )
44import Text.Pandoc.SelfContained ( makeSelfContained )
45import Text.Pandoc.Process (pipeProcess)
46import Text.Highlighting.Kate ( languages, Style, tango, pygments,
47 espresso, zenburn, kate, haddock, monochrome )
48import System.Environment ( getArgs, getProgName )
49import System.Exit ( exitWith, ExitCode (..) )
51import System.Console.GetOpt
52import Data.Char ( toLower )
53import Data.List ( delete, intercalate, isPrefixOf, isSuffixOf, sort )
54import System.Directory ( getAppUserDataDirectory, findExecutable,
55 doesFileExist, Permissions(..), getPermissions )
56import System.IO ( stdout, stderr )
57import System.IO.Error ( isDoesNotExistError )
58import qualified Control.Exception as E
59import Control.Exception.Extensible ( throwIO )
60import qualified Text.Pandoc.UTF8 as UTF8
61import Control.Monad (when, unless, (>=>))
62import Data.Maybe (fromMaybe)
63import Data.Foldable (foldrM)
64import Network.URI (parseURI, isURI, URI(..))
65import qualified Data.ByteString.Lazy as B
66import qualified Data.ByteString as BS
67import Data.Aeson (eitherDecode', encode)
68import qualified Data.Map as M
69import Data.Yaml (decode)
70import qualified Data.Yaml as Yaml
71import qualified Data.Text as T
72import Control.Applicative ((<$>), (<|>))
73import Text.Pandoc.Readers.Txt2Tags (getT2TMeta)
76import Text.Pandoc.Error
78type Transform = Pandoc -> Pandoc
80copyrightMessage :: String
81copyrightMessage = intercalate "\n" [
83 "Copyright (C) 2006-2015 John MacFarlane",
84 "Web: http://pandoc.org",
85 "This is free software; see the source for copying conditions.",
86 "There is no warranty, not even for merchantability or fitness",
87 "for a particular purpose." ]
91 "\nCompiled with texmath " ++
92 VERSION_texmath ++ ", highlighting-kate " ++ VERSION_highlighting_kate ++
93 ".\nSyntax highlighting is supported for the following languages:\n " ++
95 [map toLower l | l <- languages, l /= "Alert" && l /= "Alert_indent"]
97-- | Converts a list of strings into a single string with the items printed as
98-- comma separated words in lines with a maximum line length.
99wrapWords :: Int -> Int -> [String] -> String
100wrapWords indent c = wrap' (c - indent) (c - indent)
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
111 wrap' cols (remaining - length x - 2) xs
113isTextFormat :: String -> Bool
114isTextFormat s = takeWhile (`notElem` "+-") s `notElem` binaries
115 where binaries = ["odt","docx","epub","epub3"]
117externalFilter :: FilePath -> [String] -> Pandoc -> IO Pandoc
118externalFilter f args' d = do
119 mbexe <- if '/' `elem` f
120 -- don't check PATH if filter name has a path
122 -- we catch isDoesNotExistError because this will
123 -- be triggered if PATH not set:
124 else E.catch (findExecutable f)
125 (\e -> if isDoesNotExistError e
128 (f', args'') <- case mbexe of
129 Just x -> return (x, args')
131 exists <- doesFileExist f
134 isExecutable <- executable `fmap`
137 case map toLower $ takeExtension f of
138 _ | isExecutable -> (f, args')
139 ".py" -> ("python", f:args')
140 ".hs" -> ("runhaskell", f:args')
141 ".pl" -> ("perl", f:args')
142 ".rb" -> ("ruby", f:args')
143 ".php" -> ("php", f:args')
145 else err 85 $ "Filter " ++ f ++ " not found"
146 (exitcode, outbs, errbs) <- E.handle filterException $
147 pipeProcess Nothing f' args'' $ encode d
148 when (not $ B.null errbs) $ B.hPutStr stderr errbs
150 ExitSuccess -> return $ either error id $ eitherDecode' outbs
151 ExitFailure _ -> err 83 $ "Error running filter " ++ f
152 where filterException :: E.SomeException -> IO a
153 filterException e = err 83 $ "Error running filter " ++ f ++ "\n" ++
156-- | Data structure for command line options.
158 { optTabStop :: Int -- ^ Number of spaces per tab
159 , optPreserveTabs :: Bool -- ^ Preserve tabs instead of converting to spaces
160 , optStandalone :: Bool -- ^ Include header, footer
161 , optReader :: String -- ^ Reader format
162 , optWriter :: String -- ^ Writer format
163 , optParseRaw :: Bool -- ^ Parse unconvertable HTML and TeX
164 , optTableOfContents :: Bool -- ^ Include table of contents
165 , optTransforms :: [Transform] -- ^ Doc transforms to apply
166 , optTemplate :: Maybe FilePath -- ^ Custom template
167 , optVariables :: [(String,String)] -- ^ Template variables to set
168 , optMetadata :: M.Map String MetaValue -- ^ Metadata fields to set
169 , optOutputFile :: String -- ^ Name of output file
170 , optNumberSections :: Bool -- ^ Number sections in LaTeX
171 , optNumberOffset :: [Int] -- ^ Starting number for sections
172 , optSectionDivs :: Bool -- ^ Put sections in div tags in HTML
173 , optIncremental :: Bool -- ^ Use incremental lists in Slidy/Slideous/S5
174 , optSelfContained :: Bool -- ^ Make HTML accessible offline
175 , optSmart :: Bool -- ^ Use smart typography
176 , optOldDashes :: Bool -- ^ Parse dashes like pandoc <=1.8.2.1
177 , optHtml5 :: Bool -- ^ Produce HTML5 in HTML
178 , optHtmlQTags :: Bool -- ^ Use <q> tags in HTML
179 , optHighlight :: Bool -- ^ Highlight source code
180 , optHighlightStyle :: Style -- ^ Style to use for highlighted code
181 , optChapters :: Bool -- ^ Use chapter for top-level sects
182 , optHTMLMathMethod :: HTMLMathMethod -- ^ Method to print HTML math
183 , optReferenceODT :: Maybe FilePath -- ^ Path of reference.odt
184 , optReferenceDocx :: Maybe FilePath -- ^ Path of reference.docx
185 , optEpubStylesheet :: Maybe String -- ^ EPUB stylesheet
186 , optEpubMetadata :: String -- ^ EPUB metadata
187 , optEpubFonts :: [FilePath] -- ^ EPUB fonts to embed
188 , optEpubChapterLevel :: Int -- ^ Header level at which to split chapters
189 , optTOCDepth :: Int -- ^ Number of levels to include in TOC
190 , optDumpArgs :: Bool -- ^ Output command-line arguments
191 , optIgnoreArgs :: Bool -- ^ Ignore command-line arguments
192 , optVerbose :: Bool -- ^ Verbose diagnostic output
193 , optReferenceLinks :: Bool -- ^ Use reference links in writing markdown, rst
194 , optWrapText :: Bool -- ^ Wrap text
195 , optColumns :: Int -- ^ Line length in characters
196 , optFilters :: [FilePath] -- ^ Filters to apply
197 , optEmailObfuscation :: ObfuscationMethod
198 , optIdentifierPrefix :: String
199 , optIndentedCodeClasses :: [String] -- ^ Default classes for indented code blocks
200 , optDataDir :: Maybe FilePath
201 , optCiteMethod :: CiteMethod -- ^ Method to output cites
202 , optListings :: Bool -- ^ Use listings package for code blocks
203 , optLaTeXEngine :: String -- ^ Program to use for latex -> pdf
204 , optLaTeXEngineArgs :: [String] -- ^ Flags to pass to the latex-engine
205 , optSlideLevel :: Maybe Int -- ^ Header level that creates slides
206 , optSetextHeaders :: Bool -- ^ Use atx headers for markdown level 1-2
207 , optAscii :: Bool -- ^ Use ascii characters only in html
208 , optTeXLigatures :: Bool -- ^ Use TeX ligatures for quotes/dashes
209 , optDefaultImageExtension :: String -- ^ Default image extension
210 , optExtractMedia :: Maybe FilePath -- ^ Path to extract embedded media
211 , optTrace :: Bool -- ^ Print debug information
212 , optTrackChanges :: TrackChanges -- ^ Accept or reject MS Word track-changes.
213 , optKaTeXStylesheet :: Maybe String -- ^ Path to stylesheet for KaTeX
214 , optKaTeXJS :: Maybe String -- ^ Path to js file for KaTeX
217-- | Defaults for command-line options.
221 , optPreserveTabs = False
222 , optStandalone = False
223 , optReader = "" -- null for default reader
224 , optWriter = "" -- null for default writer
225 , optParseRaw = False
226 , optTableOfContents = False
228 , optTemplate = Nothing
230 , optMetadata = M.empty
231 , optOutputFile = "-" -- "-" means stdout
232 , optNumberSections = False
233 , optNumberOffset = [0,0,0,0,0,0]
234 , optSectionDivs = False
235 , optIncremental = False
236 , optSelfContained = False
238 , optOldDashes = False
240 , optHtmlQTags = False
241 , optHighlight = True
242 , optHighlightStyle = pygments
243 , optChapters = False
244 , optHTMLMathMethod = PlainMath
245 , optReferenceODT = Nothing
246 , optReferenceDocx = Nothing
247 , optEpubStylesheet = Nothing
248 , optEpubMetadata = ""
250 , optEpubChapterLevel = 1
252 , optDumpArgs = False
253 , optIgnoreArgs = False
255 , optReferenceLinks = False
259 , optEmailObfuscation = JavascriptObfuscation
260 , optIdentifierPrefix = ""
261 , optIndentedCodeClasses = []
262 , optDataDir = Nothing
263 , optCiteMethod = Citeproc
264 , optListings = False
265 , optLaTeXEngine = "pdflatex"
266 , optLaTeXEngineArgs = []
267 , optSlideLevel = Nothing
268 , optSetextHeaders = True
270 , optTeXLigatures = True
271 , optDefaultImageExtension = ""
272 , optExtractMedia = Nothing
274 , optTrackChanges = AcceptChanges
275 , optKaTeXStylesheet = Nothing
276 , optKaTeXJS = Nothing
279-- | A list of functions, each transforming the options data structure
280-- in response to a command-line option.
281options :: [OptDescr (Opt -> IO Opt)]
283 [ Option "fr" ["from","read"]
285 (\arg opt -> return opt { optReader = arg })
289 , Option "tw" ["to","write"]
291 (\arg opt -> return opt { optWriter = arg })
295 , Option "o" ["output"]
297 (\arg opt -> return opt { optOutputFile = arg })
299 "" -- "Name of output file"
301 , Option "" ["data-dir"]
303 (\arg opt -> return opt { optDataDir = Just arg })
304 "DIRECTORY") -- "Directory containing pandoc data files."
307 , Option "" ["strict"]
310 err 59 $ "The --strict option has been removed.\n" ++
311 "Use `markdown_strict' input or output format instead."
313 "" -- "Disable markdown syntax extensions"
315 , Option "R" ["parse-raw"]
317 (\opt -> return opt { optParseRaw = True }))
318 "" -- "Parse untranslatable HTML codes and LaTeX environments as raw"
320 , Option "S" ["smart"]
322 (\opt -> return opt { optSmart = True }))
323 "" -- "Use smart quotes, dashes, and ellipses"
325 , Option "" ["old-dashes"]
327 (\opt -> return opt { optSmart = True
328 , optOldDashes = True }))
329 "" -- "Use smart quotes, dashes, and ellipses"
331 , Option "" ["base-header-level"]
336 let oldTransforms = optTransforms opt
338 return opt{ optTransforms =
339 headerShift shift : oldTransforms }
341 "base-header-level must be a number > 0")
343 "" -- "Headers base level"
345 , Option "" ["indented-code-classes"]
347 (\arg opt -> return opt { optIndentedCodeClasses = words $
348 map (\c -> if c == ',' then ' ' else c) arg })
350 "" -- "Classes (whitespace- or comma-separated) to use for indented code-blocks"
352 , Option "F" ["filter"]
354 (\arg opt -> return opt { optFilters = arg : optFilters opt })
356 "" -- "External JSON filter"
358 , Option "" ["normalize"]
360 (\opt -> return opt { optTransforms =
361 normalize : optTransforms opt } ))
362 "" -- "Normalize the Pandoc AST"
364 , Option "p" ["preserve-tabs"]
366 (\opt -> return opt { optPreserveTabs = True }))
367 "" -- "Preserve tabs instead of converting to spaces"
369 , Option "" ["tab-stop"]
373 Just t | t > 0 -> return opt { optTabStop = t }
375 "tab-stop must be a number greater than 0")
377 "" -- "Tab stop (default 4)"
379 , Option "" ["track-changes"]
382 action <- case arg of
383 "accept" -> return AcceptChanges
384 "reject" -> return RejectChanges
385 "all" -> return AllChanges
387 ("Unknown option for track-changes: " ++ arg)
388 return opt { optTrackChanges = action })
390 "" -- "Accepting or reject MS Word track-changes.""
392 , Option "" ["extract-media"]
395 return opt { optExtractMedia = Just arg })
397 "" -- "Directory to which to extract embedded media"
399 , Option "s" ["standalone"]
401 (\opt -> return opt { optStandalone = True }))
402 "" -- "Include needed header and footer on output"
404 , Option "" ["template"]
407 return opt{ optTemplate = Just arg,
408 optStandalone = True })
410 "" -- "Use custom template"
412 , Option "M" ["metadata"]
415 let (key,val) = case break (`elem` ":=") arg of
416 (k,_:v) -> (k, readMetaValue v)
417 (k,_) -> (k, MetaBool True)
418 return opt{ optMetadata = addMetadata key val
423 , Option "V" ["variable"]
426 let (key,val) = case break (`elem` ":=") arg of
429 return opt{ optVariables = (key,val) : optVariables opt })
433 , Option "D" ["print-default-template"]
436 templ <- getDefaultTemplate Nothing arg
438 Right t -> UTF8.hPutStr stdout t
439 Left e -> error $ show e
440 exitWith ExitSuccess)
442 "" -- "Print default template for FORMAT"
444 , Option "" ["print-default-data-file"]
447 readDataFile Nothing arg >>= BS.hPutStr stdout
448 exitWith ExitSuccess)
450 "" -- "Print default data file"
452 , Option "" ["no-wrap"]
454 (\opt -> return opt { optWrapText = False }))
455 "" -- "Do not wrap text in output"
457 , Option "" ["columns"]
461 Just t | t > 0 -> return opt { optColumns = t }
463 "columns must be a number greater than 0")
465 "" -- "Length of line in characters"
467 , Option "" ["toc", "table-of-contents"]
469 (\opt -> return opt { optTableOfContents = True }))
470 "" -- "Include table of contents"
472 , Option "" ["toc-depth"]
476 Just t | t >= 1 && t <= 6 ->
477 return opt { optTOCDepth = t }
479 "TOC level must be a number between 1 and 6")
481 "" -- "Number of levels to include in TOC"
483 , Option "" ["no-highlight"]
485 (\opt -> return opt { optHighlight = False }))
486 "" -- "Don't highlight source code"
488 , Option "" ["highlight-style"]
491 newStyle <- case map toLower arg of
492 "pygments" -> return pygments
493 "tango" -> return tango
494 "espresso" -> return espresso
495 "zenburn" -> return zenburn
496 "kate" -> return kate
497 "monochrome" -> return monochrome
498 "haddock" -> return haddock
500 "Unknown style :" ++ arg
501 return opt{ optHighlightStyle = newStyle })
503 "" -- "Style for highlighted code"
505 , Option "H" ["include-in-header"]
508 text <- UTF8.readFile arg
509 -- add new ones to end, so they're included in order specified
510 let newvars = optVariables opt ++ [("header-includes",text)]
511 return opt { optVariables = newvars,
512 optStandalone = True })
514 "" -- "File to include at end of header (implies -s)"
516 , Option "B" ["include-before-body"]
519 text <- UTF8.readFile arg
520 -- add new ones to end, so they're included in order specified
521 let newvars = optVariables opt ++ [("include-before",text)]
522 return opt { optVariables = newvars,
523 optStandalone = True })
525 "" -- "File to include before document body"
527 , Option "A" ["include-after-body"]
530 text <- UTF8.readFile arg
531 -- add new ones to end, so they're included in order specified
532 let newvars = optVariables opt ++ [("include-after",text)]
533 return opt { optVariables = newvars,
534 optStandalone = True })
536 "" -- "File to include after document body"
538 , Option "" ["self-contained"]
540 (\opt -> return opt { optSelfContained = True,
541 optStandalone = True }))
542 "" -- "Make slide shows include all the needed js and css"
544 , Option "" ["offline"]
546 (\opt -> do warn $ "--offline is deprecated. Use --self-contained instead."
547 return opt { optSelfContained = True,
548 optStandalone = True }))
549 "" -- "Make slide shows include all the needed js and css"
550 -- deprecated synonym for --self-contained
552 , Option "5" ["html5"]
555 warn $ "--html5 is deprecated. "
556 ++ "Use the html5 output format instead."
557 return opt { optHtml5 = True }))
558 "" -- "Produce HTML5 in HTML output"
560 , Option "" ["html-q-tags"]
563 return opt { optHtmlQTags = True }))
564 "" -- "Use <q> tags for quotes in HTML"
566 , Option "" ["ascii"]
568 (\opt -> return opt { optAscii = True }))
569 "" -- "Use ascii characters only in HTML output"
571 , Option "" ["reference-links"]
573 (\opt -> return opt { optReferenceLinks = True } ))
574 "" -- "Use reference links in parsing HTML"
576 , Option "" ["atx-headers"]
578 (\opt -> return opt { optSetextHeaders = False } ))
579 "" -- "Use atx-style headers for markdown"
581 , Option "" ["chapters"]
583 (\opt -> return opt { optChapters = True }))
584 "" -- "Use chapter for top-level sections in LaTeX, DocBook"
586 , Option "N" ["number-sections"]
588 (\opt -> return opt { optNumberSections = True }))
589 "" -- "Number sections in LaTeX"
591 , Option "" ["number-offset"]
594 case safeRead ('[':arg ++ "]") of
595 Just ns -> return opt { optNumberOffset = ns,
596 optNumberSections = True }
597 _ -> err 57 "could not parse number-offset")
599 "" -- "Starting number for sections, subsections, etc."
601 , Option "" ["no-tex-ligatures"]
603 (\opt -> return opt { optTeXLigatures = False }))
604 "" -- "Don't use tex ligatures for quotes, dashes"
606 , Option "" ["listings"]
608 (\opt -> return opt { optListings = True }))
609 "" -- "Use listings package for LaTeX code blocks"
611 , Option "i" ["incremental"]
613 (\opt -> return opt { optIncremental = True }))
614 "" -- "Make list items display incrementally in Slidy/Slideous/S5"
616 , Option "" ["slide-level"]
620 Just t | t >= 1 && t <= 6 ->
621 return opt { optSlideLevel = Just t }
623 "slide level must be a number between 1 and 6")
625 "" -- "Force header level for slides"
627 , Option "" ["section-divs"]
629 (\opt -> return opt { optSectionDivs = True }))
630 "" -- "Put sections in div tags in HTML"
632 , Option "" ["default-image-extension"]
634 (\arg opt -> return opt { optDefaultImageExtension = arg })
636 "" -- "Default extension for extensionless images"
638 , Option "" ["email-obfuscation"]
641 method <- case arg of
642 "references" -> return ReferenceObfuscation
643 "javascript" -> return JavascriptObfuscation
644 "none" -> return NoObfuscation
646 ("Unknown obfuscation method: " ++ arg)
647 return opt { optEmailObfuscation = method })
648 "none|javascript|references")
649 "" -- "Method for obfuscating email in HTML"
651 , Option "" ["id-prefix"]
653 (\arg opt -> return opt { optIdentifierPrefix = arg })
655 "" -- "Prefix to add to automatically generated HTML identifiers"
657 , Option "T" ["title-prefix"]
660 let newvars = ("title-prefix", arg) : optVariables opt
661 return opt { optVariables = newvars,
662 optStandalone = True })
664 "" -- "String to prefix to HTML window title"
669 -- add new link to end, so it is included in proper order
670 let newvars = optVariables opt ++ [("css",arg)]
671 return opt { optVariables = newvars,
672 optStandalone = True })
674 "" -- "Link to CSS style sheet"
676 , Option "" ["reference-odt"]
679 return opt { optReferenceODT = Just arg })
681 "" -- "Path of custom reference.odt"
683 , Option "" ["reference-docx"]
686 return opt { optReferenceDocx = Just arg })
688 "" -- "Path of custom reference.docx"
690 , Option "" ["epub-stylesheet"]
693 text <- UTF8.readFile arg
694 return opt { optEpubStylesheet = Just text })
696 "" -- "Path of epub.css"
698 , Option "" ["epub-cover-image"]
701 return opt { optVariables =
702 ("epub-cover-image", arg) : optVariables opt })
704 "" -- "Path of epub cover image"
706 , Option "" ["epub-metadata"]
709 text <- UTF8.readFile arg
710 return opt { optEpubMetadata = text })
712 "" -- "Path of epub metadata file"
714 , Option "" ["epub-embed-font"]
717 return opt{ optEpubFonts = arg : optEpubFonts opt })
719 "" -- "Directory of fonts to embed"
721 , Option "" ["epub-chapter-level"]
725 Just t | t >= 1 && t <= 6 ->
726 return opt { optEpubChapterLevel = t }
728 "chapter level must be a number between 1 and 6")
730 "" -- "Header level at which to split chapters in EPUB"
732 , Option "" ["latex-engine"]
735 let b = takeBaseName arg
736 if b `elem` ["pdflatex", "lualatex", "xelatex"]
737 then return opt { optLaTeXEngine = arg }
738 else err 45 "latex-engine must be pdflatex, lualatex, or xelatex.")
740 "" -- "Name of latex program to use in generating PDF"
742 , Option "" ["latex-engine-opt"]
745 let oldArgs = optLaTeXEngineArgs opt
746 return opt { optLaTeXEngineArgs = arg : oldArgs })
748 "" -- "Flags to pass to the LaTeX engine, all instances of this option are accumulated and used"
750 , Option "" ["bibliography"]
752 (\arg opt -> return opt{ optMetadata = addMetadata
753 "bibliography" (readMetaValue arg)
762 return opt{ optMetadata = addMetadata "csl"
768 , Option "" ["citation-abbreviations"]
771 return opt{ optMetadata = addMetadata
772 "citation-abbreviations"
778 , Option "" ["natbib"]
780 (\opt -> return opt { optCiteMethod = Natbib }))
781 "" -- "Use natbib cite commands in LaTeX output"
783 , Option "" ["biblatex"]
785 (\opt -> return opt { optCiteMethod = Biblatex }))
786 "" -- "Use biblatex cite commands in LaTeX output"
788 , Option "m" ["latexmathml", "asciimathml"]
791 return opt { optHTMLMathMethod = LaTeXMathML arg })
793 "" -- "Use LaTeXMathML script in html output"
795 , Option "" ["mathml"]
798 return opt { optHTMLMathMethod = MathML arg })
800 "" -- "Use mathml for HTML math"
802 , Option "" ["mimetex"]
805 let url' = case arg of
807 Nothing -> "/cgi-bin/mimetex.cgi?"
808 return opt { optHTMLMathMethod = WebTeX url' })
810 "" -- "Use mimetex for HTML math"
812 , Option "" ["webtex"]
815 let url' = case arg of
817 Nothing -> "http://chart.apis.google.com/chart?cht=tx&chl="
818 return opt { optHTMLMathMethod = WebTeX url' })
820 "" -- "Use web service for HTML math"
822 , Option "" ["jsmath"]
824 (\arg opt -> return opt { optHTMLMathMethod = JsMath arg})
826 "" -- "Use jsMath for HTML math"
828 , Option "" ["mathjax"]
831 let url' = case arg of
833 Nothing -> "https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"
834 return opt { optHTMLMathMethod = MathJax url'})
836 "" -- "Use MathJax for HTML math"
837 , Option "" ["katex"]
842 arg <|> Just "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.1.0/katex.min.js"})
844 "" -- Use KaTeX for HTML Math
846 , Option "" ["katex-stylesheet"]
849 return opt { optKaTeXStylesheet = Just arg })
851 "" -- Set the KaTeX Stylesheet location
853 , Option "" ["gladtex"]
855 (\opt -> return opt { optHTMLMathMethod = GladTeX }))
856 "" -- "Use gladtex for HTML math"
858 , Option "" ["trace"]
860 (\opt -> return opt { optTrace = True }))
861 "" -- "Turn on diagnostic tracing in readers."
863 , Option "" ["dump-args"]
865 (\opt -> return opt { optDumpArgs = True }))
866 "" -- "Print output filename and arguments to stdout."
868 , Option "" ["ignore-args"]
870 (\opt -> return opt { optIgnoreArgs = True }))
871 "" -- "Ignore command-line arguments."
876 manPandoc1 >>= UTF8.hPutStr stdout
877 exitWith ExitSuccess ))
878 "" -- "Print pandoc.1 man page"
883 manPandocMarkdown5 >>= UTF8.hPutStr stdout
884 exitWith ExitSuccess ))
885 "" -- "Print pandoc_markdown.5 man page"
887 , Option "" ["verbose"]
889 (\opt -> return opt { optVerbose = True }))
890 "" -- "Verbose diagnostic output."
892 , Option "v" ["version"]
896 defaultDatadir <- getAppUserDataDirectory "pandoc"
897 UTF8.hPutStrLn stdout (prg ++ " " ++ pandocVersion ++
898 compileInfo ++ "\nDefault user data directory: " ++
899 defaultDatadir ++ copyrightMessage)
900 exitWith ExitSuccess ))
901 "" -- "Print version"
903 , Option "h" ["help"]
907 UTF8.hPutStr stdout (usageMessage prg options)
908 exitWith ExitSuccess ))
914addMetadata :: String -> MetaValue -> M.Map String MetaValue
915 -> M.Map String MetaValue
916addMetadata k v m = case M.lookup k m of
917 Nothing -> M.insert k v m
918 Just (MetaList xs) -> M.insert k
919 (MetaList (xs ++ [v])) m
920 Just x -> M.insert k (MetaList [v, x]) m
922readMetaValue :: String -> MetaValue
923readMetaValue s = case decode (UTF8.fromString s) of
924 Just (Yaml.String t) -> MetaString $ T.unpack t
925 Just (Yaml.Bool b) -> MetaBool b
928-- Returns usage message
929usageMessage :: String -> [OptDescr (Opt -> IO Opt)] -> String
930usageMessage programName = usageInfo
931 (programName ++ " [OPTIONS] [FILES]" ++ "\nInput formats: " ++
932 (wrapWords 16 78 $ readers'names) ++
933 '\n' : replicate 16 ' ' ++
934 "[ *only Pandoc's JSON version of native AST]" ++ "\nOutput formats: " ++
935 (wrapWords 16 78 $ writers'names) ++
936 '\n' : replicate 16 ' ' ++
937 "[**for pdf output, use latex or beamer and -o FILENAME.pdf]\nOptions:")
939 writers'names = sort $ "json*" : "pdf**" : delete "json" (map fst writers)
940 readers'names = sort $ "json*" : delete "json" (map fst readers)
942-- Determine default reader based on source file extensions
943defaultReaderName :: String -> [FilePath] -> String
944defaultReaderName fallback [] = fallback
945defaultReaderName fallback (x:xs) =
946 case takeExtension (map toLower x) of
955 ".lhs" -> "markdown+lhs"
958 ".wiki" -> "mediawiki"
959 ".dokuwiki" -> "dokuwiki"
960 ".textile" -> "textile"
961 ".native" -> "native"
966 ".odt" -> "odt" -- so we get an "unknown reader" error
967 ".pdf" -> "pdf" -- so we get an "unknown reader" error
968 ".doc" -> "doc" -- so we get an "unknown reader" error
969 _ -> defaultReaderName fallback xs
971-- Returns True if extension of first source is .lhs
972lhsExtension :: [FilePath] -> Bool
973lhsExtension (x:_) = takeExtension x == ".lhs"
974lhsExtension _ = False
976-- Determine default writer based on output file extension
977defaultWriterName :: FilePath -> String
978defaultWriterName "-" = "html" -- no output file
980 case takeExtension (map toLower x) of
981 "" -> "markdown" -- empty extension
985 ".context" -> "context"
990 ".native" -> "native"
993 ".text" -> "markdown"
995 ".markdown" -> "markdown"
996 ".textile" -> "textile"
997 ".lhs" -> "markdown+lhs"
999 ".texinfo" -> "texinfo"
1005 ".asciidoc" -> "asciidoc"
1010 ['.',y] | y `elem` ['1'..'9'] -> "man"
1013-- Transformations of a Pandoc document post-parsing:
1015extractMedia :: MediaBag -> FilePath -> Pandoc -> IO Pandoc
1016extractMedia media dir d =
1017 case [fp | (fp, _, _) <- mediaDirectory media] of
1020 extractMediaBag True dir media
1021 return $ walk (adjustImagePath dir fps) d
1023adjustImagePath :: FilePath -> [FilePath] -> Inline -> Inline
1024adjustImagePath dir paths (Image lab (src, tit))
1025 | src `elem` paths = Image lab (dir ++ "/" ++ src, tit)
1026adjustImagePath _ _ x = x
1028adjustMetadata :: M.Map String MetaValue -> Pandoc -> IO Pandoc
1029adjustMetadata metadata d = return $ M.foldWithKey setMeta d metadata
1031applyTransforms :: [Transform] -> Pandoc -> IO Pandoc
1032applyTransforms transforms d = return $ foldr ($) d transforms
1034applyFilters :: [FilePath] -> [String] -> Pandoc -> IO Pandoc
1035applyFilters filters args d =
1036 foldrM ($) d $ map (flip externalFilter args) filters
1041 rawArgs <- map UTF8.decodeArg <$> getArgs
1043 let compatMode = (prg == "hsmarkdown")
1045 let (actions, args, errors) = if compatMode
1046 then ([], rawArgs, [])
1047 else getOpt Permute options rawArgs
1049 unless (null errors) $
1050 err 2 $ concat $ errors ++
1051 ["Try " ++ prg ++ " --help for more information."]
1053 let defaultOpts' = if compatMode
1054 then defaultOpts { optReader = "markdown_strict"
1055 , optWriter = "html"
1056 , optEmailObfuscation =
1057 ReferenceObfuscation }
1060 -- thread option data structure through all supplied option actions
1061 opts <- foldl (>>=) (return defaultOpts') actions
1063 let Opt { optTabStop = tabStop
1064 , optPreserveTabs = preserveTabs
1065 , optStandalone = standalone
1066 , optReader = readerName
1067 , optWriter = writerName
1068 , optParseRaw = parseRaw
1069 , optVariables = variables
1070 , optMetadata = metadata
1071 , optTableOfContents = toc
1072 , optTransforms = transforms
1073 , optTemplate = templatePath
1074 , optOutputFile = outputFile
1075 , optNumberSections = numberSections
1076 , optNumberOffset = numberFrom
1077 , optSectionDivs = sectionDivs
1078 , optIncremental = incremental
1079 , optSelfContained = selfContained
1081 , optOldDashes = oldDashes
1083 , optHtmlQTags = htmlQTags
1084 , optHighlight = highlight
1085 , optHighlightStyle = highlightStyle
1086 , optChapters = chapters
1087 , optHTMLMathMethod = mathMethod'
1088 , optReferenceODT = referenceODT
1089 , optReferenceDocx = referenceDocx
1090 , optEpubStylesheet = epubStylesheet
1091 , optEpubMetadata = epubMetadata
1092 , optEpubFonts = epubFonts
1093 , optEpubChapterLevel = epubChapterLevel
1094 , optTOCDepth = epubTOCDepth
1095 , optDumpArgs = dumpArgs
1096 , optIgnoreArgs = ignoreArgs
1097 , optVerbose = verbose
1098 , optReferenceLinks = referenceLinks
1099 , optWrapText = wrap
1100 , optColumns = columns
1101 , optFilters = filters
1102 , optEmailObfuscation = obfuscationMethod
1103 , optIdentifierPrefix = idPrefix
1104 , optIndentedCodeClasses = codeBlockClasses
1105 , optDataDir = mbDataDir
1106 , optCiteMethod = citeMethod
1107 , optListings = listings
1108 , optLaTeXEngine = latexEngine
1109 , optLaTeXEngineArgs = latexEngineArgs
1110 , optSlideLevel = slideLevel
1111 , optSetextHeaders = setextHeaders
1113 , optTeXLigatures = texLigatures
1114 , optDefaultImageExtension = defaultImageExtension
1115 , optExtractMedia = mbExtractMedia
1117 , optTrackChanges = trackChanges
1118 , optKaTeXStylesheet = katexStylesheet
1119 , optKaTeXJS = katexJS
1123 do UTF8.hPutStrLn stdout outputFile
1124 mapM_ (\arg -> UTF8.hPutStrLn stdout arg) args
1125 exitWith ExitSuccess
1127 let csscdn = "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.1.0/katex.min.css"
1129 case (katexJS, katexStylesheet) of
1130 (Nothing, _) -> mathMethod'
1131 (Just js, ss) -> KaTeX js (fromMaybe csscdn ss)
1134 -- --bibliography implies -F pandoc-citeproc for backwards compatibility:
1135 let needsCiteproc = any ("--bibliography" `isPrefixOf`) rawArgs &&
1136 optCiteMethod opts `notElem` [Natbib, Biblatex] &&
1137 "pandoc-citeproc" `notElem` map takeBaseName filters
1138 let filters' = if needsCiteproc then "pandoc-citeproc" : filters
1141 let sources = if ignoreArgs then [] else args
1143 datadir <- case mbDataDir of
1145 (Just <$> getAppUserDataDirectory "pandoc")
1146 (\e -> let _ = (e :: E.SomeException)
1148 Just _ -> return mbDataDir
1150 -- assign reader and writer based on options and filenames
1151 let readerName' = case map toLower readerName of
1152 [] -> defaultReaderName
1153 (if any isURI sources
1155 else "markdown") sources
1159 let writerName' = case map toLower writerName of
1160 [] -> defaultWriterName outputFile
1165 let pdfOutput = map toLower (takeExtension outputFile) == ".pdf"
1167 let laTeXOutput = "latex" `isPrefixOf` writerName' ||
1168 "beamer" `isPrefixOf` writerName'
1170 writer <- if ".lua" `isSuffixOf` writerName'
1171 -- note: use non-lowercased version writerName
1172 then return $ IOStringWriter $ writeCustom writerName
1173 else case getWriter writerName' of
1175 if writerName' == "pdf"
1177 "\nTo create a pdf with pandoc, use " ++
1178 "the latex or beamer writer and specify\n" ++
1179 "an output file with .pdf extension " ++
1180 "(pandoc -t latex -o filename.pdf)."
1184 reader <- if "t2t" == readerName'
1185 then (mkStringReader .
1187 (getT2TMeta sources outputFile)
1188 else case getReader readerName' of
1191 where e' = case readerName' of
1193 "\nPandoc can convert to ODT, but not from ODT.\nTry using LibreOffice to export as HTML, and convert that with pandoc."
1195 "\nPandoc can convert to PDF, but not from PDF."
1197 "\nPandoc can convert from DOCX, but not from DOC.\nTry using Word to save your DOC file as DOCX, and convert that with pandoc."
1200 let standalone' = standalone || not (isTextFormat writerName') || pdfOutput
1202 templ <- case templatePath of
1203 _ | not standalone' -> return ""
1205 deftemp <- getDefaultTemplate datadir writerName'
1210 -- strip off extensions
1211 let format = takeWhile (`notElem` "+-") writerName'
1212 let tp' = case takeExtension tp of
1215 E.catch (UTF8.readFile tp')
1216 (\e -> if isDoesNotExistError e
1218 (readDataFileUTF8 datadir
1219 ("templates" </> tp'))
1220 (\e' -> let _ = (e' :: E.SomeException)
1224 variables' <- case mathMethod of
1225 LaTeXMathML Nothing -> do
1226 s <- readDataFileUTF8 datadir "LaTeXMathML.js"
1227 return $ ("mathml-script", s) : variables
1228 MathML Nothing -> do
1229 s <- readDataFileUTF8 datadir "MathMLinHTML.js"
1230 return $ ("mathml-script", s) : variables
1231 _ -> return variables
1233 variables'' <- if "dzslides" `isPrefixOf` writerName'
1235 dztempl <- readDataFileUTF8 datadir
1236 ("dzslides" </> "template.html")
1237 let dzline = "<!-- {{{{ dzslides core"
1238 let dzcore = unlines
1239 $ dropWhile (not . (dzline `isPrefixOf`))
1241 return $ ("dzslides-core", dzcore) : variables'
1242 else return variables'
1244 let sourceURL = case sources of
1246 (x:_) -> case parseURI x of
1248 | uriScheme u `elem` ["http:","https:"] ->
1249 Just $ show u{ uriQuery = "",
1253 let readerOpts = def{ readerSmart = smart || (texLigatures &&
1254 (laTeXOutput || "context" `isPrefixOf` writerName'))
1255 , readerStandalone = standalone'
1256 , readerParseRaw = parseRaw
1257 , readerColumns = columns
1258 , readerTabStop = tabStop
1259 , readerOldDashes = oldDashes
1260 , readerIndentedCodeClasses = codeBlockClasses
1261 , readerApplyMacros = not laTeXOutput
1262 , readerDefaultImageExtension = defaultImageExtension
1263 , readerTrace = trace
1264 , readerTrackChanges = trackChanges
1267 when (not (isTextFormat writerName') && outputFile == "-") $
1268 err 5 $ "Cannot write " ++ writerName' ++ " output to stdout.\n" ++
1269 "Specify an output file using the -o option."
1271 let readSources [] = mapM readSource ["-"]
1272 readSources srcs = mapM readSource srcs
1273 readSource "-" = UTF8.getContents
1274 readSource src = case parseURI src of
1275 Just u | uriScheme u `elem` ["http:","https:"] ->
1277 _ -> UTF8.readFile src
1282 Right (bs,_) -> return $ UTF8.toString bs
1284 let readFiles [] = error "Cannot read archive from stdin"
1285 readFiles [x] = B.readFile x
1286 readFiles (x:xs) = mapM (warn . ("Ignoring: " ++)) xs >> B.readFile x
1288 let convertTabs = tabFilter (if preserveTabs || readerName' == "t2t"
1292 let handleIncludes' :: String -> IO (Either PandocError String)
1293 handleIncludes' = if readerName' `elem` ["latex", "latex+lhs"]
1297 (doc, media) <- fmap handleError $
1300 srcs <- convertTabs . intercalate "\n" <$> readSources sources
1301 doc <- handleIncludes' srcs
1302 either (return . Left) (\s -> fmap (,mempty) <$> r readerOpts s) doc
1303 ByteStringReader r -> readFiles sources >>= r readerOpts
1305 let writerOptions = def { writerStandalone = standalone',
1306 writerTemplate = templ,
1307 writerVariables = variables'',
1308 writerTabStop = tabStop,
1309 writerTableOfContents = toc,
1310 writerHTMLMathMethod = mathMethod,
1311 writerIncremental = incremental,
1312 writerCiteMethod = citeMethod,
1313 writerIgnoreNotes = False,
1314 writerNumberSections = numberSections,
1315 writerNumberOffset = numberFrom,
1316 writerSectionDivs = sectionDivs,
1317 writerReferenceLinks = referenceLinks,
1318 writerWrapText = wrap,
1319 writerColumns = columns,
1320 writerEmailObfuscation = obfuscationMethod,
1321 writerIdentifierPrefix = idPrefix,
1322 writerSourceURL = sourceURL,
1323 writerUserDataDir = datadir,
1324 writerHtml5 = html5,
1325 writerHtmlQTags = htmlQTags,
1326 writerChapters = chapters,
1327 writerListings = listings,
1328 writerBeamer = False,
1329 writerSlideLevel = slideLevel,
1330 writerHighlight = highlight,
1331 writerHighlightStyle = highlightStyle,
1332 writerSetextHeaders = setextHeaders,
1333 writerTeXLigatures = texLigatures,
1334 writerEpubMetadata = epubMetadata,
1335 writerEpubStylesheet = epubStylesheet,
1336 writerEpubFonts = epubFonts,
1337 writerEpubChapterLevel = epubChapterLevel,
1338 writerTOCDepth = epubTOCDepth,
1339 writerReferenceODT = referenceODT,
1340 writerReferenceDocx = referenceDocx,
1341 writerMediaBag = media,
1342 writerVerbose = verbose,
1343 writerLaTeXArgs = latexEngineArgs
1347 doc' <- (maybe return (extractMedia media) mbExtractMedia >=>
1348 adjustMetadata metadata >=>
1349 applyTransforms transforms >=>
1350 applyFilters filters' [writerName']) doc
1352 let writeBinary :: B.ByteString -> IO ()
1353 writeBinary = B.writeFile (UTF8.encodePath outputFile)
1355 let writerFn :: FilePath -> String -> IO ()
1356 writerFn "-" = UTF8.putStr
1357 writerFn f = UTF8.writeFile f
1360 IOStringWriter f -> f writerOptions doc' >>= writerFn outputFile
1361 IOByteStringWriter f -> f writerOptions doc' >>= writeBinary
1364 -- make sure writer is latex or beamer
1365 unless laTeXOutput $
1366 err 47 $ "cannot produce pdf output with " ++ writerName' ++
1369 -- check for latex program
1370 mbLatex <- findExecutable latexEngine
1371 when (mbLatex == Nothing) $
1372 err 41 $ latexEngine ++ " not found. " ++
1373 latexEngine ++ " is needed for pdf output."
1375 res <- makePDF latexEngine f writerOptions doc'
1377 Right pdf -> writeBinary pdf
1379 B.hPutStr stderr $ err'
1380 B.hPut stderr $ B.pack [10]
1381 err 43 "Error producing PDF from TeX source"
1382 | otherwise -> selfcontain (f writerOptions doc' ++
1383 ['\n' | not standalone'])
1384 >>= writerFn outputFile . handleEntities
1385 where htmlFormat = writerName' `elem`
1386 ["html","html+lhs","html5","html5+lhs",
1387 "s5","slidy","slideous","dzslides","revealjs"]
1388 selfcontain = if selfContained && htmlFormat
1389 then makeSelfContained writerOptions
1391 handleEntities = if htmlFormat && ascii
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list