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.XML ( toEntities )
43import Text.Pandoc.SelfContained ( makeSelfContained )
44import Text.Pandoc.Process (pipeProcess)
45import Text.Highlighting.Kate ( languages, Style, tango, pygments,
46 espresso, zenburn, kate, haddock, monochrome )
47import System.Environment ( getArgs, getProgName )
48import System.Exit ( exitWith, ExitCode (..) )
50import System.Console.GetOpt
51import Data.Char ( toLower )
52import Data.List ( delete, intercalate, isPrefixOf, isSuffixOf, sort )
53import System.Directory ( getAppUserDataDirectory, findExecutable,
54 doesFileExist, Permissions(..), getPermissions )
55import System.IO ( stdout, stderr )
56import System.IO.Error ( isDoesNotExistError )
57import qualified Control.Exception as E
58import Control.Exception.Extensible ( throwIO )
59import qualified Text.Pandoc.UTF8 as UTF8
60import Control.Monad (when, unless, (>=>))
61import Data.Maybe (fromMaybe, isNothing)
62import Data.Foldable (foldrM)
63import Network.URI (parseURI, isURI, URI(..))
64import qualified Data.ByteString.Lazy as B
65import qualified Data.ByteString as BS
66import Data.Aeson (eitherDecode', encode)
67import qualified Data.Map as M
68import Data.Yaml (decode)
69import qualified Data.Yaml as Yaml
70import qualified Data.Text as T
71import Control.Applicative ((<$>), (<|>))
72import Text.Pandoc.Readers.Txt2Tags (getT2TMeta)
75import Text.Pandoc.Error
77type Transform = Pandoc -> Pandoc
79copyrightMessage :: String
80copyrightMessage = intercalate "\n" [
82 "Copyright (C) 2006-2015 John MacFarlane",
83 "Web: http://pandoc.org",
84 "This is free software; see the source for copying conditions.",
85 "There is no warranty, not even for merchantability or fitness",
86 "for a particular purpose." ]
90 "\nCompiled with texmath " ++
91 VERSION_texmath ++ ", highlighting-kate " ++ VERSION_highlighting_kate ++
92 ".\nSyntax highlighting is supported for the following languages:\n " ++
94 [map toLower l | l <- languages, l /= "Alert" && l /= "Alert_indent"]
96-- | Converts a list of strings into a single string with the items printed as
97-- comma separated words in lines with a maximum line length.
98wrapWords :: Int -> Int -> [String] -> String
99wrapWords indent c = wrap' (c - indent) (c - indent)
102 wrap' cols remaining (x:xs)
103 | remaining == cols =
104 x ++ wrap' cols (remaining - length x) xs
105 | (length x + 1) > remaining =
106 ",\n" ++ replicate indent ' ' ++ x ++
107 wrap' cols (cols - length x) xs
110 wrap' cols (remaining - length x - 2) xs
112isTextFormat :: String -> Bool
113isTextFormat s = takeWhile (`notElem` "+-") s `notElem` binaries
114 where binaries = ["odt","docx","epub","epub3"]
116externalFilter :: FilePath -> [String] -> Pandoc -> IO Pandoc
117externalFilter f args' d = do
118 mbexe <- if '/' `elem` f
119 -- don't check PATH if filter name has a path
121 -- we catch isDoesNotExistError because this will
122 -- be triggered if PATH not set:
123 else E.catch (findExecutable f)
124 (\e -> if isDoesNotExistError e
127 (f', args'') <- case mbexe of
128 Just x -> return (x, args')
130 exists <- doesFileExist f
133 isExecutable <- executable `fmap`
136 case map toLower $ takeExtension f of
137 _ | isExecutable -> (f, args')
138 ".py" -> ("python", f:args')
139 ".hs" -> ("runhaskell", f:args')
140 ".pl" -> ("perl", f:args')
141 ".rb" -> ("ruby", f:args')
142 ".php" -> ("php", f:args')
144 else err 85 $ "Filter " ++ f ++ " not found"
146 mbExe <- findExecutable f'
147 when (isNothing mbExe) $
148 err 83 $ "Error running filter " ++ f ++ "\n" ++
149 show f' ++ " not found in path."
150 (exitcode, outbs, errbs) <- E.handle filterException $
151 pipeProcess Nothing f' args'' $ encode d
152 when (not $ B.null errbs) $ B.hPutStr stderr errbs
154 ExitSuccess -> return $ either error id $ eitherDecode' outbs
155 ExitFailure ec -> err 83 $ "Error running filter " ++ f ++ "\n" ++
156 "Filter returned error status " ++ show ec
157 where filterException :: E.SomeException -> IO a
158 filterException e = err 83 $ "Error running filter " ++ f ++ "\n" ++
161-- | Data structure for command line options.
163 { optTabStop :: Int -- ^ Number of spaces per tab
164 , optPreserveTabs :: Bool -- ^ Preserve tabs instead of converting to spaces
165 , optStandalone :: Bool -- ^ Include header, footer
166 , optReader :: String -- ^ Reader format
167 , optWriter :: String -- ^ Writer format
168 , optParseRaw :: Bool -- ^ Parse unconvertable HTML and TeX
169 , optTableOfContents :: Bool -- ^ Include table of contents
170 , optTransforms :: [Transform] -- ^ Doc transforms to apply
171 , optTemplate :: Maybe FilePath -- ^ Custom template
172 , optVariables :: [(String,String)] -- ^ Template variables to set
173 , optMetadata :: M.Map String MetaValue -- ^ Metadata fields to set
174 , optOutputFile :: String -- ^ Name of output file
175 , optNumberSections :: Bool -- ^ Number sections in LaTeX
176 , optNumberOffset :: [Int] -- ^ Starting number for sections
177 , optSectionDivs :: Bool -- ^ Put sections in div tags in HTML
178 , optIncremental :: Bool -- ^ Use incremental lists in Slidy/Slideous/S5
179 , optSelfContained :: Bool -- ^ Make HTML accessible offline
180 , optSmart :: Bool -- ^ Use smart typography
181 , optOldDashes :: Bool -- ^ Parse dashes like pandoc <=1.8.2.1
182 , optHtml5 :: Bool -- ^ Produce HTML5 in HTML
183 , optHtmlQTags :: Bool -- ^ Use <q> tags in HTML
184 , optHighlight :: Bool -- ^ Highlight source code
185 , optHighlightStyle :: Style -- ^ Style to use for highlighted code
186 , optChapters :: Bool -- ^ Use chapter for top-level sects
187 , optHTMLMathMethod :: HTMLMathMethod -- ^ Method to print HTML math
188 , optReferenceODT :: Maybe FilePath -- ^ Path of reference.odt
189 , optReferenceDocx :: Maybe FilePath -- ^ Path of reference.docx
190 , optEpubStylesheet :: Maybe String -- ^ EPUB stylesheet
191 , optEpubMetadata :: String -- ^ EPUB metadata
192 , optEpubFonts :: [FilePath] -- ^ EPUB fonts to embed
193 , optEpubChapterLevel :: Int -- ^ Header level at which to split chapters
194 , optTOCDepth :: Int -- ^ Number of levels to include in TOC
195 , optDumpArgs :: Bool -- ^ Output command-line arguments
196 , optIgnoreArgs :: Bool -- ^ Ignore command-line arguments
197 , optVerbose :: Bool -- ^ Verbose diagnostic output
198 , optReferenceLinks :: Bool -- ^ Use reference links in writing markdown, rst
199 , optWrapText :: Bool -- ^ Wrap text
200 , optColumns :: Int -- ^ Line length in characters
201 , optFilters :: [FilePath] -- ^ Filters to apply
202 , optEmailObfuscation :: ObfuscationMethod
203 , optIdentifierPrefix :: String
204 , optIndentedCodeClasses :: [String] -- ^ Default classes for indented code blocks
205 , optDataDir :: Maybe FilePath
206 , optCiteMethod :: CiteMethod -- ^ Method to output cites
207 , optListings :: Bool -- ^ Use listings package for code blocks
208 , optLaTeXEngine :: String -- ^ Program to use for latex -> pdf
209 , optLaTeXEngineArgs :: [String] -- ^ Flags to pass to the latex-engine
210 , optSlideLevel :: Maybe Int -- ^ Header level that creates slides
211 , optSetextHeaders :: Bool -- ^ Use atx headers for markdown level 1-2
212 , optAscii :: Bool -- ^ Use ascii characters only in html
213 , optTeXLigatures :: Bool -- ^ Use TeX ligatures for quotes/dashes
214 , optDefaultImageExtension :: String -- ^ Default image extension
215 , optExtractMedia :: Maybe FilePath -- ^ Path to extract embedded media
216 , optTrace :: Bool -- ^ Print debug information
217 , optTrackChanges :: TrackChanges -- ^ Accept or reject MS Word track-changes.
218 , optKaTeXStylesheet :: Maybe String -- ^ Path to stylesheet for KaTeX
219 , optKaTeXJS :: Maybe String -- ^ Path to js file for KaTeX
222-- | Defaults for command-line options.
226 , optPreserveTabs = False
227 , optStandalone = False
228 , optReader = "" -- null for default reader
229 , optWriter = "" -- null for default writer
230 , optParseRaw = False
231 , optTableOfContents = False
233 , optTemplate = Nothing
235 , optMetadata = M.empty
236 , optOutputFile = "-" -- "-" means stdout
237 , optNumberSections = False
238 , optNumberOffset = [0,0,0,0,0,0]
239 , optSectionDivs = False
240 , optIncremental = False
241 , optSelfContained = False
243 , optOldDashes = False
245 , optHtmlQTags = False
246 , optHighlight = True
247 , optHighlightStyle = pygments
248 , optChapters = False
249 , optHTMLMathMethod = PlainMath
250 , optReferenceODT = Nothing
251 , optReferenceDocx = Nothing
252 , optEpubStylesheet = Nothing
253 , optEpubMetadata = ""
255 , optEpubChapterLevel = 1
257 , optDumpArgs = False
258 , optIgnoreArgs = False
260 , optReferenceLinks = False
264 , optEmailObfuscation = JavascriptObfuscation
265 , optIdentifierPrefix = ""
266 , optIndentedCodeClasses = []
267 , optDataDir = Nothing
268 , optCiteMethod = Citeproc
269 , optListings = False
270 , optLaTeXEngine = "pdflatex"
271 , optLaTeXEngineArgs = []
272 , optSlideLevel = Nothing
273 , optSetextHeaders = True
275 , optTeXLigatures = True
276 , optDefaultImageExtension = ""
277 , optExtractMedia = Nothing
279 , optTrackChanges = AcceptChanges
280 , optKaTeXStylesheet = Nothing
281 , optKaTeXJS = Nothing
284-- | A list of functions, each transforming the options data structure
285-- in response to a command-line option.
286options :: [OptDescr (Opt -> IO Opt)]
288 [ Option "fr" ["from","read"]
290 (\arg opt -> return opt { optReader = arg })
294 , Option "tw" ["to","write"]
296 (\arg opt -> return opt { optWriter = arg })
300 , Option "o" ["output"]
302 (\arg opt -> return opt { optOutputFile = arg })
304 "" -- "Name of output file"
306 , Option "" ["data-dir"]
308 (\arg opt -> return opt { optDataDir = Just arg })
309 "DIRECTORY") -- "Directory containing pandoc data files."
312 , Option "" ["strict"]
315 err 59 $ "The --strict option has been removed.\n" ++
316 "Use `markdown_strict' input or output format instead."
318 "" -- "Disable markdown syntax extensions"
320 , Option "R" ["parse-raw"]
322 (\opt -> return opt { optParseRaw = True }))
323 "" -- "Parse untranslatable HTML codes and LaTeX environments as raw"
325 , Option "S" ["smart"]
327 (\opt -> return opt { optSmart = True }))
328 "" -- "Use smart quotes, dashes, and ellipses"
330 , Option "" ["old-dashes"]
332 (\opt -> return opt { optSmart = True
333 , optOldDashes = True }))
334 "" -- "Use smart quotes, dashes, and ellipses"
336 , Option "" ["base-header-level"]
341 let oldTransforms = optTransforms opt
343 return opt{ optTransforms =
344 headerShift shift : oldTransforms }
346 "base-header-level must be a number > 0")
348 "" -- "Headers base level"
350 , Option "" ["indented-code-classes"]
352 (\arg opt -> return opt { optIndentedCodeClasses = words $
353 map (\c -> if c == ',' then ' ' else c) arg })
355 "" -- "Classes (whitespace- or comma-separated) to use for indented code-blocks"
357 , Option "F" ["filter"]
359 (\arg opt -> return opt { optFilters = arg : optFilters opt })
361 "" -- "External JSON filter"
363 , Option "" ["normalize"]
365 (\opt -> return opt { optTransforms =
366 normalize : optTransforms opt } ))
367 "" -- "Normalize the Pandoc AST"
369 , Option "p" ["preserve-tabs"]
371 (\opt -> return opt { optPreserveTabs = True }))
372 "" -- "Preserve tabs instead of converting to spaces"
374 , Option "" ["tab-stop"]
378 Just t | t > 0 -> return opt { optTabStop = t }
380 "tab-stop must be a number greater than 0")
382 "" -- "Tab stop (default 4)"
384 , Option "" ["track-changes"]
387 action <- case arg of
388 "accept" -> return AcceptChanges
389 "reject" -> return RejectChanges
390 "all" -> return AllChanges
392 ("Unknown option for track-changes: " ++ arg)
393 return opt { optTrackChanges = action })
395 "" -- "Accepting or reject MS Word track-changes.""
397 , Option "" ["extract-media"]
400 return opt { optExtractMedia = Just arg })
402 "" -- "Directory to which to extract embedded media"
404 , Option "s" ["standalone"]
406 (\opt -> return opt { optStandalone = True }))
407 "" -- "Include needed header and footer on output"
409 , Option "" ["template"]
412 return opt{ optTemplate = Just arg,
413 optStandalone = True })
415 "" -- "Use custom template"
417 , Option "M" ["metadata"]
420 let (key,val) = case break (`elem` ":=") arg of
421 (k,_:v) -> (k, readMetaValue v)
422 (k,_) -> (k, MetaBool True)
423 return opt{ optMetadata = addMetadata key val
428 , Option "V" ["variable"]
431 let (key,val) = case break (`elem` ":=") arg of
434 return opt{ optVariables = (key,val) : optVariables opt })
438 , Option "D" ["print-default-template"]
441 templ <- getDefaultTemplate Nothing arg
443 Right t -> UTF8.hPutStr stdout t
444 Left e -> error $ show e
445 exitWith ExitSuccess)
447 "" -- "Print default template for FORMAT"
449 , Option "" ["print-default-data-file"]
452 readDataFile Nothing arg >>= BS.hPutStr stdout
453 exitWith ExitSuccess)
455 "" -- "Print default data file"
457 , Option "" ["no-wrap"]
459 (\opt -> return opt { optWrapText = False }))
460 "" -- "Do not wrap text in output"
462 , Option "" ["columns"]
466 Just t | t > 0 -> return opt { optColumns = t }
468 "columns must be a number greater than 0")
470 "" -- "Length of line in characters"
472 , Option "" ["toc", "table-of-contents"]
474 (\opt -> return opt { optTableOfContents = True }))
475 "" -- "Include table of contents"
477 , Option "" ["toc-depth"]
481 Just t | t >= 1 && t <= 6 ->
482 return opt { optTOCDepth = t }
484 "TOC level must be a number between 1 and 6")
486 "" -- "Number of levels to include in TOC"
488 , Option "" ["no-highlight"]
490 (\opt -> return opt { optHighlight = False }))
491 "" -- "Don't highlight source code"
493 , Option "" ["highlight-style"]
496 newStyle <- case map toLower arg of
497 "pygments" -> return pygments
498 "tango" -> return tango
499 "espresso" -> return espresso
500 "zenburn" -> return zenburn
501 "kate" -> return kate
502 "monochrome" -> return monochrome
503 "haddock" -> return haddock
505 "Unknown style :" ++ arg
506 return opt{ optHighlightStyle = newStyle })
508 "" -- "Style for highlighted code"
510 , Option "H" ["include-in-header"]
513 text <- UTF8.readFile arg
514 -- add new ones to end, so they're included in order specified
515 let newvars = optVariables opt ++ [("header-includes",text)]
516 return opt { optVariables = newvars,
517 optStandalone = True })
519 "" -- "File to include at end of header (implies -s)"
521 , Option "B" ["include-before-body"]
524 text <- UTF8.readFile arg
525 -- add new ones to end, so they're included in order specified
526 let newvars = optVariables opt ++ [("include-before",text)]
527 return opt { optVariables = newvars,
528 optStandalone = True })
530 "" -- "File to include before document body"
532 , Option "A" ["include-after-body"]
535 text <- UTF8.readFile arg
536 -- add new ones to end, so they're included in order specified
537 let newvars = optVariables opt ++ [("include-after",text)]
538 return opt { optVariables = newvars,
539 optStandalone = True })
541 "" -- "File to include after document body"
543 , Option "" ["self-contained"]
545 (\opt -> return opt { optSelfContained = True,
546 optStandalone = True }))
547 "" -- "Make slide shows include all the needed js and css"
549 , Option "" ["offline"]
551 (\opt -> do warn $ "--offline is deprecated. Use --self-contained instead."
552 return opt { optSelfContained = True,
553 optStandalone = True }))
554 "" -- "Make slide shows include all the needed js and css"
555 -- deprecated synonym for --self-contained
557 , Option "5" ["html5"]
560 warn $ "--html5 is deprecated. "
561 ++ "Use the html5 output format instead."
562 return opt { optHtml5 = True }))
563 "" -- "Produce HTML5 in HTML output"
565 , Option "" ["html-q-tags"]
568 return opt { optHtmlQTags = True }))
569 "" -- "Use <q> tags for quotes in HTML"
571 , Option "" ["ascii"]
573 (\opt -> return opt { optAscii = True }))
574 "" -- "Use ascii characters only in HTML output"
576 , Option "" ["reference-links"]
578 (\opt -> return opt { optReferenceLinks = True } ))
579 "" -- "Use reference links in parsing HTML"
581 , Option "" ["atx-headers"]
583 (\opt -> return opt { optSetextHeaders = False } ))
584 "" -- "Use atx-style headers for markdown"
586 , Option "" ["chapters"]
588 (\opt -> return opt { optChapters = True }))
589 "" -- "Use chapter for top-level sections in LaTeX, DocBook"
591 , Option "N" ["number-sections"]
593 (\opt -> return opt { optNumberSections = True }))
594 "" -- "Number sections in LaTeX"
596 , Option "" ["number-offset"]
599 case safeRead ('[':arg ++ "]") of
600 Just ns -> return opt { optNumberOffset = ns,
601 optNumberSections = True }
602 _ -> err 57 "could not parse number-offset")
604 "" -- "Starting number for sections, subsections, etc."
606 , Option "" ["no-tex-ligatures"]
608 (\opt -> return opt { optTeXLigatures = False }))
609 "" -- "Don't use tex ligatures for quotes, dashes"
611 , Option "" ["listings"]
613 (\opt -> return opt { optListings = True }))
614 "" -- "Use listings package for LaTeX code blocks"
616 , Option "i" ["incremental"]
618 (\opt -> return opt { optIncremental = True }))
619 "" -- "Make list items display incrementally in Slidy/Slideous/S5"
621 , Option "" ["slide-level"]
625 Just t | t >= 1 && t <= 6 ->
626 return opt { optSlideLevel = Just t }
628 "slide level must be a number between 1 and 6")
630 "" -- "Force header level for slides"
632 , Option "" ["section-divs"]
634 (\opt -> return opt { optSectionDivs = True }))
635 "" -- "Put sections in div tags in HTML"
637 , Option "" ["default-image-extension"]
639 (\arg opt -> return opt { optDefaultImageExtension = arg })
641 "" -- "Default extension for extensionless images"
643 , Option "" ["email-obfuscation"]
646 method <- case arg of
647 "references" -> return ReferenceObfuscation
648 "javascript" -> return JavascriptObfuscation
649 "none" -> return NoObfuscation
651 ("Unknown obfuscation method: " ++ arg)
652 return opt { optEmailObfuscation = method })
653 "none|javascript|references")
654 "" -- "Method for obfuscating email in HTML"
656 , Option "" ["id-prefix"]
658 (\arg opt -> return opt { optIdentifierPrefix = arg })
660 "" -- "Prefix to add to automatically generated HTML identifiers"
662 , Option "T" ["title-prefix"]
665 let newvars = ("title-prefix", arg) : optVariables opt
666 return opt { optVariables = newvars,
667 optStandalone = True })
669 "" -- "String to prefix to HTML window title"
674 -- add new link to end, so it is included in proper order
675 let newvars = optVariables opt ++ [("css",arg)]
676 return opt { optVariables = newvars,
677 optStandalone = True })
679 "" -- "Link to CSS style sheet"
681 , Option "" ["reference-odt"]
684 return opt { optReferenceODT = Just arg })
686 "" -- "Path of custom reference.odt"
688 , Option "" ["reference-docx"]
691 return opt { optReferenceDocx = Just arg })
693 "" -- "Path of custom reference.docx"
695 , Option "" ["epub-stylesheet"]
698 text <- UTF8.readFile arg
699 return opt { optEpubStylesheet = Just text })
701 "" -- "Path of epub.css"
703 , Option "" ["epub-cover-image"]
706 return opt { optVariables =
707 ("epub-cover-image", arg) : optVariables opt })
709 "" -- "Path of epub cover image"
711 , Option "" ["epub-metadata"]
714 text <- UTF8.readFile arg
715 return opt { optEpubMetadata = text })
717 "" -- "Path of epub metadata file"
719 , Option "" ["epub-embed-font"]
722 return opt{ optEpubFonts = arg : optEpubFonts opt })
724 "" -- "Directory of fonts to embed"
726 , Option "" ["epub-chapter-level"]
730 Just t | t >= 1 && t <= 6 ->
731 return opt { optEpubChapterLevel = t }
733 "chapter level must be a number between 1 and 6")
735 "" -- "Header level at which to split chapters in EPUB"
737 , Option "" ["latex-engine"]
740 let b = takeBaseName arg
741 if b `elem` ["pdflatex", "lualatex", "xelatex"]
742 then return opt { optLaTeXEngine = arg }
743 else err 45 "latex-engine must be pdflatex, lualatex, or xelatex.")
745 "" -- "Name of latex program to use in generating PDF"
747 , Option "" ["latex-engine-opt"]
750 let oldArgs = optLaTeXEngineArgs opt
751 return opt { optLaTeXEngineArgs = arg : oldArgs })
753 "" -- "Flags to pass to the LaTeX engine, all instances of this option are accumulated and used"
755 , Option "" ["bibliography"]
757 (\arg opt -> return opt{ optMetadata = addMetadata
758 "bibliography" (readMetaValue arg)
767 return opt{ optMetadata = addMetadata "csl"
773 , Option "" ["citation-abbreviations"]
776 return opt{ optMetadata = addMetadata
777 "citation-abbreviations"
783 , Option "" ["natbib"]
785 (\opt -> return opt { optCiteMethod = Natbib }))
786 "" -- "Use natbib cite commands in LaTeX output"
788 , Option "" ["biblatex"]
790 (\opt -> return opt { optCiteMethod = Biblatex }))
791 "" -- "Use biblatex cite commands in LaTeX output"
793 , Option "m" ["latexmathml", "asciimathml"]
796 return opt { optHTMLMathMethod = LaTeXMathML arg })
798 "" -- "Use LaTeXMathML script in html output"
800 , Option "" ["mathml"]
803 return opt { optHTMLMathMethod = MathML arg })
805 "" -- "Use mathml for HTML math"
807 , Option "" ["mimetex"]
810 let url' = case arg of
812 Nothing -> "/cgi-bin/mimetex.cgi?"
813 return opt { optHTMLMathMethod = WebTeX url' })
815 "" -- "Use mimetex for HTML math"
817 , Option "" ["webtex"]
820 let url' = case arg of
822 Nothing -> "http://chart.apis.google.com/chart?cht=tx&chl="
823 return opt { optHTMLMathMethod = WebTeX url' })
825 "" -- "Use web service for HTML math"
827 , Option "" ["jsmath"]
829 (\arg opt -> return opt { optHTMLMathMethod = JsMath arg})
831 "" -- "Use jsMath for HTML math"
833 , Option "" ["mathjax"]
836 let url' = case arg of
838 Nothing -> "https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"
839 return opt { optHTMLMathMethod = MathJax url'})
841 "" -- "Use MathJax for HTML math"
842 , Option "" ["katex"]
847 arg <|> Just "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.1.0/katex.min.js"})
849 "" -- Use KaTeX for HTML Math
851 , Option "" ["katex-stylesheet"]
854 return opt { optKaTeXStylesheet = Just arg })
856 "" -- Set the KaTeX Stylesheet location
858 , Option "" ["gladtex"]
860 (\opt -> return opt { optHTMLMathMethod = GladTeX }))
861 "" -- "Use gladtex for HTML math"
863 , Option "" ["trace"]
865 (\opt -> return opt { optTrace = True }))
866 "" -- "Turn on diagnostic tracing in readers."
868 , Option "" ["dump-args"]
870 (\opt -> return opt { optDumpArgs = True }))
871 "" -- "Print output filename and arguments to stdout."
873 , Option "" ["ignore-args"]
875 (\opt -> return opt { optIgnoreArgs = True }))
876 "" -- "Ignore command-line arguments."
878 , Option "" ["verbose"]
880 (\opt -> return opt { optVerbose = True }))
881 "" -- "Verbose diagnostic output."
883 , Option "v" ["version"]
887 defaultDatadir <- getAppUserDataDirectory "pandoc"
888 UTF8.hPutStrLn stdout (prg ++ " " ++ pandocVersion ++
889 compileInfo ++ "\nDefault user data directory: " ++
890 defaultDatadir ++ copyrightMessage)
891 exitWith ExitSuccess ))
892 "" -- "Print version"
894 , Option "h" ["help"]
898 UTF8.hPutStr stdout (usageMessage prg options)
899 exitWith ExitSuccess ))
905addMetadata :: String -> MetaValue -> M.Map String MetaValue
906 -> M.Map String MetaValue
907addMetadata k v m = case M.lookup k m of
908 Nothing -> M.insert k v m
909 Just (MetaList xs) -> M.insert k
910 (MetaList (xs ++ [v])) m
911 Just x -> M.insert k (MetaList [v, x]) m
913readMetaValue :: String -> MetaValue
914readMetaValue s = case decode (UTF8.fromString s) of
915 Just (Yaml.String t) -> MetaString $ T.unpack t
916 Just (Yaml.Bool b) -> MetaBool b
919-- Returns usage message
920usageMessage :: String -> [OptDescr (Opt -> IO Opt)] -> String
921usageMessage programName = usageInfo
922 (programName ++ " [OPTIONS] [FILES]" ++ "\nInput formats: " ++
923 (wrapWords 16 78 $ readers'names) ++
924 '\n' : replicate 16 ' ' ++
925 "[ *only Pandoc's JSON version of native AST]" ++ "\nOutput formats: " ++
926 (wrapWords 16 78 $ writers'names) ++
927 '\n' : replicate 16 ' ' ++
928 "[**for pdf output, use latex or beamer and -o FILENAME.pdf]\nOptions:")
930 writers'names = sort $ "json*" : "pdf**" : delete "json" (map fst writers)
931 readers'names = sort $ "json*" : delete "json" (map fst readers)
933-- Determine default reader based on source file extensions
934defaultReaderName :: String -> [FilePath] -> String
935defaultReaderName fallback [] = fallback
936defaultReaderName fallback (x:xs) =
937 case takeExtension (map toLower x) of
946 ".lhs" -> "markdown+lhs"
949 ".wiki" -> "mediawiki"
950 ".dokuwiki" -> "dokuwiki"
951 ".textile" -> "textile"
952 ".native" -> "native"
957 ".odt" -> "odt" -- so we get an "unknown reader" error
958 ".pdf" -> "pdf" -- so we get an "unknown reader" error
959 ".doc" -> "doc" -- so we get an "unknown reader" error
960 _ -> defaultReaderName fallback xs
962-- Returns True if extension of first source is .lhs
963lhsExtension :: [FilePath] -> Bool
964lhsExtension (x:_) = takeExtension x == ".lhs"
965lhsExtension _ = False
967-- Determine default writer based on output file extension
968defaultWriterName :: FilePath -> String
969defaultWriterName "-" = "html" -- no output file
971 case takeExtension (map toLower x) of
972 "" -> "markdown" -- empty extension
976 ".context" -> "context"
981 ".native" -> "native"
984 ".text" -> "markdown"
986 ".markdown" -> "markdown"
987 ".textile" -> "textile"
988 ".lhs" -> "markdown+lhs"
990 ".texinfo" -> "texinfo"
996 ".asciidoc" -> "asciidoc"
1001 ['.',y] | y `elem` ['1'..'9'] -> "man"
1004-- Transformations of a Pandoc document post-parsing:
1006extractMedia :: MediaBag -> FilePath -> Pandoc -> IO Pandoc
1007extractMedia media dir d =
1008 case [fp | (fp, _, _) <- mediaDirectory media] of
1011 extractMediaBag True dir media
1012 return $ walk (adjustImagePath dir fps) d
1014adjustImagePath :: FilePath -> [FilePath] -> Inline -> Inline
1015adjustImagePath dir paths (Image lab (src, tit))
1016 | src `elem` paths = Image lab (dir ++ "/" ++ src, tit)
1017adjustImagePath _ _ x = x
1019adjustMetadata :: M.Map String MetaValue -> Pandoc -> IO Pandoc
1020adjustMetadata metadata d = return $ M.foldWithKey setMeta d metadata
1022applyTransforms :: [Transform] -> Pandoc -> IO Pandoc
1023applyTransforms transforms d = return $ foldr ($) d transforms
1025applyFilters :: [FilePath] -> [String] -> Pandoc -> IO Pandoc
1026applyFilters filters args d =
1027 foldrM ($) d $ map (flip externalFilter args) filters
1032 rawArgs <- map UTF8.decodeArg <$> getArgs
1034 let compatMode = (prg == "hsmarkdown")
1036 let (actions, args, errors) = if compatMode
1037 then ([], rawArgs, [])
1038 else getOpt Permute options rawArgs
1040 unless (null errors) $
1041 err 2 $ concat $ errors ++
1042 ["Try " ++ prg ++ " --help for more information."]
1044 let defaultOpts' = if compatMode
1045 then defaultOpts { optReader = "markdown_strict"
1046 , optWriter = "html"
1047 , optEmailObfuscation =
1048 ReferenceObfuscation }
1051 -- thread option data structure through all supplied option actions
1052 opts <- foldl (>>=) (return defaultOpts') actions
1054 let Opt { optTabStop = tabStop
1055 , optPreserveTabs = preserveTabs
1056 , optStandalone = standalone
1057 , optReader = readerName
1058 , optWriter = writerName
1059 , optParseRaw = parseRaw
1060 , optVariables = variables
1061 , optMetadata = metadata
1062 , optTableOfContents = toc
1063 , optTransforms = transforms
1064 , optTemplate = templatePath
1065 , optOutputFile = outputFile
1066 , optNumberSections = numberSections
1067 , optNumberOffset = numberFrom
1068 , optSectionDivs = sectionDivs
1069 , optIncremental = incremental
1070 , optSelfContained = selfContained
1072 , optOldDashes = oldDashes
1074 , optHtmlQTags = htmlQTags
1075 , optHighlight = highlight
1076 , optHighlightStyle = highlightStyle
1077 , optChapters = chapters
1078 , optHTMLMathMethod = mathMethod'
1079 , optReferenceODT = referenceODT
1080 , optReferenceDocx = referenceDocx
1081 , optEpubStylesheet = epubStylesheet
1082 , optEpubMetadata = epubMetadata
1083 , optEpubFonts = epubFonts
1084 , optEpubChapterLevel = epubChapterLevel
1085 , optTOCDepth = epubTOCDepth
1086 , optDumpArgs = dumpArgs
1087 , optIgnoreArgs = ignoreArgs
1088 , optVerbose = verbose
1089 , optReferenceLinks = referenceLinks
1090 , optWrapText = wrap
1091 , optColumns = columns
1092 , optFilters = filters
1093 , optEmailObfuscation = obfuscationMethod
1094 , optIdentifierPrefix = idPrefix
1095 , optIndentedCodeClasses = codeBlockClasses
1096 , optDataDir = mbDataDir
1097 , optCiteMethod = citeMethod
1098 , optListings = listings
1099 , optLaTeXEngine = latexEngine
1100 , optLaTeXEngineArgs = latexEngineArgs
1101 , optSlideLevel = slideLevel
1102 , optSetextHeaders = setextHeaders
1104 , optTeXLigatures = texLigatures
1105 , optDefaultImageExtension = defaultImageExtension
1106 , optExtractMedia = mbExtractMedia
1108 , optTrackChanges = trackChanges
1109 , optKaTeXStylesheet = katexStylesheet
1110 , optKaTeXJS = katexJS
1114 do UTF8.hPutStrLn stdout outputFile
1115 mapM_ (\arg -> UTF8.hPutStrLn stdout arg) args
1116 exitWith ExitSuccess
1118 let csscdn = "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.1.0/katex.min.css"
1120 case (katexJS, katexStylesheet) of
1121 (Nothing, _) -> mathMethod'
1122 (Just js, ss) -> KaTeX js (fromMaybe csscdn ss)
1125 -- --bibliography implies -F pandoc-citeproc for backwards compatibility:
1126 let needsCiteproc = any ("--bibliography" `isPrefixOf`) rawArgs &&
1127 optCiteMethod opts `notElem` [Natbib, Biblatex] &&
1128 "pandoc-citeproc" `notElem` map takeBaseName filters
1129 let filters' = if needsCiteproc then "pandoc-citeproc" : filters
1132 let sources = if ignoreArgs then [] else args
1134 datadir <- case mbDataDir of
1136 (Just <$> getAppUserDataDirectory "pandoc")
1137 (\e -> let _ = (e :: E.SomeException)
1139 Just _ -> return mbDataDir
1141 -- assign reader and writer based on options and filenames
1142 let readerName' = case map toLower readerName of
1143 [] -> defaultReaderName
1144 (if any isURI sources
1146 else "markdown") sources
1150 let writerName' = case map toLower writerName of
1151 [] -> defaultWriterName outputFile
1156 let pdfOutput = map toLower (takeExtension outputFile) == ".pdf"
1158 let laTeXOutput = "latex" `isPrefixOf` writerName' ||
1159 "beamer" `isPrefixOf` writerName'
1161 writer <- if ".lua" `isSuffixOf` writerName'
1162 -- note: use non-lowercased version writerName
1163 then return $ IOStringWriter $ writeCustom writerName
1164 else case getWriter writerName' of
1166 if writerName' == "pdf"
1168 "\nTo create a pdf with pandoc, use " ++
1169 "the latex or beamer writer and specify\n" ++
1170 "an output file with .pdf extension " ++
1171 "(pandoc -t latex -o filename.pdf)."
1175 reader <- if "t2t" == readerName'
1176 then (mkStringReader .
1178 (getT2TMeta sources outputFile)
1179 else case getReader readerName' of
1182 where e' = case readerName' of
1184 "\nPandoc can convert to ODT, but not from ODT.\nTry using LibreOffice to export as HTML, and convert that with pandoc."
1186 "\nPandoc can convert to PDF, but not from PDF."
1188 "\nPandoc can convert from DOCX, but not from DOC.\nTry using Word to save your DOC file as DOCX, and convert that with pandoc."
1191 let standalone' = standalone || not (isTextFormat writerName') || pdfOutput
1193 templ <- case templatePath of
1194 _ | not standalone' -> return ""
1196 deftemp <- getDefaultTemplate datadir writerName'
1201 -- strip off extensions
1202 let format = takeWhile (`notElem` "+-") writerName'
1203 let tp' = case takeExtension tp of
1206 E.catch (UTF8.readFile tp')
1207 (\e -> if isDoesNotExistError e
1209 (readDataFileUTF8 datadir
1210 ("templates" </> tp'))
1211 (\e' -> let _ = (e' :: E.SomeException)
1215 variables' <- case mathMethod of
1216 LaTeXMathML Nothing -> do
1217 s <- readDataFileUTF8 datadir "LaTeXMathML.js"
1218 return $ ("mathml-script", s) : variables
1219 MathML Nothing -> do
1220 s <- readDataFileUTF8 datadir "MathMLinHTML.js"
1221 return $ ("mathml-script", s) : variables
1222 _ -> return variables
1224 variables'' <- if "dzslides" `isPrefixOf` writerName'
1226 dztempl <- readDataFileUTF8 datadir
1227 ("dzslides" </> "template.html")
1228 let dzline = "<!-- {{{{ dzslides core"
1229 let dzcore = unlines
1230 $ dropWhile (not . (dzline `isPrefixOf`))
1232 return $ ("dzslides-core", dzcore) : variables'
1233 else return variables'
1235 let sourceURL = case sources of
1237 (x:_) -> case parseURI x of
1239 | uriScheme u `elem` ["http:","https:"] ->
1240 Just $ show u{ uriQuery = "",
1244 let readerOpts = def{ readerSmart = smart || (texLigatures &&
1245 (laTeXOutput || "context" `isPrefixOf` writerName'))
1246 , readerStandalone = standalone'
1247 , readerParseRaw = parseRaw
1248 , readerColumns = columns
1249 , readerTabStop = tabStop
1250 , readerOldDashes = oldDashes
1251 , readerIndentedCodeClasses = codeBlockClasses
1252 , readerApplyMacros = not laTeXOutput
1253 , readerDefaultImageExtension = defaultImageExtension
1254 , readerTrace = trace
1255 , readerTrackChanges = trackChanges
1258 when (not (isTextFormat writerName') && outputFile == "-") $
1259 err 5 $ "Cannot write " ++ writerName' ++ " output to stdout.\n" ++
1260 "Specify an output file using the -o option."
1262 let readSources [] = mapM readSource ["-"]
1263 readSources srcs = mapM readSource srcs
1264 readSource "-" = UTF8.getContents
1265 readSource src = case parseURI src of
1266 Just u | uriScheme u `elem` ["http:","https:"] ->
1268 _ -> UTF8.readFile src
1273 Right (bs,_) -> return $ UTF8.toString bs
1275 let readFiles [] = error "Cannot read archive from stdin"
1276 readFiles [x] = B.readFile x
1277 readFiles (x:xs) = mapM (warn . ("Ignoring: " ++)) xs >> B.readFile x
1279 let convertTabs = tabFilter (if preserveTabs || readerName' == "t2t"
1283 let handleIncludes' :: String -> IO (Either PandocError String)
1284 handleIncludes' = if readerName' `elem` ["latex", "latex+lhs"]
1288 (doc, media) <- fmap handleError $
1291 srcs <- convertTabs . intercalate "\n" <$> readSources sources
1292 doc <- handleIncludes' srcs
1293 either (return . Left) (\s -> fmap (,mempty) <$> r readerOpts s) doc
1294 ByteStringReader r -> readFiles sources >>= r readerOpts
1296 let writerOptions = def { writerStandalone = standalone',
1297 writerTemplate = templ,
1298 writerVariables = variables'',
1299 writerTabStop = tabStop,
1300 writerTableOfContents = toc,
1301 writerHTMLMathMethod = mathMethod,
1302 writerIncremental = incremental,
1303 writerCiteMethod = citeMethod,
1304 writerIgnoreNotes = False,
1305 writerNumberSections = numberSections,
1306 writerNumberOffset = numberFrom,
1307 writerSectionDivs = sectionDivs,
1308 writerReferenceLinks = referenceLinks,
1309 writerWrapText = wrap,
1310 writerColumns = columns,
1311 writerEmailObfuscation = obfuscationMethod,
1312 writerIdentifierPrefix = idPrefix,
1313 writerSourceURL = sourceURL,
1314 writerUserDataDir = datadir,
1315 writerHtml5 = html5,
1316 writerHtmlQTags = htmlQTags,
1317 writerChapters = chapters,
1318 writerListings = listings,
1319 writerBeamer = False,
1320 writerSlideLevel = slideLevel,
1321 writerHighlight = highlight,
1322 writerHighlightStyle = highlightStyle,
1323 writerSetextHeaders = setextHeaders,
1324 writerTeXLigatures = texLigatures,
1325 writerEpubMetadata = epubMetadata,
1326 writerEpubStylesheet = epubStylesheet,
1327 writerEpubFonts = epubFonts,
1328 writerEpubChapterLevel = epubChapterLevel,
1329 writerTOCDepth = epubTOCDepth,
1330 writerReferenceODT = referenceODT,
1331 writerReferenceDocx = referenceDocx,
1332 writerMediaBag = media,
1333 writerVerbose = verbose,
1334 writerLaTeXArgs = latexEngineArgs
1338 doc' <- (maybe return (extractMedia media) mbExtractMedia >=>
1339 adjustMetadata metadata >=>
1340 applyTransforms transforms >=>
1341 applyFilters filters' [writerName']) doc
1343 let writeBinary :: B.ByteString -> IO ()
1344 writeBinary = B.writeFile (UTF8.encodePath outputFile)
1346 let writerFn :: FilePath -> String -> IO ()
1347 writerFn "-" = UTF8.putStr
1348 writerFn f = UTF8.writeFile f
1351 IOStringWriter f -> f writerOptions doc' >>= writerFn outputFile
1352 IOByteStringWriter f -> f writerOptions doc' >>= writeBinary
1355 -- make sure writer is latex or beamer
1356 unless laTeXOutput $
1357 err 47 $ "cannot produce pdf output with " ++ writerName' ++
1360 -- check for latex program
1361 mbLatex <- findExecutable latexEngine
1362 when (mbLatex == Nothing) $
1363 err 41 $ latexEngine ++ " not found. " ++
1364 latexEngine ++ " is needed for pdf output."
1366 res <- makePDF latexEngine f writerOptions doc'
1368 Right pdf -> writeBinary pdf
1370 B.hPutStr stderr $ err'
1371 B.hPut stderr $ B.pack [10]
1372 err 43 "Error producing PDF from TeX source"
1373 | otherwise -> selfcontain (f writerOptions doc' ++
1374 ['\n' | not standalone'])
1375 >>= writerFn outputFile . handleEntities
1376 where htmlFormat = writerName' `elem`
1377 ["html","html+lhs","html5","html5+lhs",
1378 "s5","slidy","slideous","dzslides","revealjs"]
1379 selfcontain = if selfContained && htmlFormat
1380 then makeSelfContained writerOptions
1382 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