3Copyright (C) 2006-2013 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-2013 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.Readers.LaTeX (handleIncludes)
37import Text.Pandoc.Shared ( tabFilter, readDataFileUTF8, readDataFile,
38 safeRead, headerShift, normalize, err, warn,
40import Text.Pandoc.XML ( toEntities )
41import Text.Pandoc.SelfContained ( makeSelfContained )
42import Text.Pandoc.Process (pipeProcess)
43import Text.Highlighting.Kate ( languages, Style, tango, pygments,
44 espresso, zenburn, kate, haddock, monochrome )
45import System.Environment ( getArgs, getProgName )
46import System.Exit ( exitWith, ExitCode (..) )
48import System.Console.GetOpt
49import Data.Char ( toLower )
50import Data.List ( intercalate, isPrefixOf, isSuffixOf, sort )
51import System.Directory ( getAppUserDataDirectory, findExecutable,
53import System.IO ( stdout, stderr )
54import System.IO.Error ( isDoesNotExistError )
55import qualified Control.Exception as E
56import Control.Exception.Extensible ( throwIO )
57import qualified Text.Pandoc.UTF8 as UTF8
58import Control.Monad (when, unless, liftM)
59import Data.Foldable (foldrM)
60import Network.URI (parseURI, isURI, URI(..))
61import qualified Data.ByteString.Lazy as B
62import qualified Data.ByteString as BS
63import Data.Aeson (eitherDecode', encode)
64import qualified Data.Map as M
65import System.IO.Error(ioeGetErrorType)
66import GHC.IO.Exception (IOErrorType(ResourceVanished))
67import Data.Yaml (decode)
68import qualified Data.Yaml as Yaml
69import qualified Data.Text as T
71copyrightMessage :: String
72copyrightMessage = "\nCopyright (C) 2006-2013 John MacFarlane\n" ++
73 "Web: http://johnmacfarlane.net/pandoc\n" ++
74 "This is free software; see the source for copying conditions. There is no\n" ++
75 "warranty, not even for merchantability or fitness for a particular purpose."
79 "\nCompiled with texmath " ++
80 VERSION_texmath ++ ", highlighting-kate " ++ VERSION_highlighting_kate ++
81 ".\nSyntax highlighting is supported for the following languages:\n " ++
83 [map toLower l | l <- languages, l /= "Alert" && l /= "Alert_indent"]
85-- | Converts a list of strings into a single string with the items printed as
86-- comma separated words in lines with a maximum line length.
87wrapWords :: Int -> Int -> [String] -> String
88wrapWords indent c = wrap' (c - indent) (c - indent)
89 where wrap' _ _ [] = ""
90 wrap' cols remaining (x:xs) = if remaining == cols
91 then x ++ wrap' cols (remaining - length x) xs
92 else if (length x + 1) > remaining
93 then ",\n" ++ replicate indent ' ' ++ x ++ wrap' cols (cols - length x) xs
94 else ", " ++ x ++ wrap' cols (remaining - (length x + 2)) xs
96isTextFormat :: String -> Bool
97isTextFormat s = takeWhile (`notElem` "+-") s `notElem` ["odt","docx","epub","epub3"]
99externalFilter :: FilePath -> [String] -> Pandoc -> IO Pandoc
100externalFilter f args' d = do
101 mbexe <- findExecutable f
102 (f', args'') <- case mbexe of
103 Just x -> return (x, args')
105 exists <- doesFileExist f
108 case map toLower $ takeExtension f of
109 ".py" -> ("python", f:args')
110 ".hs" -> ("runhaskell", f:args')
111 ".pl" -> ("perl", f:args')
112 ".rb" -> ("ruby", f:args')
113 ".php" -> ("php", f:args')
115 else err 85 $ "Filter " ++ f ++ " not found"
116 (exitcode, outbs, errbs) <- E.handle filterException $
117 pipeProcess Nothing f' args'' $ encode d
118 when (not $ B.null errbs) $ B.hPutStr stderr errbs
120 ExitSuccess -> return $ either error id $ eitherDecode' outbs
121 ExitFailure _ -> err 83 $ "Error running filter " ++ f
122 where filterException :: E.SomeException -> IO a
123 filterException e = err 83 $ "Error running filter " ++ f ++ "\n" ++
124 if ioeGetErrorType `fmap` E.fromException e ==
125 Just ResourceVanished
126 then f ++ " not found in path"
129-- | Data structure for command line options.
131 { optTabStop :: Int -- ^ Number of spaces per tab
132 , optPreserveTabs :: Bool -- ^ Preserve tabs instead of converting to spaces
133 , optStandalone :: Bool -- ^ Include header, footer
134 , optReader :: String -- ^ Reader format
135 , optWriter :: String -- ^ Writer format
136 , optParseRaw :: Bool -- ^ Parse unconvertable HTML and TeX
137 , optTableOfContents :: Bool -- ^ Include table of contents
138 , optTransforms :: [Pandoc -> Pandoc] -- ^ Doc transforms to apply
139 , optTemplate :: Maybe FilePath -- ^ Custom template
140 , optVariables :: [(String,String)] -- ^ Template variables to set
141 , optMetadata :: M.Map String MetaValue -- ^ Metadata fields to set
142 , optOutputFile :: String -- ^ Name of output file
143 , optNumberSections :: Bool -- ^ Number sections in LaTeX
144 , optNumberOffset :: [Int] -- ^ Starting number for sections
145 , optSectionDivs :: Bool -- ^ Put sections in div tags in HTML
146 , optIncremental :: Bool -- ^ Use incremental lists in Slidy/Slideous/S5
147 , optSelfContained :: Bool -- ^ Make HTML accessible offline
148 , optSmart :: Bool -- ^ Use smart typography
149 , optOldDashes :: Bool -- ^ Parse dashes like pandoc <=1.8.2.1
150 , optHtml5 :: Bool -- ^ Produce HTML5 in HTML
151 , optHtmlQTags :: Bool -- ^ Use <q> tags in HTML
152 , optHighlight :: Bool -- ^ Highlight source code
153 , optHighlightStyle :: Style -- ^ Style to use for highlighted code
154 , optChapters :: Bool -- ^ Use chapter for top-level sects
155 , optHTMLMathMethod :: HTMLMathMethod -- ^ Method to print HTML math
156 , optReferenceODT :: Maybe FilePath -- ^ Path of reference.odt
157 , optReferenceDocx :: Maybe FilePath -- ^ Path of reference.docx
158 , optEpubStylesheet :: Maybe String -- ^ EPUB stylesheet
159 , optEpubMetadata :: String -- ^ EPUB metadata
160 , optEpubFonts :: [FilePath] -- ^ EPUB fonts to embed
161 , optEpubChapterLevel :: Int -- ^ Header level at which to split chapters
162 , optTOCDepth :: Int -- ^ Number of levels to include in TOC
163 , optDumpArgs :: Bool -- ^ Output command-line arguments
164 , optIgnoreArgs :: Bool -- ^ Ignore command-line arguments
165 , optReferenceLinks :: Bool -- ^ Use reference links in writing markdown, rst
166 , optWrapText :: Bool -- ^ Wrap text
167 , optColumns :: Int -- ^ Line length in characters
168 , optFilters :: [FilePath] -- ^ Filters to apply
169 , optEmailObfuscation :: ObfuscationMethod
170 , optIdentifierPrefix :: String
171 , optIndentedCodeClasses :: [String] -- ^ Default classes for indented code blocks
172 , optDataDir :: Maybe FilePath
173 , optCiteMethod :: CiteMethod -- ^ Method to output cites
174 , optListings :: Bool -- ^ Use listings package for code blocks
175 , optLaTeXEngine :: String -- ^ Program to use for latex -> pdf
176 , optSlideLevel :: Maybe Int -- ^ Header level that creates slides
177 , optSetextHeaders :: Bool -- ^ Use atx headers for markdown level 1-2
178 , optAscii :: Bool -- ^ Use ascii characters only in html
179 , optTeXLigatures :: Bool -- ^ Use TeX ligatures for quotes/dashes
180 , optDefaultImageExtension :: String -- ^ Default image extension
181 , optTrace :: Bool -- ^ Print debug information
184-- | Defaults for command-line options.
188 , optPreserveTabs = False
189 , optStandalone = False
190 , optReader = "" -- null for default reader
191 , optWriter = "" -- null for default writer
192 , optParseRaw = False
193 , optTableOfContents = False
195 , optTemplate = Nothing
197 , optMetadata = M.empty
198 , optOutputFile = "-" -- "-" means stdout
199 , optNumberSections = False
200 , optNumberOffset = [0,0,0,0,0,0]
201 , optSectionDivs = False
202 , optIncremental = False
203 , optSelfContained = False
205 , optOldDashes = False
207 , optHtmlQTags = False
208 , optHighlight = True
209 , optHighlightStyle = pygments
210 , optChapters = False
211 , optHTMLMathMethod = PlainMath
212 , optReferenceODT = Nothing
213 , optReferenceDocx = Nothing
214 , optEpubStylesheet = Nothing
215 , optEpubMetadata = ""
217 , optEpubChapterLevel = 1
219 , optDumpArgs = False
220 , optIgnoreArgs = False
221 , optReferenceLinks = False
225 , optEmailObfuscation = JavascriptObfuscation
226 , optIdentifierPrefix = ""
227 , optIndentedCodeClasses = []
228 , optDataDir = Nothing
229 , optCiteMethod = Citeproc
230 , optListings = False
231 , optLaTeXEngine = "pdflatex"
232 , optSlideLevel = Nothing
233 , optSetextHeaders = True
235 , optTeXLigatures = True
236 , optDefaultImageExtension = ""
240-- | A list of functions, each transforming the options data structure
241-- in response to a command-line option.
242options :: [OptDescr (Opt -> IO Opt)]
244 [ Option "fr" ["from","read"]
246 (\arg opt -> return opt { optReader = arg })
250 , Option "tw" ["to","write"]
252 (\arg opt -> return opt { optWriter = arg })
256 , Option "o" ["output"]
258 (\arg opt -> return opt { optOutputFile = arg })
260 "" -- "Name of output file"
262 , Option "" ["data-dir"]
264 (\arg opt -> return opt { optDataDir = Just arg })
265 "DIRECTORY") -- "Directory containing pandoc data files."
268 , Option "" ["strict"]
271 err 59 $ "The --strict option has been removed.\n" ++
272 "Use `markdown_strict' input or output format instead."
274 "" -- "Disable markdown syntax extensions"
276 , Option "R" ["parse-raw"]
278 (\opt -> return opt { optParseRaw = True }))
279 "" -- "Parse untranslatable HTML codes and LaTeX environments as raw"
281 , Option "S" ["smart"]
283 (\opt -> return opt { optSmart = True }))
284 "" -- "Use smart quotes, dashes, and ellipses"
286 , Option "" ["old-dashes"]
288 (\opt -> return opt { optSmart = True
289 , optOldDashes = True }))
290 "" -- "Use smart quotes, dashes, and ellipses"
292 , Option "" ["base-header-level"]
297 let oldTransforms = optTransforms opt
299 return opt{ optTransforms =
300 headerShift shift : oldTransforms }
302 "base-header-level must be a number > 0")
304 "" -- "Headers base level"
306 , Option "" ["indented-code-classes"]
308 (\arg opt -> return opt { optIndentedCodeClasses = words $
309 map (\c -> if c == ',' then ' ' else c) arg })
311 "" -- "Classes (whitespace- or comma-separated) to use for indented code-blocks"
313 , Option "F" ["filter"]
315 (\arg opt -> return opt { optFilters = arg : optFilters opt })
317 "" -- "External JSON filter"
319 , Option "" ["normalize"]
321 (\opt -> return opt { optTransforms =
322 normalize : optTransforms opt } ))
323 "" -- "Normalize the Pandoc AST"
325 , Option "p" ["preserve-tabs"]
327 (\opt -> return opt { optPreserveTabs = True }))
328 "" -- "Preserve tabs instead of converting to spaces"
330 , Option "" ["tab-stop"]
334 Just t | t > 0 -> return opt { optTabStop = t }
336 "tab-stop must be a number greater than 0")
338 "" -- "Tab stop (default 4)"
340 , Option "s" ["standalone"]
342 (\opt -> return opt { optStandalone = True }))
343 "" -- "Include needed header and footer on output"
345 , Option "" ["template"]
348 return opt{ optTemplate = Just arg,
349 optStandalone = True })
351 "" -- "Use custom template"
353 , Option "M" ["metadata"]
356 let (key,val) = case break (`elem` ":=") arg of
357 (k,_:v) -> (k, readMetaValue v)
358 (k,_) -> (k, MetaBool True)
359 return opt{ optMetadata = addMetadata key val
364 , Option "V" ["variable"]
367 let (key,val) = case break (`elem` ":=") arg of
370 return opt{ optVariables = (key,val) : optVariables opt })
374 , Option "D" ["print-default-template"]
377 templ <- getDefaultTemplate Nothing arg
379 Right t -> UTF8.hPutStr stdout t
380 Left e -> error $ show e
381 exitWith ExitSuccess)
383 "" -- "Print default template for FORMAT"
385 , Option "" ["print-default-data-file"]
388 readDataFile Nothing arg >>= BS.hPutStr stdout
389 exitWith ExitSuccess)
391 "" -- "Print default data file"
393 , Option "" ["no-wrap"]
395 (\opt -> return opt { optWrapText = False }))
396 "" -- "Do not wrap text in output"
398 , Option "" ["columns"]
402 Just t | t > 0 -> return opt { optColumns = t }
404 "columns must be a number greater than 0")
406 "" -- "Length of line in characters"
408 , Option "" ["toc", "table-of-contents"]
410 (\opt -> return opt { optTableOfContents = True }))
411 "" -- "Include table of contents"
413 , Option "" ["toc-depth"]
417 Just t | t >= 1 && t <= 6 ->
418 return opt { optTOCDepth = t }
420 "TOC level must be a number between 1 and 6")
422 "" -- "Number of levels to include in TOC"
424 , Option "" ["no-highlight"]
426 (\opt -> return opt { optHighlight = False }))
427 "" -- "Don't highlight source code"
429 , Option "" ["highlight-style"]
432 newStyle <- case map toLower arg of
433 "pygments" -> return pygments
434 "tango" -> return tango
435 "espresso" -> return espresso
436 "zenburn" -> return zenburn
437 "kate" -> return kate
438 "monochrome" -> return monochrome
439 "haddock" -> return haddock
441 "Unknown style :" ++ arg
442 return opt{ optHighlightStyle = newStyle })
444 "" -- "Style for highlighted code"
446 , Option "H" ["include-in-header"]
449 text <- UTF8.readFile arg
450 -- add new ones to end, so they're included in order specified
451 let newvars = optVariables opt ++ [("header-includes",text)]
452 return opt { optVariables = newvars,
453 optStandalone = True })
455 "" -- "File to include at end of header (implies -s)"
457 , Option "B" ["include-before-body"]
460 text <- UTF8.readFile arg
461 -- add new ones to end, so they're included in order specified
462 let newvars = optVariables opt ++ [("include-before",text)]
463 return opt { optVariables = newvars,
464 optStandalone = True })
466 "" -- "File to include before document body"
468 , Option "A" ["include-after-body"]
471 text <- UTF8.readFile arg
472 -- add new ones to end, so they're included in order specified
473 let newvars = optVariables opt ++ [("include-after",text)]
474 return opt { optVariables = newvars,
475 optStandalone = True })
477 "" -- "File to include after document body"
479 , Option "" ["self-contained"]
481 (\opt -> return opt { optSelfContained = True,
482 optStandalone = True }))
483 "" -- "Make slide shows include all the needed js and css"
485 , Option "" ["offline"]
487 (\opt -> do warn $ "--offline is deprecated. Use --self-contained instead."
488 return opt { optSelfContained = True,
489 optStandalone = True }))
490 "" -- "Make slide shows include all the needed js and css"
491 -- deprecated synonym for --self-contained
493 , Option "5" ["html5"]
496 warn $ "--html5 is deprecated. "
497 ++ "Use the html5 output format instead."
498 return opt { optHtml5 = True }))
499 "" -- "Produce HTML5 in HTML output"
501 , Option "" ["html-q-tags"]
504 return opt { optHtmlQTags = True }))
505 "" -- "Use <q> tags for quotes in HTML"
507 , Option "" ["ascii"]
509 (\opt -> return opt { optAscii = True }))
510 "" -- "Use ascii characters only in HTML output"
512 , Option "" ["reference-links"]
514 (\opt -> return opt { optReferenceLinks = True } ))
515 "" -- "Use reference links in parsing HTML"
517 , Option "" ["atx-headers"]
519 (\opt -> return opt { optSetextHeaders = False } ))
520 "" -- "Use atx-style headers for markdown"
522 , Option "" ["chapters"]
524 (\opt -> return opt { optChapters = True }))
525 "" -- "Use chapter for top-level sections in LaTeX, DocBook"
527 , Option "N" ["number-sections"]
529 (\opt -> return opt { optNumberSections = True }))
530 "" -- "Number sections in LaTeX"
532 , Option "" ["number-offset"]
535 case safeRead ('[':arg ++ "]") of
536 Just ns -> return opt { optNumberOffset = ns,
537 optNumberSections = True }
538 _ -> err 57 "could not parse number-offset")
540 "" -- "Starting number for sections, subsections, etc."
542 , Option "" ["no-tex-ligatures"]
544 (\opt -> return opt { optTeXLigatures = False }))
545 "" -- "Don't use tex ligatures for quotes, dashes"
547 , Option "" ["listings"]
549 (\opt -> return opt { optListings = True }))
550 "" -- "Use listings package for LaTeX code blocks"
552 , Option "i" ["incremental"]
554 (\opt -> return opt { optIncremental = True }))
555 "" -- "Make list items display incrementally in Slidy/Slideous/S5"
557 , Option "" ["slide-level"]
561 Just t | t >= 1 && t <= 6 ->
562 return opt { optSlideLevel = Just t }
564 "slide level must be a number between 1 and 6")
566 "" -- "Force header level for slides"
568 , Option "" ["section-divs"]
570 (\opt -> return opt { optSectionDivs = True }))
571 "" -- "Put sections in div tags in HTML"
573 , Option "" ["default-image-extension"]
575 (\arg opt -> return opt { optDefaultImageExtension = arg })
577 "" -- "Default extension for extensionless images"
579 , Option "" ["email-obfuscation"]
582 method <- case arg of
583 "references" -> return ReferenceObfuscation
584 "javascript" -> return JavascriptObfuscation
585 "none" -> return NoObfuscation
587 ("Unknown obfuscation method: " ++ arg)
588 return opt { optEmailObfuscation = method })
589 "none|javascript|references")
590 "" -- "Method for obfuscating email in HTML"
592 , Option "" ["id-prefix"]
594 (\arg opt -> return opt { optIdentifierPrefix = arg })
596 "" -- "Prefix to add to automatically generated HTML identifiers"
598 , Option "T" ["title-prefix"]
601 let newvars = ("title-prefix", arg) : optVariables opt
602 return opt { optVariables = newvars,
603 optStandalone = True })
605 "" -- "String to prefix to HTML window title"
610 -- add new link to end, so it is included in proper order
611 let newvars = optVariables opt ++ [("css",arg)]
612 return opt { optVariables = newvars,
613 optStandalone = True })
615 "" -- "Link to CSS style sheet"
617 , Option "" ["reference-odt"]
620 return opt { optReferenceODT = Just arg })
622 "" -- "Path of custom reference.odt"
624 , Option "" ["reference-docx"]
627 return opt { optReferenceDocx = Just arg })
629 "" -- "Path of custom reference.docx"
631 , Option "" ["epub-stylesheet"]
634 text <- UTF8.readFile arg
635 return opt { optEpubStylesheet = Just text })
637 "" -- "Path of epub.css"
639 , Option "" ["epub-cover-image"]
642 return opt { optVariables =
643 ("epub-cover-image", arg) : optVariables opt })
645 "" -- "Path of epub cover image"
647 , Option "" ["epub-metadata"]
650 text <- UTF8.readFile arg
651 return opt { optEpubMetadata = text })
653 "" -- "Path of epub metadata file"
655 , Option "" ["epub-embed-font"]
658 return opt{ optEpubFonts = arg : optEpubFonts opt })
660 "" -- "Directory of fonts to embed"
662 , Option "" ["epub-chapter-level"]
666 Just t | t >= 1 && t <= 6 ->
667 return opt { optEpubChapterLevel = t }
669 "chapter level must be a number between 1 and 6")
671 "" -- "Header level at which to split chapters in EPUB"
673 , Option "" ["latex-engine"]
676 let b = takeBaseName arg
677 if b `elem` ["pdflatex", "lualatex", "xelatex"]
678 then return opt { optLaTeXEngine = arg }
679 else err 45 "latex-engine must be pdflatex, lualatex, or xelatex.")
681 "" -- "Name of latex program to use in generating PDF"
683 , Option "" ["bibliography"]
685 (\arg opt -> return opt{ optMetadata = addMetadata
686 "bibliography" (readMetaValue arg)
689 ("biblio-files", dropExtension arg) :
698 return opt{ optMetadata = addMetadata "csl"
704 , Option "" ["citation-abbreviations"]
707 return opt{ optMetadata = addMetadata
708 "citation-abbreviations"
714 , Option "" ["natbib"]
716 (\opt -> return opt { optCiteMethod = Natbib }))
717 "" -- "Use natbib cite commands in LaTeX output"
719 , Option "" ["biblatex"]
721 (\opt -> return opt { optCiteMethod = Biblatex }))
722 "" -- "Use biblatex cite commands in LaTeX output"
724 , Option "m" ["latexmathml", "asciimathml"]
727 return opt { optHTMLMathMethod = LaTeXMathML arg })
729 "" -- "Use LaTeXMathML script in html output"
731 , Option "" ["mathml"]
734 return opt { optHTMLMathMethod = MathML arg })
736 "" -- "Use mathml for HTML math"
738 , Option "" ["mimetex"]
741 let url' = case arg of
743 Nothing -> "/cgi-bin/mimetex.cgi?"
744 return opt { optHTMLMathMethod = WebTeX url' })
746 "" -- "Use mimetex for HTML math"
748 , Option "" ["webtex"]
751 let url' = case arg of
753 Nothing -> "http://chart.apis.google.com/chart?cht=tx&chl="
754 return opt { optHTMLMathMethod = WebTeX url' })
756 "" -- "Use web service for HTML math"
758 , Option "" ["jsmath"]
760 (\arg opt -> return opt { optHTMLMathMethod = JsMath arg})
762 "" -- "Use jsMath for HTML math"
764 , Option "" ["mathjax"]
767 let url' = case arg of
769 Nothing -> "http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"
770 return opt { optHTMLMathMethod = MathJax url'})
772 "" -- "Use MathJax for HTML math"
774 , Option "" ["gladtex"]
776 (\opt -> return opt { optHTMLMathMethod = GladTeX }))
777 "" -- "Use gladtex for HTML math"
779 , Option "" ["trace"]
781 (\opt -> return opt { optTrace = True }))
782 "" -- "Turn on diagnostic tracing in readers."
784 , Option "" ["dump-args"]
786 (\opt -> return opt { optDumpArgs = True }))
787 "" -- "Print output filename and arguments to stdout."
789 , Option "" ["ignore-args"]
791 (\opt -> return opt { optIgnoreArgs = True }))
792 "" -- "Ignore command-line arguments."
794 , Option "v" ["version"]
798 defaultDatadir <- getAppUserDataDirectory "pandoc"
799 UTF8.hPutStrLn stdout (prg ++ " " ++ pandocVersion ++
800 compileInfo ++ "\nDefault user data directory: " ++
801 defaultDatadir ++ copyrightMessage)
802 exitWith ExitSuccess ))
803 "" -- "Print version"
805 , Option "h" ["help"]
809 UTF8.hPutStr stdout (usageMessage prg options)
810 exitWith ExitSuccess ))
815addMetadata :: String -> MetaValue -> M.Map String MetaValue
816 -> M.Map String MetaValue
817addMetadata k v m = case M.lookup k m of
818 Nothing -> M.insert k v m
819 Just (MetaList xs) -> M.insert k
820 (MetaList (xs ++ [v])) m
821 Just x -> M.insert k (MetaList [v, x]) m
823readMetaValue :: String -> MetaValue
824readMetaValue s = case decode (UTF8.fromString s) of
825 Just (Yaml.String t) -> MetaString $ T.unpack t
826 Just (Yaml.Bool b) -> MetaBool b
829-- Returns usage message
830usageMessage :: String -> [OptDescr (Opt -> IO Opt)] -> String
831usageMessage programName = usageInfo
832 (programName ++ " [OPTIONS] [FILES]" ++ "\nInput formats: " ++
833 (wrapWords 16 78 $ readers'names) ++ "\nOutput formats: " ++
834 (wrapWords 16 78 $ writers'names) ++
835 '\n' : replicate 16 ' ' ++
836 "[*for pdf output, use latex or beamer and -o FILENAME.pdf]\nOptions:")
838 writers'names = sort $ "pdf*" : map fst writers
839 readers'names = sort $ map fst readers
841-- Determine default reader based on source file extensions
842defaultReaderName :: String -> [FilePath] -> String
843defaultReaderName fallback [] = fallback
844defaultReaderName fallback (x:xs) =
845 case takeExtension (map toLower x) of
854 ".lhs" -> "markdown+lhs"
857 ".wiki" -> "mediawiki"
858 ".textile" -> "textile"
859 ".native" -> "native"
861 _ -> defaultReaderName fallback xs
863-- Returns True if extension of first source is .lhs
864lhsExtension :: [FilePath] -> Bool
865lhsExtension (x:_) = takeExtension x == ".lhs"
866lhsExtension _ = False
868-- Determine default writer based on output file extension
869defaultWriterName :: FilePath -> String
870defaultWriterName "-" = "html" -- no output file
872 case takeExtension (map toLower x) of
873 "" -> "markdown" -- empty extension
877 ".context" -> "context"
882 ".native" -> "native"
885 ".text" -> "markdown"
887 ".markdown" -> "markdown"
888 ".textile" -> "textile"
889 ".lhs" -> "markdown+lhs"
891 ".texinfo" -> "texinfo"
897 ".asciidoc" -> "asciidoc"
901 ['.',y] | y `elem` ['1'..'9'] -> "man"
907 rawArgs <- liftM (map UTF8.decodeArg) getArgs
909 let compatMode = (prg == "hsmarkdown")
911 let (actions, args, errors) = if compatMode
912 then ([], rawArgs, [])
913 else getOpt Permute options rawArgs
915 unless (null errors) $
916 err 2 $ concat $ errors ++
917 ["Try " ++ prg ++ " --help for more information."]
919 let defaultOpts' = if compatMode
920 then defaultOpts { optReader = "markdown_strict"
922 , optEmailObfuscation =
923 ReferenceObfuscation }
926 -- thread option data structure through all supplied option actions
927 opts <- foldl (>>=) (return defaultOpts') actions
929 let Opt { optTabStop = tabStop
930 , optPreserveTabs = preserveTabs
931 , optStandalone = standalone
932 , optReader = readerName
933 , optWriter = writerName
934 , optParseRaw = parseRaw
935 , optVariables = variables
936 , optMetadata = metadata
937 , optTableOfContents = toc
938 , optTransforms = transforms
939 , optTemplate = templatePath
940 , optOutputFile = outputFile
941 , optNumberSections = numberSections
942 , optNumberOffset = numberFrom
943 , optSectionDivs = sectionDivs
944 , optIncremental = incremental
945 , optSelfContained = selfContained
947 , optOldDashes = oldDashes
949 , optHtmlQTags = htmlQTags
950 , optHighlight = highlight
951 , optHighlightStyle = highlightStyle
952 , optChapters = chapters
953 , optHTMLMathMethod = mathMethod
954 , optReferenceODT = referenceODT
955 , optReferenceDocx = referenceDocx
956 , optEpubStylesheet = epubStylesheet
957 , optEpubMetadata = epubMetadata
958 , optEpubFonts = epubFonts
959 , optEpubChapterLevel = epubChapterLevel
960 , optTOCDepth = epubTOCDepth
961 , optDumpArgs = dumpArgs
962 , optIgnoreArgs = ignoreArgs
963 , optReferenceLinks = referenceLinks
965 , optColumns = columns
966 , optFilters = filters
967 , optEmailObfuscation = obfuscationMethod
968 , optIdentifierPrefix = idPrefix
969 , optIndentedCodeClasses = codeBlockClasses
970 , optDataDir = mbDataDir
971 , optCiteMethod = citeMethod
972 , optListings = listings
973 , optLaTeXEngine = latexEngine
974 , optSlideLevel = slideLevel
975 , optSetextHeaders = setextHeaders
977 , optTeXLigatures = texLigatures
978 , optDefaultImageExtension = defaultImageExtension
983 do UTF8.hPutStrLn stdout outputFile
984 mapM_ (\arg -> UTF8.hPutStrLn stdout arg) args
987 -- --bibliography implies -F pandoc-citeproc for backwards compatibility:
988 let filters' = case M.lookup "bibliography" metadata of
989 Just _ | optCiteMethod opts /= Natbib &&
990 optCiteMethod opts /= Biblatex &&
991 all (\f -> takeBaseName f /= "pandoc-citeproc")
992 filters -> "pandoc-citeproc" : filters
994 let plugins = map externalFilter filters'
996 let sources = if ignoreArgs then [] else args
998 datadir <- case mbDataDir of
1000 (liftM Just $ getAppUserDataDirectory "pandoc")
1001 (\e -> let _ = (e :: E.SomeException)
1003 Just _ -> return mbDataDir
1005 -- assign reader and writer based on options and filenames
1006 let readerName' = case map toLower readerName of
1007 [] -> defaultReaderName
1008 (if any isURI sources
1010 else "markdown") sources
1014 let writerName' = case map toLower writerName of
1015 [] -> defaultWriterName outputFile
1020 let pdfOutput = map toLower (takeExtension outputFile) == ".pdf"
1022 let laTeXOutput = "latex" `isPrefixOf` writerName' ||
1023 "beamer" `isPrefixOf` writerName'
1025 writer <- if ".lua" `isSuffixOf` writerName'
1026 -- note: use non-lowercased version writerName
1027 then return $ IOStringWriter $ writeCustom writerName
1028 else case getWriter writerName' of
1030 if writerName' == "pdf"
1031 then e ++ "\nTo create a pdf with pandoc, use " ++
1032 "the latex or beamer writer and specify\n" ++
1033 "an output file with .pdf extension " ++
1034 "(pandoc -t latex -o filename.pdf)."
1038 reader <- case getReader readerName' of
1042 let standalone' = standalone || not (isTextFormat writerName') || pdfOutput
1044 templ <- case templatePath of
1045 _ | not standalone' -> return ""
1047 deftemp <- getDefaultTemplate datadir writerName'
1052 -- strip off extensions
1053 let format = takeWhile (`notElem` "+-") writerName'
1054 let tp' = case takeExtension tp of
1057 E.catch (UTF8.readFile tp')
1058 (\e -> if isDoesNotExistError e
1060 (readDataFileUTF8 datadir
1061 ("templates" </> tp'))
1062 (\e' -> let _ = (e' :: E.SomeException)
1066 variables' <- case mathMethod of
1067 LaTeXMathML Nothing -> do
1068 s <- readDataFileUTF8 datadir "LaTeXMathML.js"
1069 return $ ("mathml-script", s) : variables
1070 MathML Nothing -> do
1071 s <- readDataFileUTF8 datadir "MathMLinHTML.js"
1072 return $ ("mathml-script", s) : variables
1073 _ -> return variables
1075 variables'' <- if "dzslides" `isPrefixOf` writerName'
1077 dztempl <- readDataFileUTF8 datadir
1078 ("dzslides" </> "template.html")
1079 let dzcore = unlines $ dropWhile (not . isPrefixOf "<!-- {{{{ dzslides core")
1081 return $ ("dzslides-core", dzcore) : variables'
1082 else return variables'
1083 let sourceURL = case sources of
1085 (x:_) -> case parseURI x of
1087 | uriScheme u `elem` ["http:","https:"] ->
1088 Just $ show u{ uriPath = "",
1093 let readerOpts = def{ readerSmart = smart || (texLigatures &&
1094 (laTeXOutput || "context" `isPrefixOf` writerName'))
1095 , readerStandalone = standalone'
1096 , readerParseRaw = parseRaw
1097 , readerColumns = columns
1098 , readerTabStop = tabStop
1099 , readerOldDashes = oldDashes
1100 , readerIndentedCodeClasses = codeBlockClasses
1101 , readerApplyMacros = not laTeXOutput
1102 , readerDefaultImageExtension = defaultImageExtension
1103 , readerTrace = trace
1106 let writerOptions = def { writerStandalone = standalone',
1107 writerTemplate = templ,
1108 writerVariables = variables'',
1109 writerTabStop = tabStop,
1110 writerTableOfContents = toc,
1111 writerHTMLMathMethod = mathMethod,
1112 writerIncremental = incremental,
1113 writerCiteMethod = citeMethod,
1114 writerIgnoreNotes = False,
1115 writerNumberSections = numberSections,
1116 writerNumberOffset = numberFrom,
1117 writerSectionDivs = sectionDivs,
1118 writerReferenceLinks = referenceLinks,
1119 writerWrapText = wrap,
1120 writerColumns = columns,
1121 writerEmailObfuscation = obfuscationMethod,
1122 writerIdentifierPrefix = idPrefix,
1123 writerSourceURL = sourceURL,
1124 writerUserDataDir = datadir,
1125 writerHtml5 = html5,
1126 writerHtmlQTags = htmlQTags,
1127 writerChapters = chapters,
1128 writerListings = listings,
1129 writerBeamer = False,
1130 writerSlideLevel = slideLevel,
1131 writerHighlight = highlight,
1132 writerHighlightStyle = highlightStyle,
1133 writerSetextHeaders = setextHeaders,
1134 writerTeXLigatures = texLigatures,
1135 writerEpubMetadata = epubMetadata,
1136 writerEpubStylesheet = epubStylesheet,
1137 writerEpubFonts = epubFonts,
1138 writerEpubChapterLevel = epubChapterLevel,
1139 writerTOCDepth = epubTOCDepth,
1140 writerReferenceODT = referenceODT,
1141 writerReferenceDocx = referenceDocx
1144 when (not (isTextFormat writerName') && outputFile == "-") $
1145 err 5 $ "Cannot write " ++ writerName' ++ " output to stdout.\n" ++
1146 "Specify an output file using the -o option."
1148 let readSources [] = mapM readSource ["-"]
1149 readSources srcs = mapM readSource srcs
1150 readSource "-" = UTF8.getContents
1151 readSource src = case parseURI src of
1152 Just u | uriScheme u `elem` ["http:","https:"] ->
1154 _ -> UTF8.readFile src
1159 Right (bs,_) -> return $ UTF8.toString bs
1161 let convertTabs = tabFilter (if preserveTabs then 0 else tabStop)
1163 let handleIncludes' = if readerName' == "latex" || readerName' == "latex+lhs"
1167 doc <- readSources sources >>=
1168 handleIncludes' . convertTabs . intercalate "\n" >>=
1172 let doc0 = M.foldWithKey setMeta doc metadata
1173 let doc1 = foldr ($) doc0 transforms
1174 doc2 <- foldrM ($) doc1 $ map ($ [writerName']) plugins
1176 let writeBinary :: B.ByteString -> IO ()
1177 writeBinary = B.writeFile (UTF8.encodePath outputFile)
1179 let writerFn :: FilePath -> String -> IO ()
1180 writerFn "-" = UTF8.putStr
1181 writerFn f = UTF8.writeFile f
1184 IOStringWriter f -> f writerOptions doc2 >>= writerFn outputFile
1185 IOByteStringWriter f -> f writerOptions doc2 >>= writeBinary
1188 -- make sure writer is latex or beamer
1189 unless laTeXOutput $
1190 err 47 $ "cannot produce pdf output with " ++ writerName' ++
1193 -- check for latex program
1194 mbLatex <- findExecutable latexEngine
1195 when (mbLatex == Nothing) $
1196 err 41 $ latexEngine ++ " not found. " ++
1197 latexEngine ++ " is needed for pdf output."
1199 res <- makePDF latexEngine f writerOptions doc2
1201 Right pdf -> writeBinary pdf
1203 B.hPutStr stderr $ err'
1204 B.hPut stderr $ B.pack [10]
1205 err 43 "Error producing PDF from TeX source"
1206 | otherwise -> selfcontain (f writerOptions doc2 ++
1207 ['\n' | not standalone'])
1208 >>= writerFn outputFile . handleEntities
1209 where htmlFormat = writerName' `elem`
1210 ["html","html+lhs","html5","html5+lhs",
1211 "s5","slidy","slideous","dzslides","revealjs"]
1212 selfcontain = if selfContained && htmlFormat
1213 then makeSelfContained datadir
1215 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