{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Text.Pandoc.Lua.Module.Utils
( pushModule
) where
import Control.Applicative ((<|>))
import Control.Monad.Catch (try)
import Data.Data (showConstr, toConstr)
import Data.Default (def)
import Data.Version (Version)
import Foreign.Lua (Peekable, Lua, NumResults (..))
import Text.Pandoc.Definition
import Text.Pandoc.Error (PandocError)
import Text.Pandoc.Lua.Marshaling ()
import Text.Pandoc.Lua.Marshaling.SimpleTable
( SimpleTable (..)
, pushSimpleTable
)
import Text.Pandoc.Lua.PandocLua (PandocLua, addFunction, liftPandocLua)
import qualified Data.Digest.Pure.SHA as SHA
import qualified Data.ByteString.Lazy as BSL
import qualified Data.Text as T
import qualified Foreign.Lua as Lua
import qualified Text.Pandoc.Builder as B
import qualified Text.Pandoc.Filter.JSON as JSONFilter
import qualified Text.Pandoc.Shared as Shared
import qualified Text.Pandoc.Writers.Shared as Shared
pushModule :: PandocLua NumResults
pushModule :: PandocLua NumResults
pushModule = do
Lua () -> PandocLua ()
forall a. Lua a -> PandocLua a
liftPandocLua Lua ()
Lua.newtable
String
-> ([Block] -> Optional [Inline] -> PandocLua [Inline])
-> PandocLua ()
forall a. ToHaskellFunction a => String -> a -> PandocLua ()
addFunction String
"blocks_to_inlines" [Block] -> Optional [Inline] -> PandocLua [Inline]
blocksToInlines
String
-> (AstElement -> AstElement -> PandocLua Bool) -> PandocLua ()
forall a. ToHaskellFunction a => String -> a -> PandocLua ()
addFunction String
"equals" AstElement -> AstElement -> PandocLua Bool
equals
String -> (SimpleTable -> Lua NumResults) -> PandocLua ()
forall a. ToHaskellFunction a => String -> a -> PandocLua ()
addFunction String
"from_simple_table" SimpleTable -> Lua NumResults
from_simple_table
String
-> (Bool -> Optional Int -> [Block] -> Lua [Block]) -> PandocLua ()
forall a. ToHaskellFunction a => String -> a -> PandocLua ()
addFunction String
"make_sections" Bool -> Optional Int -> [Block] -> Lua [Block]
makeSections
String -> (Text -> Lua (Optional Text)) -> PandocLua ()
forall a. ToHaskellFunction a => String -> a -> PandocLua ()
addFunction String
"normalize_date" Text -> Lua (Optional Text)
normalizeDate
String
-> (Pandoc -> String -> Optional [String] -> PandocLua Pandoc)
-> PandocLua ()
forall a. ToHaskellFunction a => String -> a -> PandocLua ()
addFunction String
"run_json_filter" Pandoc -> String -> Optional [String] -> PandocLua Pandoc
runJSONFilter
String -> (ByteString -> Lua Text) -> PandocLua ()
forall a. ToHaskellFunction a => String -> a -> PandocLua ()
addFunction String
"sha1" ByteString -> Lua Text
sha1
String -> (AstElement -> PandocLua Text) -> PandocLua ()
forall a. ToHaskellFunction a => String -> a -> PandocLua ()
addFunction String
"stringify" AstElement -> PandocLua Text
stringify
String -> (Integer -> PandocLua Text) -> PandocLua ()
forall a. ToHaskellFunction a => String -> a -> PandocLua ()
addFunction String
"to_roman_numeral" Integer -> PandocLua Text
toRomanNumeral
String -> (Block -> Lua NumResults) -> PandocLua ()
forall a. ToHaskellFunction a => String -> a -> PandocLua ()
addFunction String
"to_simple_table" Block -> Lua NumResults
to_simple_table
String -> (Version -> Lua Version) -> PandocLua ()
forall a. ToHaskellFunction a => String -> a -> PandocLua ()
addFunction String
"Version" (Version -> Lua Version
forall (m :: * -> *) a. Monad m => a -> m a
return :: Version -> Lua Version)
NumResults -> PandocLua NumResults
forall (m :: * -> *) a. Monad m => a -> m a
return NumResults
1
blocksToInlines :: [Block] -> Lua.Optional [Inline] -> PandocLua [Inline]
blocksToInlines :: [Block] -> Optional [Inline] -> PandocLua [Inline]
blocksToInlines [Block]
blks Optional [Inline]
optSep = Lua [Inline] -> PandocLua [Inline]
forall a. Lua a -> PandocLua a
liftPandocLua (Lua [Inline] -> PandocLua [Inline])
-> Lua [Inline] -> PandocLua [Inline]
forall a b. (a -> b) -> a -> b
$ do
let sep :: Inlines
sep = Inlines -> ([Inline] -> Inlines) -> Maybe [Inline] -> Inlines
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Inlines
Shared.defaultBlocksSeparator [Inline] -> Inlines
forall a. [a] -> Many a
B.fromList
(Maybe [Inline] -> Inlines) -> Maybe [Inline] -> Inlines
forall a b. (a -> b) -> a -> b
$ Optional [Inline] -> Maybe [Inline]
forall a. Optional a -> Maybe a
Lua.fromOptional Optional [Inline]
optSep
[Inline] -> Lua [Inline]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Inline] -> Lua [Inline]) -> [Inline] -> Lua [Inline]
forall a b. (a -> b) -> a -> b
$ Inlines -> [Inline]
forall a. Many a -> [a]
B.toList (Inlines -> [Block] -> Inlines
Shared.blocksToInlinesWithSep Inlines
sep [Block]
blks)
makeSections :: Bool -> Lua.Optional Int -> [Block] -> Lua [Block]
makeSections :: Bool -> Optional Int -> [Block] -> Lua [Block]
makeSections Bool
number Optional Int
baselevel =
[Block] -> Lua [Block]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Block] -> Lua [Block])
-> ([Block] -> [Block]) -> [Block] -> Lua [Block]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> Maybe Int -> [Block] -> [Block]
Shared.makeSections Bool
number (Optional Int -> Maybe Int
forall a. Optional a -> Maybe a
Lua.fromOptional Optional Int
baselevel)
normalizeDate :: T.Text -> Lua (Lua.Optional T.Text)
normalizeDate :: Text -> Lua (Optional Text)
normalizeDate = Optional Text -> Lua (Optional Text)
forall (m :: * -> *) a. Monad m => a -> m a
return (Optional Text -> Lua (Optional Text))
-> (Text -> Optional Text) -> Text -> Lua (Optional Text)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe Text -> Optional Text
forall a. Maybe a -> Optional a
Lua.Optional (Maybe Text -> Optional Text)
-> (Text -> Maybe Text) -> Text -> Optional Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Maybe Text
Shared.normalizeDate
runJSONFilter :: Pandoc
-> FilePath
-> Lua.Optional [String]
-> PandocLua Pandoc
runJSONFilter :: Pandoc -> String -> Optional [String] -> PandocLua Pandoc
runJSONFilter Pandoc
doc String
filterFile Optional [String]
optArgs = do
[String]
args <- case Optional [String] -> Maybe [String]
forall a. Optional a -> Maybe a
Lua.fromOptional Optional [String]
optArgs of
Just [String]
x -> [String] -> PandocLua [String]
forall (m :: * -> *) a. Monad m => a -> m a
return [String]
x
Maybe [String]
Nothing -> Lua [String] -> PandocLua [String]
forall a. Lua a -> PandocLua a
liftPandocLua (Lua [String] -> PandocLua [String])
-> Lua [String] -> PandocLua [String]
forall a b. (a -> b) -> a -> b
$ do
String -> Lua ()
Lua.getglobal String
"FORMAT"
(String -> [String] -> [String]
forall a. a -> [a] -> [a]
:[]) (String -> [String]) -> Lua String -> Lua [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Lua String
forall a. Peekable a => Lua a
Lua.popValue
ReaderOptions -> [String] -> String -> Pandoc -> PandocLua Pandoc
forall (m :: * -> *).
MonadIO m =>
ReaderOptions -> [String] -> String -> Pandoc -> m Pandoc
JSONFilter.apply ReaderOptions
forall a. Default a => a
def [String]
args String
filterFile Pandoc
doc
sha1 :: BSL.ByteString
-> Lua T.Text
sha1 :: ByteString -> Lua Text
sha1 = Text -> Lua Text
forall (m :: * -> *) a. Monad m => a -> m a
return (Text -> Lua Text)
-> (ByteString -> Text) -> ByteString -> Lua Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
T.pack (String -> Text) -> (ByteString -> String) -> ByteString -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Digest SHA1State -> String
forall t. Digest t -> String
SHA.showDigest (Digest SHA1State -> String)
-> (ByteString -> Digest SHA1State) -> ByteString -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Digest SHA1State
SHA.sha1
stringify :: AstElement -> PandocLua T.Text
stringify :: AstElement -> PandocLua Text
stringify AstElement
el = Text -> PandocLua Text
forall (m :: * -> *) a. Monad m => a -> m a
return (Text -> PandocLua Text) -> Text -> PandocLua Text
forall a b. (a -> b) -> a -> b
$ case AstElement
el of
PandocElement Pandoc
pd -> Pandoc -> Text
forall a. Walkable Inline a => a -> Text
Shared.stringify Pandoc
pd
InlineElement Inline
i -> Inline -> Text
forall a. Walkable Inline a => a -> Text
Shared.stringify Inline
i
BlockElement Block
b -> Block -> Text
forall a. Walkable Inline a => a -> Text
Shared.stringify Block
b
MetaElement Meta
m -> Meta -> Text
forall a. Walkable Inline a => a -> Text
Shared.stringify Meta
m
CitationElement Citation
c -> Citation -> Text
forall a. Walkable Inline a => a -> Text
Shared.stringify Citation
c
MetaValueElement MetaValue
m -> MetaValue -> Text
stringifyMetaValue MetaValue
m
AstElement
_ -> Text
forall a. Monoid a => a
mempty
stringifyMetaValue :: MetaValue -> T.Text
stringifyMetaValue :: MetaValue -> Text
stringifyMetaValue MetaValue
mv = case MetaValue
mv of
MetaBool Bool
b -> Text -> Text
T.toLower (Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack (Bool -> String
forall a. Show a => a -> String
show Bool
b)
MetaString Text
s -> Text
s
MetaValue
_ -> MetaValue -> Text
forall a. Walkable Inline a => a -> Text
Shared.stringify MetaValue
mv
equals :: AstElement -> AstElement -> PandocLua Bool
equals :: AstElement -> AstElement -> PandocLua Bool
equals AstElement
e1 AstElement
e2 = Bool -> PandocLua Bool
forall (m :: * -> *) a. Monad m => a -> m a
return (AstElement
e1 AstElement -> AstElement -> Bool
forall a. Eq a => a -> a -> Bool
== AstElement
e2)
data AstElement
= PandocElement Pandoc
| MetaElement Meta
| BlockElement Block
| InlineElement Inline
| MetaValueElement MetaValue
| AttrElement Attr
| ListAttributesElement ListAttributes
| CitationElement Citation
deriving (AstElement -> AstElement -> Bool
(AstElement -> AstElement -> Bool)
-> (AstElement -> AstElement -> Bool) -> Eq AstElement
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: AstElement -> AstElement -> Bool
$c/= :: AstElement -> AstElement -> Bool
== :: AstElement -> AstElement -> Bool
$c== :: AstElement -> AstElement -> Bool
Eq, Int -> AstElement -> ShowS
[AstElement] -> ShowS
AstElement -> String
(Int -> AstElement -> ShowS)
-> (AstElement -> String)
-> ([AstElement] -> ShowS)
-> Show AstElement
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [AstElement] -> ShowS
$cshowList :: [AstElement] -> ShowS
show :: AstElement -> String
$cshow :: AstElement -> String
showsPrec :: Int -> AstElement -> ShowS
$cshowsPrec :: Int -> AstElement -> ShowS
Show)
instance Peekable AstElement where
peek :: StackIndex -> Lua AstElement
peek StackIndex
idx = do
Either PandocError AstElement
res <- Lua AstElement -> Lua (Either PandocError AstElement)
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
m a -> m (Either e a)
try (Lua AstElement -> Lua (Either PandocError AstElement))
-> Lua AstElement -> Lua (Either PandocError AstElement)
forall a b. (a -> b) -> a -> b
$ (Pandoc -> AstElement
PandocElement (Pandoc -> AstElement) -> Lua Pandoc -> Lua AstElement
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StackIndex -> Lua Pandoc
forall a. Peekable a => StackIndex -> Lua a
Lua.peek StackIndex
idx)
Lua AstElement -> Lua AstElement -> Lua AstElement
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (Inline -> AstElement
InlineElement (Inline -> AstElement) -> Lua Inline -> Lua AstElement
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StackIndex -> Lua Inline
forall a. Peekable a => StackIndex -> Lua a
Lua.peek StackIndex
idx)
Lua AstElement -> Lua AstElement -> Lua AstElement
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (Block -> AstElement
BlockElement (Block -> AstElement) -> Lua Block -> Lua AstElement
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StackIndex -> Lua Block
forall a. Peekable a => StackIndex -> Lua a
Lua.peek StackIndex
idx)
Lua AstElement -> Lua AstElement -> Lua AstElement
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (Attr -> AstElement
AttrElement (Attr -> AstElement) -> Lua Attr -> Lua AstElement
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StackIndex -> Lua Attr
forall a. Peekable a => StackIndex -> Lua a
Lua.peek StackIndex
idx)
Lua AstElement -> Lua AstElement -> Lua AstElement
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (ListAttributes -> AstElement
ListAttributesElement (ListAttributes -> AstElement)
-> Lua ListAttributes -> Lua AstElement
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StackIndex -> Lua ListAttributes
forall a. Peekable a => StackIndex -> Lua a
Lua.peek StackIndex
idx)
Lua AstElement -> Lua AstElement -> Lua AstElement
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (Meta -> AstElement
MetaElement (Meta -> AstElement) -> Lua Meta -> Lua AstElement
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StackIndex -> Lua Meta
forall a. Peekable a => StackIndex -> Lua a
Lua.peek StackIndex
idx)
Lua AstElement -> Lua AstElement -> Lua AstElement
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (MetaValue -> AstElement
MetaValueElement (MetaValue -> AstElement) -> Lua MetaValue -> Lua AstElement
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StackIndex -> Lua MetaValue
forall a. Peekable a => StackIndex -> Lua a
Lua.peek StackIndex
idx)
case Either PandocError AstElement
res of
Right AstElement
x -> AstElement -> Lua AstElement
forall (m :: * -> *) a. Monad m => a -> m a
return AstElement
x
Left (PandocError
_ :: PandocError) -> String -> Lua AstElement
forall a. String -> Lua a
Lua.throwMessage
String
"Expected an AST element, but could not parse value as such."
from_simple_table :: SimpleTable -> Lua NumResults
from_simple_table :: SimpleTable -> Lua NumResults
from_simple_table (SimpleTable [Inline]
capt [Alignment]
aligns [Double]
widths [[Block]]
head' [[[Block]]]
body) = do
Block -> Lua ()
forall a. Pushable a => a -> Lua ()
Lua.push (Block -> Lua ()) -> Block -> Lua ()
forall a b. (a -> b) -> a -> b
$ Attr
-> Caption
-> [ColSpec]
-> TableHead
-> [TableBody]
-> TableFoot
-> Block
Table
Attr
nullAttr
(Maybe [Inline] -> [Block] -> Caption
Caption Maybe [Inline]
forall a. Maybe a
Nothing [[Inline] -> Block
Plain [Inline]
capt])
((Alignment -> Double -> ColSpec)
-> [Alignment] -> [Double] -> [ColSpec]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (\Alignment
a Double
w -> (Alignment
a, Double -> ColWidth
toColWidth Double
w)) [Alignment]
aligns [Double]
widths)
(Attr -> [Row] -> TableHead
TableHead Attr
nullAttr [[[Block]] -> Row
blockListToRow [[Block]]
head'])
[Attr -> RowHeadColumns -> [Row] -> [Row] -> TableBody
TableBody Attr
nullAttr RowHeadColumns
0 [] ([Row] -> TableBody) -> [Row] -> TableBody
forall a b. (a -> b) -> a -> b
$ ([[Block]] -> Row) -> [[[Block]]] -> [Row]
forall a b. (a -> b) -> [a] -> [b]
map [[Block]] -> Row
blockListToRow [[[Block]]]
body]
(Attr -> [Row] -> TableFoot
TableFoot Attr
nullAttr [])
NumResults -> Lua NumResults
forall (m :: * -> *) a. Monad m => a -> m a
return (CInt -> NumResults
NumResults CInt
1)
where
blockListToRow :: [[Block]] -> Row
blockListToRow :: [[Block]] -> Row
blockListToRow = Attr -> [Cell] -> Row
Row Attr
nullAttr ([Cell] -> Row) -> ([[Block]] -> [Cell]) -> [[Block]] -> Row
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Block] -> Cell) -> [[Block]] -> [Cell]
forall a b. (a -> b) -> [a] -> [b]
map (Blocks -> Cell
B.simpleCell (Blocks -> Cell) -> ([Block] -> Blocks) -> [Block] -> Cell
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Block] -> Blocks
forall a. [a] -> Many a
B.fromList)
toColWidth :: Double -> ColWidth
toColWidth :: Double -> ColWidth
toColWidth Double
0 = ColWidth
ColWidthDefault
toColWidth Double
w = Double -> ColWidth
ColWidth Double
w
to_simple_table :: Block -> Lua NumResults
to_simple_table :: Block -> Lua NumResults
to_simple_table = \case
Table Attr
_attr Caption
caption [ColSpec]
specs TableHead
thead [TableBody]
tbodies TableFoot
tfoot -> do
let ([Inline]
capt, [Alignment]
aligns, [Double]
widths, [[Block]]
headers, [[[Block]]]
rows) =
Caption
-> [ColSpec]
-> TableHead
-> [TableBody]
-> TableFoot
-> ([Inline], [Alignment], [Double], [[Block]], [[[Block]]])
Shared.toLegacyTable Caption
caption [ColSpec]
specs TableHead
thead [TableBody]
tbodies TableFoot
tfoot
SimpleTable -> Lua ()
pushSimpleTable (SimpleTable -> Lua ()) -> SimpleTable -> Lua ()
forall a b. (a -> b) -> a -> b
$ [Inline]
-> [Alignment]
-> [Double]
-> [[Block]]
-> [[[Block]]]
-> SimpleTable
SimpleTable [Inline]
capt [Alignment]
aligns [Double]
widths [[Block]]
headers [[[Block]]]
rows
NumResults -> Lua NumResults
forall (m :: * -> *) a. Monad m => a -> m a
return (CInt -> NumResults
NumResults CInt
1)
Block
blk ->
String -> Lua NumResults
forall a. String -> Lua a
Lua.throwMessage (String -> Lua NumResults) -> String -> Lua NumResults
forall a b. (a -> b) -> a -> b
$
String
"Expected Table, got " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Constr -> String
showConstr (Block -> Constr
forall a. Data a => a -> Constr
toConstr Block
blk) String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
"."
toRomanNumeral :: Lua.Integer -> PandocLua T.Text
toRomanNumeral :: Integer -> PandocLua Text
toRomanNumeral = Text -> PandocLua Text
forall (m :: * -> *) a. Monad m => a -> m a
return (Text -> PandocLua Text)
-> (Integer -> Text) -> Integer -> PandocLua Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Text
Shared.toRomanNumeral (Int -> Text) -> (Integer -> Int) -> Integer -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral