#if MIN_VERSION_base(4,8,0)
#else
#endif
module Text.Pandoc.Writers.Custom ( writeCustom ) where
import Text.Pandoc.Definition
import Text.Pandoc.Options
import Data.List ( intersperse )
import Data.Char ( toLower )
import Data.Typeable
import Scripting.Lua (LuaState, StackValue, callfunc)
import Text.Pandoc.Writers.Shared
import qualified Scripting.Lua as Lua
import qualified Text.Pandoc.UTF8 as UTF8
import Control.Monad (when)
import Control.Exception
import qualified Data.Map as M
import Text.Pandoc.Templates
import GHC.IO.Encoding (getForeignEncoding,setForeignEncoding, utf8)
attrToMap :: Attr -> M.Map String String
attrToMap (id',classes,keyvals) = M.fromList
$ ("id", id')
: ("class", unwords classes)
: keyvals
#if MIN_VERSION_hslua(0,4,0)
#if MIN_VERSION_base(4,8,0)
instance StackValue [Char] where
#else
instance StackValue [Char] where
#endif
push lua cs = Lua.push lua (UTF8.fromString cs)
peek lua i = do
res <- Lua.peek lua i
return $ UTF8.toString `fmap` res
valuetype _ = Lua.TSTRING
#else
#if MIN_VERSION_base(4,8,0)
instance StackValue a => StackValue [a] where
#else
instance StackValue a => StackValue [a] where
#endif
push lua xs = do
Lua.createtable lua (length xs + 1) 0
let addValue (i, x) = Lua.push lua x >> Lua.rawseti lua (2) i
mapM_ addValue $ zip [1..] xs
peek lua i = do
top <- Lua.gettop lua
let i' = if i < 0 then top + i + 1 else i
Lua.pushnil lua
lst <- getList lua i'
Lua.pop lua 1
return (Just lst)
valuetype _ = Lua.TTABLE
getList :: StackValue a => LuaState -> Int -> IO [a]
getList lua i' = do
continue <- Lua.next lua i'
if continue
then do
next <- Lua.peek lua (1)
Lua.pop lua 1
x <- maybe (fail "peek returned Nothing") return next
rest <- getList lua i'
return (x : rest)
else return []
#endif
instance StackValue Format where
push lua (Format f) = Lua.push lua (map toLower f)
peek l n = fmap Format `fmap` Lua.peek l n
valuetype _ = Lua.TSTRING
instance (StackValue a, StackValue b) => StackValue (M.Map a b) where
push lua m = do
let xs = M.toList m
Lua.createtable lua (length xs + 1) 0
let addValue (k, v) = Lua.push lua k >> Lua.push lua v >>
Lua.rawset lua (3)
mapM_ addValue xs
peek _ _ = undefined
valuetype _ = Lua.TTABLE
instance (StackValue a, StackValue b) => StackValue (a,b) where
push lua (k,v) = do
Lua.createtable lua 2 0
Lua.push lua k
Lua.push lua v
Lua.rawset lua (3)
peek _ _ = undefined
valuetype _ = Lua.TTABLE
#if MIN_VERSION_base(4,8,0)
instance StackValue [Inline] where
#else
instance StackValue [Inline] where
#endif
push l ils = Lua.push l =<< inlineListToCustom l ils
peek _ _ = undefined
valuetype _ = Lua.TSTRING
#if MIN_VERSION_base(4,8,0)
instance StackValue [Block] where
#else
instance StackValue [Block] where
#endif
push l ils = Lua.push l =<< blockListToCustom l ils
peek _ _ = undefined
valuetype _ = Lua.TSTRING
instance StackValue MetaValue where
push l (MetaMap m) = Lua.push l m
push l (MetaList xs) = Lua.push l xs
push l (MetaBool x) = Lua.push l x
push l (MetaString s) = Lua.push l s
push l (MetaInlines ils) = Lua.push l ils
push l (MetaBlocks bs) = Lua.push l bs
peek _ _ = undefined
valuetype (MetaMap _) = Lua.TTABLE
valuetype (MetaList _) = Lua.TTABLE
valuetype (MetaBool _) = Lua.TBOOLEAN
valuetype (MetaString _) = Lua.TSTRING
valuetype (MetaInlines _) = Lua.TSTRING
valuetype (MetaBlocks _) = Lua.TSTRING
instance StackValue Citation where
push lua cit = do
Lua.createtable lua 6 0
let addValue (k :: String, v) = Lua.push lua k >> Lua.push lua v >>
Lua.rawset lua (3)
addValue ("citationId", citationId cit)
addValue ("citationPrefix", citationPrefix cit)
addValue ("citationSuffix", citationSuffix cit)
addValue ("citationMode", show (citationMode cit))
addValue ("citationNoteNum", citationNoteNum cit)
addValue ("citationHash", citationHash cit)
peek = undefined
valuetype _ = Lua.TTABLE
data PandocLuaException = PandocLuaException String
deriving (Show, Typeable)
instance Exception PandocLuaException
writeCustom :: FilePath -> WriterOptions -> Pandoc -> IO String
writeCustom luaFile opts doc@(Pandoc meta _) = do
luaScript <- UTF8.readFile luaFile
enc <- getForeignEncoding
setForeignEncoding utf8
lua <- Lua.newstate
Lua.openlibs lua
status <- Lua.loadstring lua luaScript luaFile
when (status /= 0) $
#if MIN_VERSION_hslua(0,4,0)
Lua.tostring lua 1 >>= throw . PandocLuaException . UTF8.toString
#else
Lua.tostring lua 1 >>= throw . PandocLuaException
#endif
Lua.call lua 0 0
rendered <- docToCustom lua opts doc
context <- metaToJSON opts
(blockListToCustom lua)
(inlineListToCustom lua)
meta
Lua.close lua
setForeignEncoding enc
let body = rendered
if writerStandalone opts
then do
let context' = setField "body" body context
return $ renderTemplate' (writerTemplate opts) context'
else return body
docToCustom :: LuaState -> WriterOptions -> Pandoc -> IO String
docToCustom lua opts (Pandoc (Meta metamap) blocks) = do
body <- blockListToCustom lua blocks
callfunc lua "Doc" body metamap (writerVariables opts)
blockToCustom :: LuaState
-> Block
-> IO String
blockToCustom _ Null = return ""
blockToCustom lua (Plain inlines) = callfunc lua "Plain" inlines
blockToCustom lua (Para [Image attr txt (src,tit)]) =
callfunc lua "CaptionedImage" src tit txt (attrToMap attr)
blockToCustom lua (Para inlines) = callfunc lua "Para" inlines
blockToCustom lua (RawBlock format str) =
callfunc lua "RawBlock" format str
blockToCustom lua HorizontalRule = callfunc lua "HorizontalRule"
blockToCustom lua (Header level attr inlines) =
callfunc lua "Header" level inlines (attrToMap attr)
blockToCustom lua (CodeBlock attr str) =
callfunc lua "CodeBlock" str (attrToMap attr)
blockToCustom lua (BlockQuote blocks) = callfunc lua "BlockQuote" blocks
blockToCustom lua (Table capt aligns widths headers rows') =
callfunc lua "Table" capt (map show aligns) widths headers rows'
blockToCustom lua (BulletList items) = callfunc lua "BulletList" items
blockToCustom lua (OrderedList (num,sty,delim) items) =
callfunc lua "OrderedList" items num (show sty) (show delim)
blockToCustom lua (DefinitionList items) =
callfunc lua "DefinitionList" items
blockToCustom lua (Div attr items) =
callfunc lua "Div" items (attrToMap attr)
blockListToCustom :: LuaState
-> [Block]
-> IO String
blockListToCustom lua xs = do
blocksep <- callfunc lua "Blocksep"
bs <- mapM (blockToCustom lua) xs
return $ mconcat $ intersperse blocksep bs
inlineListToCustom :: LuaState -> [Inline] -> IO String
inlineListToCustom lua lst = do
xs <- mapM (inlineToCustom lua) lst
return $ concat xs
inlineToCustom :: LuaState -> Inline -> IO String
inlineToCustom lua (Str str) = callfunc lua "Str" str
inlineToCustom lua Space = callfunc lua "Space"
inlineToCustom lua SoftBreak = callfunc lua "SoftBreak"
inlineToCustom lua (Emph lst) = callfunc lua "Emph" lst
inlineToCustom lua (Strong lst) = callfunc lua "Strong" lst
inlineToCustom lua (Strikeout lst) = callfunc lua "Strikeout" lst
inlineToCustom lua (Superscript lst) = callfunc lua "Superscript" lst
inlineToCustom lua (Subscript lst) = callfunc lua "Subscript" lst
inlineToCustom lua (SmallCaps lst) = callfunc lua "SmallCaps" lst
inlineToCustom lua (Quoted SingleQuote lst) = callfunc lua "SingleQuoted" lst
inlineToCustom lua (Quoted DoubleQuote lst) = callfunc lua "DoubleQuoted" lst
inlineToCustom lua (Cite cs lst) = callfunc lua "Cite" lst cs
inlineToCustom lua (Code attr str) =
callfunc lua "Code" str (attrToMap attr)
inlineToCustom lua (Math DisplayMath str) =
callfunc lua "DisplayMath" str
inlineToCustom lua (Math InlineMath str) =
callfunc lua "InlineMath" str
inlineToCustom lua (RawInline format str) =
callfunc lua "RawInline" format str
inlineToCustom lua (LineBreak) = callfunc lua "LineBreak"
inlineToCustom lua (Link attr txt (src,tit)) =
callfunc lua "Link" txt src tit (attrToMap attr)
inlineToCustom lua (Image attr alt (src,tit)) =
callfunc lua "Image" alt src tit (attrToMap attr)
inlineToCustom lua (Note contents) = callfunc lua "Note" contents
inlineToCustom lua (Span attr items) =
callfunc lua "Span" items (attrToMap attr)