diff --git a/pandoc.cabal b/pandoc.cabal
index 0f6cdbf75..33087716c 100644
--- a/pandoc.cabal
+++ b/pandoc.cabal
@@ -514,7 +514,8 @@ library
                    Text.Pandoc.ImageSize,
                    Text.Pandoc.BCP47,
                    Text.Pandoc.Class
-  other-modules:   Text.Pandoc.Filter.JSON,
+  other-modules:   Text.Pandoc.App.CommandLineOptions,
+                   Text.Pandoc.Filter.JSON,
                    Text.Pandoc.Filter.Lua,
                    Text.Pandoc.Filter.Path,
                    Text.Pandoc.Readers.Docx.Lists,
diff --git a/src/Text/Pandoc/App.hs b/src/Text/Pandoc/App.hs
index d83f184f3..cf4c9173d 100644
--- a/src/Text/Pandoc/App.hs
+++ b/src/Text/Pandoc/App.hs
@@ -1,8 +1,6 @@
 {-# LANGUAGE NoImplicitPrelude #-}
 {-# LANGUAGE CPP                 #-}
-{-# LANGUAGE DeriveGeneric       #-}
 {-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE TemplateHaskell     #-}
 {-# LANGUAGE TupleSections       #-}
 {-
 Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
@@ -48,13 +46,10 @@ import qualified Control.Exception as E
 import Control.Monad
 import Control.Monad.Except (catchError, throwError)
 import Control.Monad.Trans
-import Data.Aeson (defaultOptions)
-import Data.Aeson.TH (deriveJSON)
 import qualified Data.ByteString as BS
 import qualified Data.ByteString.Lazy as B
-import Data.Char (toLower, toUpper)
-import Data.List (find, intercalate, isPrefixOf, isSuffixOf, sort)
-import qualified Data.Map as M
+import Data.Char (toLower)
+import Data.List (find, isPrefixOf, isSuffixOf)
 import Data.Maybe (fromMaybe, isJust, isNothing)
 import qualified Data.Set as Set
 import Data.Text (Text)
@@ -63,85 +58,31 @@ import qualified Data.Text.Lazy as TL
 import qualified Data.Text.Lazy.Encoding as TE
 import qualified Data.Text.Encoding.Error as TE
 import qualified Data.YAML as YAML
-import GHC.Generics
 import Network.URI (URI (..), parseURI)
-#ifdef EMBED_DATA_FILES
-import Text.Pandoc.Data (dataFiles)
-#else
-import System.Directory (getDirectoryContents)
-import Paths_pandoc (getDataDir)
-#endif
-import Data.Aeson.Encode.Pretty (encodePretty', Config(..), keyOrder,
-         defConfig, Indent(..), NumberFormat(..))
-import Skylighting (Style, Syntax (..), defaultSyntaxMap, parseTheme,
-                    pygments)
+import Skylighting (defaultSyntaxMap)
 import Skylighting.Parser (addSyntaxDefinition, parseSyntaxDefinition)
-import System.Console.GetOpt
 import System.Directory (getAppUserDataDirectory)
-import System.Environment (getArgs, getProgName)
 import System.Exit (exitSuccess)
 import System.FilePath
 import System.IO (nativeNewline, stdout)
 import qualified System.IO as IO (Newline (..))
 import Text.Pandoc
+import Text.Pandoc.App.CommandLineOptions (Opt (..), LineEnding (..),
+        defaultOpts, engines, parseOptions, options)
 import Text.Pandoc.BCP47 (Lang (..), parseBCP47)
 import Text.Pandoc.Builder (setMeta, deleteMeta)
 import Text.Pandoc.Filter (Filter (JSONFilter, LuaFilter), applyFilters)
-import Text.Pandoc.Highlighting (highlightingStyles)
 import Text.Pandoc.PDF (makePDF)
 import Text.Pandoc.Readers.Markdown (yamlToMeta)
 import Text.Pandoc.SelfContained (makeDataURI, makeSelfContained)
 import Text.Pandoc.Shared (eastAsianLineBreakFilter, stripEmptyParagraphs,
-         headerShift, isURI, ordNub, safeRead, tabFilter, uriPathToPath)
+         headerShift, isURI, tabFilter, uriPathToPath)
 import qualified Text.Pandoc.UTF8 as UTF8
-import Text.Pandoc.Writers.Math (defaultKaTeXURL, defaultMathJaxURL)
-import Text.Printf
 #ifndef _WINDOWS
 import System.Posix.IO (stdOutput)
 import System.Posix.Terminal (queryTerminal)
 #endif
 
-data LineEnding = LF | CRLF | Native deriving (Show, Generic)
-
-parseOptions :: [OptDescr (Opt -> IO Opt)] -> Opt -> IO Opt
-parseOptions options' defaults = do
-  rawArgs <- map UTF8.decodeArg <$> getArgs
-  prg <- getProgName
-
-  let (actions, args, unrecognizedOpts, errors) =
-           getOpt' Permute options' rawArgs
-
-  let unknownOptionErrors =
-       foldr (handleUnrecognizedOption . takeWhile (/= '=')) []
-       unrecognizedOpts
-
-  unless (null errors && null unknownOptionErrors) $
-     E.throwIO $ PandocOptionError $
-        concat errors ++ unlines unknownOptionErrors ++
-        ("Try " ++ prg ++ " --help for more information.")
-
-  -- thread option data structure through all supplied option actions
-  opts <- foldl (>>=) (return defaults) actions
-  return (opts{ optInputFiles = args })
-
-latexEngines :: [String]
-latexEngines  = ["pdflatex", "lualatex", "xelatex"]
-
-htmlEngines :: [String]
-htmlEngines  = ["wkhtmltopdf", "weasyprint", "prince"]
-
-engines :: [(String, String)]
-engines = map ("html",) htmlEngines ++
-          map ("html5",) htmlEngines ++
-          map ("latex",) latexEngines ++
-          map ("beamer",) latexEngines ++
-          [ ("ms", "pdfroff")
-          , ("context", "context")
-          ]
-
-pdfEngines :: [String]
-pdfEngines = ordNub $ map snd engines
-
 pdfIsNoWriterErrorMsg :: String
 pdfIsNoWriterErrorMsg =
   "To create a pdf using pandoc, use " ++
@@ -264,7 +205,6 @@ convertWithOpts opts = do
   let standalone = optStandalone opts || not (isTextFormat format) || pdfOutput
   let addStringAsVariable varname s vars = return $ (varname, s) : vars
 
-  highlightStyle <- lookupHighlightStyle $ optHighlightStyle opts
   let addSyntaxMap existingmap f = do
         res <- parseSyntaxDefinition f
         case res of
@@ -374,7 +314,7 @@ convertWithOpts opts = do
                           return $ ("dzslides-core", dzcore) : vars
                       else return vars)
 
-    abbrevs <- (Set.fromList . filter (not . null) . lines) <$>
+    abbrevs <- Set.fromList . filter (not . null) . lines <$>
                case optAbbreviations opts of
                     Nothing -> UTF8.toString <$> readDataFile "abbreviations"
                     Just f  -> UTF8.toString <$> readFileStrict f
@@ -438,7 +378,7 @@ convertWithOpts opts = do
           , writerTopLevelDivision = optTopLevelDivision opts
           , writerListings         = optListings opts
           , writerSlideLevel       = optSlideLevel opts
-          , writerHighlightStyle   = highlightStyle
+          , writerHighlightStyle   = optHighlightStyle opts
           , writerSetextHeaders    = optSetextHeaders opts
           , writerEpubSubdirectory = optEpubSubdirectory opts
           , writerEpubMetadata     = epubMetadata
@@ -540,151 +480,6 @@ type Transform = Pandoc -> Pandoc
 isTextFormat :: String -> Bool
 isTextFormat s = s `notElem` ["odt","docx","epub2","epub3","epub","pptx"]
 
--- | Data structure for command line options.
-data Opt = Opt
-    { optTabStop               :: Int     -- ^ Number of spaces per tab
-    , optPreserveTabs          :: Bool    -- ^ Preserve tabs instead of converting to spaces
-    , optStandalone            :: Bool    -- ^ Include header, footer
-    , optReader                :: Maybe String  -- ^ Reader format
-    , optWriter                :: Maybe String  -- ^ Writer format
-    , optTableOfContents       :: Bool    -- ^ Include table of contents
-    , optBaseHeaderLevel       :: Int     -- ^ Base header level
-    , optTemplate              :: Maybe FilePath  -- ^ Custom template
-    , optVariables             :: [(String,String)] -- ^ Template variables to set
-    , optMetadata              :: [(String, String)] -- ^ Metadata fields to set
-    , optMetadataFile          :: Maybe FilePath  -- ^ Name of YAML metadata file
-    , optOutputFile            :: Maybe FilePath  -- ^ Name of output file
-    , optInputFiles            :: [FilePath] -- ^ Names of input files
-    , optNumberSections        :: Bool    -- ^ Number sections in LaTeX
-    , optNumberOffset          :: [Int]   -- ^ Starting number for sections
-    , optSectionDivs           :: Bool    -- ^ Put sections in div tags in HTML
-    , optIncremental           :: Bool    -- ^ Use incremental lists in Slidy/Slideous/S5
-    , optSelfContained         :: Bool    -- ^ Make HTML accessible offline
-    , optHtmlQTags             :: Bool    -- ^ Use <q> tags in HTML
-    , optHighlightStyle        :: Maybe String -- ^ Style to use for highlighted code
-    , optSyntaxDefinitions     :: [FilePath]  -- ^ xml syntax defs to load
-    , optTopLevelDivision      :: TopLevelDivision -- ^ Type of the top-level divisions
-    , optHTMLMathMethod        :: HTMLMathMethod -- ^ Method to print HTML math
-    , optAbbreviations         :: Maybe FilePath -- ^ Path to abbrevs file
-    , optReferenceDoc          :: Maybe FilePath -- ^ Path of reference doc
-    , optEpubSubdirectory      :: String -- ^ EPUB subdir in OCF container
-    , optEpubMetadata          :: Maybe FilePath   -- ^ EPUB metadata
-    , optEpubFonts             :: [FilePath] -- ^ EPUB fonts to embed
-    , optEpubChapterLevel      :: Int     -- ^ Header level at which to split chapters
-    , optEpubCoverImage        :: Maybe FilePath -- ^ Cover image for epub
-    , optTOCDepth              :: Int     -- ^ Number of levels to include in TOC
-    , optDumpArgs              :: Bool    -- ^ Output command-line arguments
-    , optIgnoreArgs            :: Bool    -- ^ Ignore command-line arguments
-    , optVerbosity             :: Verbosity  -- ^ Verbosity of diagnostic output
-    , optTrace                 :: Bool  -- ^ Enable tracing
-    , optLogFile               :: Maybe FilePath -- ^ File to write JSON log output
-    , optFailIfWarnings        :: Bool    -- ^ Fail on warnings
-    , optReferenceLinks        :: Bool    -- ^ Use reference links in writing markdown, rst
-    , optReferenceLocation     :: ReferenceLocation -- ^ location for footnotes and link references in markdown output
-    , optDpi                   :: Int     -- ^ Dpi
-    , optWrapText              :: WrapOption  -- ^ Options for wrapping text
-    , optColumns               :: Int     -- ^ Line length in characters
-    , optFilters               :: [Filter] -- ^ Filters to apply
-    , optEmailObfuscation      :: ObfuscationMethod
-    , optIdentifierPrefix      :: String
-    , optStripEmptyParagraphs  :: Bool -- ^ Strip empty paragraphs
-    , optIndentedCodeClasses   :: [String] -- ^ Default classes for indented code blocks
-    , optDataDir               :: Maybe FilePath
-    , optCiteMethod            :: CiteMethod -- ^ Method to output cites
-    , optListings              :: Bool       -- ^ Use listings package for code blocks
-    , optPdfEngine             :: Maybe String -- ^ Program to use for latex/html -> pdf
-    , optPdfEngineArgs         :: [String]   -- ^ Flags to pass to the engine
-    , optSlideLevel            :: Maybe Int  -- ^ Header level that creates slides
-    , optSetextHeaders         :: Bool       -- ^ Use atx headers for markdown level 1-2
-    , optAscii                 :: Bool       -- ^ Prefer ascii output
-    , optDefaultImageExtension :: String -- ^ Default image extension
-    , optExtractMedia          :: Maybe FilePath -- ^ Path to extract embedded media
-    , optTrackChanges          :: TrackChanges -- ^ Accept or reject MS Word track-changes.
-    , optFileScope             :: Bool         -- ^ Parse input files before combining
-    , optTitlePrefix           :: Maybe String     -- ^ Prefix for title
-    , optCss                   :: [FilePath]       -- ^ CSS files to link to
-    , optIncludeBeforeBody     :: [FilePath]       -- ^ Files to include before
-    , optIncludeAfterBody      :: [FilePath]       -- ^ Files to include after body
-    , optIncludeInHeader       :: [FilePath]       -- ^ Files to include in header
-    , optResourcePath          :: [FilePath] -- ^ Path to search for images etc
-    , optRequestHeaders        :: [(String, String)] -- ^ Headers for HTTP requests
-    , optEol                   :: LineEnding -- ^ Style of line-endings to use
-    , optStripComments         :: Bool       -- ^ Skip HTML comments
-    } deriving (Generic, Show)
-
--- | Defaults for command-line options.
-defaultOpts :: Opt
-defaultOpts = Opt
-    { optTabStop               = 4
-    , optPreserveTabs          = False
-    , optStandalone            = False
-    , optReader                = Nothing
-    , optWriter                = Nothing
-    , optTableOfContents       = False
-    , optBaseHeaderLevel       = 1
-    , optTemplate              = Nothing
-    , optVariables             = []
-    , optMetadata              = []
-    , optMetadataFile          = Nothing
-    , optOutputFile            = Nothing
-    , optInputFiles            = []
-    , optNumberSections        = False
-    , optNumberOffset          = [0,0,0,0,0,0]
-    , optSectionDivs           = False
-    , optIncremental           = False
-    , optSelfContained         = False
-    , optHtmlQTags             = False
-    , optHighlightStyle        = Just "pygments"
-    , optSyntaxDefinitions     = []
-    , optTopLevelDivision      = TopLevelDefault
-    , optHTMLMathMethod        = PlainMath
-    , optAbbreviations         = Nothing
-    , optReferenceDoc          = Nothing
-    , optEpubSubdirectory      = "EPUB"
-    , optEpubMetadata          = Nothing
-    , optEpubFonts             = []
-    , optEpubChapterLevel      = 1
-    , optEpubCoverImage        = Nothing
-    , optTOCDepth              = 3
-    , optDumpArgs              = False
-    , optIgnoreArgs            = False
-    , optVerbosity             = WARNING
-    , optTrace                 = False
-    , optLogFile               = Nothing
-    , optFailIfWarnings        = False
-    , optReferenceLinks        = False
-    , optReferenceLocation     = EndOfDocument
-    , optDpi                   = 96
-    , optWrapText              = WrapAuto
-    , optColumns               = 72
-    , optFilters               = []
-    , optEmailObfuscation      = NoObfuscation
-    , optIdentifierPrefix      = ""
-    , optStripEmptyParagraphs  = False
-    , optIndentedCodeClasses   = []
-    , optDataDir               = Nothing
-    , optCiteMethod            = Citeproc
-    , optListings              = False
-    , optPdfEngine             = Nothing
-    , optPdfEngineArgs         = []
-    , optSlideLevel            = Nothing
-    , optSetextHeaders         = True
-    , optAscii                 = False
-    , optDefaultImageExtension = ""
-    , optExtractMedia          = Nothing
-    , optTrackChanges          = AcceptChanges
-    , optFileScope             = False
-    , optTitlePrefix           = Nothing
-    , optCss                   = []
-    , optIncludeBeforeBody     = []
-    , optIncludeAfterBody      = []
-    , optIncludeInHeader       = []
-    , optResourcePath          = ["."]
-    , optRequestHeaders        = []
-    , optEol                   = Native
-    , optStripComments          = False
-    }
-
 addNonPresentMetadata :: Text.Pandoc.Meta -> Pandoc -> Pandoc
 addNonPresentMetadata newmeta (Pandoc meta bs) = Pandoc (meta <> newmeta) bs
 
@@ -800,828 +595,6 @@ writerFn :: MonadIO m => IO.Newline -> FilePath -> Text -> m ()
 writerFn eol "-" = liftIO . UTF8.putStrWith eol . T.unpack
 writerFn eol f   = liftIO . UTF8.writeFileWith eol f . T.unpack
 
-lookupHighlightStyle :: Maybe String -> IO (Maybe Style)
-lookupHighlightStyle Nothing = return Nothing
-lookupHighlightStyle (Just s)
-  | takeExtension s == ".theme" = -- attempt to load KDE theme
-    do contents <- B.readFile s
-       case parseTheme contents of
-            Left _    -> E.throwIO $ PandocOptionError $
-                           "Could not read highlighting theme " ++ s
-            Right sty -> return (Just sty)
-  | otherwise =
-  case lookup (map toLower s) highlightingStyles of
-       Just sty -> return (Just sty)
-       Nothing  -> E.throwIO $ PandocOptionError $
-                      "Unknown highlight-style " ++ s
-
--- | A list of functions, each transforming the options data structure
---   in response to a command-line option.
-options :: [OptDescr (Opt -> IO Opt)]
-options =
-    [ Option "fr" ["from","read"]
-                 (ReqArg
-                  (\arg opt -> return opt { optReader =
-                                              Just (map toLower arg) })
-                  "FORMAT")
-                 ""
-
-    , Option "tw" ["to","write"]
-                 (ReqArg
-                  (\arg opt -> return opt { optWriter = Just arg })
-                  "FORMAT")
-                 ""
-
-    , Option "o" ["output"]
-                 (ReqArg
-                  (\arg opt -> return opt { optOutputFile = Just arg })
-                  "FILE")
-                 "" -- "Name of output file"
-
-    , Option "" ["data-dir"]
-                 (ReqArg
-                  (\arg opt -> return opt { optDataDir = Just arg })
-                 "DIRECTORY") -- "Directory containing pandoc data files."
-                ""
-
-    , Option "" ["base-header-level"]
-                 (ReqArg
-                  (\arg opt ->
-                      case safeRead arg of
-                           Just t | t > 0 && t < 6 ->
-                               return opt{ optBaseHeaderLevel = t }
-                           _              -> E.throwIO $ PandocOptionError
-                                               "base-header-level must be 1-5")
-                  "NUMBER")
-                 "" -- "Headers base level"
-
-    , Option "" ["strip-empty-paragraphs"]
-                 (NoArg
-                  (\opt -> do
-                      deprecatedOption "--stripEmptyParagraphs"
-                        "Use +empty_paragraphs extension."
-                      return opt{ optStripEmptyParagraphs = True }))
-                 "" -- "Strip empty paragraphs"
-
-    , Option "" ["indented-code-classes"]
-                  (ReqArg
-                   (\arg opt -> return opt { optIndentedCodeClasses = words $
-                                             map (\c -> if c == ',' then ' ' else c) arg })
-                   "STRING")
-                  "" -- "Classes (whitespace- or comma-separated) to use for indented code-blocks"
-
-    , Option "F" ["filter"]
-                 (ReqArg
-                  (\arg opt -> return opt { optFilters =
-                                    JSONFilter arg : optFilters opt })
-                  "PROGRAM")
-                 "" -- "External JSON filter"
-
-    , Option "" ["lua-filter"]
-                 (ReqArg
-                  (\arg opt -> return opt { optFilters =
-                                    LuaFilter arg : optFilters opt })
-                  "SCRIPTPATH")
-                 "" -- "Lua filter"
-
-    , Option "p" ["preserve-tabs"]
-                 (NoArg
-                  (\opt -> return opt { optPreserveTabs = True }))
-                 "" -- "Preserve tabs instead of converting to spaces"
-
-    , Option "" ["tab-stop"]
-                 (ReqArg
-                  (\arg opt ->
-                      case safeRead arg of
-                           Just t | t > 0 -> return opt { optTabStop = t }
-                           _              -> E.throwIO $ PandocOptionError
-                                  "tab-stop must be a number greater than 0")
-                  "NUMBER")
-                 "" -- "Tab stop (default 4)"
-
-    , Option "" ["track-changes"]
-                 (ReqArg
-                  (\arg opt -> do
-                     action <- case arg of
-                            "accept" -> return AcceptChanges
-                            "reject" -> return RejectChanges
-                            "all"    -> return AllChanges
-                            _        -> E.throwIO $ PandocOptionError
-                               ("Unknown option for track-changes: " ++ arg)
-                     return opt { optTrackChanges = action })
-                  "accept|reject|all")
-                 "" -- "Accepting or reject MS Word track-changes.""
-
-    , Option "" ["file-scope"]
-                 (NoArg
-                  (\opt -> return opt { optFileScope = True }))
-                 "" -- "Parse input files before combining"
-
-    , Option "" ["extract-media"]
-                 (ReqArg
-                  (\arg opt ->
-                    return opt { optExtractMedia = Just arg })
-                  "PATH")
-                 "" -- "Directory to which to extract embedded media"
-
-    , Option "s" ["standalone"]
-                 (NoArg
-                  (\opt -> return opt { optStandalone = True }))
-                 "" -- "Include needed header and footer on output"
-
-    , Option "" ["template"]
-                 (ReqArg
-                  (\arg opt ->
-                     return opt{ optTemplate = Just arg,
-                                 optStandalone = True })
-                  "FILE")
-                 "" -- "Use custom template"
-
-    , Option "M" ["metadata"]
-                 (ReqArg
-                  (\arg opt -> do
-                     let (key, val) = splitField arg
-                     return opt{ optMetadata = (key, val) : optMetadata opt })
-                  "KEY[:VALUE]")
-                 ""
-
-    , Option "" ["metadata-file"]
-                 (ReqArg
-                  (\arg opt -> return opt{ optMetadataFile = Just arg })
-                  "FILE")
-                 ""
-
-    , Option "V" ["variable"]
-                 (ReqArg
-                  (\arg opt -> do
-                     let (key, val) = splitField arg
-                     return opt{ optVariables = (key, val) : optVariables opt })
-                  "KEY[:VALUE]")
-                 ""
-
-    , Option "D" ["print-default-template"]
-                 (ReqArg
-                  (\arg _ -> do
-                     templ <- runIO $ do
-                                setUserDataDir Nothing
-                                getDefaultTemplate arg
-                     case templ of
-                          Right "" -> do -- e.g. for docx, odt, json:
-                            E.throwIO $ PandocCouldNotFindDataFileError
-                               ("templates/default." ++ arg)
-                          Right t -> UTF8.hPutStr stdout t
-                          Left e  -> E.throwIO e
-                     exitSuccess)
-                  "FORMAT")
-                 "" -- "Print default template for FORMAT"
-
-    , Option "" ["print-default-data-file"]
-                 (ReqArg
-                  (\arg _ -> do
-                     runIOorExplode $
-                       readDefaultDataFile arg >>= liftIO . BS.hPutStr stdout
-                     exitSuccess)
-                  "FILE")
-                  "" -- "Print default data file"
-
-    , Option "" ["print-highlight-style"]
-                 (ReqArg
-                  (\arg _ -> do
-                     sty <- fromMaybe pygments <$>
-                              lookupHighlightStyle (Just arg)
-                     B.putStr $ encodePretty'
-                       defConfig{confIndent = Spaces 4
-                                ,confCompare = keyOrder
-                                  (map T.pack
-                                   ["text-color"
-                                   ,"background-color"
-                                   ,"line-number-color"
-                                   ,"line-number-background-color"
-                                   ,"bold"
-                                   ,"italic"
-                                   ,"underline"
-                                   ,"text-styles"])
-                                ,confNumFormat = Generic
-                                ,confTrailingNewline = True} sty
-                     exitSuccess)
-                  "STYLE|FILE")
-                 "" -- "Print default template for FORMAT"
-
-    , Option "" ["dpi"]
-                 (ReqArg
-                  (\arg opt ->
-                    case safeRead arg of
-                         Just t | t > 0 -> return opt { optDpi = t }
-                         _              -> E.throwIO $ PandocOptionError
-                                        "dpi must be a number greater than 0")
-                  "NUMBER")
-                 "" -- "Dpi (default 96)"
-
-    , Option "" ["eol"]
-                 (ReqArg
-                  (\arg opt ->
-                    case toLower <$> arg of
-                      "crlf"   -> return opt { optEol = CRLF }
-                      "lf"     -> return opt { optEol = LF }
-                      "native" -> return opt { optEol = Native }
-                      -- mac-syntax (cr) is not supported in ghc-base.
-                      _      -> E.throwIO $ PandocOptionError
-                                "--eol must be crlf, lf, or native")
-                  "crlf|lf|native")
-                 "" -- "EOL (default OS-dependent)"
-
-    , Option "" ["wrap"]
-                 (ReqArg
-                  (\arg opt ->
-                    case safeRead ("Wrap" ++ uppercaseFirstLetter arg) of
-                          Just o   -> return opt { optWrapText = o }
-                          Nothing  -> E.throwIO $ PandocOptionError
-                                     "--wrap must be auto, none, or preserve")
-                 "auto|none|preserve")
-                 "" -- "Option for wrapping text in output"
-
-    , Option "" ["columns"]
-                 (ReqArg
-                  (\arg opt ->
-                      case safeRead arg of
-                           Just t | t > 0 -> return opt { optColumns = t }
-                           _              -> E.throwIO $ PandocOptionError
-                                   "columns must be a number greater than 0")
-                 "NUMBER")
-                 "" -- "Length of line in characters"
-
-    , Option "" ["strip-comments"]
-                (NoArg
-                 (\opt -> return opt { optStripComments = True }))
-               "" -- "Strip HTML comments"
-
-    , Option "" ["toc", "table-of-contents"]
-                (NoArg
-                 (\opt -> return opt { optTableOfContents = True }))
-               "" -- "Include table of contents"
-
-    , Option "" ["toc-depth"]
-                 (ReqArg
-                  (\arg opt ->
-                      case safeRead arg of
-                           Just t | t >= 1 && t <= 6 ->
-                                    return opt { optTOCDepth = t }
-                           _      -> E.throwIO $ PandocOptionError
-                                    "TOC level must be a number between 1 and 6")
-                 "NUMBER")
-                 "" -- "Number of levels to include in TOC"
-
-    , Option "" ["no-highlight"]
-                (NoArg
-                 (\opt -> return opt { optHighlightStyle = Nothing }))
-                 "" -- "Don't highlight source code"
-
-    , Option "" ["highlight-style"]
-                (ReqArg
-                 (\arg opt -> return opt{ optHighlightStyle = Just arg })
-                 "STYLE|FILE")
-                 "" -- "Style for highlighted code"
-
-    , Option "" ["syntax-definition"]
-                (ReqArg
-                 (\arg opt -> do
-                   let tr c d = map (\x -> if x == c then d else x)
-                   let arg' = case arg of -- see #4836
-                                   -- HXT confuses Windows path with URI
-                                   _:':':'\\':_ ->
-                                       "file:///" ++ tr '\\' '/' arg
-                                   _ -> arg
-                   return opt{ optSyntaxDefinitions = arg' :
-                                optSyntaxDefinitions opt })
-                 "FILE")
-                "" -- "Syntax definition (xml) file"
-
-    , Option "H" ["include-in-header"]
-                 (ReqArg
-                  (\arg opt -> return opt{ optIncludeInHeader =
-                                              arg : optIncludeInHeader opt,
-                                            optStandalone = True })
-                  "FILE")
-                 "" -- "File to include at end of header (implies -s)"
-
-    , Option "B" ["include-before-body"]
-                 (ReqArg
-                  (\arg opt -> return opt{ optIncludeBeforeBody =
-                                              arg : optIncludeBeforeBody opt,
-                                           optStandalone = True })
-                  "FILE")
-                 "" -- "File to include before document body"
-
-    , Option "A" ["include-after-body"]
-                 (ReqArg
-                  (\arg opt -> return opt{ optIncludeAfterBody =
-                                              arg : optIncludeAfterBody opt,
-                                           optStandalone = True })
-                  "FILE")
-                 "" -- "File to include after document body"
-
-    , Option "" ["resource-path"]
-                (ReqArg
-                  (\arg opt -> return opt { optResourcePath =
-                                   splitSearchPath arg })
-                   "SEARCHPATH")
-                  "" -- "Paths to search for images and other resources"
-
-    , Option "" ["request-header"]
-                 (ReqArg
-                  (\arg opt -> do
-                     let (key, val) = splitField arg
-                     return opt{ optRequestHeaders =
-                       (key, val) : optRequestHeaders opt })
-                  "NAME:VALUE")
-                 ""
-
-    , Option "" ["self-contained"]
-                 (NoArg
-                  (\opt -> return opt { optSelfContained = True,
-                                        optStandalone = True }))
-                 "" -- "Make slide shows include all the needed js and css"
-
-    , Option "" ["html-q-tags"]
-                 (NoArg
-                  (\opt ->
-                     return opt { optHtmlQTags = True }))
-                 "" -- "Use <q> tags for quotes in HTML"
-
-    , Option "" ["ascii"]
-                 (NoArg
-                  (\opt -> return opt { optAscii = True }))
-                 ""  -- "Prefer ASCII output"
-
-    , Option "" ["reference-links"]
-                 (NoArg
-                  (\opt -> return opt { optReferenceLinks = True } ))
-                 "" -- "Use reference links in parsing HTML"
-
-    , Option "" ["reference-location"]
-                 (ReqArg
-                  (\arg opt -> do
-                     action <- case arg of
-                            "block"    -> return EndOfBlock
-                            "section"  -> return EndOfSection
-                            "document" -> return EndOfDocument
-                            _        -> E.throwIO $ PandocOptionError
-                               ("Unknown option for reference-location: " ++ arg)
-                     return opt { optReferenceLocation = action })
-                  "block|section|document")
-                 "" -- "Accepting or reject MS Word track-changes.""
-
-    , Option "" ["atx-headers"]
-                 (NoArg
-                  (\opt -> return opt { optSetextHeaders = False } ))
-                 "" -- "Use atx-style headers for markdown"
-
-    , Option "" ["top-level-division"]
-                 (ReqArg
-                  (\arg opt -> do
-                      let tldName = "TopLevel" ++ uppercaseFirstLetter arg
-                      case safeRead tldName of
-                        Just tlDiv -> return opt { optTopLevelDivision = tlDiv }
-                        _       -> E.throwIO $ PandocOptionError
-                                     ("Top-level division must be " ++
-                                      "section,  chapter, part, or default"))
-                   "section|chapter|part")
-                 "" -- "Use top-level division type in LaTeX, ConTeXt, DocBook"
-
-    , Option "N" ["number-sections"]
-                 (NoArg
-                  (\opt -> return opt { optNumberSections = True }))
-                 "" -- "Number sections in LaTeX"
-
-    , Option "" ["number-offset"]
-                 (ReqArg
-                  (\arg opt ->
-                      case safeRead ('[':arg ++ "]") of
-                           Just ns -> return opt { optNumberOffset = ns,
-                                                   optNumberSections = True }
-                           _      -> E.throwIO $ PandocOptionError
-                                       "could not parse number-offset")
-                 "NUMBERS")
-                 "" -- "Starting number for sections, subsections, etc."
-
-    , Option "" ["listings"]
-                 (NoArg
-                  (\opt -> return opt { optListings = True }))
-                 "" -- "Use listings package for LaTeX code blocks"
-
-    , Option "i" ["incremental"]
-                 (NoArg
-                  (\opt -> return opt { optIncremental = True }))
-                 "" -- "Make list items display incrementally in Slidy/Slideous/S5"
-
-    , Option "" ["slide-level"]
-                 (ReqArg
-                  (\arg opt ->
-                      case safeRead arg of
-                           Just t | t >= 1 && t <= 6 ->
-                                    return opt { optSlideLevel = Just t }
-                           _      -> E.throwIO $ PandocOptionError
-                                    "slide level must be a number between 1 and 6")
-                 "NUMBER")
-                 "" -- "Force header level for slides"
-
-    , Option "" ["section-divs"]
-                 (NoArg
-                  (\opt -> return opt { optSectionDivs = True }))
-                 "" -- "Put sections in div tags in HTML"
-
-    , Option "" ["default-image-extension"]
-                 (ReqArg
-                  (\arg opt -> return opt { optDefaultImageExtension = arg })
-                   "extension")
-                  "" -- "Default extension for extensionless images"
-
-    , Option "" ["email-obfuscation"]
-                 (ReqArg
-                  (\arg opt -> do
-                     method <- case arg of
-                            "references" -> return ReferenceObfuscation
-                            "javascript" -> return JavascriptObfuscation
-                            "none"       -> return NoObfuscation
-                            _            -> E.throwIO $ PandocOptionError
-                               ("Unknown obfuscation method: " ++ arg)
-                     return opt { optEmailObfuscation = method })
-                  "none|javascript|references")
-                 "" -- "Method for obfuscating email in HTML"
-
-     , Option "" ["id-prefix"]
-                  (ReqArg
-                   (\arg opt -> return opt { optIdentifierPrefix = arg })
-                   "STRING")
-                  "" -- "Prefix to add to automatically generated HTML identifiers"
-
-    , Option "T" ["title-prefix"]
-                 (ReqArg
-                  (\arg opt -> do
-                    let newvars = ("title-prefix", arg) : optVariables opt
-                    return opt { optVariables = newvars,
-                                 optStandalone = True })
-                  "STRING")
-                 "" -- "String to prefix to HTML window title"
-
-    , Option "c" ["css"]
-                 (ReqArg
-                  (\arg opt -> return opt{ optCss = arg : optCss opt })
-                  -- add new link to end, so it is included in proper order
-                  "URL")
-                 "" -- "Link to CSS style sheet"
-
-    , Option "" ["reference-doc"]
-                 (ReqArg
-                  (\arg opt ->
-                    return opt { optReferenceDoc = Just arg })
-                  "FILE")
-                 "" -- "Path of custom reference doc"
-
-    , Option "" ["epub-subdirectory"]
-             (ReqArg
-                  (\arg opt ->
-                     return opt { optEpubSubdirectory = arg })
-                  "DIRNAME")
-                 "" -- "Name of subdirectory for epub content in OCF container"
-
-    , Option "" ["epub-cover-image"]
-                 (ReqArg
-                  (\arg opt ->
-                     return opt { optVariables =
-                                 ("epub-cover-image", arg) : optVariables opt })
-                  "FILE")
-                 "" -- "Path of epub cover image"
-
-    , Option "" ["epub-metadata"]
-                 (ReqArg
-                  (\arg opt -> return opt { optEpubMetadata = Just arg })
-                  "FILE")
-                 "" -- "Path of epub metadata file"
-
-    , Option "" ["epub-embed-font"]
-                 (ReqArg
-                  (\arg opt ->
-                     return opt{ optEpubFonts = arg : optEpubFonts opt })
-                  "FILE")
-                 "" -- "Directory of fonts to embed"
-
-    , Option "" ["epub-chapter-level"]
-                 (ReqArg
-                  (\arg opt ->
-                      case safeRead arg of
-                           Just t | t >= 1 && t <= 6 ->
-                                    return opt { optEpubChapterLevel = t }
-                           _      -> E.throwIO $ PandocOptionError
-                                    "chapter level must be a number between 1 and 6")
-                 "NUMBER")
-                 "" -- "Header level at which to split chapters in EPUB"
-
-    , Option "" ["pdf-engine"]
-                 (ReqArg
-                  (\arg opt -> do
-                     let b = takeBaseName arg
-                     if b `elem` pdfEngines
-                        then return opt { optPdfEngine = Just arg }
-                        else E.throwIO $ PandocOptionError $ "pdf-engine must be one of "
-                               ++ intercalate ", " pdfEngines)
-                  "PROGRAM")
-                 "" -- "Name of program to use in generating PDF"
-
-    , Option "" ["pdf-engine-opt"]
-                 (ReqArg
-                  (\arg opt -> do
-                      let oldArgs = optPdfEngineArgs opt
-                      return opt { optPdfEngineArgs = oldArgs ++ [arg]})
-                  "STRING")
-                 "" -- "Flags to pass to the PDF-engine, all instances of this option are accumulated and used"
-
-    , Option "" ["bibliography"]
-                 (ReqArg
-                  (\arg opt -> return opt{ optMetadata =
-                                 ("bibliography", arg) : optMetadata opt })
-                   "FILE")
-                 ""
-
-     , Option "" ["csl"]
-                 (ReqArg
-                  (\arg opt ->
-                     return opt{ optMetadata =
-                                   ("csl", arg) : optMetadata opt })
-                   "FILE")
-                 ""
-
-     , Option "" ["citation-abbreviations"]
-                 (ReqArg
-                  (\arg opt ->
-                     return opt{ optMetadata =
-                              ("citation-abbreviations", arg): optMetadata opt })
-                   "FILE")
-                 ""
-
-    , Option "" ["natbib"]
-                 (NoArg
-                  (\opt -> return opt { optCiteMethod = Natbib }))
-                 "" -- "Use natbib cite commands in LaTeX output"
-
-    , Option "" ["biblatex"]
-                 (NoArg
-                  (\opt -> return opt { optCiteMethod = Biblatex }))
-                 "" -- "Use biblatex cite commands in LaTeX output"
-
-    , Option "" ["mathml"]
-                 (NoArg
-                  (\opt ->
-                      return opt { optHTMLMathMethod = MathML }))
-                 "" -- "Use mathml for HTML math"
-
-    , Option "" ["webtex"]
-                 (OptArg
-                  (\arg opt -> do
-                      let url' = fromMaybe "https://latex.codecogs.com/png.latex?" arg
-                      return opt { optHTMLMathMethod = WebTeX url' })
-                  "URL")
-                 "" -- "Use web service for HTML math"
-
-    , Option "" ["mathjax"]
-                 (OptArg
-                  (\arg opt -> do
-                      let url' = fromMaybe (defaultMathJaxURL ++
-                                  "MathJax.js?config=TeX-AMS_CHTML-full") arg
-                      return opt { optHTMLMathMethod = MathJax url'})
-                  "URL")
-                 "" -- "Use MathJax for HTML math"
-
-    , Option "" ["katex"]
-                 (OptArg
-                  (\arg opt ->
-                      return opt
-                        { optHTMLMathMethod = KaTeX $
-                           fromMaybe defaultKaTeXURL arg })
-                  "URL")
-                  "" -- Use KaTeX for HTML Math
-
-    , Option "" ["gladtex"]
-                 (NoArg
-                  (\opt ->
-                      return opt { optHTMLMathMethod = GladTeX }))
-                 "" -- "Use gladtex for HTML math"
-
-    , Option "" ["abbreviations"]
-                (ReqArg
-                 (\arg opt -> return opt { optAbbreviations = Just arg })
-                "FILE")
-                "" -- "Specify file for custom abbreviations"
-
-    , Option "" ["trace"]
-                 (NoArg
-                  (\opt -> return opt { optTrace = True }))
-                 "" -- "Turn on diagnostic tracing in readers."
-
-    , Option "" ["dump-args"]
-                 (NoArg
-                  (\opt -> return opt { optDumpArgs = True }))
-                 "" -- "Print output filename and arguments to stdout."
-
-    , Option "" ["ignore-args"]
-                 (NoArg
-                  (\opt -> return opt { optIgnoreArgs = True }))
-                 "" -- "Ignore command-line arguments."
-
-    , Option "" ["verbose"]
-                 (NoArg
-                  (\opt -> return opt { optVerbosity = INFO }))
-                 "" -- "Verbose diagnostic output."
-
-    , Option "" ["quiet"]
-                 (NoArg
-                  (\opt -> return opt { optVerbosity = ERROR }))
-                 "" -- "Suppress warnings."
-
-    , Option "" ["fail-if-warnings"]
-                 (NoArg
-                  (\opt -> return opt { optFailIfWarnings = True }))
-                 "" -- "Exit with error status if there were  warnings."
-
-    , Option "" ["log"]
-                 (ReqArg
-                  (\arg opt -> return opt{ optLogFile = Just arg })
-                "FILE")
-                "" -- "Log messages in JSON format to this file."
-
-    , Option "" ["bash-completion"]
-                 (NoArg
-                  (\_ -> do
-                     datafiles <- getDataFileNames
-                     tpl <- runIOorExplode $
-                              UTF8.toString <$>
-                                readDefaultDataFile "bash_completion.tpl"
-                     let optnames (Option shorts longs _ _) =
-                           map (\c -> ['-',c]) shorts ++
-                           map ("--" ++) longs
-                     let allopts = unwords (concatMap optnames options)
-                     UTF8.hPutStrLn stdout $ printf tpl allopts
-                         (unwords readersNames)
-                         (unwords writersNames)
-                         (unwords $ map fst highlightingStyles)
-                         (unwords datafiles)
-                     exitSuccess ))
-                 "" -- "Print bash completion script"
-
-    , Option "" ["list-input-formats"]
-                 (NoArg
-                  (\_ -> do
-                     mapM_ (UTF8.hPutStrLn stdout) readersNames
-                     exitSuccess ))
-                 ""
-
-    , Option "" ["list-output-formats"]
-                 (NoArg
-                  (\_ -> do
-                     mapM_ (UTF8.hPutStrLn stdout) writersNames
-                     exitSuccess ))
-                 ""
-
-    , Option "" ["list-extensions"]
-                 (OptArg
-                  (\arg _ -> do
-                     let exts = getDefaultExtensions (fromMaybe "markdown" arg)
-                     let showExt x = (if extensionEnabled x exts
-                                         then '+'
-                                         else '-') : drop 4 (show x)
-                     mapM_ (UTF8.hPutStrLn stdout . showExt)
-                               ([minBound..maxBound] :: [Extension])
-                     exitSuccess )
-                  "FORMAT")
-                 ""
-
-    , Option "" ["list-highlight-languages"]
-                 (NoArg
-                  (\_ -> do
-                     let langs = [ T.unpack (T.toLower (sShortname s))
-                                 | s <- M.elems defaultSyntaxMap
-                                 , sShortname s `notElem`
-                                    [T.pack "Alert", T.pack "Alert_indent"]
-                                 ]
-                     mapM_ (UTF8.hPutStrLn stdout) langs
-                     exitSuccess ))
-                 ""
-
-    , Option "" ["list-highlight-styles"]
-                 (NoArg
-                  (\_ -> do
-                     mapM_ (UTF8.hPutStrLn stdout . fst) highlightingStyles
-                     exitSuccess ))
-                 ""
-
-    , Option "v" ["version"]
-                 (NoArg
-                  (\_ -> do
-                     prg <- getProgName
-                     defaultDatadir <- E.catch
-                            (getAppUserDataDirectory "pandoc")
-                            (\e -> let _ = (e :: E.SomeException)
-                                   in  return "")
-                     UTF8.hPutStrLn stdout (prg ++ " " ++ pandocVersion ++
-                       compileInfo ++ "\nDefault user data directory: " ++
-                       defaultDatadir ++ copyrightMessage)
-                     exitSuccess ))
-                 "" -- "Print version"
-
-    , Option "h" ["help"]
-                 (NoArg
-                  (\_ -> do
-                     prg <- getProgName
-                     UTF8.hPutStr stdout (usageMessage prg options)
-                     exitSuccess ))
-                 "" -- "Show help"
-
-    ]
-
-getDataFileNames :: IO [FilePath]
-getDataFileNames = do
-#ifdef EMBED_DATA_FILES
-  let allDataFiles = map fst dataFiles
-#else
-  allDataFiles <- filter (\x -> x /= "." && x /= "..") <$>
-                      (getDataDir >>= getDirectoryContents)
-#endif
-  return $ "reference.docx" : "reference.odt" : "reference.pptx" : allDataFiles
-
--- Returns usage message
-usageMessage :: String -> [OptDescr (Opt -> IO Opt)] -> String
-usageMessage programName = usageInfo (programName ++ " [OPTIONS] [FILES]")
-
-copyrightMessage :: String
-copyrightMessage = intercalate "\n" [
-  "",
-  "Copyright (C) 2006-2018 John MacFarlane",
-  "Web:  http://pandoc.org",
-  "This is free software; see the source for copying conditions.",
-  "There is no warranty, not even for merchantability or fitness",
-  "for a particular purpose." ]
-
-compileInfo :: String
-compileInfo =
-  "\nCompiled with pandoc-types " ++ VERSION_pandoc_types ++ ", texmath " ++
-  VERSION_texmath ++ ", skylighting " ++ VERSION_skylighting
-
-handleUnrecognizedOption :: String -> [String] -> [String]
-handleUnrecognizedOption "--smart" =
-  (("--smart/-S has been removed.  Use +smart or -smart extension instead.\n" ++
-    "For example: pandoc -f markdown+smart -t markdown-smart.") :)
-handleUnrecognizedOption "--normalize" =
-  ("--normalize has been removed.  Normalization is now automatic." :)
-handleUnrecognizedOption "-S" = handleUnrecognizedOption "--smart"
-handleUnrecognizedOption "--old-dashes" =
-  ("--old-dashes has been removed.  Use +old_dashes extension instead." :)
-handleUnrecognizedOption "--no-wrap" =
-  ("--no-wrap has been removed.  Use --wrap=none instead." :)
-handleUnrecognizedOption "--latex-engine" =
-  ("--latex-engine has been removed.  Use --pdf-engine instead." :)
-handleUnrecognizedOption "--latex-engine-opt" =
-  ("--latex-engine-opt has been removed.  Use --pdf-engine-opt instead." :)
-handleUnrecognizedOption "--chapters" =
-  ("--chapters has been removed. Use --top-level-division=chapter instead." :)
-handleUnrecognizedOption "--reference-docx" =
-  ("--reference-docx has been removed. Use --reference-doc instead." :)
-handleUnrecognizedOption "--reference-odt" =
-  ("--reference-odt has been removed. Use --reference-doc instead." :)
-handleUnrecognizedOption "--parse-raw" =
-  ("--parse-raw/-R has been removed. Use +raw_html or +raw_tex extension.\n" :)
-handleUnrecognizedOption "--epub-stylesheet" =
-  ("--epub-stylesheet has been removed. Use --css instead.\n" :)
-handleUnrecognizedOption "-R" = handleUnrecognizedOption "--parse-raw"
-handleUnrecognizedOption x =
-  (("Unknown option " ++ x ++ ".") :)
-
-uppercaseFirstLetter :: String -> String
-uppercaseFirstLetter (c:cs) = toUpper c : cs
-uppercaseFirstLetter []     = []
-
-readersNames :: [String]
-readersNames = sort (map fst (readers :: [(String, Reader PandocIO)]))
-
-writersNames :: [String]
-writersNames = sort (map fst (writers :: [(String, Writer PandocIO)]))
-
-splitField :: String -> (String, String)
-splitField s =
-  case break (`elem` ":=") s of
-       (k,_:v) -> (k,v)
-       (k,[])  -> (k,"true")
 
 baseWriterName :: String -> String
 baseWriterName = takeWhile (\c -> c /= '+' && c /= '-')
-
-deprecatedOption :: String -> String -> IO ()
-deprecatedOption o msg =
-  runIO (report $ Deprecated o msg) >>=
-    \r -> case r of
-       Right () -> return ()
-       Left e   -> E.throwIO e
-
--- see https://github.com/jgm/pandoc/pull/4083
--- using generic deriving caused long compilation times
-$(deriveJSON defaultOptions ''LineEnding)
-$(deriveJSON defaultOptions ''Opt)
diff --git a/src/Text/Pandoc/App/CommandLineOptions.hs b/src/Text/Pandoc/App/CommandLineOptions.hs
new file mode 100644
index 000000000..d97b43b2f
--- /dev/null
+++ b/src/Text/Pandoc/App/CommandLineOptions.hs
@@ -0,0 +1,1091 @@
+{-# LANGUAGE NoImplicitPrelude   #-}
+{-# LANGUAGE CPP                 #-}
+{-# LANGUAGE DeriveGeneric       #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TemplateHaskell     #-}
+{-# LANGUAGE TupleSections       #-}
+{-
+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+-}
+
+{- |
+   Module      : Text.Pandoc.App.CommandLineOptions
+   Copyright   : Copyright (C) 2006-2018 John MacFarlane
+   License     : GNU GPL, version 2 or above
+
+   Maintainer  : John MacFarlane <jgm@berkeley@edu>
+   Stability   : alpha
+   Portability : portable
+
+Does a pandoc conversion based on command-line options.
+-}
+module Text.Pandoc.App.CommandLineOptions (
+            Opt(..)
+          , LineEnding (..)
+          , defaultOpts
+          , parseOptions
+          , options
+          , engines
+          ) where
+import Prelude
+import Control.Monad
+import Control.Monad.Trans
+import Data.Aeson.Encode.Pretty (encodePretty', Config(..), keyOrder,
+         defConfig, Indent(..), NumberFormat(..))
+import Data.Aeson.TH (deriveJSON, defaultOptions)
+import Data.Char (toLower, toUpper)
+import Data.List (intercalate, sort)
+import Data.Maybe (fromMaybe)
+import GHC.Generics
+import Skylighting (Style, Syntax (..), defaultSyntaxMap, parseTheme,
+                    pygments)
+import System.Console.GetOpt
+import System.Environment (getArgs, getProgName)
+import System.Exit (exitSuccess)
+import System.FilePath
+import System.IO (stdout)
+import Text.Pandoc
+import Text.Pandoc.Filter (Filter (..))
+import Text.Pandoc.Highlighting (highlightingStyles)
+import Text.Pandoc.Writers.Math (defaultMathJaxURL, defaultKaTeXURL)
+import Text.Pandoc.Shared (ordNub, safeRead)
+import Text.Printf
+
+#ifdef EMBED_DATA_FILES
+import Text.Pandoc.Data (dataFiles)
+import System.Directory (getAppUserDataDirectory)
+#else
+import Paths_pandoc (getDataDir)
+import System.Directory (getAppUserDataDirectory, getDirectoryContents)
+#endif
+
+import qualified Control.Exception as E
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.Lazy as B
+import qualified Data.Map as M
+import qualified Data.Text as T
+import qualified Text.Pandoc.UTF8 as UTF8
+
+-- | The type of line-endings to be used when writing plain-text.
+data LineEnding = LF | CRLF | Native deriving (Show, Generic)
+
+parseOptions :: [OptDescr (Opt -> IO Opt)] -> Opt -> IO Opt
+parseOptions options' defaults = do
+  rawArgs <- map UTF8.decodeArg <$> getArgs
+  prg <- getProgName
+
+  let (actions, args, unrecognizedOpts, errors) =
+           getOpt' Permute options' rawArgs
+
+  let unknownOptionErrors =
+       foldr (handleUnrecognizedOption . takeWhile (/= '=')) []
+       unrecognizedOpts
+
+  unless (null errors && null unknownOptionErrors) $
+     E.throwIO $ PandocOptionError $
+        concat errors ++ unlines unknownOptionErrors ++
+        ("Try " ++ prg ++ " --help for more information.")
+
+  -- thread option data structure through all supplied option actions
+  opts <- foldl (>>=) (return defaults) actions
+  return (opts{ optInputFiles = args })
+
+latexEngines :: [String]
+latexEngines  = ["pdflatex", "lualatex", "xelatex"]
+
+htmlEngines :: [String]
+htmlEngines  = ["wkhtmltopdf", "weasyprint", "prince"]
+
+engines :: [(String, String)]
+engines = map ("html",) htmlEngines ++
+          map ("html5",) htmlEngines ++
+          map ("latex",) latexEngines ++
+          map ("beamer",) latexEngines ++
+          [ ("ms", "pdfroff")
+          , ("context", "context")
+          ]
+
+pdfEngines :: [String]
+pdfEngines = ordNub $ map snd engines
+
+
+-- | Data structure for command line options.
+data Opt = Opt
+    { optTabStop               :: Int     -- ^ Number of spaces per tab
+    , optPreserveTabs          :: Bool    -- ^ Preserve tabs instead of converting to spaces
+    , optStandalone            :: Bool    -- ^ Include header, footer
+    , optReader                :: Maybe String  -- ^ Reader format
+    , optWriter                :: Maybe String  -- ^ Writer format
+    , optTableOfContents       :: Bool    -- ^ Include table of contents
+    , optBaseHeaderLevel       :: Int     -- ^ Base header level
+    , optTemplate              :: Maybe FilePath  -- ^ Custom template
+    , optVariables             :: [(String,String)] -- ^ Template variables to set
+    , optMetadata              :: [(String, String)] -- ^ Metadata fields to set
+    , optMetadataFile          :: Maybe FilePath  -- ^ Name of YAML metadata file
+    , optOutputFile            :: Maybe FilePath  -- ^ Name of output file
+    , optInputFiles            :: [FilePath] -- ^ Names of input files
+    , optNumberSections        :: Bool    -- ^ Number sections in LaTeX
+    , optNumberOffset          :: [Int]   -- ^ Starting number for sections
+    , optSectionDivs           :: Bool    -- ^ Put sections in div tags in HTML
+    , optIncremental           :: Bool    -- ^ Use incremental lists in Slidy/Slideous/S5
+    , optSelfContained         :: Bool    -- ^ Make HTML accessible offline
+    , optHtmlQTags             :: Bool    -- ^ Use <q> tags in HTML
+    , optHighlightStyle        :: Maybe Style -- ^ Style to use for highlighted code
+    , optSyntaxDefinitions     :: [FilePath]  -- ^ xml syntax defs to load
+    , optTopLevelDivision      :: TopLevelDivision -- ^ Type of the top-level divisions
+    , optHTMLMathMethod        :: HTMLMathMethod -- ^ Method to print HTML math
+    , optAbbreviations         :: Maybe FilePath -- ^ Path to abbrevs file
+    , optReferenceDoc          :: Maybe FilePath -- ^ Path of reference doc
+    , optEpubSubdirectory      :: String -- ^ EPUB subdir in OCF container
+    , optEpubMetadata          :: Maybe FilePath   -- ^ EPUB metadata
+    , optEpubFonts             :: [FilePath] -- ^ EPUB fonts to embed
+    , optEpubChapterLevel      :: Int     -- ^ Header level at which to split chapters
+    , optEpubCoverImage        :: Maybe FilePath -- ^ Cover image for epub
+    , optTOCDepth              :: Int     -- ^ Number of levels to include in TOC
+    , optDumpArgs              :: Bool    -- ^ Output command-line arguments
+    , optIgnoreArgs            :: Bool    -- ^ Ignore command-line arguments
+    , optVerbosity             :: Verbosity  -- ^ Verbosity of diagnostic output
+    , optTrace                 :: Bool  -- ^ Enable tracing
+    , optLogFile               :: Maybe FilePath -- ^ File to write JSON log output
+    , optFailIfWarnings        :: Bool    -- ^ Fail on warnings
+    , optReferenceLinks        :: Bool    -- ^ Use reference links in writing markdown, rst
+    , optReferenceLocation     :: ReferenceLocation -- ^ location for footnotes and link references in markdown output
+    , optDpi                   :: Int     -- ^ Dpi
+    , optWrapText              :: WrapOption  -- ^ Options for wrapping text
+    , optColumns               :: Int     -- ^ Line length in characters
+    , optFilters               :: [Filter] -- ^ Filters to apply
+    , optEmailObfuscation      :: ObfuscationMethod
+    , optIdentifierPrefix      :: String
+    , optStripEmptyParagraphs  :: Bool -- ^ Strip empty paragraphs
+    , optIndentedCodeClasses   :: [String] -- ^ Default classes for indented code blocks
+    , optDataDir               :: Maybe FilePath
+    , optCiteMethod            :: CiteMethod -- ^ Method to output cites
+    , optListings              :: Bool       -- ^ Use listings package for code blocks
+    , optPdfEngine             :: Maybe String -- ^ Program to use for latex/html -> pdf
+    , optPdfEngineArgs         :: [String]   -- ^ Flags to pass to the engine
+    , optSlideLevel            :: Maybe Int  -- ^ Header level that creates slides
+    , optSetextHeaders         :: Bool       -- ^ Use atx headers for markdown level 1-2
+    , optAscii                 :: Bool       -- ^ Prefer ascii output
+    , optDefaultImageExtension :: String -- ^ Default image extension
+    , optExtractMedia          :: Maybe FilePath -- ^ Path to extract embedded media
+    , optTrackChanges          :: TrackChanges -- ^ Accept or reject MS Word track-changes.
+    , optFileScope             :: Bool         -- ^ Parse input files before combining
+    , optTitlePrefix           :: Maybe String     -- ^ Prefix for title
+    , optCss                   :: [FilePath]       -- ^ CSS files to link to
+    , optIncludeBeforeBody     :: [FilePath]       -- ^ Files to include before
+    , optIncludeAfterBody      :: [FilePath]       -- ^ Files to include after body
+    , optIncludeInHeader       :: [FilePath]       -- ^ Files to include in header
+    , optResourcePath          :: [FilePath] -- ^ Path to search for images etc
+    , optRequestHeaders        :: [(String, String)] -- ^ Headers for HTTP requests
+    , optEol                   :: LineEnding -- ^ Style of line-endings to use
+    , optStripComments         :: Bool       -- ^ Skip HTML comments
+    } deriving (Generic, Show)
+
+-- | Defaults for command-line options.
+defaultOpts :: Opt
+defaultOpts = Opt
+    { optTabStop               = 4
+    , optPreserveTabs          = False
+    , optStandalone            = False
+    , optReader                = Nothing
+    , optWriter                = Nothing
+    , optTableOfContents       = False
+    , optBaseHeaderLevel       = 1
+    , optTemplate              = Nothing
+    , optVariables             = []
+    , optMetadata              = []
+    , optMetadataFile          = Nothing
+    , optOutputFile            = Nothing
+    , optInputFiles            = []
+    , optNumberSections        = False
+    , optNumberOffset          = [0,0,0,0,0,0]
+    , optSectionDivs           = False
+    , optIncremental           = False
+    , optSelfContained         = False
+    , optHtmlQTags             = False
+    , optHighlightStyle        = Just pygments
+    , optSyntaxDefinitions     = []
+    , optTopLevelDivision      = TopLevelDefault
+    , optHTMLMathMethod        = PlainMath
+    , optAbbreviations         = Nothing
+    , optReferenceDoc          = Nothing
+    , optEpubSubdirectory      = "EPUB"
+    , optEpubMetadata          = Nothing
+    , optEpubFonts             = []
+    , optEpubChapterLevel      = 1
+    , optEpubCoverImage        = Nothing
+    , optTOCDepth              = 3
+    , optDumpArgs              = False
+    , optIgnoreArgs            = False
+    , optVerbosity             = WARNING
+    , optTrace                 = False
+    , optLogFile               = Nothing
+    , optFailIfWarnings        = False
+    , optReferenceLinks        = False
+    , optReferenceLocation     = EndOfDocument
+    , optDpi                   = 96
+    , optWrapText              = WrapAuto
+    , optColumns               = 72
+    , optFilters               = []
+    , optEmailObfuscation      = NoObfuscation
+    , optIdentifierPrefix      = ""
+    , optStripEmptyParagraphs  = False
+    , optIndentedCodeClasses   = []
+    , optDataDir               = Nothing
+    , optCiteMethod            = Citeproc
+    , optListings              = False
+    , optPdfEngine             = Nothing
+    , optPdfEngineArgs         = []
+    , optSlideLevel            = Nothing
+    , optSetextHeaders         = True
+    , optAscii                 = False
+    , optDefaultImageExtension = ""
+    , optExtractMedia          = Nothing
+    , optTrackChanges          = AcceptChanges
+    , optFileScope             = False
+    , optTitlePrefix           = Nothing
+    , optCss                   = []
+    , optIncludeBeforeBody     = []
+    , optIncludeAfterBody      = []
+    , optIncludeInHeader       = []
+    , optResourcePath          = ["."]
+    , optRequestHeaders        = []
+    , optEol                   = Native
+    , optStripComments          = False
+    }
+
+lookupHighlightStyle :: Maybe String -> IO (Maybe Style)
+lookupHighlightStyle Nothing = return Nothing
+lookupHighlightStyle (Just s)
+  | takeExtension s == ".theme" = -- attempt to load KDE theme
+    do contents <- B.readFile s
+       case parseTheme contents of
+            Left _    -> E.throwIO $ PandocOptionError $
+                           "Could not read highlighting theme " ++ s
+            Right sty -> return (Just sty)
+  | otherwise =
+  case lookup (map toLower s) highlightingStyles of
+       Just sty -> return (Just sty)
+       Nothing  -> E.throwIO $ PandocOptionError $
+                      "Unknown highlight-style " ++ s
+
+-- | A list of functions, each transforming the options data structure
+--   in response to a command-line option.
+options :: [OptDescr (Opt -> IO Opt)]
+options =
+    [ Option "fr" ["from","read"]
+                 (ReqArg
+                  (\arg opt -> return opt { optReader =
+                                              Just (map toLower arg) })
+                  "FORMAT")
+                 ""
+
+    , Option "tw" ["to","write"]
+                 (ReqArg
+                  (\arg opt -> return opt { optWriter = Just arg })
+                  "FORMAT")
+                 ""
+
+    , Option "o" ["output"]
+                 (ReqArg
+                  (\arg opt -> return opt { optOutputFile = Just arg })
+                  "FILE")
+                 "" -- "Name of output file"
+
+    , Option "" ["data-dir"]
+                 (ReqArg
+                  (\arg opt -> return opt { optDataDir = Just arg })
+                 "DIRECTORY") -- "Directory containing pandoc data files."
+                ""
+
+    , Option "" ["base-header-level"]
+                 (ReqArg
+                  (\arg opt ->
+                      case safeRead arg of
+                           Just t | t > 0 && t < 6 ->
+                               return opt{ optBaseHeaderLevel = t }
+                           _              -> E.throwIO $ PandocOptionError
+                                               "base-header-level must be 1-5")
+                  "NUMBER")
+                 "" -- "Headers base level"
+
+    , Option "" ["strip-empty-paragraphs"]
+                 (NoArg
+                  (\opt -> do
+                      deprecatedOption "--stripEmptyParagraphs"
+                        "Use +empty_paragraphs extension."
+                      return opt{ optStripEmptyParagraphs = True }))
+                 "" -- "Strip empty paragraphs"
+
+    , Option "" ["indented-code-classes"]
+                  (ReqArg
+                   (\arg opt -> return opt { optIndentedCodeClasses = words $
+                                             map (\c -> if c == ',' then ' ' else c) arg })
+                   "STRING")
+                  "" -- "Classes (whitespace- or comma-separated) to use for indented code-blocks"
+
+    , Option "F" ["filter"]
+                 (ReqArg
+                  (\arg opt -> return opt { optFilters =
+                                    JSONFilter arg : optFilters opt })
+                  "PROGRAM")
+                 "" -- "External JSON filter"
+
+    , Option "" ["lua-filter"]
+                 (ReqArg
+                  (\arg opt -> return opt { optFilters =
+                                    LuaFilter arg : optFilters opt })
+                  "SCRIPTPATH")
+                 "" -- "Lua filter"
+
+    , Option "p" ["preserve-tabs"]
+                 (NoArg
+                  (\opt -> return opt { optPreserveTabs = True }))
+                 "" -- "Preserve tabs instead of converting to spaces"
+
+    , Option "" ["tab-stop"]
+                 (ReqArg
+                  (\arg opt ->
+                      case safeRead arg of
+                           Just t | t > 0 -> return opt { optTabStop = t }
+                           _              -> E.throwIO $ PandocOptionError
+                                  "tab-stop must be a number greater than 0")
+                  "NUMBER")
+                 "" -- "Tab stop (default 4)"
+
+    , Option "" ["track-changes"]
+                 (ReqArg
+                  (\arg opt -> do
+                     action <- case arg of
+                            "accept" -> return AcceptChanges
+                            "reject" -> return RejectChanges
+                            "all"    -> return AllChanges
+                            _        -> E.throwIO $ PandocOptionError
+                               ("Unknown option for track-changes: " ++ arg)
+                     return opt { optTrackChanges = action })
+                  "accept|reject|all")
+                 "" -- "Accepting or reject MS Word track-changes.""
+
+    , Option "" ["file-scope"]
+                 (NoArg
+                  (\opt -> return opt { optFileScope = True }))
+                 "" -- "Parse input files before combining"
+
+    , Option "" ["extract-media"]
+                 (ReqArg
+                  (\arg opt ->
+                    return opt { optExtractMedia = Just arg })
+                  "PATH")
+                 "" -- "Directory to which to extract embedded media"
+
+    , Option "s" ["standalone"]
+                 (NoArg
+                  (\opt -> return opt { optStandalone = True }))
+                 "" -- "Include needed header and footer on output"
+
+    , Option "" ["template"]
+                 (ReqArg
+                  (\arg opt ->
+                     return opt{ optTemplate = Just arg,
+                                 optStandalone = True })
+                  "FILE")
+                 "" -- "Use custom template"
+
+    , Option "M" ["metadata"]
+                 (ReqArg
+                  (\arg opt -> do
+                     let (key, val) = splitField arg
+                     return opt{ optMetadata = (key, val) : optMetadata opt })
+                  "KEY[:VALUE]")
+                 ""
+
+    , Option "" ["metadata-file"]
+                 (ReqArg
+                  (\arg opt -> return opt{ optMetadataFile = Just arg })
+                  "FILE")
+                 ""
+
+    , Option "V" ["variable"]
+                 (ReqArg
+                  (\arg opt -> do
+                     let (key, val) = splitField arg
+                     return opt{ optVariables = (key, val) : optVariables opt })
+                  "KEY[:VALUE]")
+                 ""
+
+    , Option "D" ["print-default-template"]
+                 (ReqArg
+                  (\arg _ -> do
+                     templ <- runIO $ do
+                                setUserDataDir Nothing
+                                getDefaultTemplate arg
+                     case templ of
+                          Right "" -> -- e.g. for docx, odt, json:
+                            E.throwIO $ PandocCouldNotFindDataFileError
+                               ("templates/default." ++ arg)
+                          Right t -> UTF8.hPutStr stdout t
+                          Left e  -> E.throwIO e
+                     exitSuccess)
+                  "FORMAT")
+                 "" -- "Print default template for FORMAT"
+
+    , Option "" ["print-default-data-file"]
+                 (ReqArg
+                  (\arg _ -> do
+                     runIOorExplode $
+                       readDefaultDataFile arg >>= liftIO . BS.hPutStr stdout
+                     exitSuccess)
+                  "FILE")
+                  "" -- "Print default data file"
+
+    , Option "" ["print-highlight-style"]
+                 (ReqArg
+                  (\arg _ -> do
+                     sty <- fromMaybe pygments <$> lookupHighlightStyle arg
+                     B.putStr $ encodePretty'
+                       defConfig{confIndent = Spaces 4
+                                ,confCompare = keyOrder
+                                  (map T.pack
+                                   ["text-color"
+                                   ,"background-color"
+                                   ,"line-number-color"
+                                   ,"line-number-background-color"
+                                   ,"bold"
+                                   ,"italic"
+                                   ,"underline"
+                                   ,"text-styles"])
+                                ,confNumFormat = Generic
+                                ,confTrailingNewline = True} sty
+                     exitSuccess)
+                  "STYLE|FILE")
+                 "" -- "Print default template for FORMAT"
+
+    , Option "" ["dpi"]
+                 (ReqArg
+                  (\arg opt ->
+                    case safeRead arg of
+                         Just t | t > 0 -> return opt { optDpi = t }
+                         _              -> E.throwIO $ PandocOptionError
+                                        "dpi must be a number greater than 0")
+                  "NUMBER")
+                 "" -- "Dpi (default 96)"
+
+    , Option "" ["eol"]
+                 (ReqArg
+                  (\arg opt ->
+                    case toLower <$> arg of
+                      "crlf"   -> return opt { optEol = CRLF }
+                      "lf"     -> return opt { optEol = LF }
+                      "native" -> return opt { optEol = Native }
+                      -- mac-syntax (cr) is not supported in ghc-base.
+                      _      -> E.throwIO $ PandocOptionError
+                                "--eol must be crlf, lf, or native")
+                  "crlf|lf|native")
+                 "" -- "EOL (default OS-dependent)"
+
+    , Option "" ["wrap"]
+                 (ReqArg
+                  (\arg opt ->
+                    case safeRead ("Wrap" ++ uppercaseFirstLetter arg) of
+                          Just o   -> return opt { optWrapText = o }
+                          Nothing  -> E.throwIO $ PandocOptionError
+                                     "--wrap must be auto, none, or preserve")
+                 "auto|none|preserve")
+                 "" -- "Option for wrapping text in output"
+
+    , Option "" ["columns"]
+                 (ReqArg
+                  (\arg opt ->
+                      case safeRead arg of
+                           Just t | t > 0 -> return opt { optColumns = t }
+                           _              -> E.throwIO $ PandocOptionError
+                                   "columns must be a number greater than 0")
+                 "NUMBER")
+                 "" -- "Length of line in characters"
+
+    , Option "" ["strip-comments"]
+                (NoArg
+                 (\opt -> return opt { optStripComments = True }))
+               "" -- "Strip HTML comments"
+
+    , Option "" ["toc", "table-of-contents"]
+                (NoArg
+                 (\opt -> return opt { optTableOfContents = True }))
+               "" -- "Include table of contents"
+
+    , Option "" ["toc-depth"]
+                 (ReqArg
+                  (\arg opt ->
+                      case safeRead arg of
+                           Just t | t >= 1 && t <= 6 ->
+                                    return opt { optTOCDepth = t }
+                           _      -> E.throwIO $ PandocOptionError
+                                    "TOC level must be a number between 1 and 6")
+                 "NUMBER")
+                 "" -- "Number of levels to include in TOC"
+
+    , Option "" ["no-highlight"]
+                (NoArg
+                 (\opt -> return opt { optHighlightStyle = Nothing }))
+                 "" -- "Don't highlight source code"
+
+    , Option "" ["highlight-style"]
+                (ReqArg
+                 (\arg opt -> lookupHighlightStyle arg >>= \style ->
+                     return opt{ optHighlightStyle = style })
+                 "STYLE|FILE")
+                 "" -- "Style for highlighted code"
+
+    , Option "" ["syntax-definition"]
+                (ReqArg
+                 (\arg opt -> do
+                   let tr c d = map (\x -> if x == c then d else x)
+                   let arg' = case arg of -- see #4836
+                                   -- HXT confuses Windows path with URI
+                                   _:':':'\\':_ ->
+                                       "file:///" ++ tr '\\' '/' arg
+                                   _ -> arg
+                   return opt{ optSyntaxDefinitions = arg' :
+                                optSyntaxDefinitions opt })
+                 "FILE")
+                "" -- "Syntax definition (xml) file"
+
+    , Option "H" ["include-in-header"]
+                 (ReqArg
+                  (\arg opt -> return opt{ optIncludeInHeader =
+                                              arg : optIncludeInHeader opt,
+                                            optStandalone = True })
+                  "FILE")
+                 "" -- "File to include at end of header (implies -s)"
+
+    , Option "B" ["include-before-body"]
+                 (ReqArg
+                  (\arg opt -> return opt{ optIncludeBeforeBody =
+                                              arg : optIncludeBeforeBody opt,
+                                           optStandalone = True })
+                  "FILE")
+                 "" -- "File to include before document body"
+
+    , Option "A" ["include-after-body"]
+                 (ReqArg
+                  (\arg opt -> return opt{ optIncludeAfterBody =
+                                              arg : optIncludeAfterBody opt,
+                                           optStandalone = True })
+                  "FILE")
+                 "" -- "File to include after document body"
+
+    , Option "" ["resource-path"]
+                (ReqArg
+                  (\arg opt -> return opt { optResourcePath =
+                                   splitSearchPath arg })
+                   "SEARCHPATH")
+                  "" -- "Paths to search for images and other resources"
+
+    , Option "" ["request-header"]
+                 (ReqArg
+                  (\arg opt -> do
+                     let (key, val) = splitField arg
+                     return opt{ optRequestHeaders =
+                       (key, val) : optRequestHeaders opt })
+                  "NAME:VALUE")
+                 ""
+
+    , Option "" ["self-contained"]
+                 (NoArg
+                  (\opt -> return opt { optSelfContained = True,
+                                        optStandalone = True }))
+                 "" -- "Make slide shows include all the needed js and css"
+
+    , Option "" ["html-q-tags"]
+                 (NoArg
+                  (\opt ->
+                     return opt { optHtmlQTags = True }))
+                 "" -- "Use <q> tags for quotes in HTML"
+
+    , Option "" ["ascii"]
+                 (NoArg
+                  (\opt -> return opt { optAscii = True }))
+                 ""  -- "Prefer ASCII output"
+
+    , Option "" ["reference-links"]
+                 (NoArg
+                  (\opt -> return opt { optReferenceLinks = True } ))
+                 "" -- "Use reference links in parsing HTML"
+
+    , Option "" ["reference-location"]
+                 (ReqArg
+                  (\arg opt -> do
+                     action <- case arg of
+                            "block"    -> return EndOfBlock
+                            "section"  -> return EndOfSection
+                            "document" -> return EndOfDocument
+                            _        -> E.throwIO $ PandocOptionError
+                               ("Unknown option for reference-location: " ++ arg)
+                     return opt { optReferenceLocation = action })
+                  "block|section|document")
+                 "" -- "Accepting or reject MS Word track-changes.""
+
+    , Option "" ["atx-headers"]
+                 (NoArg
+                  (\opt -> return opt { optSetextHeaders = False } ))
+                 "" -- "Use atx-style headers for markdown"
+
+    , Option "" ["top-level-division"]
+                 (ReqArg
+                  (\arg opt -> do
+                      let tldName = "TopLevel" ++ uppercaseFirstLetter arg
+                      case safeRead tldName of
+                        Just tlDiv -> return opt { optTopLevelDivision = tlDiv }
+                        _       -> E.throwIO $ PandocOptionError
+                                     ("Top-level division must be " ++
+                                      "section,  chapter, part, or default"))
+                   "section|chapter|part")
+                 "" -- "Use top-level division type in LaTeX, ConTeXt, DocBook"
+
+    , Option "N" ["number-sections"]
+                 (NoArg
+                  (\opt -> return opt { optNumberSections = True }))
+                 "" -- "Number sections in LaTeX"
+
+    , Option "" ["number-offset"]
+                 (ReqArg
+                  (\arg opt ->
+                      case safeRead ('[':arg ++ "]") of
+                           Just ns -> return opt { optNumberOffset = ns,
+                                                   optNumberSections = True }
+                           _      -> E.throwIO $ PandocOptionError
+                                       "could not parse number-offset")
+                 "NUMBERS")
+                 "" -- "Starting number for sections, subsections, etc."
+
+    , Option "" ["listings"]
+                 (NoArg
+                  (\opt -> return opt { optListings = True }))
+                 "" -- "Use listings package for LaTeX code blocks"
+
+    , Option "i" ["incremental"]
+                 (NoArg
+                  (\opt -> return opt { optIncremental = True }))
+                 "" -- "Make list items display incrementally in Slidy/Slideous/S5"
+
+    , Option "" ["slide-level"]
+                 (ReqArg
+                  (\arg opt ->
+                      case safeRead arg of
+                           Just t | t >= 1 && t <= 6 ->
+                                    return opt { optSlideLevel = Just t }
+                           _      -> E.throwIO $ PandocOptionError
+                                    "slide level must be a number between 1 and 6")
+                 "NUMBER")
+                 "" -- "Force header level for slides"
+
+    , Option "" ["section-divs"]
+                 (NoArg
+                  (\opt -> return opt { optSectionDivs = True }))
+                 "" -- "Put sections in div tags in HTML"
+
+    , Option "" ["default-image-extension"]
+                 (ReqArg
+                  (\arg opt -> return opt { optDefaultImageExtension = arg })
+                   "extension")
+                  "" -- "Default extension for extensionless images"
+
+    , Option "" ["email-obfuscation"]
+                 (ReqArg
+                  (\arg opt -> do
+                     method <- case arg of
+                            "references" -> return ReferenceObfuscation
+                            "javascript" -> return JavascriptObfuscation
+                            "none"       -> return NoObfuscation
+                            _            -> E.throwIO $ PandocOptionError
+                               ("Unknown obfuscation method: " ++ arg)
+                     return opt { optEmailObfuscation = method })
+                  "none|javascript|references")
+                 "" -- "Method for obfuscating email in HTML"
+
+     , Option "" ["id-prefix"]
+                  (ReqArg
+                   (\arg opt -> return opt { optIdentifierPrefix = arg })
+                   "STRING")
+                  "" -- "Prefix to add to automatically generated HTML identifiers"
+
+    , Option "T" ["title-prefix"]
+                 (ReqArg
+                  (\arg opt -> do
+                    let newvars = ("title-prefix", arg) : optVariables opt
+                    return opt { optVariables = newvars,
+                                 optStandalone = True })
+                  "STRING")
+                 "" -- "String to prefix to HTML window title"
+
+    , Option "c" ["css"]
+                 (ReqArg
+                  (\arg opt -> return opt{ optCss = arg : optCss opt })
+                  -- add new link to end, so it is included in proper order
+                  "URL")
+                 "" -- "Link to CSS style sheet"
+
+    , Option "" ["reference-doc"]
+                 (ReqArg
+                  (\arg opt ->
+                    return opt { optReferenceDoc = Just arg })
+                  "FILE")
+                 "" -- "Path of custom reference doc"
+
+    , Option "" ["epub-subdirectory"]
+             (ReqArg
+                  (\arg opt ->
+                     return opt { optEpubSubdirectory = arg })
+                  "DIRNAME")
+                 "" -- "Name of subdirectory for epub content in OCF container"
+
+    , Option "" ["epub-cover-image"]
+                 (ReqArg
+                  (\arg opt ->
+                     return opt { optVariables =
+                                 ("epub-cover-image", arg) : optVariables opt })
+                  "FILE")
+                 "" -- "Path of epub cover image"
+
+    , Option "" ["epub-metadata"]
+                 (ReqArg
+                  (\arg opt -> return opt { optEpubMetadata = Just arg })
+                  "FILE")
+                 "" -- "Path of epub metadata file"
+
+    , Option "" ["epub-embed-font"]
+                 (ReqArg
+                  (\arg opt ->
+                     return opt{ optEpubFonts = arg : optEpubFonts opt })
+                  "FILE")
+                 "" -- "Directory of fonts to embed"
+
+    , Option "" ["epub-chapter-level"]
+                 (ReqArg
+                  (\arg opt ->
+                      case safeRead arg of
+                           Just t | t >= 1 && t <= 6 ->
+                                    return opt { optEpubChapterLevel = t }
+                           _      -> E.throwIO $ PandocOptionError
+                                    "chapter level must be a number between 1 and 6")
+                 "NUMBER")
+                 "" -- "Header level at which to split chapters in EPUB"
+
+    , Option "" ["pdf-engine"]
+                 (ReqArg
+                  (\arg opt -> do
+                     let b = takeBaseName arg
+                     if b `elem` pdfEngines
+                        then return opt { optPdfEngine = Just arg }
+                        else E.throwIO $ PandocOptionError $ "pdf-engine must be one of "
+                               ++ intercalate ", " pdfEngines)
+                  "PROGRAM")
+                 "" -- "Name of program to use in generating PDF"
+
+    , Option "" ["pdf-engine-opt"]
+                 (ReqArg
+                  (\arg opt -> do
+                      let oldArgs = optPdfEngineArgs opt
+                      return opt { optPdfEngineArgs = oldArgs ++ [arg]})
+                  "STRING")
+                 "" -- "Flags to pass to the PDF-engine, all instances of this option are accumulated and used"
+
+    , Option "" ["bibliography"]
+                 (ReqArg
+                  (\arg opt -> return opt{ optMetadata =
+                                 ("bibliography", arg) : optMetadata opt })
+                   "FILE")
+                 ""
+
+     , Option "" ["csl"]
+                 (ReqArg
+                  (\arg opt ->
+                     return opt{ optMetadata =
+                                   ("csl", arg) : optMetadata opt })
+                   "FILE")
+                 ""
+
+     , Option "" ["citation-abbreviations"]
+                 (ReqArg
+                  (\arg opt ->
+                     return opt{ optMetadata =
+                              ("citation-abbreviations", arg): optMetadata opt })
+                   "FILE")
+                 ""
+
+    , Option "" ["natbib"]
+                 (NoArg
+                  (\opt -> return opt { optCiteMethod = Natbib }))
+                 "" -- "Use natbib cite commands in LaTeX output"
+
+    , Option "" ["biblatex"]
+                 (NoArg
+                  (\opt -> return opt { optCiteMethod = Biblatex }))
+                 "" -- "Use biblatex cite commands in LaTeX output"
+
+    , Option "" ["mathml"]
+                 (NoArg
+                  (\opt ->
+                      return opt { optHTMLMathMethod = MathML }))
+                 "" -- "Use mathml for HTML math"
+
+    , Option "" ["webtex"]
+                 (OptArg
+                  (\arg opt -> do
+                      let url' = fromMaybe "https://latex.codecogs.com/png.latex?" arg
+                      return opt { optHTMLMathMethod = WebTeX url' })
+                  "URL")
+                 "" -- "Use web service for HTML math"
+
+    , Option "" ["mathjax"]
+                 (OptArg
+                  (\arg opt -> do
+                      let url' = fromMaybe (defaultMathJaxURL ++
+                                  "MathJax.js?config=TeX-AMS_CHTML-full") arg
+                      return opt { optHTMLMathMethod = MathJax url'})
+                  "URL")
+                 "" -- "Use MathJax for HTML math"
+
+    , Option "" ["katex"]
+                 (OptArg
+                  (\arg opt ->
+                      return opt
+                        { optHTMLMathMethod = KaTeX $
+                           fromMaybe defaultKaTeXURL arg })
+                  "URL")
+                  "" -- Use KaTeX for HTML Math
+
+    , Option "" ["gladtex"]
+                 (NoArg
+                  (\opt ->
+                      return opt { optHTMLMathMethod = GladTeX }))
+                 "" -- "Use gladtex for HTML math"
+
+    , Option "" ["abbreviations"]
+                (ReqArg
+                 (\arg opt -> return opt { optAbbreviations = Just arg })
+                "FILE")
+                "" -- "Specify file for custom abbreviations"
+
+    , Option "" ["trace"]
+                 (NoArg
+                  (\opt -> return opt { optTrace = True }))
+                 "" -- "Turn on diagnostic tracing in readers."
+
+    , Option "" ["dump-args"]
+                 (NoArg
+                  (\opt -> return opt { optDumpArgs = True }))
+                 "" -- "Print output filename and arguments to stdout."
+
+    , Option "" ["ignore-args"]
+                 (NoArg
+                  (\opt -> return opt { optIgnoreArgs = True }))
+                 "" -- "Ignore command-line arguments."
+
+    , Option "" ["verbose"]
+                 (NoArg
+                  (\opt -> return opt { optVerbosity = INFO }))
+                 "" -- "Verbose diagnostic output."
+
+    , Option "" ["quiet"]
+                 (NoArg
+                  (\opt -> return opt { optVerbosity = ERROR }))
+                 "" -- "Suppress warnings."
+
+    , Option "" ["fail-if-warnings"]
+                 (NoArg
+                  (\opt -> return opt { optFailIfWarnings = True }))
+                 "" -- "Exit with error status if there were  warnings."
+
+    , Option "" ["log"]
+                 (ReqArg
+                  (\arg opt -> return opt{ optLogFile = Just arg })
+                "FILE")
+                "" -- "Log messages in JSON format to this file."
+
+    , Option "" ["bash-completion"]
+                 (NoArg
+                  (\_ -> do
+                     datafiles <- getDataFileNames
+                     tpl <- runIOorExplode $
+                              UTF8.toString <$>
+                                readDefaultDataFile "bash_completion.tpl"
+                     let optnames (Option shorts longs _ _) =
+                           map (\c -> ['-',c]) shorts ++
+                           map ("--" ++) longs
+                     let allopts = unwords (concatMap optnames options)
+                     UTF8.hPutStrLn stdout $ printf tpl allopts
+                         (unwords readersNames)
+                         (unwords writersNames)
+                         (unwords $ map fst highlightingStyles)
+                         (unwords datafiles)
+                     exitSuccess ))
+                 "" -- "Print bash completion script"
+
+    , Option "" ["list-input-formats"]
+                 (NoArg
+                  (\_ -> do
+                     mapM_ (UTF8.hPutStrLn stdout) readersNames
+                     exitSuccess ))
+                 ""
+
+    , Option "" ["list-output-formats"]
+                 (NoArg
+                  (\_ -> do
+                     mapM_ (UTF8.hPutStrLn stdout) writersNames
+                     exitSuccess ))
+                 ""
+
+    , Option "" ["list-extensions"]
+                 (OptArg
+                  (\arg _ -> do
+                     let exts = getDefaultExtensions (fromMaybe "markdown" arg)
+                     let showExt x = (if extensionEnabled x exts
+                                         then '+'
+                                         else '-') : drop 4 (show x)
+                     mapM_ (UTF8.hPutStrLn stdout . showExt)
+                               ([minBound..maxBound] :: [Extension])
+                     exitSuccess )
+                  "FORMAT")
+                 ""
+
+    , Option "" ["list-highlight-languages"]
+                 (NoArg
+                  (\_ -> do
+                     let langs = [ T.unpack (T.toLower (sShortname s))
+                                 | s <- M.elems defaultSyntaxMap
+                                 , sShortname s `notElem`
+                                    [T.pack "Alert", T.pack "Alert_indent"]
+                                 ]
+                     mapM_ (UTF8.hPutStrLn stdout) langs
+                     exitSuccess ))
+                 ""
+
+    , Option "" ["list-highlight-styles"]
+                 (NoArg
+                  (\_ -> do
+                     mapM_ (UTF8.hPutStrLn stdout . fst) highlightingStyles
+                     exitSuccess ))
+                 ""
+
+    , Option "v" ["version"]
+                 (NoArg
+                  (\_ -> do
+                     prg <- getProgName
+                     defaultDatadir <- E.catch
+                            (getAppUserDataDirectory "pandoc")
+                            (\e -> let _ = (e :: E.SomeException)
+                                   in  return "")
+                     UTF8.hPutStrLn stdout (prg ++ " " ++ pandocVersion ++
+                       compileInfo ++ "\nDefault user data directory: " ++
+                       defaultDatadir ++ copyrightMessage)
+                     exitSuccess ))
+                 "" -- "Print version"
+
+    , Option "h" ["help"]
+                 (NoArg
+                  (\_ -> do
+                     prg <- getProgName
+                     UTF8.hPutStr stdout (usageMessage prg options)
+                     exitSuccess ))
+                 "" -- "Show help"
+    ]
+
+getDataFileNames :: IO [FilePath]
+getDataFileNames = do
+#ifdef EMBED_DATA_FILES
+  let allDataFiles = map fst dataFiles
+#else
+  allDataFiles <- filter (\x -> x /= "." && x /= "..") <$>
+                      (getDataDir >>= getDirectoryContents)
+#endif
+  return $ "reference.docx" : "reference.odt" : "reference.pptx" : allDataFiles
+
+-- Returns usage message
+usageMessage :: String -> [OptDescr (Opt -> IO Opt)] -> String
+usageMessage programName = usageInfo (programName ++ " [OPTIONS] [FILES]")
+
+copyrightMessage :: String
+copyrightMessage = intercalate "\n" [
+  "",
+  "Copyright (C) 2006-2018 John MacFarlane",
+  "Web:  http://pandoc.org",
+  "This is free software; see the source for copying conditions.",
+  "There is no warranty, not even for merchantability or fitness",
+  "for a particular purpose." ]
+
+compileInfo :: String
+compileInfo =
+  "\nCompiled with pandoc-types " ++ VERSION_pandoc_types ++ ", texmath " ++
+  VERSION_texmath ++ ", skylighting " ++ VERSION_skylighting
+
+handleUnrecognizedOption :: String -> [String] -> [String]
+handleUnrecognizedOption "--smart" =
+  (("--smart/-S has been removed.  Use +smart or -smart extension instead.\n" ++
+    "For example: pandoc -f markdown+smart -t markdown-smart.") :)
+handleUnrecognizedOption "--normalize" =
+  ("--normalize has been removed.  Normalization is now automatic." :)
+handleUnrecognizedOption "-S" = handleUnrecognizedOption "--smart"
+handleUnrecognizedOption "--old-dashes" =
+  ("--old-dashes has been removed.  Use +old_dashes extension instead." :)
+handleUnrecognizedOption "--no-wrap" =
+  ("--no-wrap has been removed.  Use --wrap=none instead." :)
+handleUnrecognizedOption "--latex-engine" =
+  ("--latex-engine has been removed.  Use --pdf-engine instead." :)
+handleUnrecognizedOption "--latex-engine-opt" =
+  ("--latex-engine-opt has been removed.  Use --pdf-engine-opt instead." :)
+handleUnrecognizedOption "--chapters" =
+  ("--chapters has been removed. Use --top-level-division=chapter instead." :)
+handleUnrecognizedOption "--reference-docx" =
+  ("--reference-docx has been removed. Use --reference-doc instead." :)
+handleUnrecognizedOption "--reference-odt" =
+  ("--reference-odt has been removed. Use --reference-doc instead." :)
+handleUnrecognizedOption "--parse-raw" =
+  ("--parse-raw/-R has been removed. Use +raw_html or +raw_tex extension.\n" :)
+handleUnrecognizedOption "--epub-stylesheet" =
+  ("--epub-stylesheet has been removed. Use --css instead.\n" :)
+handleUnrecognizedOption "-R" = handleUnrecognizedOption "--parse-raw"
+handleUnrecognizedOption x =
+  (("Unknown option " ++ x ++ ".") :)
+
+uppercaseFirstLetter :: String -> String
+uppercaseFirstLetter (c:cs) = toUpper c : cs
+uppercaseFirstLetter []     = []
+
+readersNames :: [String]
+readersNames = sort (map fst (readers :: [(String, Reader PandocIO)]))
+
+writersNames :: [String]
+writersNames = sort (map fst (writers :: [(String, Writer PandocIO)]))
+
+splitField :: String -> (String, String)
+splitField s =
+  case break (`elem` ":=") s of
+       (k,_:v) -> (k,v)
+       (k,[])  -> (k,"true")
+
+deprecatedOption :: String -> String -> IO ()
+deprecatedOption o msg =
+  runIO (report $ Deprecated o msg) >>=
+    \r -> case r of
+       Right () -> return ()
+       Left e   -> E.throwIO e
+
+-- see https://github.com/jgm/pandoc/pull/4083
+-- using generic deriving caused long compilation times
+$(deriveJSON defaultOptions ''LineEnding)
+$(deriveJSON defaultOptions ''Opt)