git.iko.soy/typeable/pandoc
on master help sign in
Improve parsing of --defaults.

- Add FromYAML instances to Opt and to all subsidiary types. - Remove the use of HsYAML-aeson, which doesn't give good position information on errors. - Rename some fields in Opt to better match cli options or reflect what the ycontain [API change]: + optMetadataFile -> optMetadataFiles + optPDFEngineArgs -> optPDFEngineOpts + optWrapText -> optWrap - Add IpynbOutput enumerated type to Text.Pandoc.App.Opts. Use this instead fo a string for optIpynbOutput. - Add FromYAML instance for Filter in Text.Pandoc.Filters. With these changes parsing of defaults files should be complete and should give decent error messages. Now (unlike before) we get an error if an unknown field is used.

commit7388cd3e7a49297a7368a7e77d8f2d86d6965006 authorJohn MacFarlane <jgm@berkeley.edu> dateThu 10 Oct 2019, 13:54 (7 years ago) parent2523941
12 files changed+481−118
MANUAL.txt+89−69 cabal.project+1−1 pandoc.cabal−1 src/Text/Pandoc/App.hs+8−8 src/Text/Pandoc/App/CommandLineOptions.hs+19−19 src/Text/Pandoc/App/Opt.hs+234−11 src/Text/Pandoc/App/OutputSettings.hs+1−1 src/Text/Pandoc/Filter.hs+21 src/Text/Pandoc/Logging.hs+9 src/Text/Pandoc/Options.hs+97−1 src/Text/Pandoc/Writers/Math.hs+1−5 stack.yaml+1−2
MANUAL.txt+89−69
@@ -368,7 +368,7 @@ header when requesting a document from a URL:
368368 See the section [Default files] for more information on the
369369 file format.
370370
371− If a defaults file is used, its defaults will override
371+ If a defaults file is used, its defaults will replace
372372 any options that have been previously specified on the
373373 command line, and they may be overridden by subsequent
374374 options on the command line.
@@ -842,7 +842,8 @@ header when requesting a document from a URL:
842842 which will be used for syntax highlighting of appropriately
843843 marked code blocks. This can be used to add support for
844844 new languages or to use altered syntax definitions for
845− existing languages.
845+ existing languages. This option may be repeated to add
846+ multiple syntax definitions.
846847
847848`-H` *FILE*, `--include-in-header=`*FILE*|*URL*
848849
@@ -1426,83 +1427,102 @@ of options. Here is a sample defaults file demonstrating all of
14261427the fields that may be used:
14271428
14281429``` yaml
1429−abbreviations: null
1430−ascii: false
1431−cite-method: citeproc
1432−columns: 72
1433−css:
1434− - my.css
1435−data-dir: data
1436−default-image-extension: ".jpg"
1437−dpi: 96
1438−dump-args: false
1439−email-obfuscation: none
1440−eol: Native
1441−epub-chapter-level: 1
1442−epub-cover-image: null
1443−epub-fonts: []
1444−epub-metadata: metadata.xml
1445−epub-subdirectory: EPUB
1446−extract-media: media
1447−fail-if-warnings: false
1448−file-scope: false
1449−filters:
1450− - pandoc-citeproc
1430+tab-stop: 8
1431+preserve-tabs: yes
1432+standalone: true
1433+table-of-contents: true
1434+# toc is a synonym for table-of-contents
14511435from: markdown+emoji
1436+# reader is a synonym for from
1437+to: html5
1438+# writer is a synonym for to
1439+shift-heading-level-by: 1
1440+template: leter
1441+variables:
1442+ documentclass: book
1443+ classoptions:
1444+ - twosides
1445+ - draft
1446+metadata:
1447+ author:
1448+ - Sam Smith
1449+ - Julie Liu
1450+metadata-files: []
1451+# you may also use metadata-file with a single value
1452+output-file: -
1453+input-files:
1454+- preface.md
1455+- content.md
1456+number-sections: false
1457+number-offset: [0,0,0,0,0,0]
1458+section-divs: true
1459+incremental: false
1460+self-contained: false
1461+html-q-tags: false
14521462highlight-style: pygments
1463+syntax-definitions:
1464+- c.xml
1465+# may also use syntax-definition: with a single value
1466+top-level-division: chapter
14531467html-math-method:
14541468 method: mathjax
14551469 url: "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"
1456−html-qtags: false
1457−identifier-prefix: ""
1470+abbreviations: []
1471+reference-doc: myref.docx
1472+epub-subdirectory: EPUB
1473+epub-metadata: meta.xml
1474+epub-fonts:
1475+- foobar.otf
1476+epub-chapter-level: 1
1477+epub-cover-image: cover.jpg
1478+toc-depth: 2
1479+dump-args: false
14581480ignore-args: false
1459−include-after-body: []
1460−include-before-body: []
1461−include-in-header: []
1462−incremental: false
1481+verbosity: INFO
1482+trace: false
1483+log-file: log.json
1484+fail-if-warnings: false
1485+reference-links: true
1486+reference-location: paragraph
1487+dpi: 72
1488+wrap: auto
1489+columns:78
1490+filters:
1491+- pandoc-citeproc
1492+- wordcount.lua
1493+- type: json
1494+ path: foo.lua
1495+email-obfuscation: javascript
1496+identifier-prefix: foo
1497+strip-empty-paragraphs: true
14631498indented-code-classes: []
1464−input-files: []
1465−ipynb-output: best
1499+data-dir: null
1500+cite-method: citeproc
14661501listings: false
1467−log-file: null
1468−metadata: {}
1469−metadata-file: []
1470−number-offset: [0,0,0,0,0,0]
1471−number-sections: false
1472−output-file: null
1473−pdf-engine: null
1474−pdf-engine-args: []
1475−preserve-tabs: false
1476−reference-doc: null
1477−reference-links: false
1478−reference-location: end-of-document
1479−request-headers: []
1480−resource-path: [".", "../foo"]
1481−section-divs: false
1482−self-contained: false
1502+pdf-engine: pdflatex
1503+pdf-engine-opts: []
1504+# can also use this with a single option:
1505+pdf-engine-opt:
1506+slide-level: 2
14831507setext-headers: true
1484−shift-heading-level-by: 0
1485−slide-level: null
1486−standalone: false
1508+ascii: true
1509+default-image-extension: ".jpg"
1510+extract-media: mediadir
1511+track-changes: false
1512+file-scope: false
1513+title-prefix: ""
1514+css:
1515+- site.css
1516+ipynb-output: best
1517+# Note that these take files, not their contents:
1518+include-before-body: []
1519+include-after-body: []
1520+include-in-header: []
1521+resource-path: ["."]
1522+request-headers:
1523+- ["User-Agent", "Mozilla/5.0"]
1524+eol: lf
14871525strip-comments: false
1488−strip-empty-paragraphs: false
1489−syntax-definitions: []
1490−tab-stop: 4
1491−table-of-contents: false
1492−template: letter
1493−title-prefix: null
1494−to: null
1495−toc-depth: 3
1496−top-level-division: default
1497−trace: false
1498−track-changes: accept-changes
1499−variables:
1500− documentclass: book
1501− classoptions:
1502− - twosides
1503− - draft
1504−verbosity: WARNING
1505−wrap-text: wrap-auto
15061526```
15071527
15081528# Templates
cabal.project+1−1
@@ -16,4 +16,4 @@ source-repository-package
1616source-repository-package
1717 type: git
1818 location: https://github.com/jgm/doctemplates.git
19− tag: 8c30b5955584ff96459999c4958e8a953fed214f
19+ tag: 180a5e9318e3cee44c6581f6d8ace14de684b735
pandoc.cabal−1
@@ -417,7 +417,6 @@ library
417417 case-insensitive >= 1.2 && < 1.3,
418418 unicode-transforms >= 0.3 && < 0.4,
419419 HsYAML >= 0.2 && < 0.3,
420− HsYAML-aeson >= 0.2 && < 0.3,
421420 doclayout >= 0.1 && < 0.2,
422421 ipynb >= 0.1 && < 0.2,
423422 attoparsec >= 0.12 && < 0.14
src/Text/Pandoc/App.hs+8−8
@@ -46,7 +46,8 @@ import System.IO (nativeNewline, stdout)
4646import qualified System.IO as IO (Newline (..))
4747import Text.Pandoc
4848import Text.Pandoc.App.FormatHeuristics (formatFromFilePaths)
49−import Text.Pandoc.App.Opt (Opt (..), LineEnding (..), defaultOpts)
49+import Text.Pandoc.App.Opt (Opt (..), LineEnding (..), defaultOpts,
50+ IpynbOutput (..) )
5051import Text.Pandoc.App.CommandLineOptions (parseOptions, options)
5152import Text.Pandoc.App.OutputSettings (OutputSettings (..), optToOutputSettings)
5253import Text.Pandoc.BCP47 (Lang (..), parseBCP47)
@@ -227,7 +228,7 @@ convertWithOpts opts = do
227228 }
228229
229230 metadataFromFile <-
230− case optMetadataFile opts of
231+ case optMetadataFiles opts of
231232 [] -> return mempty
232233 paths -> mapM readFileLazy paths >>= mapM (yamlToMeta readerOpts)
233234 >>= return . (foldr1 (<>))
@@ -250,17 +251,16 @@ convertWithOpts opts = do
250251 then (eastAsianLineBreakFilter :)
251252 else id) .
252253 (case optIpynbOutput opts of
253− "all" -> id
254− "none" -> (filterIpynbOutput Nothing :)
255− "best" -> (filterIpynbOutput (Just $
254+ IpynbOutputAll -> id
255+ IpynbOutputNone -> (filterIpynbOutput Nothing :)
256+ IpynbOutputBest -> (filterIpynbOutput (Just $
256257 if htmlFormat format
257258 then Format "html"
258259 else
259260 case format of
260261 "latex" -> Format "latex"
261262 "beamer" -> Format "latex"
262− _ -> Format format) :)
263− _ -> id) -- should not happen
263+ _ -> Format format) :))
264264 $ []
265265
266266 let sourceToDoc :: [FilePath] -> PandocIO Pandoc
@@ -297,7 +297,7 @@ convertWithOpts opts = do
297297 ByteStringWriter f -> f writerOptions doc >>= writeFnBinary outputFile
298298 TextWriter f -> case outputPdfProgram outputSettings of
299299 Just pdfProg -> do
300− res <- makePDF pdfProg (optPdfEngineArgs opts) f
300+ res <- makePDF pdfProg (optPdfEngineOpts opts) f
301301 writerOptions doc
302302 case res of
303303 Right pdf -> writeFnBinary outputFile pdf
src/Text/Pandoc/App/CommandLineOptions.hs+19−19
@@ -42,7 +42,7 @@ import System.FilePath
4242import System.IO (stdout)
4343import Text.Pandoc
4444import Text.Pandoc.Builder (setMeta)
45−import Text.Pandoc.App.Opt (Opt (..), LineEnding (..))
45+import Text.Pandoc.App.Opt (Opt (..), LineEnding (..), IpynbOutput (..))
4646import Text.Pandoc.Filter (Filter (..))
4747import Text.Pandoc.Highlighting (highlightingStyles)
4848import Text.Pandoc.Writers.Math (defaultMathJaxURL, defaultKaTeXURL)
@@ -64,7 +64,6 @@ import qualified Data.Text as T
6464import Data.Text (Text)
6565import Text.DocTemplates (ToContext(toVal), Context(..))
6666import qualified Text.Pandoc.UTF8 as UTF8
67−import qualified Data.YAML.Aeson as YA
6867import qualified Data.YAML as Y
6968
7069parseOptions :: [OptDescr (Opt -> IO Opt)] -> Opt -> IO Opt
@@ -156,8 +155,8 @@ options =
156155
157156 , Option "" ["metadata-file"]
158157 (ReqArg
159− (\arg opt -> return opt{ optMetadataFile =
160− normalizePath arg : optMetadataFile opt })
158+ (\arg opt -> return opt{ optMetadataFiles =
159+ normalizePath arg : optMetadataFiles opt })
161160 "FILE")
162161 ""
163162
@@ -175,15 +174,14 @@ options =
175174 Just dd -> [fp, dd </> "defaults" </> fp]
176175 fp' <- fromMaybe fp <$> findFile fps
177176 inp <- readFileLazy fp'
178− let defaults = YA.encode1 opt
179− case YA.decode1 (defaults <> inp) of
177+ case Y.decode1 inp of
180178 Right (newopts :: Opt) -> return newopts
181179 Left (errpos, errmsg) -> throwError $
182180 PandocParseError $
183− "Error parsing " ++ fp' ++
184− " (line " ++ show (Y.posLine errpos) ++
185− " column " ++ show (Y.posColumn errpos) ++
186− ")\n" ++ errmsg
181+ "Error parsing " ++ fp' ++ " line " ++
182+ show (Y.posLine errpos) ++ " column " ++
183+ show (Y.posColumn errpos) ++ ":\n" ++ errmsg
184+
187185 )
188186 "FILE")
189187 ""
@@ -219,9 +217,9 @@ options =
219217 (ReqArg
220218 (\arg opt ->
221219 case arg of
222− "auto" -> return opt{ optWrapText = WrapAuto }
223− "none" -> return opt{ optWrapText = WrapNone }
224− "preserve" -> return opt{ optWrapText = WrapPreserve }
220+ "auto" -> return opt{ optWrap = WrapAuto }
221+ "none" -> return opt{ optWrap = WrapNone }
222+ "preserve" -> return opt{ optWrap = WrapPreserve }
225223 _ -> E.throwIO $ PandocOptionError
226224 "--wrap must be auto, none, or preserve")
227225 "auto|none|preserve")
@@ -409,8 +407,8 @@ options =
409407 , Option "" ["pdf-engine-opt"]
410408 (ReqArg
411409 (\arg opt -> do
412− let oldArgs = optPdfEngineArgs opt
413− return opt { optPdfEngineArgs = oldArgs ++ [arg]})
410+ let oldArgs = optPdfEngineOpts opt
411+ return opt { optPdfEngineOpts = oldArgs ++ [arg]})
414412 "STRING")
415413 "" -- "Flags to pass to the PDF-engine, all instances of this option are accumulated and used"
416414
@@ -655,10 +653,12 @@ options =
655653 , Option "" ["ipynb-output"]
656654 (ReqArg
657655 (\arg opt ->
658− if arg `notElem` ["all","none","best"]
659− then E.throwIO $ PandocOptionError $
660− "ipynb-output must be all, none, or best"
661− else return opt { optIpynbOutput = arg })
656+ case arg of
657+ "all" -> return opt{ optIpynbOutput = IpynbOutputAll }
658+ "best" -> return opt{ optIpynbOutput = IpynbOutputBest }
659+ "none" -> return opt{ optIpynbOutput = IpynbOutputNone }
660+ _ -> E.throwIO $ PandocOptionError $
661+ "ipynb-output must be all, none, or best")
662662 "all|none|best")
663663 "" -- "Starting number for sections, subsections, etc."
664664
src/Text/Pandoc/App/Opt.hs+234−11
@@ -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
src/Text/Pandoc/App/OutputSettings.hs+1−1
@@ -211,7 +211,7 @@ optToOutputSettings opts = do
211211 , writerReferenceLinks = optReferenceLinks opts
212212 , writerReferenceLocation = optReferenceLocation opts
213213 , writerDpi = optDpi opts
214− , writerWrapText = optWrapText opts
214+ , writerWrapText = optWrap opts
215215 , writerColumns = optColumns opts
216216 , writerEmailObfuscation = optEmailObfuscation opts
217217 , writerIdentifierPrefix = optIdentifierPrefix opts
src/Text/Pandoc/Filter.hs+21
@@ -2,6 +2,7 @@
22{-# LANGUAGE DeriveGeneric #-}
33{-# LANGUAGE NoImplicitPrelude #-}
44{-# LANGUAGE TemplateHaskell #-}
5+{-# LANGUAGE OverloadedStrings #-}
56{- |
67 Module : Text.Pandoc.Filter
78 Copyright : Copyright (C) 2006-2019 John MacFarlane
@@ -28,12 +29,32 @@ import Text.Pandoc.Options (ReaderOptions)
2829import qualified Text.Pandoc.Filter.JSON as JSONFilter
2930import qualified Text.Pandoc.Filter.Lua as LuaFilter
3031import qualified Text.Pandoc.Filter.Path as Path
32+import Data.YAML
33+import qualified Data.Text as T
34+import System.FilePath (takeExtension)
35+import Control.Applicative ((<|>))
3136
3237-- | Type of filter and path to filter file.
3338data Filter = LuaFilter FilePath
3439 | JSONFilter FilePath
3540 deriving (Show, Generic)
3641
42+instance FromYAML Filter where
43+ parseYAML node =
44+ (withMap "Filter" $ \m -> do
45+ ty <- m .: "type"
46+ fp <- m .: "path"
47+ case ty of
48+ "lua" -> return $ LuaFilter $ T.unpack fp
49+ "json" -> return $ JSONFilter $ T.unpack fp
50+ _ -> fail $ "Unknown filter type " ++ show (ty :: T.Text)) node
51+ <|>
52+ (withStr "Filter" $ \t -> do
53+ let fp = T.unpack t
54+ case takeExtension fp of
55+ ".lua" -> return $ LuaFilter fp
56+ _ -> return $ JSONFilter fp) node
57+
3758-- | Modify the given document using a filter.
3859applyFilters :: ReaderOptions
3960 -> [Filter]
src/Text/Pandoc/Logging.hs+9
@@ -25,6 +25,7 @@ module Text.Pandoc.Logging (
2525
2626import Prelude
2727import Control.Monad (mzero)
28+import Data.YAML (withStr, FromYAML(..))
2829import Data.Aeson
2930import Data.Aeson.Encode.Pretty (Config (..), defConfig, encodePretty',
3031 keyOrder)
@@ -52,6 +53,14 @@ instance FromJSON Verbosity where
5253 _ -> mzero
5354 parseJSON _ = mzero
5455
56+instance FromYAML Verbosity where
57+ parseYAML = withStr "Verbosity" $ \t ->
58+ case t of
59+ "ERROR" -> return ERROR
60+ "WARNING" -> return WARNING
61+ "INFO" -> return INFO
62+ _ -> mzero
63+
5564data LogMessage =
5665 SkippedContent String SourcePos
5766 | IgnoredElement String
src/Text/Pandoc/Options.hs+97−1
@@ -3,6 +3,7 @@
33{-# LANGUAGE DeriveGeneric #-}
44{-# LANGUAGE NoImplicitPrelude #-}
55{-# LANGUAGE TemplateHaskell #-}
6+{-# LANGUAGE OverloadedStrings #-}
67{- |
78 Module : Text.Pandoc.Options
89 Copyright : Copyright (C) 2012-2019 John MacFarlane
@@ -29,12 +30,15 @@ module Text.Pandoc.Options ( module Text.Pandoc.Extensions
2930 , ReferenceLocation (..)
3031 , def
3132 , isEnabled
33+ , defaultMathJaxURL
34+ , defaultKaTeXURL
3235 ) where
3336import Prelude
37+import Control.Applicative ((<|>))
3438import Data.Char (toLower)
3539import Data.Data (Data)
3640import Data.Default
37−import Data.Text (Text)
41+import Data.Text (Text, unpack)
3842import Text.DocTemplates (Context(..))
3943import qualified Data.Set as Set
4044import Data.Typeable (Typeable)
@@ -46,6 +50,7 @@ import Text.Pandoc.Shared (camelCaseToHyphenated)
4650import Text.DocTemplates (Template)
4751import Data.Aeson.TH (deriveJSON, defaultOptions, Options(..),
4852 SumEncoding(..))
53+import Data.YAML
4954
5055class HasSyntaxExtensions a where
5156 getExtensions :: a -> Extensions
@@ -101,17 +106,58 @@ data HTMLMathMethod = PlainMath
101106 | KaTeX String -- url of KaTeX files
102107 deriving (Show, Read, Eq, Data, Typeable, Generic)
103108
109+instance FromYAML HTMLMathMethod where
110+ parseYAML node =
111+ (withMap "HTMLMathMethod" $ \m -> do
112+ method <- m .: "method"
113+ mburl <- m .:? "url"
114+ case unpack method of
115+ "plain" -> return PlainMath
116+ "webtex" -> return $ WebTeX $ maybe "" unpack mburl
117+ "gladtex" -> return GladTeX
118+ "mathml" -> return MathML
119+ "mathjax" -> return $ MathJax $
120+ maybe defaultMathJaxURL unpack mburl
121+ "katex" -> return $ KaTeX $
122+ maybe defaultKaTeXURL unpack mburl
123+ _ -> fail $ "Unknown HTML math method " ++ show method) node
124+ <|> (withStr "HTMLMathMethod" $ \method ->
125+ case unpack method of
126+ "plain" -> return PlainMath
127+ "webtex" -> return $ WebTeX ""
128+ "gladtex" -> return GladTeX
129+ "mathml" -> return MathML
130+ "mathjax" -> return $ MathJax defaultMathJaxURL
131+ "katex" -> return $ KaTeX defaultKaTeXURL
132+ _ -> fail $ "Unknown HTML math method " ++ show method) node
133+
104134data CiteMethod = Citeproc -- use citeproc to render them
105135 | Natbib -- output natbib cite commands
106136 | Biblatex -- output biblatex cite commands
107137 deriving (Show, Read, Eq, Data, Typeable, Generic)
108138
139+instance FromYAML CiteMethod where
140+ parseYAML = withStr "Citeproc" $ \t ->
141+ case t of
142+ "citeproc" -> return Citeproc
143+ "natbib" -> return Natbib
144+ "biblatex" -> return Biblatex
145+ _ -> fail $ "Unknown citation method " ++ show t
146+
109147-- | Methods for obfuscating email addresses in HTML.
110148data ObfuscationMethod = NoObfuscation
111149 | ReferenceObfuscation
112150 | JavascriptObfuscation
113151 deriving (Show, Read, Eq, Data, Typeable, Generic)
114152
153+instance FromYAML ObfuscationMethod where
154+ parseYAML = withStr "Citeproc" $ \t ->
155+ case t of
156+ "none" -> return NoObfuscation
157+ "references" -> return ReferenceObfuscation
158+ "javascript" -> return JavascriptObfuscation
159+ _ -> fail $ "Unknown obfuscation method " ++ show t
160+
115161-- | Varieties of HTML slide shows.
116162data HTMLSlideVariant = S5Slides
117163 | SlidySlides
@@ -127,12 +173,29 @@ data TrackChanges = AcceptChanges
127173 | AllChanges
128174 deriving (Show, Read, Eq, Data, Typeable, Generic)
129175
176+instance FromYAML TrackChanges where
177+ parseYAML = withStr "TrackChanges" $ \t ->
178+ case t of
179+ "accept" -> return AcceptChanges
180+ "reject" -> return RejectChanges
181+ "all" -> return AllChanges
182+ _ -> fail $ "Unknown track changes method " ++ show t
183+
130184-- | Options for wrapping text in the output.
131185data WrapOption = WrapAuto -- ^ Automatically wrap to width
132186 | WrapNone -- ^ No non-semantic newlines
133187 | WrapPreserve -- ^ Preserve wrapping of input source
134188 deriving (Show, Read, Eq, Data, Typeable, Generic)
135189
190+instance FromYAML WrapOption where
191+ parseYAML = withStr "WrapOption" $ \t ->
192+ case t of
193+ "auto" -> return WrapAuto
194+ "none" -> return WrapNone
195+ "preserve" -> return WrapPreserve
196+ _ -> fail $ "Unknown wrap method " ++ show t
197+
198+
136199-- | Options defining the type of top-level headers.
137200data TopLevelDivision = TopLevelPart -- ^ Top-level headers become parts
138201 | TopLevelChapter -- ^ Top-level headers become chapters
@@ -141,12 +204,31 @@ data TopLevelDivision = TopLevelPart -- ^ Top-level headers become parts
141204 -- heuristics
142205 deriving (Show, Read, Eq, Data, Typeable, Generic)
143206
207+instance FromYAML TopLevelDivision where
208+ parseYAML = withStr "TopLevelDivision" $ \t ->
209+ case t of
210+ "part" -> return TopLevelPart
211+ "chapter" -> return TopLevelChapter
212+ "section" -> return TopLevelSection
213+ "default" -> return TopLevelDefault
214+ _ -> fail $ "Unknown top level division " ++ show t
215+
216+
144217-- | Locations for footnotes and references in markdown output
145218data ReferenceLocation = EndOfBlock -- ^ End of block
146219 | EndOfSection -- ^ prior to next section header (or end of document)
147220 | EndOfDocument -- ^ at end of document
148221 deriving (Show, Read, Eq, Data, Typeable, Generic)
149222
223+instance FromYAML ReferenceLocation where
224+ parseYAML = withStr "ReferenceLocation" $ \t ->
225+ case t of
226+ "block" -> return EndOfBlock
227+ "section" -> return EndOfSection
228+ "document" -> return EndOfDocument
229+ _ -> fail $ "Unknown reference location " ++ show t
230+
231+
150232-- | Options for writers
151233data WriterOptions = WriterOptions
152234 { writerTemplate :: Maybe Template -- ^ Template to use
@@ -227,16 +309,25 @@ instance HasSyntaxExtensions WriterOptions where
227309isEnabled :: HasSyntaxExtensions a => Extension -> a -> Bool
228310isEnabled ext opts = ext `extensionEnabled` getExtensions opts
229311
312+defaultMathJaxURL :: String
313+defaultMathJaxURL = "https://cdn.jsdelivr.net/npm/mathjax@3/es5/"
314+
315+defaultKaTeXURL :: String
316+defaultKaTeXURL = "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.9.0/"
317+
230318$(deriveJSON defaultOptions ''ReaderOptions)
319+
231320$(deriveJSON defaultOptions{
232321 constructorTagModifier = map toLower,
233322 sumEncoding = TaggedObject{
234323 tagFieldName = "method",
235324 contentsFieldName = "url" }
236325 } ''HTMLMathMethod)
326+
237327$(deriveJSON defaultOptions{ constructorTagModifier =
238328 camelCaseToHyphenated
239329 } ''CiteMethod)
330+
240331$(deriveJSON defaultOptions{ constructorTagModifier =
241332 \t -> case t of
242333 "NoObfuscation" -> "none"
@@ -244,16 +335,21 @@ $(deriveJSON defaultOptions{ constructorTagModifier =
244335 "JavascriptObfuscation" -> "javascript"
245336 _ -> "none"
246337 } ''ObfuscationMethod)
338+
247339$(deriveJSON defaultOptions ''HTMLSlideVariant)
340+
248341$(deriveJSON defaultOptions{ constructorTagModifier =
249342 camelCaseToHyphenated
250343 } ''TrackChanges)
344+
251345$(deriveJSON defaultOptions{ constructorTagModifier =
252346 camelCaseToHyphenated
253347 } ''WrapOption)
348+
254349$(deriveJSON defaultOptions{ constructorTagModifier =
255350 camelCaseToHyphenated . drop 8
256351 } ''TopLevelDivision)
352+
257353$(deriveJSON defaultOptions{ constructorTagModifier =
258354 camelCaseToHyphenated
259355 } ''ReferenceLocation)
src/Text/Pandoc/Writers/Math.hs+1−5
@@ -12,6 +12,7 @@ import Text.Pandoc.Class
1212import Text.Pandoc.Definition
1313import Text.Pandoc.Logging
1414import Text.TeXMath (DisplayType (..), Exp, readTeX, writePandoc)
15+import Text.Pandoc.Options (defaultMathJaxURL, defaultKaTeXURL)
1516
1617-- | Converts a raw TeX math formula to a list of 'Pandoc' inlines.
1718-- Defaults to raw formula between @$@ or @$$@ characters if entire formula
@@ -51,8 +52,3 @@ convertMath writer mt str =
5152 DisplayMath -> DisplayBlock
5253 InlineMath -> DisplayInline
5354
54−defaultMathJaxURL :: String
55−defaultMathJaxURL = "https://cdn.jsdelivr.net/npm/mathjax@3/es5/"
56−
57−defaultKaTeXURL :: String
58−defaultKaTeXURL = "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.9.0/"
stack.yaml+1−2
@@ -21,10 +21,9 @@ extra-deps:
2121- regex-pcre-builtin-0.95.0.8.8.35
2222- doclayout-0.1
2323- HsYAML-0.2.0.0
24−- HsYAML-aeson-0.2.0.0
2524# - doctemplates-0.6.1
2625- git: https://github.com/jgm/doctemplates.git
27− commit: 8c30b5955584ff96459999c4958e8a953fed214f
26+ commit: 180a5e9318e3cee44c6581f6d8ace14de684b735
2827ghc-options:
2928 "$locals": -fhide-source-paths -Wno-missing-home-modules
3029resolver: lts-14.6