@@ -1,3 +1,4 @@
1+{-# LANGUAGE ScopedTypeVariables #-}
12{-# LANGUAGE OverloadedStrings #-}
23{-# LANGUAGE NoImplicitPrelude #-}
34{-# LANGUAGE CPP #-}
@@ -17,6 +18,7 @@ Options for pandoc when used as an app.
1718module Text.Pandoc.App.Opt (
1819 Opt(..)
1920 , LineEnding (..)
21+ , IpynbOutput (..)
2022 , defaultOpts
2123 ) where
2224import Prelude
@@ -31,15 +33,43 @@ import Text.Pandoc.Options (TopLevelDivision (TopLevelDefault),
3133 ObfuscationMethod (NoObfuscation),
3234 CiteMethod (Citeproc))
3335import Text.Pandoc.Shared (camelCaseToHyphenated)
34−import Text.DocTemplates (Context(..))
35−import Data.Text (Text)
36+import Text.DocTemplates (Context(..), Val(..))
37+import Data.Text (Text, unpack)
38+import qualified Data.Text as T
39+import qualified Data.Map as M
40+import Text.Pandoc.Definition (Meta(..), MetaValue(..))
3641import Data.Aeson (defaultOptions, Options(..))
3742import Data.Aeson.TH (deriveJSON)
38−import Text.Pandoc.Definition (Meta)
43+import Control.Monad (foldM)
44+import Control.Applicative ((<|>))
45+import Data.YAML
3946
4047-- | The type of line-endings to be used when writing plain-text.
4148data LineEnding = LF | CRLF | Native deriving (Show, Generic)
4249
50+instance FromYAML LineEnding where
51+ parseYAML = withStr "LineEnding" $ \t ->
52+ case T.toLower t of
53+ "lf" -> return LF
54+ "crlf" -> return CRLF
55+ "native" -> return Native
56+ _ -> fail $ "Unknown line ending type " ++ show t
57+
58+-- | How to handle output blocks in ipynb.
59+data IpynbOutput =
60+ IpynbOutputAll
61+ | IpynbOutputNone
62+ | IpynbOutputBest
63+ deriving (Show, Generic)
64+
65+instance FromYAML IpynbOutput where
66+ parseYAML = withStr "LineEnding" $ \t ->
67+ case t of
68+ "none" -> return IpynbOutputNone
69+ "all" -> return IpynbOutputAll
70+ "best" -> return IpynbOutputBest
71+ _ -> fail $ "Unknown ipynb output type " ++ show t
72+
4373-- | Data structure for command line options.
4474data Opt = Opt
4575 { optTabStop :: Int -- ^ Number of spaces per tab
@@ -52,7 +82,7 @@ data Opt = Opt
5282 , optTemplate :: Maybe FilePath -- ^ Custom template
5383 , optVariables :: Context Text -- ^ Template variables to set
5484 , optMetadata :: Meta -- ^ Metadata fields to set
55− , optMetadataFile :: [FilePath] -- ^ Name of YAML metadata file
85+ , optMetadataFiles :: [FilePath] -- ^ Name of YAML metadata files
5686 , optOutputFile :: Maybe FilePath -- ^ Name of output file
5787 , optInputFiles :: [FilePath] -- ^ Names of input files
5888 , optNumberSections :: Bool -- ^ Number sections in LaTeX
@@ -82,7 +112,7 @@ data Opt = Opt
82112 , optReferenceLinks :: Bool -- ^ Use reference links in writing markdown, rst
83113 , optReferenceLocation :: ReferenceLocation -- ^ location for footnotes and link references in markdown output
84114 , optDpi :: Int -- ^ Dpi
85− , optWrapText :: WrapOption -- ^ Options for wrapping text
115+ , optWrap :: WrapOption -- ^ Options for wrapping text
86116 , optColumns :: Int -- ^ Line length in characters
87117 , optFilters :: [Filter] -- ^ Filters to apply
88118 , optEmailObfuscation :: ObfuscationMethod
@@ -93,7 +123,7 @@ data Opt = Opt
93123 , optCiteMethod :: CiteMethod -- ^ Method to output cites
94124 , optListings :: Bool -- ^ Use listings package for code blocks
95125 , optPdfEngine :: Maybe String -- ^ Program to use for latex/html -> pdf
96− , optPdfEngineArgs :: [String] -- ^ Flags to pass to the engine
126+ , optPdfEngineOpts :: [String] -- ^ Flags to pass to the engine
97127 , optSlideLevel :: Maybe Int -- ^ Header level that creates slides
98128 , optSetextHeaders :: Bool -- ^ Use atx headers for markdown level 1-2
99129 , optAscii :: Bool -- ^ Prefer ascii output
@@ -103,7 +133,7 @@ data Opt = Opt
103133 , optFileScope :: Bool -- ^ Parse input files before combining
104134 , optTitlePrefix :: Maybe String -- ^ Prefix for title
105135 , optCss :: [FilePath] -- ^ CSS files to link to
106− , optIpynbOutput :: String -- ^ Maybe f to use best data; Nothing to omit
136+ , optIpynbOutput :: IpynbOutput -- ^ How to treat ipynb output blocks
107137 , optIncludeBeforeBody :: [FilePath] -- ^ Files to include before
108138 , optIncludeAfterBody :: [FilePath] -- ^ Files to include after body
109139 , optIncludeInHeader :: [FilePath] -- ^ Files to include in header
@@ -113,6 +143,186 @@ data Opt = Opt
113143 , optStripComments :: Bool -- ^ Skip HTML comments
114144 } deriving (Generic, Show)
115145
146+instance FromYAML Opt where
147+ parseYAML (Mapping _ _ m) =
148+ foldM doOpt defaultOpts (M.toList m)
149+ parseYAML n = failAtNode n "Expected a mapping"
150+
151+doOpt :: Opt -> (Node Pos, Node Pos) -> Parser Opt
152+doOpt opt (k',v) = do
153+ k <- case k' of
154+ Scalar _ (SStr t) -> return t
155+ Scalar _ _ -> failAtNode k' "Non-string key"
156+ _ -> failAtNode k' "Non-scalar key"
157+ case k of
158+ "tab-stop" ->
159+ parseYAML v >>= \x -> return opt{ optTabStop = x }
160+ "preserve-tabs" ->
161+ parseYAML v >>= \x -> return opt { optPreserveTabs = x }
162+ "standalone" ->
163+ parseYAML v >>= \x -> return opt { optStandalone = x }
164+ "table-of-contents" ->
165+ parseYAML v >>= \x -> return opt { optTableOfContents = x }
166+ "toc" ->
167+ parseYAML v >>= \x -> return opt { optTableOfContents = x }
168+ "from" ->
169+ parseYAML v >>= \x -> return opt { optFrom = unpack <$> x }
170+ "reader" ->
171+ parseYAML v >>= \x -> return opt { optFrom = unpack <$> x }
172+ "to" ->
173+ parseYAML v >>= \x -> return opt { optTo = unpack <$> x }
174+ "writer" ->
175+ parseYAML v >>= \x -> return opt { optTo = unpack <$> x }
176+ "shift-heading-level-by" ->
177+ parseYAML v >>= \x -> return opt { optShiftHeadingLevelBy = x }
178+ "template" ->
179+ parseYAML v >>= \x -> return opt { optTemplate = unpack <$> x }
180+ "variables" ->
181+ parseYAML v >>= \x -> return opt { optVariables = x }
182+ "metadata" ->
183+ parseYAML v >>= \x -> return opt { optMetadata = contextToMeta x }
184+ "metadata-files" ->
185+ (parseYAML v >>= \x -> return opt { optMetadataFiles = map unpack x })
186+ "metadata-file" -> -- allow either a list or a single value
187+ (parseYAML v >>= \x -> return opt { optMetadataFiles = map unpack x })
188+ <|>
189+ (parseYAML v >>= \x -> return opt { optMetadataFiles = [unpack x] })
190+ "output-file" ->
191+ parseYAML v >>= \x -> return opt { optOutputFile = Just $ unpack x }
192+ "input-files" ->
193+ parseYAML v >>= \x -> return opt { optInputFiles = map unpack x }
194+ "number-sections" ->
195+ parseYAML v >>= \x -> return opt { optNumberSections = x }
196+ "number-offset" ->
197+ parseYAML v >>= \x -> return opt { optNumberOffset = x }
198+ "section-divs" ->
199+ parseYAML v >>= \x -> return opt { optSectionDivs = x }
200+ "incremental" ->
201+ parseYAML v >>= \x -> return opt { optIncremental = x }
202+ "self-contained" ->
203+ parseYAML v >>= \x -> return opt { optSelfContained = x }
204+ "html-q-tags" ->
205+ parseYAML v >>= \x -> return opt { optHtmlQTags = x }
206+ "highlight-style" ->
207+ parseYAML v >>= \x -> return opt { optHighlightStyle = unpack <$> x }
208+ "syntax-definition" ->
209+ (parseYAML v >>= \x -> return opt { optSyntaxDefinitions = map unpack x })
210+ <|>
211+ (parseYAML v >>= \x -> return opt { optSyntaxDefinitions = [unpack x] })
212+ "syntax-definitions" ->
213+ parseYAML v >>= \x -> return opt { optSyntaxDefinitions = map unpack x }
214+ "top-level-division" ->
215+ parseYAML v >>= \x -> return opt { optTopLevelDivision = x }
216+ "html-math-method" ->
217+ parseYAML v >>= \x -> return opt { optHTMLMathMethod = x }
218+ "abbreviations" ->
219+ parseYAML v >>= \x -> return opt { optAbbreviations = unpack <$> x }
220+ "reference-doc" ->
221+ parseYAML v >>= \x -> return opt { optReferenceDoc = unpack <$> x }
222+ "epub-subdirectory" ->
223+ parseYAML v >>= \x -> return opt { optEpubSubdirectory = unpack x }
224+ "epub-metadata" ->
225+ parseYAML v >>= \x -> return opt { optEpubMetadata = unpack <$> x }
226+ "epub-fonts" ->
227+ parseYAML v >>= \x -> return opt { optEpubFonts = map unpack x }
228+ "epub-chapter-level" ->
229+ parseYAML v >>= \x -> return opt { optEpubChapterLevel = x }
230+ "epub-cover-image" ->
231+ parseYAML v >>= \x -> return opt { optEpubCoverImage = unpack <$> x }
232+ "toc-depth" ->
233+ parseYAML v >>= \x -> return opt { optTOCDepth = x }
234+ "dump-args" ->
235+ parseYAML v >>= \x -> return opt { optDumpArgs = x }
236+ "ignore-args" ->
237+ parseYAML v >>= \x -> return opt { optIgnoreArgs = x }
238+ "verbosity" ->
239+ parseYAML v >>= \x -> return opt { optVerbosity = x }
240+ "trace" ->
241+ parseYAML v >>= \x -> return opt { optTrace = x }
242+ "log-file" ->
243+ parseYAML v >>= \x -> return opt { optLogFile = unpack <$> x }
244+ "fail-if-warnings" ->
245+ parseYAML v >>= \x -> return opt { optFailIfWarnings = x }
246+ "reference-links" ->
247+ parseYAML v >>= \x -> return opt { optReferenceLinks = x }
248+ "reference-location" ->
249+ parseYAML v >>= \x -> return opt { optReferenceLocation = x }
250+ "dpi" ->
251+ parseYAML v >>= \x -> return opt { optDpi = x }
252+ "wrap" ->
253+ parseYAML v >>= \x -> return opt { optWrap = x }
254+ "columns" ->
255+ parseYAML v >>= \x -> return opt { optColumns = x }
256+ "filters" ->
257+ parseYAML v >>= \x -> return opt { optFilters = x }
258+ "email-obfuscation" ->
259+ parseYAML v >>= \x -> return opt { optEmailObfuscation = x }
260+ "identifier-prefix" ->
261+ parseYAML v >>= \x -> return opt { optIdentifierPrefix = unpack x }
262+ "strip-empty-paragraphs" ->
263+ parseYAML v >>= \x -> return opt { optStripEmptyParagraphs = x }
264+ "indented-code-classes" ->
265+ parseYAML v >>= \x -> return opt { optIndentedCodeClasses = map unpack x }
266+ "data-dir" ->
267+ parseYAML v >>= \x -> return opt { optDataDir = unpack <$> x }
268+ "cite-method" ->
269+ parseYAML v >>= \x -> return opt { optCiteMethod = x }
270+ "listings" ->
271+ parseYAML v >>= \x -> return opt { optListings = x }
272+ "pdf-engine" ->
273+ parseYAML v >>= \x -> return opt { optPdfEngine = unpack <$> x }
274+ "pdf-engine-opts" ->
275+ parseYAML v >>= \x -> return opt { optPdfEngineOpts = map unpack x }
276+ "pdf-engine-opt" ->
277+ (parseYAML v >>= \x -> return opt { optPdfEngineOpts = map unpack x })
278+ <|>
279+ (parseYAML v >>= \x -> return opt { optPdfEngineOpts = [unpack x] })
280+ "slide-level" ->
281+ parseYAML v >>= \x -> return opt { optSlideLevel = x }
282+ "setext-headers" ->
283+ parseYAML v >>= \x -> return opt { optSetextHeaders = x }
284+ "ascii" ->
285+ parseYAML v >>= \x -> return opt { optAscii = x }
286+ "default-image-extension" ->
287+ parseYAML v >>= \x -> return opt { optDefaultImageExtension = unpack x }
288+ "extract-media" ->
289+ parseYAML v >>= \x -> return opt { optExtractMedia = unpack <$> x }
290+ "track-changes" ->
291+ parseYAML v >>= \x -> return opt { optTrackChanges = x }
292+ "file-scope" ->
293+ parseYAML v >>= \x -> return opt { optFileScope = x }
294+ "title-prefix" ->
295+ parseYAML v >>= \x -> return opt { optTitlePrefix = unpack <$> x }
296+ "css" ->
297+ (parseYAML v >>= \x -> return opt { optCss = map unpack x })
298+ <|>
299+ (parseYAML v >>= \x -> return opt { optCss = [unpack x] })
300+ "ipynb-output" ->
301+ parseYAML v >>= \x -> return opt { optIpynbOutput = x }
302+ "include-before-body" ->
303+ (parseYAML v >>= \x -> return opt { optIncludeBeforeBody = map unpack x })
304+ <|>
305+ (parseYAML v >>= \x -> return opt { optIncludeBeforeBody = [unpack x] })
306+ "include-after-body" ->
307+ (parseYAML v >>= \x -> return opt { optIncludeAfterBody = map unpack x })
308+ <|>
309+ (parseYAML v >>= \x -> return opt { optIncludeAfterBody = [unpack x] })
310+ "include-in-header" ->
311+ (parseYAML v >>= \x -> return opt { optIncludeInHeader = map unpack x })
312+ <|>
313+ (parseYAML v >>= \x -> return opt { optIncludeInHeader = [unpack x] })
314+ "resource-path" ->
315+ parseYAML v >>= \x -> return opt { optResourcePath = map unpack x }
316+ "request-headers" ->
317+ parseYAML v >>= \x -> return opt { optRequestHeaders =
318+ map (\(key,val) ->
319+ (unpack key, unpack val)) x }
320+ "eol" ->
321+ parseYAML v >>= \x -> return opt { optEol = x }
322+ "strip-comments" ->
323+ parseYAML v >>= \x -> return opt { optStripComments = x }
324+ _ -> failAtNode k' $ "Unknown option " ++ show k
325+
116326-- | Defaults for command-line options.
117327defaultOpts :: Opt
118328defaultOpts = Opt
@@ -126,7 +336,7 @@ defaultOpts = Opt
126336 , optTemplate = Nothing
127337 , optVariables = mempty
128338 , optMetadata = mempty
129− , optMetadataFile = []
339+ , optMetadataFiles = []
130340 , optOutputFile = Nothing
131341 , optInputFiles = []
132342 , optNumberSections = False
@@ -156,7 +366,7 @@ defaultOpts = Opt
156366 , optReferenceLinks = False
157367 , optReferenceLocation = EndOfDocument
158368 , optDpi = 96
159− , optWrapText = WrapAuto
369+ , optWrap = WrapAuto
160370 , optColumns = 72
161371 , optFilters = []
162372 , optEmailObfuscation = NoObfuscation
@@ -167,7 +377,7 @@ defaultOpts = Opt
167377 , optCiteMethod = Citeproc
168378 , optListings = False
169379 , optPdfEngine = Nothing
170− , optPdfEngineArgs = []
380+ , optPdfEngineOpts = []
171381 , optSlideLevel = Nothing
172382 , optSetextHeaders = True
173383 , optAscii = False
@@ -177,7 +387,7 @@ defaultOpts = Opt
177387 , optFileScope = False
178388 , optTitlePrefix = Nothing
179389 , optCss = []
180− , optIpynbOutput = "best"
390+ , optIpynbOutput = IpynbOutputBest
181391 , optIncludeBeforeBody = []
182392 , optIncludeAfterBody = []
183393 , optIncludeInHeader = []
@@ -187,8 +397,21 @@ defaultOpts = Opt
187397 , optStripComments = False
188398 }
189399
400+contextToMeta :: Context Text -> Meta
401+contextToMeta (Context m) =
402+ Meta . M.mapKeys unpack . M.map valToMetaVal $ m
403+
404+valToMetaVal :: Val Text -> MetaValue
405+valToMetaVal (MapVal (Context m)) =
406+ MetaMap . M.mapKeys unpack . M.map valToMetaVal $ m
407+valToMetaVal (ListVal xs) = MetaList $ map valToMetaVal xs
408+valToMetaVal (SimpleVal t) = MetaString (unpack t)
409+valToMetaVal NullVal = MetaString ""
410+
190411-- see https://github.com/jgm/pandoc/pull/4083
191412-- using generic deriving caused long compilation times
413+$(deriveJSON
414+ defaultOptions{ fieldLabelModifier = drop 11 . map toLower } ''IpynbOutput)
192415$(deriveJSON
193416 defaultOptions{ fieldLabelModifier = map toLower } ''LineEnding)
194417$(deriveJSON