git.iko.soy/typeable/pandoc
on master help sign in
Lua module: add readers submodule

Plain text readers are exposed to lua scripts via the `pandoc.reader` submodule, which is further subdivided by format. Converting e.g. a markdown string into a pandoc document is possible from within lua: doc = pandoc.reader.markdown.read_doc("Hello, World!") A `read_block` convenience function is provided for all formats, although it will still parse the whole string but return only the first block as the result. Custom reader options are not supported yet, default options are used for all parsing operations.

commite7eb21ecca46daaf240e33584c55b9d5101eebc7 authorAlbert Krewinkel <albert@zeitkraut.de> dateSun 2 Apr 2017, 17:21 (10 years ago) parent9e78a9d
6 files changed+172−32
pandoc.cabal+4−2 src/Text/Pandoc/Lua.hs+3−28 src/Text/Pandoc/Lua/PandocModule.hs+72−2 src/Text/Pandoc/Lua/StackInstances.hs+75 test/Tests/Lua.hs+6 test/lua/markdown-reader.lua+12
pandoc.cabal+4−2
@@ -247,9 +247,10 @@ Extra-Source-Files:
247247 test/odt/odt/*.odt
248248 test/odt/markdown/*.md
249249 test/odt/native/*.native
250− test/lua/strmacro.lua
251− test/lua/plain-to-para.lua
252250 test/lua/hello-world-doc.lua
251+ test/lua/markdown-reader.lua
252+ test/lua/plain-to-para.lua
253+ test/lua/strmacro.lua
253254Source-repository head
254255 type: git
255256 location: git://github.com/jgm/pandoc.git
@@ -458,6 +459,7 @@ Library
458459 Text.Pandoc.Readers.Org.Shared,
459460 Text.Pandoc.Lua.Compat,
460461 Text.Pandoc.Lua.PandocModule,
462+ Text.Pandoc.Lua.StackInstances,
461463 Text.Pandoc.CSS,
462464 Text.Pandoc.UUID,
463465 Text.Pandoc.Slides,
src/Text/Pandoc/Lua.hs+3−28
@@ -15,11 +15,7 @@ You should have received a copy of the GNU General Public License
1515along with this program; if not, write to the Free Software
1616Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1717-}
18−{-# LANGUAGE FlexibleContexts #-}
19−{-# LANGUAGE LambdaCase #-}
2018{-# LANGUAGE OverloadedStrings #-}
21−{-# LANGUAGE ScopedTypeVariables #-}
22−{-# OPTIONS_GHC -fno-warn-orphans #-}
2319{- |
2420 Module : Text.Pandoc.Lua
2521 Copyright : Copyright © 2017 Albert Krewinkel
@@ -34,24 +30,23 @@ module Text.Pandoc.Lua ( runLuaFilter ) where
3430
3531import Control.Monad ( (>=>), when )
3632import Control.Monad.Trans ( MonadIO(..) )
37−import Data.Aeson ( FromJSON(..), ToJSON(..), Result(..), Value, fromJSON )
3833import Data.HashMap.Lazy ( HashMap )
3934import Data.Text ( Text, pack, unpack )
4035import Data.Text.Encoding ( decodeUtf8 )
4136import Scripting.Lua ( LuaState, StackValue(..) )
42−import Scripting.Lua.Aeson ()
37+import Scripting.Lua.Aeson ( newstate )
4338import Text.Pandoc.Definition ( Block(..), Inline(..), Pandoc(..) )
4439import Text.Pandoc.Lua.PandocModule
40+import Text.Pandoc.Lua.StackInstances ()
4541import Text.Pandoc.Walk
4642
4743import qualified Data.HashMap.Lazy as HashMap
4844import qualified Scripting.Lua as Lua
49−import qualified Scripting.Lua as LuaAeson
5045
5146runLuaFilter :: (MonadIO m)
5247 => FilePath -> [String] -> Pandoc -> m Pandoc
5348runLuaFilter filterPath args pd = liftIO $ do
54− lua <- LuaAeson.newstate
49+ lua <- newstate
5550 Lua.openlibs lua
5651 Lua.newtable lua
5752 Lua.setglobal lua "PANDOC_FILTER_FUNCTIONS" -- hack, store functions here
@@ -204,23 +199,3 @@ isLuaFunction lua fnName = do
204199 res <- Lua.isfunction lua (-1)
205200 Lua.pop lua (-1)
206201 return res
207−
208−maybeFromJson :: (FromJSON a) => Maybe Value -> Maybe a
209−maybeFromJson mv = fromJSON <$> mv >>= \case
210− Success x -> Just x
211− _ -> Nothing
212−
213−instance StackValue Pandoc where
214− push lua = Lua.push lua . toJSON
215− peek lua i = maybeFromJson <$> peek lua i
216− valuetype _ = Lua.TTABLE
217−
218−instance StackValue Block where
219− push lua = Lua.push lua . toJSON
220− peek lua i = maybeFromJson <$> peek lua i
221− valuetype _ = Lua.TTABLE
222−
223−instance StackValue Inline where
224− push lua = Lua.push lua . toJSON
225− peek lua i = maybeFromJson <$> peek lua i
226− valuetype _ = Lua.TTABLE
src/Text/Pandoc/Lua/PandocModule.hs+72−2
@@ -28,11 +28,25 @@ Pandoc module for lua.
2828module Text.Pandoc.Lua.PandocModule ( pushPandocModule ) where
2929
3030import Data.ByteString.Char8 ( unpack )
31−import Scripting.Lua ( LuaState, call)
31+import Data.Default ( Default(..) )
32+import Scripting.Lua ( LuaState, call, newtable, push, pushhsfunction, rawset)
33+import Text.Pandoc.Class hiding ( readDataFile )
34+import Text.Pandoc.Definition ( Pandoc(..), Block(..) )
3235import Text.Pandoc.Lua.Compat ( loadstring )
36+import Text.Pandoc.Lua.StackInstances ()
37+import Text.Pandoc.Readers.DocBook ( readDocBook )
38+import Text.Pandoc.Readers.HTML ( readHtml )
39+import Text.Pandoc.Readers.LaTeX ( readLaTeX )
40+import Text.Pandoc.Readers.Native ( readNative )
41+import Text.Pandoc.Readers.Markdown ( readMarkdown )
42+import Text.Pandoc.Readers.MediaWiki ( readMediaWiki )
43+import Text.Pandoc.Readers.Org ( readOrg )
44+import Text.Pandoc.Readers.RST ( readRST )
45+import Text.Pandoc.Readers.Textile ( readTextile )
46+import Text.Pandoc.Readers.TWiki ( readTWiki )
47+import Text.Pandoc.Readers.Txt2Tags ( readTxt2Tags )
3348import Text.Pandoc.Shared ( readDataFile )
3449
35−
3650-- | Push the "pandoc" on the lua stack.
3751pushPandocModule :: LuaState -> IO ()
3852pushPandocModule lua = do
@@ -42,7 +56,63 @@ pushPandocModule lua = do
4256 then return ()
4357 else do
4458 call lua 0 1
59+ push lua "reader"
60+ pushReadersModule lua readers
61+ rawset lua (-3)
62+
63+readers :: [(String, String -> PandocIO Pandoc)]
64+readers =
65+ [ ("docbook", readDocBook def)
66+ , ("html", readHtml def)
67+ , ("latex", readLaTeX def)
68+ , ("native", readNative def)
69+ , ("markdown", readMarkdown def)
70+ , ("mediawiki", readMediaWiki def)
71+ , ("org", readOrg def)
72+ , ("rst", readRST def)
73+ , ("textile", readTextile def)
74+ , ("twiki", readTWiki def)
75+ , ("txt2tags", readTxt2Tags def)
76+ ]
4577
4678-- | Get the string representation of the pandoc module
4779pandocModuleScript :: IO String
4880pandocModuleScript = unpack <$> readDataFile Nothing "pandoc.lua"
81+
82+-- | Push a lua table containing readers of the given formats.
83+pushReadersModule :: LuaState
84+ -> [(String, String -> PandocIO Pandoc)]
85+ -> IO ()
86+pushReadersModule lua readerFns = do
87+ newtable lua
88+ mapM_ (uncurry $ addReaderTable) readerFns
89+ where
90+ addReaderTable :: String
91+ -> (String -> PandocIO Pandoc)
92+ -> IO ()
93+ addReaderTable formatName readerFn = do
94+ let readDoc :: String -> IO Pandoc
95+ readDoc s = do
96+ res <- runIO $ readerFn s
97+ case res of
98+ (Left x) -> error (show x)
99+ (Right x) -> return x
100+ let readBlock :: String -> IO Block
101+ readBlock s = do
102+ Pandoc _ blks <- readDoc s
103+ return $ case blks of
104+ x:_ -> x
105+ _ -> Null
106+ -- Push table containing all functions for this format
107+ push lua formatName
108+ newtable lua
109+ -- set document-reading function
110+ push lua "read_doc"
111+ pushhsfunction lua readDoc
112+ rawset lua (-3)
113+ -- set block-reading function
114+ push lua "read_block"
115+ pushhsfunction lua readBlock
116+ rawset lua (-3)
117+ -- store table in readers module
118+ rawset lua (-3)
src/Text/Pandoc/Lua/StackInstances.hsnew file+75
@@ -0,0 +1,75 @@
1+{-
2+Copyright © 2012-2015 John MacFarlane <jgm@berkeley.edu>
3+ 2017 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
4+
5+This program is free software; you can redistribute it and/or modify
6+it under the terms of the GNU General Public License as published by
7+the Free Software Foundation; either version 2 of the License, or
8+(at your option) any later version.
9+
10+This program is distributed in the hope that it will be useful,
11+but WITHOUT ANY WARRANTY; without even the implied warranty of
12+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+GNU General Public License for more details.
14+
15+You should have received a copy of the GNU General Public License
16+along with this program; if not, write to the Free Software
17+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18+-}
19+{-# LANGUAGE CPP #-}
20+{-# LANGUAGE FlexibleInstances #-}
21+{-# LANGUAGE LambdaCase #-}
22+#if !MIN_VERSION_base(4,8,0)
23+{-# LANGUAGE OverlappingInstances #-}
24+#endif
25+{-# OPTIONS_GHC -fno-warn-orphans #-}
26+{- |
27+ Module : Text.Pandoc.Lua.StackInstances
28+ Copyright : Copyright © 2017 Albert Krewinkel
29+ License : GNU GPL, version 2 or above
30+
31+ Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
32+ Stability : alpha
33+
34+StackValue instances for pandoc types.
35+-}
36+module Text.Pandoc.Lua.StackInstances () where
37+
38+import Data.Aeson ( FromJSON(..), ToJSON(..), Result(..), Value, fromJSON )
39+import Scripting.Lua ( StackValue(..) )
40+import Scripting.Lua.Aeson ()
41+import Text.Pandoc.Definition ( Block(..), Inline(..), Pandoc(..) )
42+
43+import qualified Scripting.Lua as Lua
44+import qualified Text.Pandoc.UTF8 as UTF8
45+
46+maybeFromJson :: (FromJSON a) => Maybe Value -> Maybe a
47+maybeFromJson mv = fromJSON <$> mv >>= \case
48+ Success x -> Just x
49+ _ -> Nothing
50+
51+instance StackValue Pandoc where
52+ push lua = Lua.push lua . toJSON
53+ peek lua i = maybeFromJson <$> peek lua i
54+ valuetype _ = Lua.TTABLE
55+
56+instance StackValue Block where
57+ push lua = Lua.push lua . toJSON
58+ peek lua i = maybeFromJson <$> peek lua i
59+ valuetype _ = Lua.TTABLE
60+
61+instance StackValue Inline where
62+ push lua = Lua.push lua . toJSON
63+ peek lua i = maybeFromJson <$> peek lua i
64+ valuetype _ = Lua.TTABLE
65+
66+#if MIN_VERSION_base(4,8,0)
67+instance {-# OVERLAPS #-} StackValue [Char] where
68+#else
69+instance StackValue [Char] where
70+#endif
71+ push lua cs = Lua.push lua (UTF8.fromString cs)
72+ peek lua i = do
73+ res <- Lua.peek lua i
74+ return $ UTF8.toString `fmap` res
75+ valuetype _ = Lua.TSTRING
test/Tests/Lua.hs+6
@@ -26,6 +26,12 @@ tests =
2626 "hello-world-doc.lua"
2727 (doc . para $ str "Hey!" <> linebreak <> str "What's up?")
2828 (doc . para $ str "Hello," <> space <> str "World!")
29+
30+ , testCase "parse raw markdown blocks" $
31+ assertFilterConversion "raw markdown block is converted"
32+ "markdown-reader.lua"
33+ (doc $ rawBlock "markdown" "*charly* **delta**")
34+ (doc . para $ emph "charly" <> space <> strong "delta")
2935 ]
3036
3137assertFilterConversion :: String -> FilePath -> Pandoc -> Pandoc -> Assertion
test/lua/markdown-reader.luanew file+12
@@ -0,0 +1,12 @@
1+return {
2+ {
3+ RawBlock = function (blk)
4+ local format, content = unpack(blk.c)
5+ if format == "markdown" then
6+ return pandoc.reader.markdown.read_block(content)
7+ else
8+ return blk
9+ end
10+ end,
11+ }
12+}