{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE FlexibleInstances #-}
module Text.Pandoc.App.Opt (
Opt(..)
, LineEnding (..)
, IpynbOutput (..)
, defaultOpts
, addMeta
) where
import Data.Char (isLower, toLower)
import GHC.Generics hiding (Meta)
import Text.Pandoc.Builder (setMeta)
import Text.Pandoc.Filter (Filter (..))
import Text.Pandoc.Logging (Verbosity (WARNING))
import Text.Pandoc.Options (TopLevelDivision (TopLevelDefault),
TrackChanges (AcceptChanges),
WrapOption (WrapAuto), HTMLMathMethod (PlainMath),
ReferenceLocation (EndOfDocument),
ObfuscationMethod (NoObfuscation),
CiteMethod (Citeproc))
import Text.Pandoc.Shared (camelCaseStrToHyphenated)
import Text.DocLayout (render)
import Text.DocTemplates (Context(..), Val(..))
import Data.Text (Text, unpack)
import qualified Data.Text as T
import qualified Data.Map as M
import Text.Pandoc.Definition (Meta(..), MetaValue(..), lookupMeta)
import Data.Aeson (defaultOptions, Options(..))
import Data.Aeson.TH (deriveJSON)
import Control.Applicative ((<|>))
import Data.YAML
data LineEnding = LF | CRLF | Native deriving (Show, Generic)
instance FromYAML LineEnding where
parseYAML = withStr "LineEnding" $ \t ->
case T.toLower t of
"lf" -> return LF
"crlf" -> return CRLF
"native" -> return Native
_ -> fail $ "Unknown line ending type " ++ show t
data IpynbOutput =
IpynbOutputAll
| IpynbOutputNone
| IpynbOutputBest
deriving (Show, Generic)
instance FromYAML IpynbOutput where
parseYAML = withStr "LineEnding" $ \t ->
case t of
"none" -> return IpynbOutputNone
"all" -> return IpynbOutputAll
"best" -> return IpynbOutputBest
_ -> fail $ "Unknown ipynb output type " ++ show t
data Opt = Opt
{ optTabStop :: Int
, optPreserveTabs :: Bool
, optStandalone :: Bool
, optFrom :: Maybe Text
, optTo :: Maybe Text
, optTableOfContents :: Bool
, optShiftHeadingLevelBy :: Int
, optTemplate :: Maybe FilePath
, optVariables :: Context Text
, optMetadata :: Meta
, optMetadataFiles :: [FilePath]
, optOutputFile :: Maybe FilePath
, optInputFiles :: Maybe [FilePath]
, optNumberSections :: Bool
, optNumberOffset :: [Int]
, optSectionDivs :: Bool
, optIncremental :: Bool
, optSelfContained :: Bool
, optHtmlQTags :: Bool
, optHighlightStyle :: Maybe Text
, optSyntaxDefinitions :: [FilePath]
, optTopLevelDivision :: TopLevelDivision
, optHTMLMathMethod :: HTMLMathMethod
, optAbbreviations :: Maybe FilePath
, optReferenceDoc :: Maybe FilePath
, optEpubSubdirectory :: String
, optEpubMetadata :: Maybe FilePath
, optEpubFonts :: [FilePath]
, optEpubChapterLevel :: Int
, optEpubCoverImage :: Maybe FilePath
, optTOCDepth :: Int
, optDumpArgs :: Bool
, optIgnoreArgs :: Bool
, optVerbosity :: Verbosity
, optTrace :: Bool
, optLogFile :: Maybe FilePath
, optFailIfWarnings :: Bool
, optReferenceLinks :: Bool
, optReferenceLocation :: ReferenceLocation
, optDpi :: Int
, optWrap :: WrapOption
, optColumns :: Int
, optFilters :: [Filter]
, optEmailObfuscation :: ObfuscationMethod
, optIdentifierPrefix :: Text
, optStripEmptyParagraphs :: Bool
, optIndentedCodeClasses :: [Text]
, optDataDir :: Maybe FilePath
, optCiteMethod :: CiteMethod
, optListings :: Bool
, optPdfEngine :: Maybe String
, optPdfEngineOpts :: [String]
, optSlideLevel :: Maybe Int
, optSetextHeaders :: Bool
, optAscii :: Bool
, optDefaultImageExtension :: Text
, optExtractMedia :: Maybe FilePath
, optTrackChanges :: TrackChanges
, optFileScope :: Bool
, optTitlePrefix :: Maybe Text
, optCss :: [FilePath]
, optIpynbOutput :: IpynbOutput
, optIncludeBeforeBody :: [FilePath]
, optIncludeAfterBody :: [FilePath]
, optIncludeInHeader :: [FilePath]
, optResourcePath :: [FilePath]
, optRequestHeaders :: [(Text, Text)]
, optEol :: LineEnding
, optStripComments :: Bool
} deriving (Generic, Show)
instance FromYAML (Opt -> Opt) where
parseYAML (Mapping _ _ m) =
foldr (.) id <$> mapM doOpt (M.toList m)
parseYAML n = failAtNode n "Expected a mapping"
doOpt :: (Node Pos, Node Pos) -> Parser (Opt -> Opt)
doOpt (k',v) = do
k <- case k' of
Scalar _ (SStr t) -> return t
Scalar _ _ -> failAtNode k' "Non-string key"
_ -> failAtNode k' "Non-scalar key"
case k of
"tab-stop" ->
parseYAML v >>= \x -> return (\o -> o{ optTabStop = x })
"preserve-tabs" ->
parseYAML v >>= \x -> return (\o -> o{ optPreserveTabs = x })
"standalone" ->
parseYAML v >>= \x -> return (\o -> o{ optStandalone = x })
"table-of-contents" ->
parseYAML v >>= \x -> return (\o -> o{ optTableOfContents = x })
"toc" ->
parseYAML v >>= \x -> return (\o -> o{ optTableOfContents = x })
"from" ->
parseYAML v >>= \x -> return (\o -> o{ optFrom = x })
"reader" ->
parseYAML v >>= \x -> return (\o -> o{ optFrom = x })
"to" ->
parseYAML v >>= \x -> return (\o -> o{ optTo = x })
"writer" ->
parseYAML v >>= \x -> return (\o -> o{ optTo = x })
"shift-heading-level-by" ->
parseYAML v >>= \x -> return (\o -> o{ optShiftHeadingLevelBy = x })
"template" ->
parseYAML v >>= \x -> return (\o -> o{ optTemplate = unpack <$> x })
"variables" ->
parseYAML v >>= \x -> return (\o -> o{ optVariables =
x <> optVariables o })
"metadata" ->
parseYAML v >>= \x -> return (\o -> o{ optMetadata = optMetadata o <>
contextToMeta x })
"metadata-files" ->
parseYAML v >>= \x ->
return (\o -> o{ optMetadataFiles =
optMetadataFiles o <>
map unpack x })
"metadata-file" ->
(parseYAML v >>= \x -> return (\o -> o{ optMetadataFiles =
optMetadataFiles o <>
map unpack x }))
<|>
(parseYAML v >>= \x ->
return (\o -> o{ optMetadataFiles =
optMetadataFiles o <>[unpack x] }))
"output-file" ->
parseYAML v >>= \x -> return (\o -> o{ optOutputFile = unpack <$> x })
"input-files" ->
parseYAML v >>= \x -> return (\o -> o{ optInputFiles =
optInputFiles o <>
(map unpack <$> x) })
"input-file" ->
(parseYAML v >>= \x -> return (\o -> o{ optInputFiles =
optInputFiles o <>
(map unpack <$> x) }))
<|>
(parseYAML v >>= \x -> return (\o -> o{ optInputFiles =
optInputFiles o <>
((\z -> [unpack z]) <$> x)
}))
"number-sections" ->
parseYAML v >>= \x -> return (\o -> o{ optNumberSections = x })
"number-offset" ->
parseYAML v >>= \x -> return (\o -> o{ optNumberOffset = x })
"section-divs" ->
parseYAML v >>= \x -> return (\o -> o{ optSectionDivs = x })
"incremental" ->
parseYAML v >>= \x -> return (\o -> o{ optIncremental = x })
"self-contained" ->
parseYAML v >>= \x -> return (\o -> o{ optSelfContained = x })
"html-q-tags" ->
parseYAML v >>= \x -> return (\o -> o{ optHtmlQTags = x })
"highlight-style" ->
parseYAML v >>= \x -> return (\o -> o{ optHighlightStyle = x })
"syntax-definition" ->
(parseYAML v >>= \x ->
return (\o -> o{ optSyntaxDefinitions =
optSyntaxDefinitions o <> map unpack x }))
<|>
(parseYAML v >>= \x ->
return (\o -> o{ optSyntaxDefinitions =
optSyntaxDefinitions o <> [unpack x] }))
"syntax-definitions" ->
parseYAML v >>= \x ->
return (\o -> o{ optSyntaxDefinitions =
optSyntaxDefinitions o <> map unpack x })
"top-level-division" ->
parseYAML v >>= \x -> return (\o -> o{ optTopLevelDivision = x })
"html-math-method" ->
parseYAML v >>= \x -> return (\o -> o{ optHTMLMathMethod = x })
"abbreviations" ->
parseYAML v >>= \x ->
return (\o -> o{ optAbbreviations = unpack <$> x })
"reference-doc" ->
parseYAML v >>= \x ->
return (\o -> o{ optReferenceDoc = unpack <$> x })
"epub-subdirectory" ->
parseYAML v >>= \x ->
return (\o -> o{ optEpubSubdirectory = unpack x })
"epub-metadata" ->
parseYAML v >>= \x ->
return (\o -> o{ optEpubMetadata = unpack <$> x })
"epub-fonts" ->
parseYAML v >>= \x -> return (\o -> o{ optEpubFonts = optEpubFonts o <>
map unpack x })
"epub-chapter-level" ->
parseYAML v >>= \x -> return (\o -> o{ optEpubChapterLevel = x })
"epub-cover-image" ->
parseYAML v >>= \x ->
return (\o -> o{ optEpubCoverImage = unpack <$> x })
"toc-depth" ->
parseYAML v >>= \x -> return (\o -> o{ optTOCDepth = x })
"dump-args" ->
parseYAML v >>= \x -> return (\o -> o{ optDumpArgs = x })
"ignore-args" ->
parseYAML v >>= \x -> return (\o -> o{ optIgnoreArgs = x })
"verbosity" ->
parseYAML v >>= \x -> return (\o -> o{ optVerbosity = x })
"trace" ->
parseYAML v >>= \x -> return (\o -> o{ optTrace = x })
"log-file" ->
parseYAML v >>= \x -> return (\o -> o{ optLogFile = unpack <$> x })
"fail-if-warnings" ->
parseYAML v >>= \x -> return (\o -> o{ optFailIfWarnings = x })
"reference-links" ->
parseYAML v >>= \x -> return (\o -> o{ optReferenceLinks = x })
"reference-location" ->
parseYAML v >>= \x -> return (\o -> o{ optReferenceLocation = x })
"dpi" ->
parseYAML v >>= \x -> return (\o -> o{ optDpi = x })
"wrap" ->
parseYAML v >>= \x -> return (\o -> o{ optWrap = x })
"columns" ->
parseYAML v >>= \x -> return (\o -> o{ optColumns = x })
"filters" ->
parseYAML v >>= \x -> return (\o -> o{ optFilters = optFilters o <> x })
"email-obfuscation" ->
parseYAML v >>= \x -> return (\o -> o{ optEmailObfuscation = x })
"identifier-prefix" ->
parseYAML v >>= \x ->
return (\o -> o{ optIdentifierPrefix = x })
"strip-empty-paragraphs" ->
parseYAML v >>= \x -> return (\o -> o{ optStripEmptyParagraphs = x })
"indented-code-classes" ->
parseYAML v >>= \x ->
return (\o -> o{ optIndentedCodeClasses = x })
"data-dir" ->
parseYAML v >>= \x -> return (\o -> o{ optDataDir = unpack <$> x })
"cite-method" ->
parseYAML v >>= \x -> return (\o -> o{ optCiteMethod = x })
"listings" ->
parseYAML v >>= \x -> return (\o -> o{ optListings = x })
"pdf-engine" ->
parseYAML v >>= \x -> return (\o -> o{ optPdfEngine = unpack <$> x })
"pdf-engine-opts" ->
parseYAML v >>= \x ->
return (\o -> o{ optPdfEngineOpts = map unpack x })
"pdf-engine-opt" ->
(parseYAML v >>= \x ->
return (\o -> o{ optPdfEngineOpts = map unpack x }))
<|>
(parseYAML v >>= \x ->
return (\o -> o{ optPdfEngineOpts = [unpack x] }))
"slide-level" ->
parseYAML v >>= \x -> return (\o -> o{ optSlideLevel = x })
"atx-headers" ->
parseYAML v >>= \x -> return (\o -> o{ optSetextHeaders = not x })
"ascii" ->
parseYAML v >>= \x -> return (\o -> o{ optAscii = x })
"default-image-extension" ->
parseYAML v >>= \x ->
return (\o -> o{ optDefaultImageExtension = x })
"extract-media" ->
parseYAML v >>= \x ->
return (\o -> o{ optExtractMedia = unpack <$> x })
"track-changes" ->
parseYAML v >>= \x -> return (\o -> o{ optTrackChanges = x })
"file-scope" ->
parseYAML v >>= \x -> return (\o -> o{ optFileScope = x })
"title-prefix" ->
parseYAML v >>= \x -> return (\o -> o{ optTitlePrefix = x,
optStandalone = True })
"css" ->
(parseYAML v >>= \x -> return (\o -> o{ optCss = optCss o <>
map unpack x }))
<|>
(parseYAML v >>= \x -> return (\o -> o{ optCss = optCss o <>
[unpack x] }))
"bibliography" ->
do let addItem x o = o{ optMetadata =
addMeta "bibliography" (T.unpack x)
(optMetadata o) }
(parseYAML v >>= \(xs :: [Text]) -> return $ \o ->
foldr addItem o xs)
<|>
(parseYAML v >>= \(x :: Text) -> return $ \o -> addItem x o)
"csl" ->
do let addItem x o = o{ optMetadata =
addMeta "csl" (T.unpack x)
(optMetadata o) }
(parseYAML v >>= \(xs :: [Text]) -> return $ \o ->
foldr addItem o xs)
<|>
(parseYAML v >>= \(x :: Text) -> return $ \o -> addItem x o)
"ipynb-output" ->
parseYAML v >>= \x -> return (\o -> o{ optIpynbOutput = x })
"include-before-body" ->
(parseYAML v >>= \x ->
return (\o -> o{ optIncludeBeforeBody =
optIncludeBeforeBody o <> map unpack x }))
<|>
(parseYAML v >>= \x ->
return (\o -> o{ optIncludeBeforeBody =
optIncludeBeforeBody o <> [unpack x] }))
"include-after-body" ->
(parseYAML v >>= \x ->
return (\o -> o{ optIncludeAfterBody =
optIncludeAfterBody o <> map unpack x }))
<|>
(parseYAML v >>= \x ->
return (\o -> o{ optIncludeAfterBody =
optIncludeAfterBody o <> [unpack x] }))
"include-in-header" ->
(parseYAML v >>= \x ->
return (\o -> o{ optIncludeInHeader =
optIncludeInHeader o <> map unpack x }))
<|>
(parseYAML v >>= \x ->
return (\o -> o{ optIncludeInHeader =
optIncludeInHeader o <> [unpack x] }))
"resource-path" ->
parseYAML v >>= \x ->
return (\o -> o{ optResourcePath = map unpack x })
"request-headers" ->
parseYAML v >>= \x ->
return (\o -> o{ optRequestHeaders = x })
"eol" ->
parseYAML v >>= \x -> return (\o -> o{ optEol = x })
"strip-comments" ->
parseYAML v >>= \x -> return (\o -> o { optStripComments = x })
_ -> failAtNode k' $ "Unknown option " ++ show k
defaultOpts :: Opt
defaultOpts = Opt
{ optTabStop = 4
, optPreserveTabs = False
, optStandalone = False
, optFrom = Nothing
, optTo = Nothing
, optTableOfContents = False
, optShiftHeadingLevelBy = 0
, optTemplate = Nothing
, optVariables = mempty
, optMetadata = mempty
, optMetadataFiles = []
, optOutputFile = Nothing
, optInputFiles = Nothing
, 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
, optWrap = WrapAuto
, optColumns = 72
, optFilters = []
, optEmailObfuscation = NoObfuscation
, optIdentifierPrefix = ""
, optStripEmptyParagraphs = False
, optIndentedCodeClasses = []
, optDataDir = Nothing
, optCiteMethod = Citeproc
, optListings = False
, optPdfEngine = Nothing
, optPdfEngineOpts = []
, optSlideLevel = Nothing
, optSetextHeaders = True
, optAscii = False
, optDefaultImageExtension = ""
, optExtractMedia = Nothing
, optTrackChanges = AcceptChanges
, optFileScope = False
, optTitlePrefix = Nothing
, optCss = []
, optIpynbOutput = IpynbOutputBest
, optIncludeBeforeBody = []
, optIncludeAfterBody = []
, optIncludeInHeader = []
, optResourcePath = ["."]
, optRequestHeaders = []
, optEol = Native
, optStripComments = False
}
contextToMeta :: Context Text -> Meta
contextToMeta (Context m) =
Meta . M.map valToMetaVal $ m
valToMetaVal :: Val Text -> MetaValue
valToMetaVal (MapVal (Context m)) =
MetaMap . M.map valToMetaVal $ m
valToMetaVal (ListVal xs) = MetaList $ map valToMetaVal xs
valToMetaVal (SimpleVal d) = MetaString $ render Nothing d
valToMetaVal NullVal = MetaString ""
addMeta :: String -> String -> Meta -> Meta
addMeta k v 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
where
v' = readMetaValue v
k' = T.pack k
readMetaValue :: String -> MetaValue
readMetaValue s
| s == "true" = MetaBool True
| s == "True" = MetaBool True
| s == "TRUE" = MetaBool True
| s == "false" = MetaBool False
| s == "False" = MetaBool False
| s == "FALSE" = MetaBool False
| otherwise = MetaString $ T.pack s
$(deriveJSON
defaultOptions{ fieldLabelModifier = drop 11 . map toLower } ''IpynbOutput)
$(deriveJSON
defaultOptions{ fieldLabelModifier = map toLower } ''LineEnding)
$(deriveJSON
defaultOptions{ fieldLabelModifier =
camelCaseStrToHyphenated . dropWhile isLower
} ''Opt)