diff options
| author | Albert Krewinkel <albert@zeitkraut.de> | 2022-12-04 23:16:01 +0100 |
|---|---|---|
| committer | John MacFarlane <jgm@berkeley.edu> | 2022-12-05 08:52:37 -0800 |
| commit | a03b77fbd35a0547f51429cd24388728aadd2008 (patch) | |
| tree | 52d64efed811804febc2b6352e80887e9ded6792 | |
| parent | a4ac1ebb954b0eaf0eac0805b8340b1609ef5d8f (diff) | |
Lua: support `-D` CLI option for custom writers [API change]
A new error `PandocNoTemplateError` (code 87) is thrown if a template is
required but cannot be found.
| -rw-r--r-- | pandoc-lua-engine/src/Text/Pandoc/Lua/Writer.hs | 24 | ||||
| -rw-r--r-- | pandoc-lua-engine/test/Tests/Lua/Writer.hs | 10 | ||||
| -rw-r--r-- | pandoc-lua-engine/test/writer-template.lua | 2 | ||||
| -rw-r--r-- | pandoc-lua-engine/test/writer-template.out.txt | 3 | ||||
| -rw-r--r-- | src/Text/Pandoc/App/CommandLineOptions.hs | 20 | ||||
| -rw-r--r-- | src/Text/Pandoc/App/OutputSettings.hs | 15 | ||||
| -rw-r--r-- | src/Text/Pandoc/Error.hs | 3 | ||||
| -rw-r--r-- | src/Text/Pandoc/Scripting.hs | 3 |
8 files changed, 43 insertions, 37 deletions
diff --git a/pandoc-lua-engine/src/Text/Pandoc/Lua/Writer.hs b/pandoc-lua-engine/src/Text/Pandoc/Lua/Writer.hs index c5e3e2469..91573c87b 100644 --- a/pandoc-lua-engine/src/Text/Pandoc/Lua/Writer.hs +++ b/pandoc-lua-engine/src/Text/Pandoc/Lua/Writer.hs @@ -31,15 +31,13 @@ import Text.Pandoc.Format (ExtensionsConfig (..)) import Text.Pandoc.Lua.Global (Global (..), setGlobals) import Text.Pandoc.Lua.Init (runLuaWith) import Text.Pandoc.Lua.Marshal.Format (peekExtensionsConfig) -import Text.Pandoc.Lua.Marshal.Template (peekTemplate) import Text.Pandoc.Lua.Marshal.WriterOptions (pushWriterOptions) -import Text.Pandoc.Templates (Template) import Text.Pandoc.Writers (Writer (..)) import qualified Text.Pandoc.Lua.Writer.Classic as Classic -- | Convert Pandoc to custom markup. writeCustom :: (PandocMonad m, MonadIO m) - => FilePath -> m (Writer m, ExtensionsConfig, m (Template Text)) + => FilePath -> m (Writer m, ExtensionsConfig, Maybe Text) writeCustom luaFile = do luaState <- liftIO newGCManagedState luaFile' <- fromMaybe luaFile <$> findFileWithDataFallback "writers" luaFile @@ -66,19 +64,15 @@ writeCustom luaFile = do TypeNil -> ExtensionsConfig mempty mempty <$ pop 1 _ -> forcePeek $ peekExtensionsConfig top `lastly` pop 1 - -- Store template function in registry - let templateField = "Pandoc Writer Template" - rawgetglobal "Template" *> setfield registryindex templateField + mtemplate <- rawgetglobal "Template" >>= \case + TypeNil -> pure Nothing + TypeFunction -> Just <$> do + callTrace 0 1 + forcePeek $ peekText top `lastly` pop 1 + _ -> Just <$> do + forcePeek $ peekText top `lastly` pop 1 - let getTemplate = liftIO $ withGCManagedState @PandocError luaState $ do - getfield registryindex templateField >>= \case - TypeNil -> failLua $ "No default template for writer; " <> - "the global variable Template is undefined." - _ -> do - callTrace 0 1 - forcePeek $ peekTemplate top `lastly` pop 1 - - let addProperties = (, extsConf, getTemplate) + let addProperties = (, extsConf, mtemplate) rawgetglobal "Writer" >>= \case TypeNil -> rawgetglobal "ByteStringWriter" >>= \case diff --git a/pandoc-lua-engine/test/Tests/Lua/Writer.hs b/pandoc-lua-engine/test/Tests/Lua/Writer.hs index c9a0d478c..97d772bc5 100644 --- a/pandoc-lua-engine/test/Tests/Lua/Writer.hs +++ b/pandoc-lua-engine/test/Tests/Lua/Writer.hs @@ -11,6 +11,7 @@ Tests for custom Lua writers. module Tests.Lua.Writer (tests) where import Data.Default (Default (def)) +import Data.Maybe (fromMaybe) import Text.Pandoc.Class (runIOorExplode, readFileStrict) import Text.Pandoc.Extensions (Extension (..)) import Text.Pandoc.Format (ExtensionsDiff (..), FlavoredFormat (..), @@ -59,13 +60,8 @@ tests = , goldenVsString "template" "writer-template.out.txt" (runIOorExplode $ do - txt <- writeCustom "writer-template.lua" >>= \case - (TextWriter f, _, mt) -> do - template <- mt - let opts = def{ writerTemplate = Just template } - f opts (B.doc (B.plain (B.str "body goes here"))) - _ -> error "Expected a text writer" - pure $ BL.fromStrict (UTF8.fromText txt)) + (_, _, template) <- writeCustom "writer-template.lua" + pure . BL.fromStrict . UTF8.fromText $ fromMaybe "" template) , testCase "preset extensions" $ do let ediff = ExtensionsDiff{extsToEnable = [], extsToDisable = []} diff --git a/pandoc-lua-engine/test/writer-template.lua b/pandoc-lua-engine/test/writer-template.lua index c90f7c1ef..8908c0ebb 100644 --- a/pandoc-lua-engine/test/writer-template.lua +++ b/pandoc-lua-engine/test/writer-template.lua @@ -3,5 +3,5 @@ function Writer (doc, opts) end function Template () - return pandoc.template.compile '<!-- start -->\n$body$\n<!-- stop -->\n' + return '<!-- start -->\n$body$\n<!-- stop -->\n' end diff --git a/pandoc-lua-engine/test/writer-template.out.txt b/pandoc-lua-engine/test/writer-template.out.txt index 1fb343c28..18e531cff 100644 --- a/pandoc-lua-engine/test/writer-template.out.txt +++ b/pandoc-lua-engine/test/writer-template.out.txt @@ -1,4 +1,3 @@ <!-- start --> -body goes here - +$body$ <!-- stop --> diff --git a/src/Text/Pandoc/App/CommandLineOptions.hs b/src/Text/Pandoc/App/CommandLineOptions.hs index 78f548fb3..a65fe5a04 100644 --- a/src/Text/Pandoc/App/CommandLineOptions.hs +++ b/src/Text/Pandoc/App/CommandLineOptions.hs @@ -51,6 +51,7 @@ import Text.Pandoc.App.Opt (Opt (..), LineEnding (..), IpynbOutput (..), fullDefaultsPath, OptInfo(..)) import Text.Pandoc.Filter (Filter (..)) import Text.Pandoc.Highlighting (highlightingStyles, lookupHighlightingStyle) +import Text.Pandoc.Scripting (ScriptingEngine (..)) import Text.Pandoc.Shared (safeStrRead) import Text.Printf import qualified Control.Exception as E @@ -60,7 +61,6 @@ import qualified Data.ByteString.Lazy as B import qualified Data.Map as M import qualified Data.Text as T import qualified Text.Pandoc.UTF8 as UTF8 -import Text.Pandoc.Scripting (ScriptingEngine(..)) parseOptions :: [OptDescr (Opt -> ExceptT OptInfo IO Opt)] -> Opt -> IO (Either OptInfo Opt) @@ -105,7 +105,7 @@ parseOptionsFromArgs options' defaults prg rawArgs = do -- | React to an 'OptInfo' by printing the requested information -- and exiting or (if there was a parsing error) raising an error. handleOptInfo :: ScriptingEngine -> OptInfo -> IO () -handleOptInfo _engine info = E.handle (handleError . Left) $ do +handleOptInfo engine info = E.handle (handleError . Left) $ do case info of BashCompletion -> do datafiles <- getDataFileNames @@ -152,9 +152,19 @@ handleOptInfo _engine info = E.handle (handleError . Left) $ do mapM_ (UTF8.hPutStrLn stdout . fst) highlightingStyles PrintDefaultTemplate mbout fmt -> do let write = maybe (UTF8.hPutStr stdout) (UTF8.writeFile) mbout - templ <- runIO $ do - setUserDataDir Nothing - getDefaultTemplate fmt + + templ <- runIO $ + case splitExtension (T.unpack fmt) of + (_, "") -> do + -- built-in format + setUserDataDir Nothing + getDefaultTemplate fmt + _ -> do + -- format looks like a filepath => custom writer + (_, _, mt) <- engineWriteCustom engine (T.unpack fmt) + case mt of + Just t -> pure t + Nothing -> E.throw $ PandocNoTemplateError fmt case templ of Right t | T.null t -> -- e.g. for docx, odt, json: diff --git a/src/Text/Pandoc/App/OutputSettings.hs b/src/Text/Pandoc/App/OutputSettings.hs index 8b5d450cf..c3f0ade8b 100644 --- a/src/Text/Pandoc/App/OutputSettings.hs +++ b/src/Text/Pandoc/App/OutputSettings.hs @@ -107,6 +107,9 @@ optToOutputSettings scriptingEngine opts = do Format.parseFlavoredFormat writerName let standalone = optStandalone opts || not (isTextFormat format) || pdfOutput + let templateOrThrow = \case + Left e -> throwError $ PandocTemplateError (T.pack e) + Right t -> pure t let processCustomTemplate getDefault = case optTemplate opts of _ | not standalone -> return Nothing @@ -118,16 +121,18 @@ optToOutputSettings scriptingEngine opts = do _ -> tp getTemplate tp' >>= runWithPartials . compileTemplate tp' - >>= (\case - Left e -> throwError $ PandocTemplateError (T.pack e) - Right t -> return $ Just t) + >>= fmap Just . templateOrThrow (writer, writerExts, mtemplate) <- if "lua" `T.isSuffixOf` format then do - (w, extsConf, mt) <- engineWriteCustom scriptingEngine (T.unpack format) + let path = T.unpack format + (w, extsConf, mt) <- engineWriteCustom scriptingEngine path wexts <- Format.applyExtensionsDiff extsConf flvrd - templ <- processCustomTemplate mt + templ <- processCustomTemplate $ case mt of + Nothing -> throwError $ PandocNoTemplateError format + Just t -> (runWithDefaultPartials $ compileTemplate path t) >>= + templateOrThrow return (w, wexts, templ) else do tmpl <- processCustomTemplate (compileDefaultTemplate format) diff --git a/src/Text/Pandoc/Error.hs b/src/Text/Pandoc/Error.hs index 434b37240..915fa04cb 100644 --- a/src/Text/Pandoc/Error.hs +++ b/src/Text/Pandoc/Error.hs @@ -52,6 +52,7 @@ data PandocError = PandocIOError Text IOError | PandocCouldNotFindMetadataFileError Text | PandocResourceNotFound Text | PandocTemplateError Text + | PandocNoTemplateError Text | PandocAppError Text | PandocEpubSubdirectoryError Text | PandocMacroLoop Text @@ -100,6 +101,7 @@ renderError e = PandocResourceNotFound fn -> "File " <> fn <> " not found in resource path" PandocTemplateError s -> "Error compiling template " <> s + PandocNoTemplateError fp -> "No template defined in " <> fp PandocAppError s -> s PandocEpubSubdirectoryError s -> "EPUB subdirectory name '" <> s <> "' contains illegal characters" @@ -174,6 +176,7 @@ handleError (Left e) = PandocSyntaxMapError{} -> 67 PandocFilterError{} -> 83 PandocLuaError{} -> 84 + PandocNoTemplateError{} -> 87 PandocNoScriptingEngine -> 89 PandocMacroLoop{} -> 91 PandocUTF8DecodingError{} -> 92 diff --git a/src/Text/Pandoc/Scripting.hs b/src/Text/Pandoc/Scripting.hs index 29027dd6d..1942014cb 100644 --- a/src/Text/Pandoc/Scripting.hs +++ b/src/Text/Pandoc/Scripting.hs @@ -23,7 +23,6 @@ import Text.Pandoc.Definition (Pandoc) import Text.Pandoc.Error (PandocError (PandocNoScriptingEngine)) import Text.Pandoc.Filter.Environment (Environment) import Text.Pandoc.Format (ExtensionsConfig) -import Text.Pandoc.Templates (Template) import Text.Pandoc.Readers (Reader) import Text.Pandoc.Writers (Writer) @@ -42,7 +41,7 @@ data ScriptingEngine = ScriptingEngine , engineWriteCustom :: forall m. (PandocMonad m, MonadIO m) => FilePath - -> m (Writer m, ExtensionsConfig, m (Template Text)) + -> m (Writer m, ExtensionsConfig, Maybe Text) -- ^ Invoke the given script file to convert to any custom format. } |
