2Copyright (C) 2006-8 John MacFarlane <jgm@berkeley.edu>
4This program is free software; you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation; either version 2 of the License, or
7(at your option) any later version.
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
14You should have received a copy of the GNU General Public License
15along with this program; if not, write to the Free Software
16Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 Copyright : Copyright (C) 2006-8 John MacFarlane
22 License : GNU GPL, version 2 or above
24 Maintainer : John MacFarlane <jgm@berkeley@edu>
26 Portability : portable
28Parses command-line options and calls the appropriate readers and
33import Text.Pandoc.UTF8
34import Text.Pandoc.Shared ( joinWithSep, HTMLMathMethod (..) )
35import Text.Regex ( mkRegex, matchRegex )
36import System.Environment ( getArgs, getProgName, getEnvironment )
37import System.Exit ( exitWith, ExitCode (..) )
38import System.Console.GetOpt
40import Data.Maybe ( fromMaybe )
41import Data.Char ( toLower )
42import Control.Monad ( (>>=) )
44copyrightMessage :: String
45copyrightMessage = "\nCopyright (C) 2006-7 John MacFarlane\n\
46 \Web: http://johnmacfarlane.net/pandoc\n\
47 \This is free software; see the source for copying conditions. There is no\n\
48 \warranty, not even for merchantability or fitness for a particular purpose."
50-- | Association list of formats and readers.
51readers :: [(String, ParserState -> String -> Pandoc)]
52readers = [("native" , readPandoc)
53 ,("markdown" , readMarkdown)
56 ,("latex" , readLaTeX)
59-- | Reader for native Pandoc format.
60readPandoc :: ParserState -> String -> Pandoc
61readPandoc state input = read input
63-- | Association list of formats and pairs of writers and default headers.
64writers :: [ ( String, ( WriterOptions -> Pandoc -> String, String ) ) ]
65writers = [("native" , (writeDoc, ""))
66 ,("html" , (writeHtmlString, ""))
67 ,("s5" , (writeS5String, defaultS5Header))
68 ,("docbook" , (writeDocbook, defaultDocbookHeader))
69 ,("latex" , (writeLaTeX, defaultLaTeXHeader))
70 ,("context" , (writeConTeXt, defaultConTeXtHeader))
71 ,("man" , (writeMan, ""))
72 ,("markdown" , (writeMarkdown, ""))
73 ,("rst" , (writeRST, ""))
74 ,("rtf" , (writeRTF, defaultRTFHeader))
77-- | Writer for Pandoc native format.
78writeDoc :: WriterOptions -> Pandoc -> String
79writeDoc options = prettyPandoc
81-- | Data structure for command line options.
83 { optPreserveTabs :: Bool -- ^ Convert tabs to spaces
84 , optTabStop :: Int -- ^ Number of spaces per tab
85 , optStandalone :: Bool -- ^ Include header, footer
86 , optReader :: String -- ^ Reader format
87 , optWriter :: String -- ^ Writer format
88 , optParseRaw :: Bool -- ^ Parse unconvertable HTML and TeX
89 , optCSS :: [String] -- ^ CSS file to link to
90 , optTableOfContents :: Bool -- ^ Include table of contents
91 , optIncludeInHeader :: String -- ^ File to include in header
92 , optIncludeBeforeBody :: String -- ^ File to include at top of body
93 , optIncludeAfterBody :: String -- ^ File to include at end of body
94 , optCustomHeader :: String -- ^ Custom header to use, or "DEFAULT"
95 , optTitlePrefix :: String -- ^ Optional prefix for HTML title
96 , optOutputFile :: String -- ^ Name of output file
97 , optNumberSections :: Bool -- ^ Number sections in LaTeX
98 , optIncremental :: Bool -- ^ Use incremental lists in S5
99 , optSmart :: Bool -- ^ Use smart typography
100 , optHTMLMathMethod :: HTMLMathMethod -- ^ Method to print HTML math
101 , optDumpArgs :: Bool -- ^ Output command-line arguments
102 , optIgnoreArgs :: Bool -- ^ Ignore command-line arguments
103 , optStrict :: Bool -- ^ Use strict markdown syntax
104 , optReferenceLinks :: Bool -- ^ Use reference links in writing markdown, rst
105 , optWrapText :: Bool -- ^ Wrap text
106 , optSanitizeHTML :: Bool -- ^ Sanitize HTML
109-- | Defaults for command-line options.
112 { optPreserveTabs = False
114 , optStandalone = False
115 , optReader = "" -- null for default reader
116 , optWriter = "" -- null for default writer
117 , optParseRaw = False
119 , optTableOfContents = False
120 , optIncludeInHeader = ""
121 , optIncludeBeforeBody = ""
122 , optIncludeAfterBody = ""
123 , optCustomHeader = "DEFAULT"
124 , optTitlePrefix = ""
125 , optOutputFile = "-" -- "-" means stdout
126 , optNumberSections = False
127 , optIncremental = False
129 , optHTMLMathMethod = PlainMath
130 , optDumpArgs = False
131 , optIgnoreArgs = False
133 , optReferenceLinks = False
135 , optSanitizeHTML = False
138-- | A list of functions, each transforming the options data structure
139-- in response to a command-line option.
140options :: [OptDescr (Opt -> IO Opt)]
142 [ Option "fr" ["from","read"]
144 (\arg opt -> return opt { optReader = map toLower arg })
146 "" -- ("(" ++ (joinWithSep ", " $ map fst readers) ++ ")")
148 , Option "tw" ["to","write"]
150 (\arg opt -> return opt { optWriter = map toLower arg })
152 "" -- ("(" ++ (joinWithSep ", " $ map fst writers) ++ ")")
154 , Option "s" ["standalone"]
156 (\opt -> return opt { optStandalone = True }))
157 "" -- "Include needed header and footer on output"
159 , Option "o" ["output"]
161 (\arg opt -> return opt { optOutputFile = arg })
163 "" -- "Name of output file"
165 , Option "p" ["preserve-tabs"]
167 (\opt -> return opt { optPreserveTabs = True }))
168 "" -- "Preserve tabs instead of converting to spaces"
170 , Option "" ["tab-stop"]
172 (\arg opt -> return opt { optTabStop = (read arg) } )
174 "" -- "Tab stop (default 4)"
176 , Option "" ["strict"]
178 (\opt -> return opt { optStrict = True } ))
179 "" -- "Disable markdown syntax extensions"
181 , Option "" ["reference-links"]
183 (\opt -> return opt { optReferenceLinks = True } ))
184 "" -- "Use reference links in parsing HTML"
186 , Option "R" ["parse-raw"]
188 (\opt -> return opt { optParseRaw = True }))
189 "" -- "Parse untranslatable HTML codes and LaTeX environments as raw"
191 , Option "S" ["smart"]
193 (\opt -> return opt { optSmart = True }))
194 "" -- "Use smart quotes, dashes, and ellipses"
196 , Option "m" ["asciimathml"]
198 (\arg opt -> return opt { optHTMLMathMethod =
201 "" -- "Use ASCIIMathML script in html output"
203 , Option "" ["mimetex"]
205 (\arg opt -> return opt { optHTMLMathMethod = MimeTeX
206 (fromMaybe "/cgi-bin/mimetex.cgi" arg)})
208 "" -- "Use mimetex for HTML math"
210 , Option "" ["gladtex"]
212 (\opt -> return opt { optHTMLMathMethod = GladTeX }))
213 "" -- "Use gladtex for HTML math"
215 , Option "i" ["incremental"]
217 (\opt -> return opt { optIncremental = True }))
218 "" -- "Make list items display incrementally in S5"
220 , Option "N" ["number-sections"]
222 (\opt -> return opt { optNumberSections = True }))
223 "" -- "Number sections in LaTeX"
225 , Option "" ["no-wrap"]
227 (\opt -> return opt { optWrapText = False }))
228 "" -- "Do not wrap text in output"
230 , Option "" ["sanitize-html"]
232 (\opt -> return opt { optSanitizeHTML = True }))
233 "" -- "Sanitize HTML"
235 , Option "" ["toc", "table-of-contents"]
237 (\opt -> return opt { optTableOfContents = True }))
238 "" -- "Include table of contents"
244 return opt { optCSS = old ++ [arg],
245 optStandalone = True })
247 "" -- "Link to CSS style sheet"
249 , Option "H" ["include-in-header"]
252 let old = optIncludeInHeader opt
254 return opt { optIncludeInHeader = old ++ fromUTF8 text,
255 optStandalone = True })
257 "" -- "File to include at end of header (implies -s)"
259 , Option "B" ["include-before-body"]
262 let old = optIncludeBeforeBody opt
264 return opt { optIncludeBeforeBody = old ++ fromUTF8 text })
266 "" -- "File to include before document body"
268 , Option "A" ["include-after-body"]
271 let old = optIncludeAfterBody opt
273 return opt { optIncludeAfterBody = old ++ fromUTF8 text })
275 "" -- "File to include after document body"
277 , Option "C" ["custom-header"]
281 return opt { optCustomHeader = fromUTF8 text,
282 optStandalone = True })
284 "" -- "File to use for custom header (implies -s)"
286 , Option "T" ["title-prefix"]
288 (\arg opt -> return opt { optTitlePrefix = arg,
289 optStandalone = True })
291 "" -- "String to prefix to HTML window title"
293 , Option "D" ["print-default-header"]
296 let header = case (lookup arg writers) of
297 Just (writer, head) -> head
298 Nothing -> error ("Unknown reader: " ++ arg)
299 hPutStr stdout header
300 exitWith ExitSuccess)
302 "" -- "Print default header for FORMAT"
304 , Option "" ["dump-args"]
306 (\opt -> return opt { optDumpArgs = True }))
307 "" -- "Print output filename and arguments to stdout."
309 , Option "" ["ignore-args"]
311 (\opt -> return opt { optIgnoreArgs = True }))
312 "" -- "Ignore command-line arguments."
314 , Option "v" ["version"]
318 hPutStrLn stderr (prg ++ " " ++ pandocVersion ++
320 exitWith $ ExitFailure 4))
321 "" -- "Print version"
323 , Option "h" ["help"]
327 hPutStr stderr (usageMessage prg options)
328 exitWith $ ExitFailure 2))
332-- Returns usage message
333usageMessage :: String -> [OptDescr (Opt -> IO Opt)] -> String
334usageMessage programName options = usageInfo
335 (programName ++ " [OPTIONS] [FILES]" ++ "\nInput formats: " ++
336 (joinWithSep ", " $ map fst readers) ++ "\nOutput formats: " ++
337 (joinWithSep ", " $ map fst writers) ++ "\nOptions:")
340-- Determine default reader based on source file extensions
341defaultReaderName :: [String] -> String
342defaultReaderName [] = "markdown"
343defaultReaderName (x:xs) =
344 let x' = map toLower x in
345 case (matchRegex (mkRegex ".*\\.(.*)") x') of
346 Nothing -> defaultReaderName xs -- no extension
347 Just ["xhtml"] -> "html"
348 Just ["html"] -> "html"
349 Just ["htm"] -> "html"
350 Just ["tex"] -> "latex"
351 Just ["latex"] -> "latex"
352 Just ["ltx"] -> "latex"
353 Just ["rst"] -> "rst"
354 Just ["native"] -> "native"
357-- Determine default writer based on output file extension
358defaultWriterName :: String -> String
359defaultWriterName "-" = "html" -- no output file
361 let x' = map toLower x in
362 case (matchRegex (mkRegex ".*\\.(.*)") x') of
363 Nothing -> "markdown" -- no extension
364 Just [""] -> "markdown" -- empty extension
365 Just ["tex"] -> "latex"
366 Just ["latex"] -> "latex"
367 Just ["ltx"] -> "latex"
368 Just ["context"] -> "context"
369 Just ["ctx"] -> "context"
370 Just ["rtf"] -> "rtf"
371 Just ["rst"] -> "rst"
373 Just ["native"] -> "native"
374 Just ["txt"] -> "markdown"
375 Just ["text"] -> "markdown"
376 Just ["md"] -> "markdown"
377 Just ["markdown"] -> "markdown"
378 Just ["db"] -> "docbook"
379 Just ["xml"] -> "docbook"
380 Just ["sgml"] -> "docbook"
381 Just [[x]] | x `elem` ['1'..'9'] -> "man"
388 let compatMode = (prg == "hsmarkdown")
390 let (actions, args, errors) = if compatMode
391 then ([], rawArgs, [])
392 else getOpt Permute options rawArgs
394 if (not (null errors))
397 mapM (\e -> hPutStrLn stderr e) errors
398 hPutStr stderr (usageMessage name options)
399 exitWith $ ExitFailure 2
403 let defaultOpts' = if compatMode
404 then defaultOpts { optReader = "markdown"
409 -- thread option data structure through all supplied option actions
410 opts <- foldl (>>=) (return defaultOpts') actions
412 let Opt { optPreserveTabs = preserveTabs
413 , optTabStop = tabStop
414 , optStandalone = standalone
415 , optReader = readerName
416 , optWriter = writerName
417 , optParseRaw = parseRaw
419 , optTableOfContents = toc
420 , optIncludeInHeader = includeHeader
421 , optIncludeBeforeBody = includeBefore
422 , optIncludeAfterBody = includeAfter
423 , optCustomHeader = customHeader
424 , optTitlePrefix = titlePrefix
425 , optOutputFile = outputFile
426 , optNumberSections = numberSections
427 , optIncremental = incremental
429 , optHTMLMathMethod = mathMethod
430 , optDumpArgs = dumpArgs
431 , optIgnoreArgs = ignoreArgs
433 , optReferenceLinks = referenceLinks
435 , optSanitizeHTML = sanitize
440 hPutStrLn stdout outputFile
441 mapM (\arg -> hPutStrLn stdout arg) args
442 exitWith $ ExitSuccess
445 let sources = if ignoreArgs then [] else args
447 -- assign reader and writer based on options and filenames
448 let readerName' = if null readerName
449 then defaultReaderName sources
452 let writerName' = if null writerName
453 then defaultWriterName outputFile
456 reader <- case (lookup readerName' readers) of
458 Nothing -> error ("Unknown reader: " ++ readerName')
460 (writer, defaultHeader) <- case (lookup writerName' writers) of
461 Just (w,h) -> return (w, h)
462 Nothing -> error ("Unknown writer: " ++ writerName')
464 output <- if (outputFile == "-")
466 else openFile outputFile WriteMode
468 environment <- getEnvironment
469 let columns = case lookup "COLUMNS" environment of
470 Just cols -> read cols
471 Nothing -> stateColumns defaultParserState
473 let tabFilter _ [] = ""
474 tabFilter _ ('\n':xs) = '\n':(tabFilter tabStop xs)
475 -- remove DOS line endings
476 tabFilter _ ('\r':'\n':xs) = '\n':(tabFilter tabStop xs)
477 tabFilter _ ('\r':xs) = '\n':(tabFilter tabStop xs)
478 tabFilter spsToNextStop ('\t':xs) =
480 then '\t':(tabFilter tabStop xs)
481 else replicate spsToNextStop ' ' ++ tabFilter tabStop xs
483 x:(tabFilter tabStop xs)
484 tabFilter spsToNextStop (x:xs) =
485 x:(tabFilter (spsToNextStop - 1) xs)
487 let startParserState =
488 defaultParserState { stateParseRaw = parseRaw,
489 stateTabStop = tabStop,
490 stateSanitizeHTML = sanitize,
491 stateStandalone = standalone && (not strict),
492 stateSmart = smart || writerName' `elem`
493 ["latex", "context"],
494 stateColumns = columns,
495 stateStrict = strict }
496 let csslink = if null css
499 (\f -> "<link rel=\"stylesheet\" href=\"" ++
500 f ++ "\" type=\"text/css\" media=\"all\" />\n")
502 let header = (if (customHeader == "DEFAULT")
504 else customHeader) ++ csslink ++ includeHeader
505 let writerOptions = WriterOptions { writerStandalone = standalone &&
507 writerHeader = header,
508 writerTitlePrefix = titlePrefix,
509 writerTabStop = tabStop,
510 writerTableOfContents = toc &&
513 writerHTMLMathMethod = mathMethod,
514 writerS5 = (writerName=="s5"),
515 writerIgnoreNotes = False,
516 writerIncremental = incremental,
517 writerNumberSections = numberSections,
518 writerIncludeBefore = includeBefore,
519 writerIncludeAfter = includeAfter,
520 writerStrictMarkdown = strict,
521 writerReferenceLinks = referenceLinks,
522 writerWrapText = wrap }
524 (readSources sources) >>= (hPutStrLn output . toUTF8 .
525 (writer writerOptions) .
526 (reader startParserState) . tabFilter tabStop .
527 fromUTF8 . (joinWithSep "\n")) >>
531 readSources [] = mapM readSource ["-"]
532 readSources sources = mapM readSource sources
533 readSource "-" = getContents
534 readSource source = readFile source
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