2017-03-04 13:03:41 +01:00
|
|
|
{-# LANGUAGE CPP #-}
|
2017-06-01 15:09:38 +02:00
|
|
|
{-# LANGUAGE DeriveGeneric #-}
|
2017-03-04 13:03:41 +01:00
|
|
|
{-# LANGUAGE ScopedTypeVariables #-}
|
|
|
|
{-# LANGUAGE TupleSections #-}
|
2017-02-05 21:58:45 +01:00
|
|
|
{-
|
2017-05-13 23:30:13 +02:00
|
|
|
Copyright (C) 2006-2017 John MacFarlane <jgm@berkeley.edu>
|
2017-02-05 21:58:45 +01:00
|
|
|
|
|
|
|
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
|
2017-05-13 23:30:13 +02:00
|
|
|
Copyright : Copyright (C) 2006-2017 John MacFarlane
|
2017-02-05 21:58:45 +01:00
|
|
|
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 (
|
|
|
|
convertWithOpts
|
|
|
|
, Opt(..)
|
|
|
|
, defaultOpts
|
2017-02-06 14:46:48 +01:00
|
|
|
, parseOptions
|
|
|
|
, options
|
2017-02-05 21:58:45 +01:00
|
|
|
) where
|
2017-02-06 14:46:48 +01:00
|
|
|
import Control.Applicative ((<|>))
|
2017-02-05 21:58:45 +01:00
|
|
|
import qualified Control.Exception as E
|
2017-02-06 14:46:48 +01:00
|
|
|
import Control.Monad
|
2017-06-01 15:09:38 +02:00
|
|
|
import Control.Monad.Except (throwError)
|
2017-02-06 17:03:03 +01:00
|
|
|
import Control.Monad.Trans
|
2017-06-10 23:39:49 +02:00
|
|
|
import Data.Monoid
|
2017-06-01 15:09:38 +02:00
|
|
|
import Data.Aeson (FromJSON (..), ToJSON (..), defaultOptions, eitherDecode',
|
|
|
|
encode, genericToEncoding)
|
2017-02-06 14:46:48 +01:00
|
|
|
import qualified Data.ByteString as BS
|
2017-03-04 13:03:41 +01:00
|
|
|
import qualified Data.ByteString.Lazy as B
|
|
|
|
import Data.Char (toLower, toUpper)
|
|
|
|
import Data.Foldable (foldrM)
|
|
|
|
import Data.List (intercalate, isPrefixOf, isSuffixOf, sort)
|
2017-02-06 14:46:48 +01:00
|
|
|
import qualified Data.Map as M
|
2017-03-04 13:03:41 +01:00
|
|
|
import Data.Maybe (fromMaybe, isJust, isNothing)
|
2017-06-01 15:09:38 +02:00
|
|
|
import qualified Data.Set as Set
|
2017-06-10 15:55:18 +02:00
|
|
|
import Data.Text (Text)
|
2017-03-04 13:03:41 +01:00
|
|
|
import qualified Data.Text as T
|
2017-02-05 21:58:45 +01:00
|
|
|
import Data.Yaml (decode)
|
|
|
|
import qualified Data.Yaml as Yaml
|
2017-06-01 15:09:38 +02:00
|
|
|
import GHC.Generics
|
2017-05-23 09:48:11 +02:00
|
|
|
import Network.URI (URI (..), parseURI)
|
2017-02-06 14:46:48 +01:00
|
|
|
import Paths_pandoc (getDataDir)
|
2017-04-01 22:27:00 +02:00
|
|
|
import Skylighting (Style, Syntax (..), defaultSyntaxMap, parseTheme)
|
2017-06-01 15:09:38 +02:00
|
|
|
import Skylighting.Parser (addSyntaxDefinition, missingIncludes,
|
|
|
|
parseSyntaxDefinition)
|
2017-03-04 13:03:41 +01:00
|
|
|
import System.Console.GetOpt
|
|
|
|
import System.Directory (Permissions (..), doesFileExist, findExecutable,
|
|
|
|
getAppUserDataDirectory, getPermissions)
|
|
|
|
import System.Environment (getArgs, getEnvironment, getProgName)
|
|
|
|
import System.Exit (ExitCode (..), exitSuccess)
|
|
|
|
import System.FilePath
|
2017-06-01 15:09:38 +02:00
|
|
|
import System.IO (nativeNewline, stdout)
|
|
|
|
import qualified System.IO as IO (Newline (..))
|
2017-03-04 13:03:41 +01:00
|
|
|
import System.IO.Error (isDoesNotExistError)
|
|
|
|
import Text.Pandoc
|
|
|
|
import Text.Pandoc.Builder (setMeta)
|
2017-06-01 15:09:38 +02:00
|
|
|
import Text.Pandoc.Class (PandocIO, extractMedia, fillMediaBag, getLog,
|
2017-06-19 22:04:01 +02:00
|
|
|
setResourcePath, withMediaBag, setTrace)
|
2017-03-04 13:03:41 +01:00
|
|
|
import Text.Pandoc.Highlighting (highlightingStyles)
|
2017-06-20 16:09:33 +02:00
|
|
|
import Text.Pandoc.Lua (runLuaFilter, LuaException(..))
|
2017-06-19 11:10:29 +02:00
|
|
|
import Text.Pandoc.Writers.Math (defaultMathJaxURL, defaultKaTeXURL)
|
2017-03-04 13:03:41 +01:00
|
|
|
import Text.Pandoc.PDF (makePDF)
|
|
|
|
import Text.Pandoc.Process (pipeProcess)
|
2017-06-01 15:09:38 +02:00
|
|
|
import Text.Pandoc.SelfContained (makeDataURI, makeSelfContained)
|
|
|
|
import Text.Pandoc.Shared (headerShift, isURI, openURL, readDataFile,
|
2017-06-30 22:23:15 +02:00
|
|
|
readDataFileUTF8, safeRead, tabFilter,
|
|
|
|
eastAsianLineBreakFilter)
|
2017-03-04 13:03:41 +01:00
|
|
|
import qualified Text.Pandoc.UTF8 as UTF8
|
|
|
|
import Text.Pandoc.XML (toEntities)
|
|
|
|
import Text.Printf
|
2017-02-05 21:58:45 +01:00
|
|
|
#ifndef _WINDOWS
|
|
|
|
import System.Posix.IO (stdOutput)
|
2017-03-04 13:03:41 +01:00
|
|
|
import System.Posix.Terminal (queryTerminal)
|
2017-02-05 21:58:45 +01:00
|
|
|
#endif
|
2017-02-06 14:46:48 +01:00
|
|
|
|
2017-05-22 10:10:04 +02:00
|
|
|
data LineEnding = LF | CRLF | Native deriving (Show, Generic)
|
2017-05-21 11:42:50 +02:00
|
|
|
|
2017-05-22 10:10:04 +02:00
|
|
|
instance ToJSON LineEnding where
|
2017-05-21 11:42:50 +02:00
|
|
|
toEncoding = genericToEncoding defaultOptions
|
2017-05-22 10:10:04 +02:00
|
|
|
instance FromJSON LineEnding
|
2017-05-21 11:42:50 +02:00
|
|
|
|
2017-02-06 14:52:16 +01:00
|
|
|
parseOptions :: [OptDescr (Opt -> IO Opt)] -> Opt -> IO Opt
|
2017-02-06 14:46:48 +01:00
|
|
|
parseOptions options' defaults = do
|
|
|
|
rawArgs <- map UTF8.decodeArg <$> getArgs
|
|
|
|
prg <- getProgName
|
|
|
|
|
|
|
|
let (actions, args, unrecognizedOpts, errors) =
|
|
|
|
getOpt' Permute options' rawArgs
|
|
|
|
|
2017-02-06 23:33:23 +01:00
|
|
|
let unknownOptionErrors = foldr handleUnrecognizedOption [] unrecognizedOpts
|
2017-02-06 14:46:48 +01:00
|
|
|
|
|
|
|
unless (null errors && null unknownOptionErrors) $
|
2017-04-04 14:34:39 +02:00
|
|
|
E.throwIO $ PandocOptionError $
|
2017-04-02 23:02:55 +02:00
|
|
|
concat errors ++ unlines unknownOptionErrors ++
|
2017-02-06 14:46:48 +01:00
|
|
|
("Try " ++ prg ++ " --help for more information.")
|
|
|
|
|
|
|
|
-- thread option data structure through all supplied option actions
|
|
|
|
opts <- foldl (>>=) (return defaults) actions
|
2017-02-06 14:52:16 +01:00
|
|
|
return (opts{ optInputFiles = args })
|
2017-02-05 21:58:45 +01:00
|
|
|
|
2017-02-06 14:52:16 +01:00
|
|
|
convertWithOpts :: Opt -> IO ()
|
|
|
|
convertWithOpts opts = do
|
|
|
|
let args = optInputFiles opts
|
2017-02-05 21:58:45 +01:00
|
|
|
let outputFile = optOutputFile opts
|
|
|
|
let filters = optFilters opts
|
|
|
|
let verbosity = optVerbosity opts
|
|
|
|
|
|
|
|
when (optDumpArgs opts) $
|
|
|
|
do UTF8.hPutStrLn stdout outputFile
|
|
|
|
mapM_ (UTF8.hPutStrLn stdout) args
|
|
|
|
exitSuccess
|
|
|
|
|
|
|
|
epubMetadata <- case optEpubMetadata opts of
|
|
|
|
Nothing -> return Nothing
|
|
|
|
Just fp -> Just <$> UTF8.readFile fp
|
|
|
|
|
|
|
|
let mathMethod =
|
|
|
|
case (optKaTeXJS opts, optKaTeXStylesheet opts) of
|
2017-03-04 13:03:41 +01:00
|
|
|
(Nothing, _) -> optHTMLMathMethod opts
|
2017-06-19 11:10:29 +02:00
|
|
|
(Just js, ss) -> KaTeX js (fromMaybe
|
|
|
|
(defaultKaTeXURL ++ "katex.min.css") ss)
|
2017-02-05 21:58:45 +01:00
|
|
|
|
|
|
|
|
|
|
|
-- --bibliography implies -F pandoc-citeproc for backwards compatibility:
|
|
|
|
let needsCiteproc = isJust (lookup "bibliography" (optMetadata opts)) &&
|
|
|
|
optCiteMethod opts `notElem` [Natbib, Biblatex] &&
|
|
|
|
"pandoc-citeproc" `notElem` map takeBaseName filters
|
|
|
|
let filters' = if needsCiteproc then "pandoc-citeproc" : filters
|
|
|
|
else filters
|
|
|
|
|
|
|
|
let sources = case args of
|
|
|
|
[] -> ["-"]
|
|
|
|
xs | optIgnoreArgs opts -> ["-"]
|
|
|
|
| otherwise -> xs
|
|
|
|
|
|
|
|
datadir <- case optDataDir opts of
|
|
|
|
Nothing -> E.catch
|
|
|
|
(Just <$> getAppUserDataDirectory "pandoc")
|
|
|
|
(\e -> let _ = (e :: E.SomeException)
|
|
|
|
in return Nothing)
|
|
|
|
Just _ -> return $ optDataDir opts
|
|
|
|
|
|
|
|
-- assign reader and writer based on options and filenames
|
|
|
|
let readerName = case optReader opts of
|
|
|
|
Nothing -> defaultReaderName
|
|
|
|
(if any isURI sources
|
|
|
|
then "html"
|
|
|
|
else "markdown") sources
|
|
|
|
Just x -> map toLower x
|
|
|
|
|
|
|
|
let writerName = case optWriter opts of
|
2017-03-04 13:03:41 +01:00
|
|
|
Nothing -> defaultWriterName outputFile
|
|
|
|
Just x -> map toLower x
|
2017-02-05 21:58:45 +01:00
|
|
|
let format = takeWhile (`notElem` ['+','-'])
|
|
|
|
$ takeFileName writerName -- in case path to lua script
|
|
|
|
|
|
|
|
let pdfOutput = map toLower (takeExtension outputFile) == ".pdf"
|
|
|
|
|
|
|
|
let laTeXOutput = format `elem` ["latex", "beamer"]
|
|
|
|
let conTeXtOutput = format == "context"
|
|
|
|
let html5Output = format == "html5" || format == "html"
|
2017-03-23 21:24:01 +01:00
|
|
|
let msOutput = format == "ms"
|
2017-02-05 21:58:45 +01:00
|
|
|
|
|
|
|
-- disabling the custom writer for now
|
2017-06-24 13:47:10 +02:00
|
|
|
(writer, writerExts) <-
|
|
|
|
if ".lua" `isSuffixOf` format
|
2017-02-05 21:58:45 +01:00
|
|
|
-- note: use non-lowercased version writerName
|
2017-06-10 23:39:49 +02:00
|
|
|
then return (TextWriter
|
2017-03-07 15:27:45 +01:00
|
|
|
(\o d -> liftIO $ writeCustom writerName o d)
|
2017-06-24 13:47:10 +02:00
|
|
|
:: Writer PandocIO, mempty)
|
2017-02-05 21:58:45 +01:00
|
|
|
else case getWriter writerName of
|
2017-04-15 12:05:58 +02:00
|
|
|
Left e -> E.throwIO $ PandocAppError $
|
2017-02-05 21:58:45 +01:00
|
|
|
if format == "pdf"
|
|
|
|
then e ++
|
2017-04-13 16:49:44 +02:00
|
|
|
"\nTo create a pdf using pandoc, use " ++
|
|
|
|
"-t latex|beamer|context|ms|html5" ++
|
|
|
|
"\nand specify an output file with " ++
|
2017-04-13 17:02:30 +02:00
|
|
|
".pdf extension (-o filename.pdf)."
|
2017-02-05 21:58:45 +01:00
|
|
|
else e
|
2017-06-24 13:47:10 +02:00
|
|
|
Right (w, es) -> return (w :: Writer PandocIO, es)
|
2017-02-05 21:58:45 +01:00
|
|
|
|
|
|
|
-- TODO: we have to get the input and the output into the state for
|
|
|
|
-- the sake of the text2tags reader.
|
2017-06-24 13:47:10 +02:00
|
|
|
(reader, readerExts) <-
|
|
|
|
case getReader readerName of
|
|
|
|
Right (r, es) -> return (r :: Reader PandocIO, es)
|
2017-04-15 12:05:58 +02:00
|
|
|
Left e -> E.throwIO $ PandocAppError e'
|
2017-02-05 21:58:45 +01:00
|
|
|
where e' = case readerName of
|
|
|
|
"pdf" -> e ++
|
|
|
|
"\nPandoc can convert to PDF, but not from PDF."
|
|
|
|
"doc" -> e ++
|
|
|
|
"\nPandoc can convert from DOCX, but not from DOC.\nTry using Word to save your DOC file as DOCX, and convert that with pandoc."
|
|
|
|
_ -> e
|
|
|
|
|
|
|
|
let standalone = optStandalone opts || not (isTextFormat format) || pdfOutput
|
|
|
|
|
|
|
|
templ <- case optTemplate opts of
|
|
|
|
_ | not standalone -> return Nothing
|
|
|
|
Nothing -> do
|
|
|
|
deftemp <- getDefaultTemplate datadir format
|
|
|
|
case deftemp of
|
2017-04-02 23:02:55 +02:00
|
|
|
Left e -> E.throwIO e
|
2017-03-04 13:03:41 +01:00
|
|
|
Right t -> return (Just t)
|
2017-02-05 21:58:45 +01:00
|
|
|
Just tp -> do
|
|
|
|
-- strip off extensions
|
|
|
|
let tp' = case takeExtension tp of
|
2017-03-04 13:03:41 +01:00
|
|
|
"" -> tp <.> format
|
|
|
|
_ -> tp
|
2017-02-05 21:58:45 +01:00
|
|
|
Just <$> E.catch (UTF8.readFile tp')
|
|
|
|
(\e -> if isDoesNotExistError e
|
|
|
|
then E.catch
|
|
|
|
(readDataFileUTF8 datadir
|
|
|
|
("templates" </> tp'))
|
|
|
|
(\e' -> let _ = (e' :: E.SomeException)
|
2017-04-02 23:02:55 +02:00
|
|
|
in E.throwIO e')
|
|
|
|
else E.throwIO e)
|
2017-02-05 21:58:45 +01:00
|
|
|
|
|
|
|
let addStringAsVariable varname s vars = return $ (varname, s) : vars
|
|
|
|
|
|
|
|
let addContentsAsVariable varname fp vars = do
|
|
|
|
s <- UTF8.readFile fp
|
|
|
|
return $ (varname, s) : vars
|
|
|
|
|
|
|
|
-- note: this reverses the list constructed in option parsing,
|
|
|
|
-- which in turn was reversed from the command-line order,
|
|
|
|
-- so we end up with the correct order in the variable list:
|
2017-03-04 13:03:41 +01:00
|
|
|
let withList _ [] vars = return vars
|
2017-02-05 21:58:45 +01:00
|
|
|
withList f (x:xs) vars = f x vars >>= withList f xs
|
|
|
|
|
2017-03-04 12:02:16 +01:00
|
|
|
variables <-
|
2017-06-01 15:09:38 +02:00
|
|
|
|
2017-02-25 23:15:56 +01:00
|
|
|
withList (addStringAsVariable "sourcefile")
|
2017-06-01 15:09:38 +02:00
|
|
|
(reverse $ optInputFiles opts) (("outputfile", optOutputFile opts) : optVariables opts)
|
2017-02-25 23:47:19 +01:00
|
|
|
-- we reverse this list because, unlike
|
|
|
|
-- the other option lists here, it is
|
|
|
|
-- not reversed when parsed from CLI arguments.
|
|
|
|
-- See withList, above.
|
2017-02-25 23:15:56 +01:00
|
|
|
>>=
|
2017-02-05 21:58:45 +01:00
|
|
|
withList (addContentsAsVariable "include-before")
|
|
|
|
(optIncludeBeforeBody opts)
|
|
|
|
>>=
|
|
|
|
withList (addContentsAsVariable "include-after")
|
|
|
|
(optIncludeAfterBody opts)
|
|
|
|
>>=
|
|
|
|
withList (addContentsAsVariable "header-includes")
|
|
|
|
(optIncludeInHeader opts)
|
|
|
|
>>=
|
|
|
|
withList (addStringAsVariable "css") (optCss opts)
|
|
|
|
>>=
|
|
|
|
maybe return (addStringAsVariable "title-prefix") (optTitlePrefix opts)
|
|
|
|
>>=
|
|
|
|
maybe return (addStringAsVariable "epub-cover-image")
|
|
|
|
(optEpubCoverImage opts)
|
|
|
|
>>=
|
|
|
|
(\vars -> case mathMethod of
|
|
|
|
LaTeXMathML Nothing -> do
|
|
|
|
s <- readDataFileUTF8 datadir "LaTeXMathML.js"
|
|
|
|
return $ ("mathml-script", s) : vars
|
|
|
|
_ -> return vars)
|
|
|
|
>>=
|
|
|
|
(\vars -> if format == "dzslides"
|
|
|
|
then do
|
|
|
|
dztempl <- readDataFileUTF8 datadir
|
|
|
|
("dzslides" </> "template.html")
|
|
|
|
let dzline = "<!-- {{{{ dzslides core"
|
|
|
|
let dzcore = unlines
|
|
|
|
$ dropWhile (not . (dzline `isPrefixOf`))
|
|
|
|
$ lines dztempl
|
|
|
|
return $ ("dzslides-core", dzcore) : vars
|
|
|
|
else return vars)
|
|
|
|
|
|
|
|
let sourceURL = case sources of
|
|
|
|
[] -> Nothing
|
|
|
|
(x:_) -> case parseURI x of
|
|
|
|
Just u
|
|
|
|
| uriScheme u `elem` ["http:","https:"] ->
|
|
|
|
Just $ show u{ uriQuery = "",
|
|
|
|
uriFragment = "" }
|
|
|
|
_ -> Nothing
|
|
|
|
|
2017-03-16 22:16:41 +01:00
|
|
|
abbrevs <- (Set.fromList . filter (not . null) . lines) <$>
|
|
|
|
case optAbbreviations opts of
|
|
|
|
Nothing -> readDataFileUTF8 datadir "abbreviations"
|
|
|
|
Just f -> UTF8.readFile f
|
2017-03-16 21:45:50 +01:00
|
|
|
|
2017-02-05 21:58:45 +01:00
|
|
|
let readerOpts = def{ readerStandalone = standalone
|
|
|
|
, readerColumns = optColumns opts
|
|
|
|
, readerTabStop = optTabStop opts
|
|
|
|
, readerIndentedCodeClasses = optIndentedCodeClasses opts
|
|
|
|
, readerApplyMacros = not laTeXOutput
|
|
|
|
, readerDefaultImageExtension =
|
|
|
|
optDefaultImageExtension opts
|
|
|
|
, readerTrackChanges = optTrackChanges opts
|
2017-03-16 21:45:50 +01:00
|
|
|
, readerAbbreviations = abbrevs
|
2017-06-24 13:47:10 +02:00
|
|
|
, readerExtensions = readerExts
|
2017-02-05 21:58:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
highlightStyle <- lookupHighlightStyle $ optHighlightStyle opts
|
2017-03-30 21:51:11 +02:00
|
|
|
let addSyntaxMap existingmap f = do
|
|
|
|
res <- parseSyntaxDefinition f
|
|
|
|
case res of
|
2017-04-13 17:02:30 +02:00
|
|
|
Left errstr -> E.throwIO $ PandocSyntaxMapError errstr
|
2017-03-30 21:51:11 +02:00
|
|
|
Right syn -> return $ addSyntaxDefinition syn existingmap
|
|
|
|
|
|
|
|
syntaxMap <- foldM addSyntaxMap defaultSyntaxMap
|
|
|
|
(optSyntaxDefinitions opts)
|
|
|
|
|
|
|
|
case missingIncludes (M.elems syntaxMap) of
|
|
|
|
[] -> return ()
|
2017-04-13 17:02:30 +02:00
|
|
|
xs -> E.throwIO $ PandocSyntaxMapError $
|
2017-04-02 23:02:55 +02:00
|
|
|
"Missing syntax definitions:\n" ++
|
2017-03-30 21:51:11 +02:00
|
|
|
unlines (map
|
|
|
|
(\(syn,dep) -> (T.unpack syn ++ " requires " ++
|
|
|
|
T.unpack dep ++ " through IncludeRules.")) xs)
|
2017-02-05 21:58:45 +01:00
|
|
|
|
|
|
|
let writerOptions = def { writerTemplate = templ,
|
|
|
|
writerVariables = variables,
|
|
|
|
writerTabStop = optTabStop opts,
|
|
|
|
writerTableOfContents = optTableOfContents opts,
|
|
|
|
writerHTMLMathMethod = mathMethod,
|
|
|
|
writerIncremental = optIncremental opts,
|
|
|
|
writerCiteMethod = optCiteMethod opts,
|
|
|
|
writerNumberSections = optNumberSections opts,
|
|
|
|
writerNumberOffset = optNumberOffset opts,
|
|
|
|
writerSectionDivs = optSectionDivs opts,
|
2017-06-24 13:47:10 +02:00
|
|
|
writerExtensions = writerExts,
|
2017-02-05 21:58:45 +01:00
|
|
|
writerReferenceLinks = optReferenceLinks opts,
|
|
|
|
writerReferenceLocation = optReferenceLocation opts,
|
|
|
|
writerDpi = optDpi opts,
|
|
|
|
writerWrapText = optWrapText opts,
|
|
|
|
writerColumns = optColumns opts,
|
|
|
|
writerEmailObfuscation = optEmailObfuscation opts,
|
|
|
|
writerIdentifierPrefix = optIdentifierPrefix opts,
|
|
|
|
writerSourceURL = sourceURL,
|
|
|
|
writerUserDataDir = datadir,
|
|
|
|
writerHtmlQTags = optHtmlQTags opts,
|
|
|
|
writerTopLevelDivision = optTopLevelDivision opts,
|
|
|
|
writerListings = optListings opts,
|
|
|
|
writerSlideLevel = optSlideLevel opts,
|
|
|
|
writerHighlightStyle = highlightStyle,
|
|
|
|
writerSetextHeaders = optSetextHeaders opts,
|
2017-06-22 12:01:33 +02:00
|
|
|
writerEpubSubdirectory = optEpubSubdirectory opts,
|
2017-02-05 21:58:45 +01:00
|
|
|
writerEpubMetadata = epubMetadata,
|
|
|
|
writerEpubFonts = optEpubFonts opts,
|
|
|
|
writerEpubChapterLevel = optEpubChapterLevel opts,
|
|
|
|
writerTOCDepth = optTOCDepth opts,
|
|
|
|
writerReferenceDoc = optReferenceDoc opts,
|
2017-03-30 21:51:11 +02:00
|
|
|
writerLaTeXArgs = optLaTeXEngineArgs opts,
|
|
|
|
writerSyntaxMap = syntaxMap
|
2017-02-05 21:58:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef _WINDOWS
|
|
|
|
let istty = True
|
|
|
|
#else
|
|
|
|
istty <- queryTerminal stdOutput
|
|
|
|
#endif
|
|
|
|
when (istty && not (isTextFormat format) && outputFile == "-") $
|
2017-04-15 12:05:58 +02:00
|
|
|
E.throwIO $ PandocAppError $
|
2017-04-02 23:02:55 +02:00
|
|
|
"Cannot write " ++ format ++ " output to stdout.\n" ++
|
2017-02-05 21:58:45 +01:00
|
|
|
"Specify an output file using the -o option."
|
|
|
|
|
|
|
|
|
2017-06-30 22:23:15 +02:00
|
|
|
let transforms = (case optBaseHeaderLevel opts of
|
|
|
|
x | x > 1 -> (headerShift (x - 1) :)
|
|
|
|
| otherwise -> id) $
|
|
|
|
(if extensionEnabled Ext_east_asian_line_breaks
|
|
|
|
readerExts &&
|
|
|
|
not (extensionEnabled Ext_east_asian_line_breaks
|
|
|
|
writerExts &&
|
|
|
|
writerWrapText writerOptions == WrapPreserve)
|
|
|
|
then (eastAsianLineBreakFilter :)
|
|
|
|
else id)
|
|
|
|
[]
|
2017-02-05 21:58:45 +01:00
|
|
|
|
|
|
|
let convertTabs = tabFilter (if optPreserveTabs opts || readerName == "t2t"
|
2017-06-20 21:52:13 +02:00
|
|
|
then 0
|
|
|
|
else optTabStop opts)
|
2017-02-05 21:58:45 +01:00
|
|
|
|
2017-06-10 15:55:18 +02:00
|
|
|
readSources :: [FilePath] -> PandocIO Text
|
|
|
|
readSources srcs = convertTabs . T.intercalate (T.pack "\n") <$>
|
2017-02-05 21:58:45 +01:00
|
|
|
mapM readSource srcs
|
|
|
|
|
|
|
|
let runIO' :: PandocIO a -> IO a
|
|
|
|
runIO' f = do
|
|
|
|
(res, reports) <- runIOorExplode $ do
|
2017-06-19 22:04:01 +02:00
|
|
|
setTrace (optTrace opts)
|
2017-02-05 21:58:45 +01:00
|
|
|
setVerbosity verbosity
|
|
|
|
x <- f
|
|
|
|
rs <- getLog
|
|
|
|
return (x, rs)
|
2017-02-11 09:59:54 +01:00
|
|
|
case optLogFile opts of
|
2017-03-04 13:03:41 +01:00
|
|
|
Nothing -> return ()
|
2017-02-11 22:58:22 +01:00
|
|
|
Just logfile -> B.writeFile logfile (encodeLogMessages reports)
|
2017-02-10 23:59:47 +01:00
|
|
|
let isWarning msg = messageVerbosity msg == WARNING
|
2017-02-05 21:58:45 +01:00
|
|
|
when (optFailIfWarnings opts && any isWarning reports) $
|
2017-04-13 17:02:30 +02:00
|
|
|
E.throwIO PandocFailOnWarningError
|
2017-02-05 21:58:45 +01:00
|
|
|
return res
|
|
|
|
|
2017-05-07 10:34:04 +02:00
|
|
|
let sourceToDoc :: [FilePath] -> PandocIO Pandoc
|
2017-02-05 21:58:45 +01:00
|
|
|
sourceToDoc sources' =
|
|
|
|
case reader of
|
2017-06-10 18:26:44 +02:00
|
|
|
TextReader r
|
2017-05-07 10:34:04 +02:00
|
|
|
| optFileScope opts || readerName == "json" ->
|
2017-06-10 18:26:44 +02:00
|
|
|
mconcat <$> mapM (readSource >=> r readerOpts) sources
|
2017-02-05 21:58:45 +01:00
|
|
|
| otherwise ->
|
2017-06-10 18:26:44 +02:00
|
|
|
readSources sources' >>= r readerOpts
|
2017-05-07 10:34:04 +02:00
|
|
|
ByteStringReader r ->
|
|
|
|
mconcat <$> mapM (readFile' >=> r readerOpts) sources
|
2017-02-05 21:58:45 +01:00
|
|
|
|
2017-03-31 15:15:49 +02:00
|
|
|
metadata <- if format == "jats" &&
|
2017-06-01 14:16:17 +02:00
|
|
|
isNothing (lookup "csl" (optMetadata opts)) &&
|
|
|
|
isNothing (lookup "citation-style" (optMetadata opts))
|
2017-03-30 17:23:16 +02:00
|
|
|
then do
|
|
|
|
jatsCSL <- readDataFile datadir "jats.csl"
|
|
|
|
let jatsEncoded = makeDataURI ("application/xml", jatsCSL)
|
|
|
|
return $ ("csl", jatsEncoded) : optMetadata opts
|
|
|
|
else return $ optMetadata opts
|
2017-03-30 16:43:17 +02:00
|
|
|
|
2017-05-21 11:42:50 +02:00
|
|
|
let eol = case optEol opts of
|
2017-05-22 10:10:04 +02:00
|
|
|
CRLF -> IO.CRLF
|
|
|
|
LF -> IO.LF
|
|
|
|
Native -> nativeNewline
|
2017-05-17 15:13:35 +02:00
|
|
|
|
2017-02-05 21:58:45 +01:00
|
|
|
runIO' $ do
|
2017-05-21 08:59:06 +02:00
|
|
|
setResourcePath (optResourcePath opts)
|
2017-05-07 10:34:04 +02:00
|
|
|
(doc, media) <- withMediaBag $ sourceToDoc sources >>=
|
2017-05-07 11:45:33 +02:00
|
|
|
( (if isJust (optExtractMedia opts)
|
2017-05-07 21:03:18 +02:00
|
|
|
then fillMediaBag (writerSourceURL writerOptions)
|
2017-05-07 11:45:33 +02:00
|
|
|
else return)
|
|
|
|
>=> maybe return extractMedia (optExtractMedia opts)
|
2017-05-07 10:34:04 +02:00
|
|
|
>=> return . flip (foldr addMetadata) metadata
|
|
|
|
>=> applyTransforms transforms
|
|
|
|
>=> applyLuaFilters datadir (optLuaFilters opts) [format]
|
2017-05-07 11:45:33 +02:00
|
|
|
>=> applyFilters datadir filters' [format]
|
|
|
|
)
|
2017-02-05 21:58:45 +01:00
|
|
|
|
|
|
|
case writer of
|
2017-05-07 10:34:04 +02:00
|
|
|
ByteStringWriter f -> f writerOptions doc >>= writeFnBinary outputFile
|
2017-06-10 23:39:49 +02:00
|
|
|
TextWriter f
|
2017-02-05 21:58:45 +01:00
|
|
|
| pdfOutput -> do
|
2017-03-23 21:24:01 +01:00
|
|
|
-- make sure writer is latex, beamer, context, html5 or ms
|
|
|
|
unless (laTeXOutput || conTeXtOutput || html5Output ||
|
|
|
|
msOutput) $
|
2017-04-15 12:05:58 +02:00
|
|
|
liftIO $ E.throwIO $ PandocAppError $
|
2017-04-02 23:02:55 +02:00
|
|
|
"cannot produce pdf output with " ++ format ++ " writer"
|
2017-02-05 21:58:45 +01:00
|
|
|
|
|
|
|
let pdfprog = case () of
|
|
|
|
_ | conTeXtOutput -> "context"
|
2017-03-23 21:24:01 +01:00
|
|
|
| html5Output -> "wkhtmltopdf"
|
|
|
|
| html5Output -> "wkhtmltopdf"
|
|
|
|
| msOutput -> "pdfroff"
|
|
|
|
| otherwise -> optLaTeXEngine opts
|
2017-02-05 21:58:45 +01:00
|
|
|
-- check for pdf creating program
|
|
|
|
mbPdfProg <- liftIO $ findExecutable pdfprog
|
2017-04-13 17:02:30 +02:00
|
|
|
when (isNothing mbPdfProg) $ liftIO $ E.throwIO $
|
|
|
|
PandocPDFProgramNotFoundError pdfprog
|
2017-02-05 21:58:45 +01:00
|
|
|
|
2017-05-07 10:34:04 +02:00
|
|
|
res <- makePDF pdfprog f writerOptions verbosity media doc
|
2017-02-05 21:58:45 +01:00
|
|
|
case res of
|
|
|
|
Right pdf -> writeFnBinary outputFile pdf
|
2017-04-15 13:46:46 +02:00
|
|
|
Left err' -> liftIO $
|
2017-04-13 17:38:42 +02:00
|
|
|
E.throwIO $ PandocPDFError (UTF8.toStringLazy err')
|
2017-02-05 21:58:45 +01:00
|
|
|
| otherwise -> do
|
|
|
|
let htmlFormat = format `elem`
|
|
|
|
["html","html4","html5","s5","slidy","slideous","dzslides","revealjs"]
|
2017-02-25 13:34:46 +01:00
|
|
|
handleEntities = if (htmlFormat ||
|
|
|
|
format == "docbook4" ||
|
|
|
|
format == "docbook5" ||
|
|
|
|
format == "docbook") && optAscii opts
|
2017-02-05 21:58:45 +01:00
|
|
|
then toEntities
|
|
|
|
else id
|
2017-06-10 23:39:49 +02:00
|
|
|
addNl = if standalone
|
|
|
|
then id
|
|
|
|
else (<> T.singleton '\n')
|
|
|
|
output <- (addNl . handleEntities) <$> f writerOptions doc
|
|
|
|
writerFn eol outputFile =<<
|
|
|
|
if optSelfContained opts && htmlFormat
|
|
|
|
-- TODO not maximally efficient; change type
|
|
|
|
-- of makeSelfContained so it works w/ Text
|
|
|
|
then T.pack <$> makeSelfContained writerOptions
|
|
|
|
(T.unpack output)
|
|
|
|
else return output
|
2017-02-05 21:58:45 +01:00
|
|
|
|
|
|
|
type Transform = Pandoc -> Pandoc
|
|
|
|
|
|
|
|
isTextFormat :: String -> Bool
|
|
|
|
isTextFormat s = s `notElem` ["odt","docx","epub","epub3"]
|
|
|
|
|
|
|
|
externalFilter :: MonadIO m => FilePath -> [String] -> Pandoc -> m Pandoc
|
|
|
|
externalFilter f args' d = liftIO $ do
|
|
|
|
exists <- doesFileExist f
|
|
|
|
isExecutable <- if exists
|
|
|
|
then executable <$> getPermissions f
|
|
|
|
else return True
|
|
|
|
let (f', args'') = if exists
|
|
|
|
then case map toLower (takeExtension f) of
|
2017-03-04 13:03:41 +01:00
|
|
|
_ | isExecutable -> ("." </> f, args')
|
2017-02-05 21:58:45 +01:00
|
|
|
".py" -> ("python", f:args')
|
|
|
|
".hs" -> ("runhaskell", f:args')
|
|
|
|
".pl" -> ("perl", f:args')
|
|
|
|
".rb" -> ("ruby", f:args')
|
|
|
|
".php" -> ("php", f:args')
|
|
|
|
".js" -> ("node", f:args')
|
|
|
|
_ -> (f, args')
|
|
|
|
else (f, args')
|
|
|
|
unless (exists && isExecutable) $ do
|
|
|
|
mbExe <- findExecutable f'
|
|
|
|
when (isNothing mbExe) $
|
2017-04-13 19:24:50 +02:00
|
|
|
E.throwIO $ PandocFilterError f ("Could not find executable " ++ f')
|
2017-02-05 21:58:45 +01:00
|
|
|
env <- getEnvironment
|
|
|
|
let env' = Just $ ("PANDOC_VERSION", pandocVersion) : env
|
|
|
|
(exitcode, outbs) <- E.handle filterException $
|
|
|
|
pipeProcess env' f' args'' $ encode d
|
|
|
|
case exitcode of
|
2017-06-20 16:16:32 +02:00
|
|
|
ExitSuccess -> either (E.throwIO . PandocFilterError f)
|
|
|
|
return $ eitherDecode' outbs
|
2017-04-13 19:24:50 +02:00
|
|
|
ExitFailure ec -> E.throwIO $ PandocFilterError f
|
|
|
|
("Filter returned error status " ++ show ec)
|
2017-02-05 21:58:45 +01:00
|
|
|
where filterException :: E.SomeException -> IO a
|
2017-04-13 19:24:50 +02:00
|
|
|
filterException e = E.throwIO $ PandocFilterError f (show e)
|
2017-02-05 21:58:45 +01:00
|
|
|
|
|
|
|
-- | Data structure for command line options.
|
|
|
|
data Opt = Opt
|
2017-03-04 13:03:41 +01:00
|
|
|
{ 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
|
|
|
|
, optOutputFile :: 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
|
2017-03-30 21:51:11 +02:00
|
|
|
, optSyntaxDefinitions :: [FilePath] -- ^ xml syntax defs to load
|
2017-03-04 13:03:41 +01:00
|
|
|
, optTopLevelDivision :: TopLevelDivision -- ^ Type of the top-level divisions
|
|
|
|
, optHTMLMathMethod :: HTMLMathMethod -- ^ Method to print HTML math
|
2017-03-16 21:45:50 +01:00
|
|
|
, optAbbreviations :: Maybe FilePath -- ^ Path to abbrevs file
|
2017-03-04 13:03:41 +01:00
|
|
|
, optReferenceDoc :: Maybe FilePath -- ^ Path of reference doc
|
2017-06-22 12:01:33 +02:00
|
|
|
, optEpubSubdirectory :: String -- ^ EPUB subdir in OCF container
|
2017-03-04 13:03:41 +01:00
|
|
|
, 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
|
2017-06-19 22:04:01 +02:00
|
|
|
, optTrace :: Bool -- ^ Enable tracing
|
2017-03-04 13:03:41 +01:00
|
|
|
, 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 :: [FilePath] -- ^ Filters to apply
|
2017-03-20 15:17:03 +01:00
|
|
|
, optLuaFilters :: [FilePath] -- ^ Lua filters to apply
|
2017-03-04 13:03:41 +01:00
|
|
|
, optEmailObfuscation :: ObfuscationMethod
|
|
|
|
, optIdentifierPrefix :: String
|
|
|
|
, 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
|
|
|
|
, optLaTeXEngine :: String -- ^ Program to use for latex -> pdf
|
|
|
|
, optLaTeXEngineArgs :: [String] -- ^ Flags to pass to the latex-engine
|
|
|
|
, optSlideLevel :: Maybe Int -- ^ Header level that creates slides
|
|
|
|
, optSetextHeaders :: Bool -- ^ Use atx headers for markdown level 1-2
|
|
|
|
, optAscii :: Bool -- ^ Use ascii characters only in html
|
2017-02-05 21:58:45 +01:00
|
|
|
, optDefaultImageExtension :: String -- ^ Default image extension
|
2017-03-04 13:03:41 +01:00
|
|
|
, optExtractMedia :: Maybe FilePath -- ^ Path to extract embedded media
|
|
|
|
, optTrackChanges :: TrackChanges -- ^ Accept or reject MS Word track-changes.
|
|
|
|
, optFileScope :: Bool -- ^ Parse input files before combining
|
|
|
|
, optKaTeXStylesheet :: Maybe String -- ^ Path to stylesheet for KaTeX
|
|
|
|
, optKaTeXJS :: Maybe String -- ^ Path to js file for KaTeX
|
|
|
|
, 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
|
2017-05-20 21:43:53 +02:00
|
|
|
, optResourcePath :: [FilePath] -- ^ Path to search for images etc
|
2017-05-22 10:10:04 +02:00
|
|
|
, optEol :: LineEnding -- ^ Style of line-endings to use
|
2017-05-21 11:42:50 +02:00
|
|
|
} deriving (Generic, Show)
|
|
|
|
|
|
|
|
instance ToJSON Opt where
|
|
|
|
toEncoding = genericToEncoding defaultOptions
|
|
|
|
instance FromJSON Opt
|
2017-02-05 21:58:45 +01:00
|
|
|
|
|
|
|
-- | 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 = []
|
|
|
|
, optOutputFile = "-" -- "-" means stdout
|
2017-02-06 14:52:16 +01:00
|
|
|
, optInputFiles = []
|
2017-02-05 21:58:45 +01:00
|
|
|
, optNumberSections = False
|
|
|
|
, optNumberOffset = [0,0,0,0,0,0]
|
|
|
|
, optSectionDivs = False
|
|
|
|
, optIncremental = False
|
|
|
|
, optSelfContained = False
|
|
|
|
, optHtmlQTags = False
|
|
|
|
, optHighlightStyle = Just "pygments"
|
2017-03-30 21:51:11 +02:00
|
|
|
, optSyntaxDefinitions = []
|
2017-02-05 21:58:45 +01:00
|
|
|
, optTopLevelDivision = TopLevelDefault
|
|
|
|
, optHTMLMathMethod = PlainMath
|
2017-03-16 21:45:50 +01:00
|
|
|
, optAbbreviations = Nothing
|
2017-02-05 21:58:45 +01:00
|
|
|
, optReferenceDoc = Nothing
|
2017-06-22 12:01:33 +02:00
|
|
|
, optEpubSubdirectory = "EPUB"
|
2017-02-05 21:58:45 +01:00
|
|
|
, optEpubMetadata = Nothing
|
|
|
|
, optEpubFonts = []
|
|
|
|
, optEpubChapterLevel = 1
|
|
|
|
, optEpubCoverImage = Nothing
|
|
|
|
, optTOCDepth = 3
|
|
|
|
, optDumpArgs = False
|
|
|
|
, optIgnoreArgs = False
|
|
|
|
, optVerbosity = WARNING
|
2017-06-19 22:04:01 +02:00
|
|
|
, optTrace = False
|
2017-02-11 09:59:54 +01:00
|
|
|
, optLogFile = Nothing
|
2017-02-05 21:58:45 +01:00
|
|
|
, optFailIfWarnings = False
|
|
|
|
, optReferenceLinks = False
|
|
|
|
, optReferenceLocation = EndOfDocument
|
|
|
|
, optDpi = 96
|
|
|
|
, optWrapText = WrapAuto
|
|
|
|
, optColumns = 72
|
|
|
|
, optFilters = []
|
2017-03-20 15:17:03 +01:00
|
|
|
, optLuaFilters = []
|
2017-02-05 21:58:45 +01:00
|
|
|
, optEmailObfuscation = NoObfuscation
|
|
|
|
, optIdentifierPrefix = ""
|
|
|
|
, optIndentedCodeClasses = []
|
|
|
|
, optDataDir = Nothing
|
|
|
|
, optCiteMethod = Citeproc
|
|
|
|
, optListings = False
|
|
|
|
, optLaTeXEngine = "pdflatex"
|
|
|
|
, optLaTeXEngineArgs = []
|
|
|
|
, optSlideLevel = Nothing
|
|
|
|
, optSetextHeaders = True
|
|
|
|
, optAscii = False
|
|
|
|
, optDefaultImageExtension = ""
|
|
|
|
, optExtractMedia = Nothing
|
|
|
|
, optTrackChanges = AcceptChanges
|
|
|
|
, optFileScope = False
|
|
|
|
, optKaTeXStylesheet = Nothing
|
|
|
|
, optKaTeXJS = Nothing
|
|
|
|
, optTitlePrefix = Nothing
|
|
|
|
, optCss = []
|
|
|
|
, optIncludeBeforeBody = []
|
|
|
|
, optIncludeAfterBody = []
|
|
|
|
, optIncludeInHeader = []
|
2017-05-21 08:59:06 +02:00
|
|
|
, optResourcePath = ["."]
|
2017-05-22 10:10:04 +02:00
|
|
|
, optEol = Native
|
2017-02-05 21:58:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
addMetadata :: (String, String) -> Pandoc -> Pandoc
|
|
|
|
addMetadata (k, v) (Pandoc meta bs) = Pandoc meta' bs
|
|
|
|
where meta' = case lookupMeta k meta of
|
|
|
|
Nothing -> setMeta k v' meta
|
|
|
|
Just (MetaList xs) ->
|
|
|
|
setMeta k (MetaList (xs ++ [v'])) meta
|
|
|
|
Just x -> setMeta k (MetaList [x, v']) meta
|
|
|
|
v' = readMetaValue v
|
|
|
|
|
|
|
|
readMetaValue :: String -> MetaValue
|
|
|
|
readMetaValue s = case decode (UTF8.fromString s) of
|
|
|
|
Just (Yaml.String t) -> MetaString $ T.unpack t
|
|
|
|
Just (Yaml.Bool b) -> MetaBool b
|
|
|
|
_ -> MetaString s
|
|
|
|
|
|
|
|
-- Determine default reader based on source file extensions
|
|
|
|
defaultReaderName :: String -> [FilePath] -> String
|
|
|
|
defaultReaderName fallback [] = fallback
|
|
|
|
defaultReaderName fallback (x:xs) =
|
|
|
|
case takeExtension (map toLower x) of
|
|
|
|
".xhtml" -> "html"
|
|
|
|
".html" -> "html"
|
|
|
|
".htm" -> "html"
|
|
|
|
".md" -> "markdown"
|
|
|
|
".markdown" -> "markdown"
|
|
|
|
".tex" -> "latex"
|
|
|
|
".latex" -> "latex"
|
|
|
|
".ltx" -> "latex"
|
|
|
|
".rst" -> "rst"
|
|
|
|
".org" -> "org"
|
|
|
|
".lhs" -> "markdown+lhs"
|
|
|
|
".db" -> "docbook"
|
|
|
|
".opml" -> "opml"
|
|
|
|
".wiki" -> "mediawiki"
|
|
|
|
".dokuwiki" -> "dokuwiki"
|
|
|
|
".textile" -> "textile"
|
|
|
|
".native" -> "native"
|
|
|
|
".json" -> "json"
|
|
|
|
".docx" -> "docx"
|
|
|
|
".t2t" -> "t2t"
|
|
|
|
".epub" -> "epub"
|
|
|
|
".odt" -> "odt"
|
|
|
|
".pdf" -> "pdf" -- so we get an "unknown reader" error
|
|
|
|
".doc" -> "doc" -- so we get an "unknown reader" error
|
|
|
|
_ -> defaultReaderName fallback xs
|
|
|
|
|
|
|
|
-- Determine default writer based on output file extension
|
|
|
|
defaultWriterName :: FilePath -> String
|
|
|
|
defaultWriterName "-" = "html" -- no output file
|
|
|
|
defaultWriterName x =
|
|
|
|
case takeExtension (map toLower x) of
|
|
|
|
"" -> "markdown" -- empty extension
|
|
|
|
".tex" -> "latex"
|
|
|
|
".latex" -> "latex"
|
|
|
|
".ltx" -> "latex"
|
|
|
|
".context" -> "context"
|
|
|
|
".ctx" -> "context"
|
|
|
|
".rtf" -> "rtf"
|
|
|
|
".rst" -> "rst"
|
|
|
|
".s5" -> "s5"
|
|
|
|
".native" -> "native"
|
|
|
|
".json" -> "json"
|
|
|
|
".txt" -> "markdown"
|
|
|
|
".text" -> "markdown"
|
|
|
|
".md" -> "markdown"
|
|
|
|
".markdown" -> "markdown"
|
|
|
|
".textile" -> "textile"
|
|
|
|
".lhs" -> "markdown+lhs"
|
|
|
|
".texi" -> "texinfo"
|
|
|
|
".texinfo" -> "texinfo"
|
|
|
|
".db" -> "docbook"
|
|
|
|
".odt" -> "odt"
|
|
|
|
".docx" -> "docx"
|
|
|
|
".epub" -> "epub"
|
|
|
|
".org" -> "org"
|
|
|
|
".asciidoc" -> "asciidoc"
|
|
|
|
".adoc" -> "asciidoc"
|
|
|
|
".pdf" -> "latex"
|
|
|
|
".fb2" -> "fb2"
|
|
|
|
".opml" -> "opml"
|
|
|
|
".icml" -> "icml"
|
|
|
|
".tei.xml" -> "tei"
|
|
|
|
".tei" -> "tei"
|
2017-03-15 21:04:14 +01:00
|
|
|
".ms" -> "ms"
|
2017-03-24 09:40:02 +01:00
|
|
|
".roff" -> "ms"
|
2017-03-04 13:03:41 +01:00
|
|
|
['.',y] | y `elem` ['1'..'9'] -> "man"
|
2017-02-05 21:58:45 +01:00
|
|
|
_ -> "html"
|
|
|
|
|
|
|
|
-- Transformations of a Pandoc document post-parsing:
|
|
|
|
|
|
|
|
applyTransforms :: Monad m => [Transform] -> Pandoc -> m Pandoc
|
|
|
|
applyTransforms transforms d = return $ foldr ($) d transforms
|
|
|
|
|
|
|
|
-- First we check to see if a filter is found. If not, and if it's
|
|
|
|
-- not an absolute path, we check to see whether it's in `userdir/filters`.
|
|
|
|
-- If not, we leave it unchanged.
|
|
|
|
expandFilterPath :: MonadIO m => Maybe FilePath -> FilePath -> m FilePath
|
|
|
|
expandFilterPath mbDatadir fp = liftIO $ do
|
|
|
|
fpExists <- doesFileExist fp
|
|
|
|
if fpExists
|
|
|
|
then return fp
|
|
|
|
else case mbDatadir of
|
|
|
|
Just datadir | isRelative fp -> do
|
2017-03-04 12:02:16 +01:00
|
|
|
let filterPath = datadir </> "filters" </> fp
|
2017-02-05 21:58:45 +01:00
|
|
|
filterPathExists <- doesFileExist filterPath
|
|
|
|
if filterPathExists
|
|
|
|
then return filterPath
|
|
|
|
else return fp
|
|
|
|
_ -> return fp
|
|
|
|
|
2017-03-20 15:17:03 +01:00
|
|
|
applyLuaFilters :: MonadIO m
|
2017-06-20 16:09:33 +02:00
|
|
|
=> Maybe FilePath -> [FilePath] -> [String] -> Pandoc
|
|
|
|
-> m Pandoc
|
2017-03-20 15:17:03 +01:00
|
|
|
applyLuaFilters mbDatadir filters args d = do
|
|
|
|
expandedFilters <- mapM (expandFilterPath mbDatadir) filters
|
2017-06-20 16:09:33 +02:00
|
|
|
let go f d' = liftIO $ do
|
2017-06-29 17:13:19 +02:00
|
|
|
res <- E.try (runLuaFilter mbDatadir f args d')
|
2017-06-20 16:09:33 +02:00
|
|
|
case res of
|
|
|
|
Right x -> return x
|
|
|
|
Left (LuaException s) -> E.throw (PandocFilterError f s)
|
|
|
|
foldrM ($) d $ map go expandedFilters
|
2017-03-20 15:17:03 +01:00
|
|
|
|
2017-02-05 21:58:45 +01:00
|
|
|
applyFilters :: MonadIO m
|
|
|
|
=> Maybe FilePath -> [FilePath] -> [String] -> Pandoc -> m Pandoc
|
|
|
|
applyFilters mbDatadir filters args d = do
|
|
|
|
expandedFilters <- mapM (expandFilterPath mbDatadir) filters
|
|
|
|
foldrM ($) d $ map (flip externalFilter args) expandedFilters
|
|
|
|
|
2017-06-10 15:55:18 +02:00
|
|
|
readSource :: FilePath -> PandocIO Text
|
2017-06-11 21:22:44 +02:00
|
|
|
readSource "-" = liftIO (UTF8.toText <$> BS.getContents)
|
2017-02-05 21:58:45 +01:00
|
|
|
readSource src = case parseURI src of
|
|
|
|
Just u | uriScheme u `elem` ["http:","https:"] ->
|
|
|
|
readURI src
|
|
|
|
| uriScheme u == "file:" ->
|
2017-06-10 15:55:18 +02:00
|
|
|
liftIO $ UTF8.toText <$>
|
|
|
|
BS.readFile (uriPath u)
|
|
|
|
_ -> liftIO $ UTF8.toText <$>
|
|
|
|
BS.readFile src
|
2017-02-05 21:58:45 +01:00
|
|
|
|
2017-06-10 15:55:18 +02:00
|
|
|
readURI :: FilePath -> PandocIO Text
|
2017-05-07 13:11:04 +02:00
|
|
|
readURI src = do
|
|
|
|
res <- liftIO $ openURL src
|
|
|
|
case res of
|
2017-06-01 15:09:38 +02:00
|
|
|
Left e -> throwError $ PandocHttpError src e
|
2017-06-10 15:55:18 +02:00
|
|
|
Right (contents, _) -> return $ UTF8.toText contents
|
2017-02-05 21:58:45 +01:00
|
|
|
|
|
|
|
readFile' :: MonadIO m => FilePath -> m B.ByteString
|
2017-03-04 12:02:16 +01:00
|
|
|
readFile' "-" = liftIO B.getContents
|
2017-02-05 21:58:45 +01:00
|
|
|
readFile' f = liftIO $ B.readFile f
|
|
|
|
|
|
|
|
writeFnBinary :: MonadIO m => FilePath -> B.ByteString -> m ()
|
|
|
|
writeFnBinary "-" = liftIO . B.putStr
|
|
|
|
writeFnBinary f = liftIO . B.writeFile (UTF8.encodePath f)
|
|
|
|
|
2017-06-10 23:39:49 +02:00
|
|
|
writerFn :: MonadIO m => IO.Newline -> FilePath -> Text -> m ()
|
|
|
|
-- TODO this implementation isn't maximally efficient:
|
|
|
|
writerFn eol "-" = liftIO . UTF8.putStrWith eol . T.unpack
|
|
|
|
writerFn eol f = liftIO . UTF8.writeFileWith eol f . T.unpack
|
2017-02-05 21:58:45 +01:00
|
|
|
|
|
|
|
lookupHighlightStyle :: Maybe String -> IO (Maybe Style)
|
|
|
|
lookupHighlightStyle Nothing = return Nothing
|
2017-04-01 22:27:00 +02:00
|
|
|
lookupHighlightStyle (Just s)
|
|
|
|
| takeExtension s == ".theme" = -- attempt to load KDE theme
|
|
|
|
do contents <- B.readFile s
|
|
|
|
case parseTheme contents of
|
2017-04-15 11:52:51 +02:00
|
|
|
Left _ -> E.throwIO $ PandocOptionError $
|
2017-04-02 23:02:55 +02:00
|
|
|
"Could not read highlighting theme " ++ s
|
2017-04-01 22:27:00 +02:00
|
|
|
Right sty -> return (Just sty)
|
|
|
|
| otherwise =
|
2017-02-05 21:58:45 +01:00
|
|
|
case lookup (map toLower s) highlightingStyles of
|
|
|
|
Just sty -> return (Just sty)
|
2017-04-15 11:52:51 +02:00
|
|
|
Nothing -> E.throwIO $ PandocOptionError $
|
2017-04-02 23:02:55 +02:00
|
|
|
"Unknown highlight-style " ++ s
|
2017-02-06 14:46:48 +01:00
|
|
|
|
|
|
|
-- | 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 arg })
|
|
|
|
"FORMAT")
|
|
|
|
""
|
|
|
|
|
|
|
|
, Option "tw" ["to","write"]
|
|
|
|
(ReqArg
|
|
|
|
(\arg opt -> return opt { optWriter = Just arg })
|
|
|
|
"FORMAT")
|
|
|
|
""
|
|
|
|
|
|
|
|
, Option "o" ["output"]
|
|
|
|
(ReqArg
|
|
|
|
(\arg opt -> return opt { optOutputFile = arg })
|
2017-03-16 21:45:50 +01:00
|
|
|
"FILE")
|
2017-02-06 14:46:48 +01:00
|
|
|
"" -- "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
|
2017-03-04 12:02:16 +01:00
|
|
|
Just t | t > 0 && t < 6 ->
|
2017-02-06 14:46:48 +01:00
|
|
|
return opt{ optBaseHeaderLevel = t }
|
2017-04-15 11:52:51 +02:00
|
|
|
_ -> E.throwIO $ PandocOptionError
|
2017-04-02 23:02:55 +02:00
|
|
|
"base-header-level must be 1-5")
|
2017-02-06 14:46:48 +01:00
|
|
|
"NUMBER")
|
|
|
|
"" -- "Headers base level"
|
|
|
|
|
|
|
|
, 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 = arg : optFilters opt })
|
|
|
|
"PROGRAM")
|
|
|
|
"" -- "External JSON filter"
|
|
|
|
|
2017-03-20 15:17:03 +01:00
|
|
|
, Option "" ["lua-filter"]
|
|
|
|
(ReqArg
|
|
|
|
(\arg opt -> return opt { optLuaFilters = arg : optLuaFilters opt })
|
|
|
|
"SCRIPTPATH")
|
|
|
|
"" -- "Lua filter"
|
|
|
|
|
2017-02-06 14:46:48 +01:00
|
|
|
, 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 }
|
2017-04-15 11:52:51 +02:00
|
|
|
_ -> E.throwIO $ PandocOptionError
|
2017-04-02 23:02:55 +02:00
|
|
|
"tab-stop must be a number greater than 0")
|
2017-02-06 14:46:48 +01:00
|
|
|
"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
|
2017-04-15 11:52:51 +02:00
|
|
|
_ -> E.throwIO $ PandocOptionError
|
2017-02-06 14:46:48 +01:00
|
|
|
("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 })
|
2017-03-16 21:45:50 +01:00
|
|
|
"FILE")
|
2017-02-06 14:46:48 +01:00
|
|
|
"" -- "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 "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 <- getDefaultTemplate Nothing arg
|
|
|
|
case templ of
|
|
|
|
Right t -> UTF8.hPutStr stdout t
|
2017-06-20 16:16:32 +02:00
|
|
|
Left e -> E.throwIO $ PandocAppError (show e)
|
2017-02-06 14:46:48 +01:00
|
|
|
exitSuccess)
|
|
|
|
"FORMAT")
|
|
|
|
"" -- "Print default template for FORMAT"
|
|
|
|
|
|
|
|
, Option "" ["print-default-data-file"]
|
|
|
|
(ReqArg
|
|
|
|
(\arg _ -> do
|
|
|
|
readDataFile Nothing arg >>= BS.hPutStr stdout
|
|
|
|
exitSuccess)
|
|
|
|
"FILE")
|
|
|
|
"" -- "Print default data file"
|
|
|
|
|
|
|
|
, Option "" ["dpi"]
|
|
|
|
(ReqArg
|
|
|
|
(\arg opt ->
|
|
|
|
case safeRead arg of
|
|
|
|
Just t | t > 0 -> return opt { optDpi = t }
|
2017-04-15 11:52:51 +02:00
|
|
|
_ -> E.throwIO $ PandocOptionError
|
2017-02-06 14:46:48 +01:00
|
|
|
"dpi must be a number greater than 0")
|
|
|
|
"NUMBER")
|
|
|
|
"" -- "Dpi (default 96)"
|
|
|
|
|
2017-05-17 15:13:35 +02:00
|
|
|
, Option "" ["eol"]
|
|
|
|
(ReqArg
|
|
|
|
(\arg opt ->
|
|
|
|
case toLower <$> arg of
|
2017-05-22 10:10:04 +02:00
|
|
|
"crlf" -> return opt { optEol = CRLF }
|
|
|
|
"lf" -> return opt { optEol = LF }
|
|
|
|
"native" -> return opt { optEol = Native }
|
2017-05-17 15:13:35 +02:00
|
|
|
-- mac-syntax (cr) is not supported in ghc-base.
|
|
|
|
_ -> E.throwIO $ PandocOptionError
|
2017-05-22 10:10:04 +02:00
|
|
|
"--eol must be crlf, lf, or native")
|
|
|
|
"crlf|lf|native")
|
2017-05-17 15:13:35 +02:00
|
|
|
"" -- "EOL (default OS-dependent)"
|
|
|
|
|
2017-02-06 14:46:48 +01:00
|
|
|
, Option "" ["wrap"]
|
|
|
|
(ReqArg
|
|
|
|
(\arg opt ->
|
|
|
|
case safeRead ("Wrap" ++ uppercaseFirstLetter arg) of
|
|
|
|
Just o -> return opt { optWrapText = o }
|
2017-04-15 11:52:51 +02:00
|
|
|
Nothing -> E.throwIO $ PandocOptionError
|
2017-04-02 23:02:55 +02:00
|
|
|
"--wrap must be auto, none, or preserve")
|
2017-02-06 14:46:48 +01:00
|
|
|
"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 }
|
2017-04-15 11:52:51 +02:00
|
|
|
_ -> E.throwIO $ PandocOptionError
|
2017-02-06 14:46:48 +01:00
|
|
|
"columns must be a number greater than 0")
|
|
|
|
"NUMBER")
|
|
|
|
"" -- "Length of line in characters"
|
|
|
|
|
|
|
|
, 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 }
|
2017-04-15 11:52:51 +02:00
|
|
|
_ -> E.throwIO $ PandocOptionError
|
2017-02-06 14:46:48 +01:00
|
|
|
"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")
|
|
|
|
"" -- "Style for highlighted code"
|
|
|
|
|
2017-03-30 21:51:11 +02:00
|
|
|
, Option "" ["syntax-definition"]
|
|
|
|
(ReqArg
|
|
|
|
(\arg opt -> return opt{ optSyntaxDefinitions = arg :
|
|
|
|
optSyntaxDefinitions opt })
|
|
|
|
"FILE")
|
|
|
|
"" -- "Syntax definition (xml) file"
|
|
|
|
|
2017-02-06 14:46:48 +01:00
|
|
|
, Option "H" ["include-in-header"]
|
|
|
|
(ReqArg
|
|
|
|
(\arg opt -> return opt{ optIncludeInHeader =
|
|
|
|
arg : optIncludeInHeader opt,
|
|
|
|
optStandalone = True })
|
2017-03-16 21:45:50 +01:00
|
|
|
"FILE")
|
2017-02-06 14:46:48 +01:00
|
|
|
"" -- "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 })
|
2017-03-16 21:45:50 +01:00
|
|
|
"FILE")
|
2017-02-06 14:46:48 +01:00
|
|
|
"" -- "File to include before document body"
|
|
|
|
|
|
|
|
, Option "A" ["include-after-body"]
|
|
|
|
(ReqArg
|
|
|
|
(\arg opt -> return opt{ optIncludeAfterBody =
|
|
|
|
arg : optIncludeAfterBody opt,
|
|
|
|
optStandalone = True })
|
2017-03-16 21:45:50 +01:00
|
|
|
"FILE")
|
2017-02-06 14:46:48 +01:00
|
|
|
"" -- "File to include after document body"
|
|
|
|
|
2017-05-20 21:43:53 +02:00
|
|
|
, Option "" ["resource-path"]
|
|
|
|
(ReqArg
|
|
|
|
(\arg opt -> return opt { optResourcePath =
|
|
|
|
splitSearchPath arg })
|
|
|
|
"SEARCHPATH")
|
|
|
|
"" -- "Paths to search for images and other resources"
|
|
|
|
|
|
|
|
|
2017-02-06 14:46:48 +01:00
|
|
|
, 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 }))
|
|
|
|
"" -- "Use ascii characters only in HTML 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
|
2017-04-15 11:52:51 +02:00
|
|
|
_ -> E.throwIO $ PandocOptionError
|
2017-02-06 14:46:48 +01:00
|
|
|
("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 }
|
2017-04-15 11:52:51 +02:00
|
|
|
_ -> E.throwIO $ PandocOptionError
|
2017-04-02 23:02:55 +02:00
|
|
|
("Top-level division must be " ++
|
|
|
|
"section, chapter, part, or default"))
|
2017-02-06 14:46:48 +01:00
|
|
|
"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 }
|
2017-04-15 11:52:51 +02:00
|
|
|
_ -> E.throwIO $ PandocOptionError
|
2017-04-02 23:02:55 +02:00
|
|
|
"could not parse number-offset")
|
2017-02-06 14:46:48 +01:00
|
|
|
"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 }
|
2017-04-15 11:52:51 +02:00
|
|
|
_ -> E.throwIO $ PandocOptionError
|
2017-02-06 14:46:48 +01:00
|
|
|
"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
|
2017-04-15 11:52:51 +02:00
|
|
|
_ -> E.throwIO $ PandocOptionError
|
2017-02-06 14:46:48 +01:00
|
|
|
("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 })
|
2017-03-16 21:45:50 +01:00
|
|
|
"FILE")
|
2017-02-06 14:46:48 +01:00
|
|
|
"" -- "Path of custom reference doc"
|
|
|
|
|
2017-06-22 12:01:33 +02:00
|
|
|
, Option "" ["epub-subdirectory"]
|
|
|
|
(ReqArg
|
|
|
|
(\arg opt ->
|
|
|
|
return opt { optEpubSubdirectory = arg })
|
|
|
|
"DIRNAME")
|
|
|
|
"" -- "Name of subdirectory for epub content in OCF container"
|
|
|
|
|
2017-02-06 14:46:48 +01:00
|
|
|
, Option "" ["epub-cover-image"]
|
|
|
|
(ReqArg
|
|
|
|
(\arg opt ->
|
|
|
|
return opt { optVariables =
|
|
|
|
("epub-cover-image", arg) : optVariables opt })
|
2017-03-16 21:45:50 +01:00
|
|
|
"FILE")
|
2017-02-06 14:46:48 +01:00
|
|
|
"" -- "Path of epub cover image"
|
|
|
|
|
|
|
|
, Option "" ["epub-metadata"]
|
|
|
|
(ReqArg
|
|
|
|
(\arg opt -> return opt { optEpubMetadata = Just arg })
|
2017-03-16 21:45:50 +01:00
|
|
|
"FILE")
|
2017-02-06 14:46:48 +01:00
|
|
|
"" -- "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 }
|
2017-04-15 11:52:51 +02:00
|
|
|
_ -> E.throwIO $ PandocOptionError
|
2017-02-06 14:46:48 +01:00
|
|
|
"chapter level must be a number between 1 and 6")
|
|
|
|
"NUMBER")
|
|
|
|
"" -- "Header level at which to split chapters in EPUB"
|
|
|
|
|
|
|
|
, Option "" ["latex-engine"]
|
|
|
|
(ReqArg
|
|
|
|
(\arg opt -> do
|
|
|
|
let b = takeBaseName arg
|
|
|
|
if b `elem` ["pdflatex", "lualatex", "xelatex"]
|
|
|
|
then return opt { optLaTeXEngine = arg }
|
2017-04-15 11:52:51 +02:00
|
|
|
else E.throwIO $ PandocOptionError "latex-engine must be pdflatex, lualatex, or xelatex.")
|
2017-02-06 14:46:48 +01:00
|
|
|
"PROGRAM")
|
|
|
|
"" -- "Name of latex program to use in generating PDF"
|
|
|
|
|
|
|
|
, Option "" ["latex-engine-opt"]
|
|
|
|
(ReqArg
|
|
|
|
(\arg opt -> do
|
|
|
|
let oldArgs = optLaTeXEngineArgs opt
|
|
|
|
return opt { optLaTeXEngineArgs = arg : oldArgs })
|
|
|
|
"STRING")
|
|
|
|
"" -- "Flags to pass to the LaTeX 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 "m" ["latexmathml", "asciimathml"]
|
|
|
|
(OptArg
|
|
|
|
(\arg opt ->
|
|
|
|
return opt { optHTMLMathMethod = LaTeXMathML arg })
|
|
|
|
"URL")
|
|
|
|
"" -- "Use LaTeXMathML script in html output"
|
|
|
|
|
|
|
|
, Option "" ["mathml"]
|
|
|
|
(NoArg
|
|
|
|
(\opt ->
|
|
|
|
return opt { optHTMLMathMethod = MathML }))
|
|
|
|
"" -- "Use mathml for HTML math"
|
|
|
|
|
|
|
|
, Option "" ["mimetex"]
|
|
|
|
(OptArg
|
|
|
|
(\arg opt -> do
|
|
|
|
let url' = case arg of
|
2017-03-04 13:03:41 +01:00
|
|
|
Just u -> u ++ "?"
|
|
|
|
Nothing -> "/cgi-bin/mimetex.cgi?"
|
2017-02-06 14:46:48 +01:00
|
|
|
return opt { optHTMLMathMethod = WebTeX url' })
|
|
|
|
"URL")
|
|
|
|
"" -- "Use mimetex 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 "" ["jsmath"]
|
|
|
|
(OptArg
|
|
|
|
(\arg opt -> return opt { optHTMLMathMethod = JsMath arg})
|
|
|
|
"URL")
|
|
|
|
"" -- "Use jsMath for HTML math"
|
|
|
|
|
|
|
|
, Option "" ["mathjax"]
|
|
|
|
(OptArg
|
|
|
|
(\arg opt -> do
|
2017-06-19 11:10:29 +02:00
|
|
|
let url' = fromMaybe (defaultMathJaxURL ++
|
|
|
|
"MathJax.js?config=TeX-AMS_CHTML-full") arg
|
2017-02-06 14:46:48 +01:00
|
|
|
return opt { optHTMLMathMethod = MathJax url'})
|
|
|
|
"URL")
|
|
|
|
"" -- "Use MathJax for HTML math"
|
|
|
|
, Option "" ["katex"]
|
|
|
|
(OptArg
|
|
|
|
(\arg opt ->
|
|
|
|
return opt
|
|
|
|
{ optKaTeXJS =
|
2017-06-19 11:10:29 +02:00
|
|
|
arg <|> Just (defaultKaTeXURL ++ "katex.min.js")})
|
2017-02-06 14:46:48 +01:00
|
|
|
"URL")
|
|
|
|
"" -- Use KaTeX for HTML Math
|
|
|
|
|
|
|
|
, Option "" ["katex-stylesheet"]
|
|
|
|
(ReqArg
|
|
|
|
(\arg opt ->
|
|
|
|
return opt { optKaTeXStylesheet = Just arg })
|
|
|
|
"URL")
|
|
|
|
"" -- Set the KaTeX Stylesheet location
|
|
|
|
|
|
|
|
, Option "" ["gladtex"]
|
|
|
|
(NoArg
|
|
|
|
(\opt -> return opt { optHTMLMathMethod = GladTeX }))
|
|
|
|
"" -- "Use gladtex for HTML math"
|
|
|
|
|
2017-03-16 21:45:50 +01:00
|
|
|
, Option "" ["abbreviations"]
|
|
|
|
(ReqArg
|
|
|
|
(\arg opt -> return opt { optAbbreviations = Just arg })
|
|
|
|
"FILE")
|
|
|
|
"" -- "Specify file for custom abbreviations"
|
|
|
|
|
2017-02-06 14:46:48 +01:00
|
|
|
, Option "" ["trace"]
|
|
|
|
(NoArg
|
2017-06-19 22:04:01 +02:00
|
|
|
(\opt -> return opt { optTrace = True }))
|
2017-02-06 14:46:48 +01:00
|
|
|
"" -- "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."
|
|
|
|
|
2017-02-11 09:59:54 +01:00
|
|
|
, Option "" ["log"]
|
|
|
|
(ReqArg
|
|
|
|
(\arg opt -> return opt{ optLogFile = Just arg })
|
|
|
|
"FILE")
|
|
|
|
"" -- "Log messages in JSON format to this file."
|
|
|
|
|
2017-02-06 14:46:48 +01:00
|
|
|
, Option "" ["bash-completion"]
|
|
|
|
(NoArg
|
|
|
|
(\_ -> do
|
|
|
|
ddir <- getDataDir
|
|
|
|
tpl <- readDataFileUTF8 Nothing "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
|
2017-06-01 14:14:42 +02:00
|
|
|
(unwords readersNames)
|
|
|
|
(unwords writersNames)
|
2017-02-06 14:46:48 +01:00
|
|
|
(unwords $ map fst highlightingStyles)
|
|
|
|
ddir
|
|
|
|
exitSuccess ))
|
|
|
|
"" -- "Print bash completion script"
|
|
|
|
|
|
|
|
, Option "" ["list-input-formats"]
|
|
|
|
(NoArg
|
|
|
|
(\_ -> do
|
2017-06-01 14:14:42 +02:00
|
|
|
mapM_ (UTF8.hPutStrLn stdout) readersNames
|
2017-02-06 14:46:48 +01:00
|
|
|
exitSuccess ))
|
|
|
|
""
|
|
|
|
|
|
|
|
, Option "" ["list-output-formats"]
|
|
|
|
(NoArg
|
|
|
|
(\_ -> do
|
2017-06-01 14:14:42 +02:00
|
|
|
mapM_ (UTF8.hPutStrLn stdout) writersNames
|
2017-02-06 14:46:48 +01:00
|
|
|
exitSuccess ))
|
|
|
|
""
|
|
|
|
|
|
|
|
, Option "" ["list-extensions"]
|
|
|
|
(NoArg
|
|
|
|
(\_ -> do
|
|
|
|
let showExt x = drop 4 (show x) ++
|
|
|
|
if extensionEnabled x pandocExtensions
|
|
|
|
then " +"
|
|
|
|
else " -"
|
|
|
|
mapM_ (UTF8.hPutStrLn stdout . showExt)
|
|
|
|
([minBound..maxBound] :: [Extension])
|
|
|
|
exitSuccess ))
|
|
|
|
""
|
|
|
|
|
|
|
|
, 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
|
2017-03-04 12:02:16 +01:00
|
|
|
mapM_ (UTF8.hPutStrLn stdout . fst) highlightingStyles
|
2017-02-06 14:46:48 +01:00
|
|
|
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"
|
|
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
-- Returns usage message
|
|
|
|
usageMessage :: String -> [OptDescr (Opt -> IO Opt)] -> String
|
|
|
|
usageMessage programName = usageInfo (programName ++ " [OPTIONS] [FILES]")
|
|
|
|
|
|
|
|
copyrightMessage :: String
|
|
|
|
copyrightMessage = intercalate "\n" [
|
|
|
|
"",
|
2017-02-06 14:53:31 +01:00
|
|
|
"Copyright (C) 2006-2017 John MacFarlane",
|
2017-02-06 14:46:48 +01:00
|
|
|
"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
|
|
|
|
|
2017-02-06 23:33:23 +01:00
|
|
|
handleUnrecognizedOption :: String -> [String] -> [String]
|
|
|
|
handleUnrecognizedOption "--smart" =
|
|
|
|
(("--smart/-S has been removed. Use +smart or -smart extension instead.\n" ++
|
2017-02-06 14:46:48 +01:00
|
|
|
"For example: pandoc -f markdown+smart -t markdown-smart.") :)
|
2017-02-06 23:33:23 +01:00
|
|
|
handleUnrecognizedOption "-S" = handleUnrecognizedOption "--smart"
|
|
|
|
handleUnrecognizedOption "--old-dashes" =
|
2017-02-06 14:46:48 +01:00
|
|
|
("--old-dashes has been removed. Use +old_dashes extension instead." :)
|
2017-02-06 23:33:23 +01:00
|
|
|
handleUnrecognizedOption "--no-wrap" =
|
2017-02-06 14:46:48 +01:00
|
|
|
("--no-wrap has been removed. Use --wrap=none instead." :)
|
2017-02-06 23:33:23 +01:00
|
|
|
handleUnrecognizedOption "--chapters" =
|
2017-02-06 14:46:48 +01:00
|
|
|
("--chapters has been removed. Use --top-level-division=chapter instead." :)
|
2017-02-06 23:33:23 +01:00
|
|
|
handleUnrecognizedOption "--reference-docx" =
|
2017-02-06 14:46:48 +01:00
|
|
|
("--reference-docx has been removed. Use --reference-doc instead." :)
|
2017-02-06 23:33:23 +01:00
|
|
|
handleUnrecognizedOption "--reference-odt" =
|
2017-02-06 14:46:48 +01:00
|
|
|
("--reference-odt has been removed. Use --reference-doc instead." :)
|
2017-02-06 23:33:23 +01:00
|
|
|
handleUnrecognizedOption "--parse-raw" =
|
2017-03-04 12:02:16 +01:00
|
|
|
("--parse-raw/-R has been removed. Use +raw_html or +raw_tex extension.\n" :)
|
2017-02-27 21:29:16 +01:00
|
|
|
handleUnrecognizedOption "--epub-stylesheet" =
|
2017-03-04 12:02:16 +01:00
|
|
|
("--epub-stylesheet has been removed. Use --css instead.\n" :)
|
2017-02-06 23:33:23 +01:00
|
|
|
handleUnrecognizedOption "-R" = handleUnrecognizedOption "--parse-raw"
|
|
|
|
handleUnrecognizedOption x =
|
2017-02-06 14:46:48 +01:00
|
|
|
(("Unknown option " ++ x ++ ".") :)
|
|
|
|
|
|
|
|
uppercaseFirstLetter :: String -> String
|
|
|
|
uppercaseFirstLetter (c:cs) = toUpper c : cs
|
2017-03-04 13:03:41 +01:00
|
|
|
uppercaseFirstLetter [] = []
|
2017-02-06 14:46:48 +01:00
|
|
|
|
2017-06-01 14:14:42 +02:00
|
|
|
readersNames :: [String]
|
|
|
|
readersNames = sort (map fst (readers :: [(String, Reader PandocIO)]))
|
2017-02-06 14:46:48 +01:00
|
|
|
|
2017-06-01 14:14:42 +02:00
|
|
|
writersNames :: [String]
|
|
|
|
writersNames = sort (map fst (writers :: [(String, Writer PandocIO)]))
|
2017-02-06 14:46:48 +01:00
|
|
|
|
|
|
|
splitField :: String -> (String, String)
|
|
|
|
splitField s =
|
|
|
|
case break (`elem` ":=") s of
|
|
|
|
(k,_:v) -> (k,v)
|
|
|
|
(k,[]) -> (k,"true")
|
2017-06-02 15:06:14 +02:00
|
|
|
|