pandoc/src/Text/Pandoc/Writers/Custom.hs

250 lines
7.6 KiB
Haskell
Raw Normal View History

{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleInstances #-}
#if MIN_VERSION_base(4,8,0)
#else
{-# LANGUAGE OverlappingInstances #-}
#endif
{- Copyright (C) 2012-2017 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
{- |
Module : Text.Pandoc.Writers.Custom
Copyright : Copyright (C) 2012-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
Stability : alpha
Portability : portable
Conversion of 'Pandoc' documents to custom markup using
a lua writer.
-}
module Text.Pandoc.Writers.Custom ( writeCustom ) where
import Control.Exception
import Control.Monad (when)
import Data.Char (toLower)
import Data.List (intersperse)
import qualified Data.Map as M
import Data.Text (Text, pack)
import Data.Typeable
2017-08-13 12:37:10 +02:00
import Foreign.Lua (Lua, ToLuaStack (..), callFunc, runLua)
import Foreign.Lua.Api
import GHC.IO.Encoding (getForeignEncoding, setForeignEncoding, utf8)
import Text.Pandoc.Definition
import Text.Pandoc.Error
import Text.Pandoc.Lua.Util (addValue)
import Text.Pandoc.Options
import Text.Pandoc.Templates
import qualified Text.Pandoc.UTF8 as UTF8
import Text.Pandoc.Writers.Shared
attrToMap :: Attr -> M.Map String String
attrToMap (id',classes,keyvals) = M.fromList
$ ("id", id')
: ("class", unwords classes)
: keyvals
instance ToLuaStack Double where
push = push . (realToFrac :: Double -> LuaNumber)
instance ToLuaStack Int where
push = push . (fromIntegral :: Int -> LuaInteger)
2017-08-13 12:37:10 +02:00
instance ToLuaStack Format where
push (Format f) = push (map toLower f)
2013-08-10 17:23:51 -07:00
2015-05-31 13:57:14 +02:00
#if MIN_VERSION_base(4,8,0)
2017-08-13 12:37:10 +02:00
instance {-# OVERLAPS #-} ToLuaStack [Inline] where
2015-05-31 13:57:14 +02:00
#else
2017-08-13 12:37:10 +02:00
instance ToLuaStack [Inline] where
2015-05-31 13:57:14 +02:00
#endif
2017-08-13 12:37:10 +02:00
push ils = push =<< inlineListToCustom ils
2015-05-31 13:57:14 +02:00
#if MIN_VERSION_base(4,8,0)
2017-08-13 12:37:10 +02:00
instance {-# OVERLAPS #-} ToLuaStack [Block] where
2015-05-31 13:57:14 +02:00
#else
2017-08-13 12:37:10 +02:00
instance ToLuaStack [Block] where
2015-05-31 13:57:14 +02:00
#endif
2017-08-13 12:37:10 +02:00
push ils = push =<< blockListToCustom ils
instance ToLuaStack MetaValue where
push (MetaMap m) = push m
push (MetaList xs) = push xs
push (MetaBool x) = push x
push (MetaString s) = push s
push (MetaInlines ils) = push ils
push (MetaBlocks bs) = push bs
instance ToLuaStack Citation where
push cit = do
createtable 6 0
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
data PandocLuaException = PandocLuaException String
deriving (Show, Typeable)
instance Exception PandocLuaException
-- | Convert Pandoc to custom markup.
writeCustom :: FilePath -> WriterOptions -> Pandoc -> IO Text
writeCustom luaFile opts doc@(Pandoc meta _) = do
luaScript <- UTF8.readFile luaFile
enc <- getForeignEncoding
setForeignEncoding utf8
2017-08-13 12:37:10 +02:00
(body, context) <- runLua $ do
openlibs
stat <- loadstring luaScript
-- check for error in lua script (later we'll change the return type
-- to handle this more gracefully):
when (stat /= OK) $
tostring 1 >>= throw . PandocLuaException . UTF8.toString
call 0 0
-- TODO - call hierarchicalize, so we have that info
2017-08-13 12:37:10 +02:00
rendered <- docToCustom opts doc
context <- metaToJSON opts
blockListToCustom
inlineListToCustom
meta
return (rendered, context)
setForeignEncoding enc
case writerTemplate opts of
Nothing -> return $ pack body
Just tpl ->
case applyTemplate (pack tpl) $ setField "body" body context of
Left e -> throw (PandocTemplateError e)
Right r -> return (pack r)
2017-08-13 12:37:10 +02:00
docToCustom :: WriterOptions -> Pandoc -> Lua String
docToCustom opts (Pandoc (Meta metamap) blocks) = do
body <- blockListToCustom blocks
callFunc "Doc" body metamap (writerVariables opts)
-- | Convert Pandoc block element to Custom.
2017-08-13 12:37:10 +02:00
blockToCustom :: Block -- ^ Block element
-> Lua String
2017-08-13 12:37:10 +02:00
blockToCustom Null = return ""
2017-08-13 12:37:10 +02:00
blockToCustom (Plain inlines) = callFunc "Plain" inlines
2017-08-13 12:37:10 +02:00
blockToCustom (Para [Image attr txt (src,tit)]) =
callFunc "CaptionedImage" src tit txt (attrToMap attr)
2017-08-13 12:37:10 +02:00
blockToCustom (Para inlines) = callFunc "Para" inlines
2017-08-13 12:37:10 +02:00
blockToCustom (LineBlock linesList) = callFunc "LineBlock" linesList
2017-08-13 12:37:10 +02:00
blockToCustom (RawBlock format str) =
callFunc "RawBlock" format str
2017-08-13 12:37:10 +02:00
blockToCustom HorizontalRule = callFunc "HorizontalRule"
2017-08-13 12:37:10 +02:00
blockToCustom (Header level attr inlines) =
callFunc "Header" level inlines (attrToMap attr)
2017-08-13 12:37:10 +02:00
blockToCustom (CodeBlock attr str) =
callFunc "CodeBlock" str (attrToMap attr)
2017-08-13 12:37:10 +02:00
blockToCustom (BlockQuote blocks) = callFunc "BlockQuote" blocks
2017-08-13 12:37:10 +02:00
blockToCustom (Table capt aligns widths headers rows') =
callFunc "Table" capt (map show aligns) widths headers rows'
2017-08-13 12:37:10 +02:00
blockToCustom (BulletList items) = callFunc "BulletList" items
2017-08-13 12:37:10 +02:00
blockToCustom (OrderedList (num,sty,delim) items) =
callFunc "OrderedList" items num (show sty) (show delim)
2017-08-13 12:37:10 +02:00
blockToCustom (DefinitionList items) =
callFunc "DefinitionList" items
2017-08-13 12:37:10 +02:00
blockToCustom (Div attr items) =
callFunc "Div" items (attrToMap attr)
-- | Convert list of Pandoc block elements to Custom.
2017-08-13 12:37:10 +02:00
blockListToCustom :: [Block] -- ^ List of block elements
-> Lua String
blockListToCustom xs = do
blocksep <- callFunc "Blocksep"
bs <- mapM blockToCustom xs
return $ mconcat $ intersperse blocksep bs
-- | Convert list of Pandoc inline elements to Custom.
2017-08-13 12:37:10 +02:00
inlineListToCustom :: [Inline] -> Lua String
inlineListToCustom lst = do
xs <- mapM inlineToCustom lst
return $ mconcat xs
-- | Convert Pandoc inline element to Custom.
2017-08-13 12:37:10 +02:00
inlineToCustom :: Inline -> Lua String
2017-08-13 12:37:10 +02:00
inlineToCustom (Str str) = callFunc "Str" str
2017-08-13 12:37:10 +02:00
inlineToCustom Space = callFunc "Space"
2017-08-13 12:37:10 +02:00
inlineToCustom SoftBreak = callFunc "SoftBreak"
2017-08-13 12:37:10 +02:00
inlineToCustom (Emph lst) = callFunc "Emph" lst
2017-08-13 12:37:10 +02:00
inlineToCustom (Strong lst) = callFunc "Strong" lst
2017-08-13 12:37:10 +02:00
inlineToCustom (Strikeout lst) = callFunc "Strikeout" lst
2017-08-13 12:37:10 +02:00
inlineToCustom (Superscript lst) = callFunc "Superscript" lst
2017-08-13 12:37:10 +02:00
inlineToCustom (Subscript lst) = callFunc "Subscript" lst
2017-08-13 12:37:10 +02:00
inlineToCustom (SmallCaps lst) = callFunc "SmallCaps" lst
2017-08-13 12:37:10 +02:00
inlineToCustom (Quoted SingleQuote lst) = callFunc "SingleQuoted" lst
2017-08-13 12:37:10 +02:00
inlineToCustom (Quoted DoubleQuote lst) = callFunc "DoubleQuoted" lst
2017-08-13 12:37:10 +02:00
inlineToCustom (Cite cs lst) = callFunc "Cite" lst cs
2017-08-13 12:37:10 +02:00
inlineToCustom (Code attr str) =
callFunc "Code" str (attrToMap attr)
2017-08-13 12:37:10 +02:00
inlineToCustom (Math DisplayMath str) =
callFunc "DisplayMath" str
2017-08-13 12:37:10 +02:00
inlineToCustom (Math InlineMath str) =
callFunc "InlineMath" str
2017-08-13 12:37:10 +02:00
inlineToCustom (RawInline format str) =
callFunc "RawInline" format str
2017-08-13 12:37:10 +02:00
inlineToCustom (LineBreak) = callFunc "LineBreak"
2017-08-13 12:37:10 +02:00
inlineToCustom (Link attr txt (src,tit)) =
callFunc "Link" txt src tit (attrToMap attr)
2017-08-13 12:37:10 +02:00
inlineToCustom (Image attr alt (src,tit)) =
callFunc "Image" alt src tit (attrToMap attr)
2017-08-13 12:37:10 +02:00
inlineToCustom (Note contents) = callFunc "Note" contents
2017-08-13 12:37:10 +02:00
inlineToCustom (Span attr items) =
callFunc "Span" items (attrToMap attr)