git.iko.soy/typeable/pandoc
on 1.10.0.1 help sign in
typeable/pandoc/pandoc.hs
1093 lines 47 kB history raw
1{-# LANGUAGE CPP #-}
2{-
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
18-}
20{- |
21 Module : Main
22 Copyright : Copyright (C) 2006-2013 John MacFarlane
23 License : GNU GPL, version 2 or above
25 Maintainer : John MacFarlane <jgm@berkeley@edu>
26 Stability : alpha
27 Portability : portable
29Parses command-line options and calls the appropriate readers and
30writers.
31-}
32module Main where
33import Text.Pandoc
34import Text.Pandoc.PDF (tex2pdf)
35import Text.Pandoc.Readers.LaTeX (handleIncludes)
36import Text.Pandoc.Shared ( tabFilter, readDataFileUTF8, safeRead,
37 headerShift, normalize, err, warn )
38import Text.Pandoc.XML ( toEntities, fromEntities )
39import Text.Pandoc.SelfContained ( makeSelfContained )
40import Text.Pandoc.Highlighting ( languages, Style, tango, pygments,
41 espresso, zenburn, kate, haddock, monochrome )
42import System.Environment ( getArgs, getProgName )
43import System.Exit ( exitWith, ExitCode (..) )
44import System.FilePath
45import System.Console.GetOpt
46import Data.Char ( toLower )
47import Data.List ( intercalate, isPrefixOf )
48import System.Directory ( getAppUserDataDirectory, doesFileExist, findExecutable )
49import System.IO ( stdout )
50import System.IO.Error ( isDoesNotExistError )
51import qualified Control.Exception as E
52import Control.Exception.Extensible ( throwIO )
53import qualified Text.Pandoc.UTF8 as UTF8
54import qualified Text.CSL as CSL
55import Control.Monad (when, unless, liftM)
56import Network.HTTP (simpleHTTP, mkRequest, getResponseBody, RequestMethod(..))
57import Network.URI (parseURI, isURI, URI(..))
58import qualified Data.ByteString.Lazy as B
59import Text.CSL.Reference (Reference(..))
61copyrightMessage :: String
62copyrightMessage = "\nCopyright (C) 2006-2013 John MacFarlane\n" ++
63 "Web: http://johnmacfarlane.net/pandoc\n" ++
64 "This is free software; see the source for copying conditions. There is no\n" ++
65 "warranty, not even for merchantability or fitness for a particular purpose."
67compileInfo :: String
68compileInfo =
69 "\nCompiled with citeproc-hs " ++ VERSION_citeproc_hs ++ ", texmath " ++
70 VERSION_texmath ++ ", highlighting-kate " ++ VERSION_highlighting_kate ++
71 ".\nSyntax highlighting is supported for the following languages:\n " ++
72 wrapWords 4 78 languages
74-- | Converts a list of strings into a single string with the items printed as
75-- comma separated words in lines with a maximum line length.
76wrapWords :: Int -> Int -> [String] -> String
77wrapWords indent c = wrap' (c - indent) (c - indent)
78 where wrap' _ _ [] = ""
79 wrap' cols remaining (x:xs) = if remaining == cols
80 then x ++ wrap' cols (remaining - length x) xs
81 else if (length x + 1) > remaining
82 then ",\n" ++ replicate indent ' ' ++ x ++ wrap' cols (cols - length x) xs
83 else ", " ++ x ++ wrap' cols (remaining - (length x + 2)) xs
85isTextFormat :: String -> Bool
86isTextFormat s = takeWhile (`notElem` "+-") s `notElem` ["odt","docx","epub","epub3"]
88-- | Data structure for command line options.
89data Opt = Opt
90 { optTabStop :: Int -- ^ Number of spaces per tab
91 , optPreserveTabs :: Bool -- ^ Preserve tabs instead of converting to spaces
92 , optStandalone :: Bool -- ^ Include header, footer
93 , optReader :: String -- ^ Reader format
94 , optWriter :: String -- ^ Writer format
95 , optParseRaw :: Bool -- ^ Parse unconvertable HTML and TeX
96 , optTableOfContents :: Bool -- ^ Include table of contents
97 , optTransforms :: [Pandoc -> Pandoc] -- ^ Doc transforms to apply
98 , optTemplate :: Maybe FilePath -- ^ Custom template
99 , optVariables :: [(String,String)] -- ^ Template variables to set
100 , optOutputFile :: String -- ^ Name of output file
101 , optNumberSections :: Bool -- ^ Number sections in LaTeX
102 , optSectionDivs :: Bool -- ^ Put sections in div tags in HTML
103 , optIncremental :: Bool -- ^ Use incremental lists in Slidy/Slideous/S5
104 , optSelfContained :: Bool -- ^ Make HTML accessible offline
105 , optSmart :: Bool -- ^ Use smart typography
106 , optOldDashes :: Bool -- ^ Parse dashes like pandoc <=1.8.2.1
107 , optHtml5 :: Bool -- ^ Produce HTML5 in HTML
108 , optHtmlQTags :: Bool -- ^ Use <q> tags in HTML
109 , optHighlight :: Bool -- ^ Highlight source code
110 , optHighlightStyle :: Style -- ^ Style to use for highlighted code
111 , optChapters :: Bool -- ^ Use chapter for top-level sects
112 , optHTMLMathMethod :: HTMLMathMethod -- ^ Method to print HTML math
113 , optReferenceODT :: Maybe FilePath -- ^ Path of reference.odt
114 , optReferenceDocx :: Maybe FilePath -- ^ Path of reference.docx
115 , optEpubStylesheet :: Maybe String -- ^ EPUB stylesheet
116 , optEpubMetadata :: String -- ^ EPUB metadata
117 , optEpubFonts :: [FilePath] -- ^ EPUB fonts to embed
118 , optEpubChapterLevel :: Int -- ^ Header level at which to split chapters
119 , optTOCDepth :: Int -- ^ Number of levels to include in TOC
120 , optDumpArgs :: Bool -- ^ Output command-line arguments
121 , optIgnoreArgs :: Bool -- ^ Ignore command-line arguments
122 , optReferenceLinks :: Bool -- ^ Use reference links in writing markdown, rst
123 , optWrapText :: Bool -- ^ Wrap text
124 , optColumns :: Int -- ^ Line length in characters
125 , optPlugins :: [Pandoc -> IO Pandoc] -- ^ Plugins to apply
126 , optEmailObfuscation :: ObfuscationMethod
127 , optIdentifierPrefix :: String
128 , optIndentedCodeClasses :: [String] -- ^ Default classes for indented code blocks
129 , optDataDir :: Maybe FilePath
130 , optCiteMethod :: CiteMethod -- ^ Method to output cites
131 , optBibliography :: [String]
132 , optCslFile :: Maybe FilePath
133 , optAbbrevsFile :: Maybe FilePath
134 , optListings :: Bool -- ^ Use listings package for code blocks
135 , optLaTeXEngine :: String -- ^ Program to use for latex -> pdf
136 , optSlideLevel :: Maybe Int -- ^ Header level that creates slides
137 , optSetextHeaders :: Bool -- ^ Use atx headers for markdown level 1-2
138 , optAscii :: Bool -- ^ Use ascii characters only in html
139 , optTeXLigatures :: Bool -- ^ Use TeX ligatures for quotes/dashes
140 }
142-- | Defaults for command-line options.
143defaultOpts :: Opt
144defaultOpts = Opt
145 { optTabStop = 4
146 , optPreserveTabs = False
147 , optStandalone = False
148 , optReader = "" -- null for default reader
149 , optWriter = "" -- null for default writer
150 , optParseRaw = False
151 , optTableOfContents = False
152 , optTransforms = []
153 , optTemplate = Nothing
154 , optVariables = []
155 , optOutputFile = "-" -- "-" means stdout
156 , optNumberSections = False
157 , optSectionDivs = False
158 , optIncremental = False
159 , optSelfContained = False
160 , optSmart = False
161 , optOldDashes = False
162 , optHtml5 = False
163 , optHtmlQTags = False
164 , optHighlight = True
165 , optHighlightStyle = pygments
166 , optChapters = False
167 , optHTMLMathMethod = PlainMath
168 , optReferenceODT = Nothing
169 , optReferenceDocx = Nothing
170 , optEpubStylesheet = Nothing
171 , optEpubMetadata = ""
172 , optEpubFonts = []
173 , optEpubChapterLevel = 1
174 , optTOCDepth = 3
175 , optDumpArgs = False
176 , optIgnoreArgs = False
177 , optReferenceLinks = False
178 , optWrapText = True
179 , optColumns = 72
180 , optPlugins = []
181 , optEmailObfuscation = JavascriptObfuscation
182 , optIdentifierPrefix = ""
183 , optIndentedCodeClasses = []
184 , optDataDir = Nothing
185 , optCiteMethod = Citeproc
186 , optBibliography = []
187 , optCslFile = Nothing
188 , optAbbrevsFile = Nothing
189 , optListings = False
190 , optLaTeXEngine = "pdflatex"
191 , optSlideLevel = Nothing
192 , optSetextHeaders = True
193 , optAscii = False
194 , optTeXLigatures = True
195 }
197-- | A list of functions, each transforming the options data structure
198-- in response to a command-line option.
199options :: [OptDescr (Opt -> IO Opt)]
200options =
201 [ Option "fr" ["from","read"]
202 (ReqArg
203 (\arg opt -> return opt { optReader = map toLower arg })
204 "FORMAT")
205 ""
207 , Option "tw" ["to","write"]
208 (ReqArg
209 (\arg opt -> return opt { optWriter = map toLower arg })
210 "FORMAT")
211 ""
213 , Option "o" ["output"]
214 (ReqArg
215 (\arg opt -> return opt { optOutputFile = arg })
216 "FILENAME")
217 "" -- "Name of output file"
219 , Option "" ["data-dir"]
220 (ReqArg
221 (\arg opt -> return opt { optDataDir = Just arg })
222 "DIRECTORY") -- "Directory containing pandoc data files."
223 ""
225 , Option "" ["strict"]
226 (NoArg
227 (\opt -> do
228 err 59 $ "The --strict option has been removed.\n" ++
229 "Use `markdown_strict' input or output format instead."
230 return opt ))
231 "" -- "Disable markdown syntax extensions"
233 , Option "R" ["parse-raw"]
234 (NoArg
235 (\opt -> return opt { optParseRaw = True }))
236 "" -- "Parse untranslatable HTML codes and LaTeX environments as raw"
238 , Option "S" ["smart"]
239 (NoArg
240 (\opt -> return opt { optSmart = True }))
241 "" -- "Use smart quotes, dashes, and ellipses"
243 , Option "" ["old-dashes"]
244 (NoArg
245 (\opt -> return opt { optSmart = True
246 , optOldDashes = True }))
247 "" -- "Use smart quotes, dashes, and ellipses"
249 , Option "" ["base-header-level"]
250 (ReqArg
251 (\arg opt ->
252 case safeRead arg of
253 Just t | t > 0 -> do
254 let oldTransforms = optTransforms opt
255 let shift = t - 1
256 return opt{ optTransforms =
257 headerShift shift : oldTransforms }
258 _ -> err 19
259 "base-header-level must be a number > 0")
260 "NUMBER")
261 "" -- "Headers base level"
263 , Option "" ["indented-code-classes"]
264 (ReqArg
265 (\arg opt -> return opt { optIndentedCodeClasses = words $
266 map (\c -> if c == ',' then ' ' else c) arg })
267 "STRING")
268 "" -- "Classes (whitespace- or comma-separated) to use for indented code-blocks"
270 , Option "" ["normalize"]
271 (NoArg
272 (\opt -> return opt { optTransforms =
273 normalize : optTransforms opt } ))
274 "" -- "Normalize the Pandoc AST"
276 , Option "p" ["preserve-tabs"]
277 (NoArg
278 (\opt -> return opt { optPreserveTabs = True }))
279 "" -- "Preserve tabs instead of converting to spaces"
281 , Option "" ["tab-stop"]
282 (ReqArg
283 (\arg opt ->
284 case safeRead arg of
285 Just t | t > 0 -> return opt { optTabStop = t }
286 _ -> err 31
287 "tab-stop must be a number greater than 0")
288 "NUMBER")
289 "" -- "Tab stop (default 4)"
291 , Option "s" ["standalone"]
292 (NoArg
293 (\opt -> return opt { optStandalone = True }))
294 "" -- "Include needed header and footer on output"
296 , Option "" ["template"]
297 (ReqArg
298 (\arg opt -> do
299 return opt{ optTemplate = Just arg,
300 optStandalone = True })
301 "FILENAME")
302 "" -- "Use custom template"
304 , Option "V" ["variable"]
305 (ReqArg
306 (\arg opt -> do
307 let (key,val) = case break (`elem` ":=") arg of
308 (k,_:v) -> (k,v)
309 (k,_) -> (k,"true")
310 return opt{ optVariables = (key,val) : optVariables opt })
311 "KEY[:VALUE]")
312 "" -- "Use custom template"
314 , Option "D" ["print-default-template"]
315 (ReqArg
316 (\arg _ -> do
317 templ <- getDefaultTemplate Nothing arg
318 case templ of
319 Right t -> UTF8.hPutStr stdout t
320 Left e -> error $ show e
321 exitWith ExitSuccess)
322 "FORMAT")
323 "" -- "Print default template for FORMAT"
325 , Option "" ["no-wrap"]
326 (NoArg
327 (\opt -> return opt { optWrapText = False }))
328 "" -- "Do not wrap text in output"
330 , Option "" ["columns"]
331 (ReqArg
332 (\arg opt ->
333 case safeRead arg of
334 Just t | t > 0 -> return opt { optColumns = t }
335 _ -> err 33 $
336 "columns must be a number greater than 0")
337 "NUMBER")
338 "" -- "Length of line in characters"
340 , Option "" ["toc", "table-of-contents"]
341 (NoArg
342 (\opt -> return opt { optTableOfContents = True }))
343 "" -- "Include table of contents"
345 , Option "" ["toc-depth"]
346 (ReqArg
347 (\arg opt -> do
348 case safeRead arg of
349 Just t | t >= 1 && t <= 6 ->
350 return opt { optTOCDepth = t,
351 optTableOfContents = True }
352 _ -> err 57 $
353 "TOC level must be a number between 1 and 6")
354 "NUMBER")
355 "" -- "Number of levels to include in TOC"
357 , Option "" ["no-highlight"]
358 (NoArg
359 (\opt -> return opt { optHighlight = False }))
360 "" -- "Don't highlight source code"
362 , Option "" ["highlight-style"]
363 (ReqArg
364 (\arg opt -> do
365 newStyle <- case map toLower arg of
366 "pygments" -> return pygments
367 "tango" -> return tango
368 "espresso" -> return espresso
369 "zenburn" -> return zenburn
370 "kate" -> return kate
371 "monochrome" -> return monochrome
372 "haddock" -> return haddock
373 _ -> err 39 $
374 "Unknown style :" ++ arg
375 return opt{ optHighlightStyle = newStyle })
376 "STYLE")
377 "" -- "Style for highlighted code"
379 , Option "H" ["include-in-header"]
380 (ReqArg
381 (\arg opt -> do
382 text <- UTF8.readFile arg
383 -- add new ones to end, so they're included in order specified
384 let newvars = optVariables opt ++ [("header-includes",text)]
385 return opt { optVariables = newvars,
386 optStandalone = True })
387 "FILENAME")
388 "" -- "File to include at end of header (implies -s)"
390 , Option "B" ["include-before-body"]
391 (ReqArg
392 (\arg opt -> do
393 text <- UTF8.readFile arg
394 -- add new ones to end, so they're included in order specified
395 let newvars = optVariables opt ++ [("include-before",text)]
396 return opt { optVariables = newvars,
397 optStandalone = True })
398 "FILENAME")
399 "" -- "File to include before document body"
401 , Option "A" ["include-after-body"]
402 (ReqArg
403 (\arg opt -> do
404 text <- UTF8.readFile arg
405 -- add new ones to end, so they're included in order specified
406 let newvars = optVariables opt ++ [("include-after",text)]
407 return opt { optVariables = newvars,
408 optStandalone = True })
409 "FILENAME")
410 "" -- "File to include after document body"
412 , Option "" ["self-contained"]
413 (NoArg
414 (\opt -> return opt { optSelfContained = True,
415 optVariables = ("slidy-url","slidy") :
416 optVariables opt,
417 optStandalone = True }))
418 "" -- "Make slide shows include all the needed js and css"
420 , Option "" ["offline"]
421 (NoArg
422 (\opt -> do warn $ "--offline is deprecated. Use --self-contained instead."
423 return opt { optSelfContained = True,
424 optStandalone = True }))
425 "" -- "Make slide shows include all the needed js and css"
426 -- deprecated synonym for --self-contained
428 , Option "5" ["html5"]
429 (NoArg
430 (\opt -> do
431 warn $ "--html5 is deprecated. "
432 ++ "Use the html5 output format instead."
433 return opt { optHtml5 = True }))
434 "" -- "Produce HTML5 in HTML output"
436 , Option "" ["html-q-tags"]
437 (NoArg
438 (\opt -> do
439 return opt { optHtmlQTags = True }))
440 "" -- "Use <q> tags for quotes in HTML"
442 , Option "" ["ascii"]
443 (NoArg
444 (\opt -> return opt { optAscii = True }))
445 "" -- "Use ascii characters only in HTML output"
447 , Option "" ["reference-links"]
448 (NoArg
449 (\opt -> return opt { optReferenceLinks = True } ))
450 "" -- "Use reference links in parsing HTML"
452 , Option "" ["atx-headers"]
453 (NoArg
454 (\opt -> return opt { optSetextHeaders = False } ))
455 "" -- "Use atx-style headers for markdown"
457 , Option "" ["chapters"]
458 (NoArg
459 (\opt -> return opt { optChapters = True }))
460 "" -- "Use chapter for top-level sections in LaTeX, DocBook"
462 , Option "N" ["number-sections"]
463 (NoArg
464 (\opt -> return opt { optNumberSections = True }))
465 "" -- "Number sections in LaTeX"
467 , Option "" ["no-tex-ligatures"]
468 (NoArg
469 (\opt -> return opt { optTeXLigatures = False }))
470 "" -- "Don't use tex ligatures for quotes, dashes"
472 , Option "" ["listings"]
473 (NoArg
474 (\opt -> return opt { optListings = True }))
475 "" -- "Use listings package for LaTeX code blocks"
477 , Option "i" ["incremental"]
478 (NoArg
479 (\opt -> return opt { optIncremental = True }))
480 "" -- "Make list items display incrementally in Slidy/Slideous/S5"
482 , Option "" ["slide-level"]
483 (ReqArg
484 (\arg opt -> do
485 case safeRead arg of
486 Just t | t >= 1 && t <= 6 ->
487 return opt { optSlideLevel = Just t }
488 _ -> err 39 $
489 "slide level must be a number between 1 and 6")
490 "NUMBER")
491 "" -- "Force header level for slides"
493 , Option "" ["section-divs"]
494 (NoArg
495 (\opt -> return opt { optSectionDivs = True }))
496 "" -- "Put sections in div tags in HTML"
498 , Option "" ["email-obfuscation"]
499 (ReqArg
500 (\arg opt -> do
501 method <- case arg of
502 "references" -> return ReferenceObfuscation
503 "javascript" -> return JavascriptObfuscation
504 "none" -> return NoObfuscation
505 _ -> err 6
506 ("Unknown obfuscation method: " ++ arg)
507 return opt { optEmailObfuscation = method })
508 "none|javascript|references")
509 "" -- "Method for obfuscating email in HTML"
511 , Option "" ["id-prefix"]
512 (ReqArg
513 (\arg opt -> return opt { optIdentifierPrefix = arg })
514 "STRING")
515 "" -- "Prefix to add to automatically generated HTML identifiers"
517 , Option "T" ["title-prefix"]
518 (ReqArg
519 (\arg opt -> do
520 let newvars = ("title-prefix", arg) : optVariables opt
521 return opt { optVariables = newvars,
522 optStandalone = True })
523 "STRING")
524 "" -- "String to prefix to HTML window title"
526 , Option "c" ["css"]
527 (ReqArg
528 (\arg opt -> do
529 -- add new link to end, so it is included in proper order
530 let newvars = optVariables opt ++ [("css",arg)]
531 return opt { optVariables = newvars,
532 optStandalone = True })
533 "URL")
534 "" -- "Link to CSS style sheet"
536 , Option "" ["reference-odt"]
537 (ReqArg
538 (\arg opt -> do
539 return opt { optReferenceODT = Just arg })
540 "FILENAME")
541 "" -- "Path of custom reference.odt"
543 , Option "" ["reference-docx"]
544 (ReqArg
545 (\arg opt -> do
546 return opt { optReferenceDocx = Just arg })
547 "FILENAME")
548 "" -- "Path of custom reference.docx"
550 , Option "" ["epub-stylesheet"]
551 (ReqArg
552 (\arg opt -> do
553 text <- UTF8.readFile arg
554 return opt { optEpubStylesheet = Just text })
555 "FILENAME")
556 "" -- "Path of epub.css"
558 , Option "" ["epub-cover-image"]
559 (ReqArg
560 (\arg opt ->
561 return opt { optVariables =
562 ("epub-cover-image", arg) : optVariables opt })
563 "FILENAME")
564 "" -- "Path of epub cover image"
566 , Option "" ["epub-metadata"]
567 (ReqArg
568 (\arg opt -> do
569 text <- UTF8.readFile arg
570 return opt { optEpubMetadata = text })
571 "FILENAME")
572 "" -- "Path of epub metadata file"
574 , Option "" ["epub-embed-font"]
575 (ReqArg
576 (\arg opt -> do
577 return opt{ optEpubFonts = arg : optEpubFonts opt })
578 "FILE")
579 "" -- "Directory of fonts to embed"
581 , Option "" ["epub-chapter-level"]
582 (ReqArg
583 (\arg opt -> do
584 case safeRead arg of
585 Just t | t >= 1 && t <= 6 ->
586 return opt { optEpubChapterLevel = t }
587 _ -> err 59 $
588 "chapter level must be a number between 1 and 6")
589 "NUMBER")
590 "" -- "Header level at which to split chapters in EPUB"
592 , Option "" ["latex-engine"]
593 (ReqArg
594 (\arg opt -> do
595 let b = takeBaseName arg
596 if (b == "pdflatex" || b == "lualatex" || b == "xelatex")
597 then return opt { optLaTeXEngine = arg }
598 else err 45 "latex-engine must be pdflatex, lualatex, or xelatex.")
599 "PROGRAM")
600 "" -- "Name of latex program to use in generating PDF"
602 , Option "" ["bibliography"]
603 (ReqArg
604 (\arg opt -> return opt { optBibliography = (optBibliography opt) ++ [arg] })
605 "FILENAME")
606 ""
608 , Option "" ["csl"]
609 (ReqArg
610 (\arg opt -> return opt { optCslFile = Just arg })
611 "FILENAME")
612 ""
614 , Option "" ["citation-abbreviations"]
615 (ReqArg
616 (\arg opt -> return opt { optAbbrevsFile = Just arg })
617 "FILENAME")
618 ""
620 , Option "" ["natbib"]
621 (NoArg
622 (\opt -> return opt { optCiteMethod = Natbib }))
623 "" -- "Use natbib cite commands in LaTeX output"
625 , Option "" ["biblatex"]
626 (NoArg
627 (\opt -> return opt { optCiteMethod = Biblatex }))
628 "" -- "Use biblatex cite commands in LaTeX output"
630 , Option "m" ["latexmathml", "asciimathml"]
631 (OptArg
632 (\arg opt ->
633 return opt { optHTMLMathMethod = LaTeXMathML arg })
634 "URL")
635 "" -- "Use LaTeXMathML script in html output"
637 , Option "" ["mathml"]
638 (OptArg
639 (\arg opt ->
640 return opt { optHTMLMathMethod = MathML arg })
641 "URL")
642 "" -- "Use mathml for HTML math"
644 , Option "" ["mimetex"]
645 (OptArg
646 (\arg opt -> do
647 let url' = case arg of
648 Just u -> u ++ "?"
649 Nothing -> "/cgi-bin/mimetex.cgi?"
650 return opt { optHTMLMathMethod = WebTeX url' })
651 "URL")
652 "" -- "Use mimetex for HTML math"
654 , Option "" ["webtex"]
655 (OptArg
656 (\arg opt -> do
657 let url' = case arg of
658 Just u -> u
659 Nothing -> "http://chart.apis.google.com/chart?cht=tx&chl="
660 return opt { optHTMLMathMethod = WebTeX url' })
661 "URL")
662 "" -- "Use web service for HTML math"
664 , Option "" ["jsmath"]
665 (OptArg
666 (\arg opt -> return opt { optHTMLMathMethod = JsMath arg})
667 "URL")
668 "" -- "Use jsMath for HTML math"
670 , Option "" ["mathjax"]
671 (OptArg
672 (\arg opt -> do
673 let url' = case arg of
674 Just u -> u
675 Nothing -> "http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"
676 return opt { optHTMLMathMethod = MathJax url'})
677 "URL")
678 "" -- "Use MathJax for HTML math"
680 , Option "" ["gladtex"]
681 (NoArg
682 (\opt -> return opt { optHTMLMathMethod = GladTeX }))
683 "" -- "Use gladtex for HTML math"
685 , Option "" ["dump-args"]
686 (NoArg
687 (\opt -> return opt { optDumpArgs = True }))
688 "" -- "Print output filename and arguments to stdout."
690 , Option "" ["ignore-args"]
691 (NoArg
692 (\opt -> return opt { optIgnoreArgs = True }))
693 "" -- "Ignore command-line arguments."
695 , Option "v" ["version"]
696 (NoArg
697 (\_ -> do
698 prg <- getProgName
699 UTF8.hPutStrLn stdout (prg ++ " " ++ pandocVersion ++ compileInfo ++
700 copyrightMessage)
701 exitWith ExitSuccess ))
702 "" -- "Print version"
704 , Option "h" ["help"]
705 (NoArg
706 (\_ -> do
707 prg <- getProgName
708 UTF8.hPutStr stdout (usageMessage prg options)
709 exitWith ExitSuccess ))
710 "" -- "Show help"
712 ]
714-- Returns usage message
715usageMessage :: String -> [OptDescr (Opt -> IO Opt)] -> String
716usageMessage programName = usageInfo
717 (programName ++ " [OPTIONS] [FILES]" ++ "\nInput formats: " ++
718 (wrapWords 16 78 $ readers'names) ++ "\nOutput formats: " ++
719 (wrapWords 16 78 $ writers'names) ++ "\nOptions:")
720 where
721 writers'names = map fst writers
722 readers'names = map fst readers
724-- Determine default reader based on source file extensions
725defaultReaderName :: String -> [FilePath] -> String
726defaultReaderName fallback [] = fallback
727defaultReaderName fallback (x:xs) =
728 case takeExtension (map toLower x) of
729 ".xhtml" -> "html"
730 ".html" -> "html"
731 ".htm" -> "html"
732 ".tex" -> "latex"
733 ".latex" -> "latex"
734 ".ltx" -> "latex"
735 ".rst" -> "rst"
736 ".lhs" -> "markdown+lhs"
737 ".db" -> "docbook"
738 ".wiki" -> "mediawiki"
739 ".textile" -> "textile"
740 ".native" -> "native"
741 ".json" -> "json"
742 _ -> defaultReaderName fallback xs
744-- Returns True if extension of first source is .lhs
745lhsExtension :: [FilePath] -> Bool
746lhsExtension (x:_) = takeExtension x == ".lhs"
747lhsExtension _ = False
749-- Determine default writer based on output file extension
750defaultWriterName :: FilePath -> String
751defaultWriterName "-" = "html" -- no output file
752defaultWriterName x =
753 case takeExtension (map toLower x) of
754 "" -> "markdown" -- empty extension
755 ".tex" -> "latex"
756 ".latex" -> "latex"
757 ".ltx" -> "latex"
758 ".context" -> "context"
759 ".ctx" -> "context"
760 ".rtf" -> "rtf"
761 ".rst" -> "rst"
762 ".s5" -> "s5"
763 ".native" -> "native"
764 ".json" -> "json"
765 ".txt" -> "markdown"
766 ".text" -> "markdown"
767 ".md" -> "markdown"
768 ".markdown" -> "markdown"
769 ".textile" -> "textile"
770 ".lhs" -> "markdown+lhs"
771 ".texi" -> "texinfo"
772 ".texinfo" -> "texinfo"
773 ".db" -> "docbook"
774 ".odt" -> "odt"
775 ".docx" -> "docx"
776 ".epub" -> "epub"
777 ".org" -> "org"
778 ".asciidoc" -> "asciidoc"
779 ".pdf" -> "latex"
780 ".fb2" -> "fb2"
781 ['.',y] | y `elem` ['1'..'9'] -> "man"
782 _ -> "html"
784main :: IO ()
785main = do
787 rawArgs <- liftM (map UTF8.decodeArg) getArgs
788 prg <- getProgName
789 let compatMode = (prg == "hsmarkdown")
791 let (actions, args, errors) = if compatMode
792 then ([], rawArgs, [])
793 else getOpt Permute options rawArgs
795 unless (null errors) $
796 err 2 $ concat $ errors ++
797 ["Try " ++ prg ++ " --help for more information."]
799 let defaultOpts' = if compatMode
800 then defaultOpts { optReader = "markdown_strict"
801 , optWriter = "html"
802 , optEmailObfuscation =
803 ReferenceObfuscation }
804 else defaultOpts
806 -- thread option data structure through all supplied option actions
807 opts <- foldl (>>=) (return defaultOpts') actions
809 let Opt { optTabStop = tabStop
810 , optPreserveTabs = preserveTabs
811 , optStandalone = standalone
812 , optReader = readerName
813 , optWriter = writerName
814 , optParseRaw = parseRaw
815 , optVariables = variables
816 , optTableOfContents = toc
817 , optTransforms = transforms
818 , optTemplate = templatePath
819 , optOutputFile = outputFile
820 , optNumberSections = numberSections
821 , optSectionDivs = sectionDivs
822 , optIncremental = incremental
823 , optSelfContained = selfContained
824 , optSmart = smart
825 , optOldDashes = oldDashes
826 , optHtml5 = html5
827 , optHtmlQTags = htmlQTags
828 , optHighlight = highlight
829 , optHighlightStyle = highlightStyle
830 , optChapters = chapters
831 , optHTMLMathMethod = mathMethod
832 , optReferenceODT = referenceODT
833 , optReferenceDocx = referenceDocx
834 , optEpubStylesheet = epubStylesheet
835 , optEpubMetadata = epubMetadata
836 , optEpubFonts = epubFonts
837 , optEpubChapterLevel = epubChapterLevel
838 , optTOCDepth = epubTOCDepth
839 , optDumpArgs = dumpArgs
840 , optIgnoreArgs = ignoreArgs
841 , optReferenceLinks = referenceLinks
842 , optWrapText = wrap
843 , optColumns = columns
844 , optEmailObfuscation = obfuscationMethod
845 , optIdentifierPrefix = idPrefix
846 , optIndentedCodeClasses = codeBlockClasses
847 , optDataDir = mbDataDir
848 , optBibliography = reffiles
849 , optCslFile = mbCsl
850 , optAbbrevsFile = cslabbrevs
851 , optCiteMethod = citeMethod
852 , optListings = listings
853 , optLaTeXEngine = latexEngine
854 , optSlideLevel = slideLevel
855 , optSetextHeaders = setextHeaders
856 , optAscii = ascii
857 , optTeXLigatures = texLigatures
858 } = opts
860 when dumpArgs $
861 do UTF8.hPutStrLn stdout outputFile
862 mapM_ (\arg -> UTF8.hPutStrLn stdout arg) args
863 exitWith ExitSuccess
865 let sources = if ignoreArgs then [] else args
867 datadir <- case mbDataDir of
868 Nothing -> E.catch
869 (liftM Just $ getAppUserDataDirectory "pandoc")
870 (\e -> let _ = (e :: E.SomeException)
871 in return Nothing)
872 Just _ -> return mbDataDir
874 -- assign reader and writer based on options and filenames
875 let readerName' = if null readerName
876 then let fallback = if any isURI sources
877 then "html"
878 else "markdown"
879 in defaultReaderName fallback sources
880 else readerName
882 let writerName' = if null writerName
883 then defaultWriterName outputFile
884 else writerName
886 let pdfOutput = map toLower (takeExtension outputFile) == ".pdf"
888 let laTeXOutput = "latex" `isPrefixOf` writerName' ||
889 "beamer" `isPrefixOf` writerName'
891 when pdfOutput $ do
892 -- make sure writer is latex or beamer
893 unless laTeXOutput $
894 err 47 $ "cannot produce pdf output with " ++ writerName' ++ " writer"
895 -- check for latex program
896 mbLatex <- findExecutable latexEngine
897 case mbLatex of
898 Nothing -> err 41 $
899 latexEngine ++ " not found. " ++
900 latexEngine ++ " is needed for pdf output."
901 Just _ -> return ()
903 reader <- case getReader readerName' of
904 Right r -> return r
905 Left e -> err 7 e
907 let standalone' = standalone || not (isTextFormat writerName') || pdfOutput
909 templ <- case templatePath of
910 _ | not standalone' -> return ""
911 Nothing -> do
912 deftemp <- getDefaultTemplate datadir writerName'
913 case deftemp of
914 Left e -> throwIO e
915 Right t -> return t
916 Just tp -> do
917 -- strip off extensions
918 let format = takeWhile (`notElem` "+-") writerName'
919 let tp' = case takeExtension tp of
920 "" -> tp <.> format
921 _ -> tp
922 E.catch (UTF8.readFile tp')
923 (\e -> if isDoesNotExistError e
924 then E.catch
925 (readDataFileUTF8 datadir
926 ("templates" </> tp'))
927 (\e' -> let _ = (e' :: E.SomeException)
928 in throwIO e')
929 else throwIO e)
931 variables' <- case mathMethod of
932 LaTeXMathML Nothing -> do
933 s <- readDataFileUTF8 datadir
934 ("LaTeXMathML.js")
935 return $ ("mathml-script", s) : variables
936 MathML Nothing -> do
937 s <- readDataFileUTF8 datadir
938 ("MathMLinHTML.js")
939 return $ ("mathml-script", s) : variables
940 _ -> return variables
942 variables'' <- if "dzslides" `isPrefixOf` writerName'
943 then do
944 dztempl <- readDataFileUTF8 datadir
945 ("dzslides" </> "template.html")
946 let dzcore = unlines $ dropWhile (not . isPrefixOf "<!-- {{{{ dzslides core")
947 $ lines dztempl
948 return $ ("dzslides-core", dzcore) : variables'
949 else return variables'
951 -- unescape reference ids, which may contain XML entities, so
952 -- that we can do lookups with regular string equality
953 let unescapeRefId ref = ref{ refId = fromEntities (refId ref) }
955 refs <- mapM (\f -> E.catch (CSL.readBiblioFile f)
956 (\e -> let _ = (e :: E.SomeException)
957 in err 23 $ "Error reading bibliography `" ++ f ++
958 "'" ++ "\n" ++ show e))
959 reffiles >>=
960 return . map unescapeRefId . concat
962 mbsty <- if citeMethod == Citeproc && not (null refs)
963 then do
964 csl <- CSL.parseCSL =<<
965 case mbCsl of
966 Nothing -> readDataFileUTF8 datadir
967 "default.csl"
968 Just cslfile -> do
969 exists <- doesFileExist cslfile
970 if exists
971 then UTF8.readFile cslfile
972 else do
973 csldir <- getAppUserDataDirectory "csl"
974 readDataFileUTF8 (Just csldir)
975 (replaceExtension cslfile "csl")
976 abbrevs <- maybe (return []) CSL.readJsonAbbrevFile cslabbrevs
977 return $ Just csl { CSL.styleAbbrevs = abbrevs }
978 else return Nothing
980 let sourceDir = case sources of
981 [] -> "."
982 (x:_) -> case parseURI x of
983 Just u
984 | uriScheme u `elem` ["http:","https:"] ->
985 show u{ uriPath = "", uriQuery = "", uriFragment = "" }
986 _ -> takeDirectory x
988 let readerOpts = def{ readerSmart = smart || (texLigatures &&
989 (laTeXOutput || "context" `isPrefixOf` writerName'))
990 , readerStandalone = standalone'
991 , readerParseRaw = parseRaw
992 , readerColumns = columns
993 , readerTabStop = tabStop
994 , readerOldDashes = oldDashes
995 , readerReferences = refs
996 , readerCitationStyle = mbsty
997 , readerIndentedCodeClasses = codeBlockClasses
998 , readerApplyMacros = not laTeXOutput
999 }
1001 let writerOptions = def { writerStandalone = standalone',
1002 writerTemplate = templ,
1003 writerVariables = variables'',
1004 writerTabStop = tabStop,
1005 writerTableOfContents = toc,
1006 writerHTMLMathMethod = mathMethod,
1007 writerIncremental = incremental,
1008 writerCiteMethod = citeMethod,
1009 writerBiblioFiles = reffiles,
1010 writerIgnoreNotes = False,
1011 writerNumberSections = numberSections,
1012 writerSectionDivs = sectionDivs,
1013 writerReferenceLinks = referenceLinks,
1014 writerWrapText = wrap,
1015 writerColumns = columns,
1016 writerEmailObfuscation = obfuscationMethod,
1017 writerIdentifierPrefix = idPrefix,
1018 writerSourceDirectory = sourceDir,
1019 writerUserDataDir = datadir,
1020 writerHtml5 = html5,
1021 writerHtmlQTags = htmlQTags,
1022 writerChapters = chapters,
1023 writerListings = listings,
1024 writerBeamer = False,
1025 writerSlideLevel = slideLevel,
1026 writerHighlight = highlight,
1027 writerHighlightStyle = highlightStyle,
1028 writerSetextHeaders = setextHeaders,
1029 writerTeXLigatures = texLigatures,
1030 writerEpubMetadata = epubMetadata,
1031 writerEpubStylesheet = epubStylesheet,
1032 writerEpubFonts = epubFonts,
1033 writerEpubChapterLevel = epubChapterLevel,
1034 writerTOCDepth = epubTOCDepth,
1035 writerReferenceODT = referenceODT,
1036 writerReferenceDocx = referenceDocx
1039 when (not (isTextFormat writerName') && outputFile == "-") $
1040 err 5 $ "Cannot write " ++ writerName' ++ " output to stdout.\n" ++
1041 "Specify an output file using the -o option."
1043 let readSources [] = mapM readSource ["-"]
1044 readSources srcs = mapM readSource srcs
1045 readSource "-" = UTF8.getContents
1046 readSource src = case parseURI src of
1047 Just u | uriScheme u `elem` ["http:","https:"] ->
1048 readURI u
1049 _ -> UTF8.readFile src
1050 readURI uri = simpleHTTP (mkRequest GET uri) >>= getResponseBody >>=
1051 return . UTF8.toStringLazy -- treat all as UTF8
1053 let convertTabs = tabFilter (if preserveTabs then 0 else tabStop)
1055 let handleIncludes' = if readerName' == "latex" || readerName' == "latex+lhs"
1056 then handleIncludes
1057 else return
1059 doc <- readSources sources >>=
1060 handleIncludes' . convertTabs . intercalate "\n" >>=
1061 reader readerOpts
1063 let doc0 = foldr ($) doc transforms
1065 let writeBinary :: B.ByteString -> IO ()
1066 writeBinary = B.writeFile (UTF8.encodePath outputFile)
1068 let writerFn :: FilePath -> String -> IO ()
1069 writerFn "-" = UTF8.putStr
1070 writerFn f = UTF8.writeFile f
1072 case getWriter writerName' of
1073 Left e -> err 9 e
1074 Right (IOStringWriter f) -> f writerOptions doc0 >>= writerFn outputFile
1075 Right (IOByteStringWriter f) -> f writerOptions doc0 >>= writeBinary
1076 Right (PureStringWriter f)
1077 | pdfOutput -> do
1078 res <- tex2pdf latexEngine $ f writerOptions doc0
1079 case res of
1080 Right pdf -> writeBinary pdf
1081 Left err' -> err 43 $ UTF8.toStringLazy err'
1082 | otherwise -> selfcontain (f writerOptions doc0 ++
1083 ['\n' | not standalone'])
1084 >>= writerFn outputFile . handleEntities
1085 where htmlFormat = writerName' `elem`
1086 ["html","html+lhs","html5","html5+lhs",
1087 "s5","slidy","slideous","dzslides"]
1088 selfcontain = if selfContained && htmlFormat
1089 then makeSelfContained datadir
1090 else return
1091 handleEntities = if htmlFormat && ascii
1092 then toEntities
1093 else id