{-# LANGUAGE LambdaCase           #-}
{-# LANGUAGE OverloadedStrings    #-}
{- |
   Module      : Text.Pandoc.Lua.Marshal.Chunks
   Copyright   : © 2022 Albert Krewinkel
   License     : GPL-2.0-or-later
   Maintainer  : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>

Marshaling chunks, i.e., pandoc subdocuments.
-}
module Text.Pandoc.Lua.Marshal.Chunks
  ( peekChunk
  , pushChunk
  , peekChunkedDoc
  , pushChunkedDoc
  ) where

import Control.Monad ((<$!>))
import Data.Tree (Tree (..))
import HsLua
import Text.Pandoc.Chunks (Chunk (..), ChunkedDoc (..), SecInfo (..))
import Text.Pandoc.Lua.Marshal.AST

-- | Retrieves a 'Chunk' from the Lua stack.
peekChunk :: LuaError e => Peeker e Chunk
peekChunk :: forall e. LuaError e => Peeker e Chunk
peekChunk = forall e fn a itemtype.
LuaError e =>
UDTypeWithList e fn a itemtype -> Peeker e a
peekUD forall e. LuaError e => DocumentedType e Chunk
typeChunk

-- | Pushes a 'Chunk' to the top of the Lua stack.
pushChunk :: LuaError e => Pusher e Chunk
pushChunk :: forall e. LuaError e => Pusher e Chunk
pushChunk = forall e fn a itemtype.
LuaError e =>
UDTypeWithList e fn a itemtype -> a -> LuaE e ()
pushUD forall e. LuaError e => DocumentedType e Chunk
typeChunk

typeChunk :: LuaError e => DocumentedType e Chunk
typeChunk :: forall e. LuaError e => DocumentedType e Chunk
typeChunk = forall e a.
LuaError e =>
Name
-> [(Operation, DocumentedFunction e)]
-> [Member e (DocumentedFunction e) a]
-> DocumentedType e a
deftype Name
"pandoc.Chunk"
  [ forall e.
Operation
-> DocumentedFunction e -> (Operation, DocumentedFunction e)
operation Operation
Tostring forall a b. (a -> b) -> a -> b
$ forall a e. a -> HsFnPrecursor e a
lambda
    ### liftPure show
    forall e a b.
HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
<#> forall e a itemtype.
LuaError e =>
DocumentedTypeWithList e a itemtype
-> Text -> Text -> Parameter e a
udparam forall e. LuaError e => DocumentedType e Chunk
typeChunk Text
"chunk" Text
"chunk to print in native format"
    forall e a.
HsFnPrecursor e (LuaE e a)
-> FunctionResults e a -> DocumentedFunction e
=#> forall e a. Pusher e a -> Text -> Text -> FunctionResults e a
functionResult forall e. String -> LuaE e ()
pushString Text
"string" Text
"Haskell representation"
  ]
  [ forall e b a fn.
LuaError e =>
Name
-> Text
-> (Pusher e b, a -> b)
-> (Peeker e b, a -> b -> a)
-> Member e fn a
property Name
"heading"
    Text
"heading text"
    (forall e. LuaError e => Pusher e [Inline]
pushInlines, Chunk -> [Inline]
chunkHeading)
    (forall e. LuaError e => Peeker e [Inline]
peekInlinesFuzzy, \Chunk
chunk [Inline]
inlns -> Chunk
chunk{ chunkHeading :: [Inline]
chunkHeading = [Inline]
inlns })

  , forall e b a fn.
LuaError e =>
Name
-> Text
-> (Pusher e b, a -> b)
-> (Peeker e b, a -> b -> a)
-> Member e fn a
property Name
"id"
    Text
"identifier"
    (forall e. Pusher e Text
pushText, Chunk -> Text
chunkId)
    (forall e. Peeker e Text
peekText, \Chunk
chunk Text
ident -> Chunk
chunk{ chunkId :: Text
chunkId = Text
ident })

  , forall e b a fn.
LuaError e =>
Name
-> Text
-> (Pusher e b, a -> b)
-> (Peeker e b, a -> b -> a)
-> Member e fn a
property Name
"level"
    Text
"level of topmost heading in chunk"
    (forall a e. (Integral a, Show a) => a -> LuaE e ()
pushIntegral, Chunk -> Int
chunkLevel)
    (forall a e. (Integral a, Read a) => Peeker e a
peekIntegral, \Chunk
chunk Int
level -> Chunk
chunk{ chunkLevel :: Int
chunkLevel = Int
level })

  , forall e b a fn.
LuaError e =>
Name
-> Text
-> (Pusher e b, a -> b)
-> (Peeker e b, a -> b -> a)
-> Member e fn a
property Name
"number"
    Text
"chunk number"
    (forall a e. (Integral a, Show a) => a -> LuaE e ()
pushIntegral, Chunk -> Int
chunkNumber)
    (forall a e. (Integral a, Read a) => Peeker e a
peekIntegral, \Chunk
chunk Int
number -> Chunk
chunk{ chunkNumber :: Int
chunkNumber = Int
number })

  , forall e b a fn.
LuaError e =>
Name
-> Text
-> (Pusher e b, a -> b)
-> (Peeker e b, a -> b -> a)
-> Member e fn a
property Name
"section_number"
    Text
"hierarchical section number"
    (forall e a. LuaError e => Pusher e a -> Pusher e (Maybe a)
pushMaybe forall e. Pusher e Text
pushText, Chunk -> Maybe Text
chunkSectionNumber)
    (forall e a. LuaError e => Peeker e a -> Peeker e (Maybe a)
peekMaybe forall e. Peeker e Text
peekText, \Chunk
chunk Maybe Text
secnum -> Chunk
chunk{ chunkSectionNumber :: Maybe Text
chunkSectionNumber = Maybe Text
secnum })

  , forall e b a fn.
LuaError e =>
Name
-> Text
-> (Pusher e b, a -> b)
-> (Peeker e b, a -> b -> a)
-> Member e fn a
property Name
"path"
    Text
"target filepath for this chunk"
    (forall e. String -> LuaE e ()
pushString, Chunk -> String
chunkPath)
    (forall e. Peeker e String
peekString, \Chunk
chunk String
path -> Chunk
chunk{ chunkPath :: String
chunkPath = String
path })

  , forall e b a fn.
LuaError e =>
Name
-> Text
-> (Pusher e b, a -> b)
-> (Peeker e b, a -> b -> a)
-> Member e fn a
property Name
"up"
    Text
"link to the enclosing section chunk, if any"
    (forall e a. LuaError e => Pusher e a -> Pusher e (Maybe a)
pushMaybe forall e. LuaError e => Pusher e Chunk
pushChunk, Chunk -> Maybe Chunk
chunkUp)
    (forall e a. LuaError e => Peeker e a -> Peeker e (Maybe a)
peekMaybe forall e. LuaError e => Peeker e Chunk
peekChunk, \Chunk
chunk Maybe Chunk
up -> Chunk
chunk{ chunkUp :: Maybe Chunk
chunkUp = Maybe Chunk
up })

  , forall e b a fn.
LuaError e =>
Name
-> Text
-> (Pusher e b, a -> b)
-> (Peeker e b, a -> b -> a)
-> Member e fn a
property Name
"prev"
    Text
"link to the previous section, if any"
    (forall e a. LuaError e => Pusher e a -> Pusher e (Maybe a)
pushMaybe forall e. LuaError e => Pusher e Chunk
pushChunk, Chunk -> Maybe Chunk
chunkPrev)
    (forall e a. LuaError e => Peeker e a -> Peeker e (Maybe a)
peekMaybe forall e. LuaError e => Peeker e Chunk
peekChunk, \Chunk
chunk Maybe Chunk
prev -> Chunk
chunk{ chunkPrev :: Maybe Chunk
chunkPrev = Maybe Chunk
prev })

  , forall e b a fn.
LuaError e =>
Name
-> Text
-> (Pusher e b, a -> b)
-> (Peeker e b, a -> b -> a)
-> Member e fn a
property Name
"next"
    Text
"link to the next section, if any"
    (forall e a. LuaError e => Pusher e a -> Pusher e (Maybe a)
pushMaybe forall e. LuaError e => Pusher e Chunk
pushChunk, Chunk -> Maybe Chunk
chunkNext)
    (forall e a. LuaError e => Peeker e a -> Peeker e (Maybe a)
peekMaybe forall e. LuaError e => Peeker e Chunk
peekChunk, \Chunk
chunk Maybe Chunk
next' -> Chunk
chunk{ chunkNext :: Maybe Chunk
chunkNext = Maybe Chunk
next' })

  , forall e b a fn.
LuaError e =>
Name
-> Text
-> (Pusher e b, a -> b)
-> (Peeker e b, a -> b -> a)
-> Member e fn a
property Name
"unlisted"
    ( Text
"whether the section in this chunk should be listed in the TOC" forall a. Semigroup a => a -> a -> a
<>
      Text
"even if the chunk has no section number" )
    (forall e. Pusher e Bool
pushBool, Chunk -> Bool
chunkUnlisted)
    (forall e. Peeker e Bool
peekBool, \Chunk
chunk Bool
unlisted -> Chunk
chunk { chunkUnlisted :: Bool
chunkUnlisted = Bool
unlisted })

  , forall e b a fn.
LuaError e =>
Name
-> Text
-> (Pusher e b, a -> b)
-> (Peeker e b, a -> b -> a)
-> Member e fn a
property Name
"contents"
    Text
"the chunk's block contents"
    (forall e. LuaError e => Pusher e [Block]
pushBlocks, Chunk -> [Block]
chunkContents)
    (forall e. LuaError e => Peeker e [Block]
peekBlocksFuzzy, \Chunk
chunk [Block]
blks -> Chunk
chunk{ chunkContents :: [Block]
chunkContents = [Block]
blks })
  ]

-- | Retrieves a 'ChunkedDoc' from the Lua stack.
peekChunkedDoc :: LuaError e => Peeker e ChunkedDoc
peekChunkedDoc :: forall e. LuaError e => Peeker e ChunkedDoc
peekChunkedDoc = forall e fn a itemtype.
LuaError e =>
UDTypeWithList e fn a itemtype -> Peeker e a
peekUD forall e. LuaError e => DocumentedType e ChunkedDoc
typeChunkedDoc

-- | Pushes a 'ChunkedDoc to the top of the Lua stack.
pushChunkedDoc :: LuaError e => Pusher e ChunkedDoc
pushChunkedDoc :: forall e. LuaError e => Pusher e ChunkedDoc
pushChunkedDoc = forall e fn a itemtype.
LuaError e =>
UDTypeWithList e fn a itemtype -> a -> LuaE e ()
pushUD forall e. LuaError e => DocumentedType e ChunkedDoc
typeChunkedDoc

-- | Lua type for 'ChunkedDoc' values.
typeChunkedDoc :: LuaError e => DocumentedType e ChunkedDoc
typeChunkedDoc :: forall e. LuaError e => DocumentedType e ChunkedDoc
typeChunkedDoc = forall e a.
LuaError e =>
Name
-> [(Operation, DocumentedFunction e)]
-> [Member e (DocumentedFunction e) a]
-> DocumentedType e a
deftype Name
"pandoc.ChunkedDoc"
  []
  [ forall e b a fn.
Name -> Text -> (Pusher e b, a -> b) -> Member e fn a
readonly Name
"chunks"
    Text
"list of chunks that make up the document"
    (forall e a. LuaError e => Pusher e a -> [a] -> LuaE e ()
pushList forall e. LuaError e => Pusher e Chunk
pushChunk, ChunkedDoc -> [Chunk]
chunkedChunks)

  , forall e b a fn.
Name -> Text -> (Pusher e b, a -> b) -> Member e fn a
readonly Name
"meta"
    Text
"the document's metadata"
    (forall e. LuaError e => Pusher e Meta
pushMeta, ChunkedDoc -> Meta
chunkedMeta)

  , forall e b a fn.
Name -> Text -> (Pusher e b, a -> b) -> Member e fn a
readonly Name
"toc"
    Text
"table of contents information"
    (forall e. LuaError e => Pusher e (Tree SecInfo)
pushTocTree, ChunkedDoc -> Tree SecInfo
chunkedTOC)
  ]

-- | Pushes a TOC tree to the stack. The resulting object is a list with
-- the top-level entry placed at index @0@ and all subentries as the
-- rest of the list.
pushTocTree :: LuaError e => Pusher e (Tree SecInfo)
pushTocTree :: forall e. LuaError e => Pusher e (Tree SecInfo)
pushTocTree (Node SecInfo
secInfo [Tree SecInfo]
subSecInfo) = do
  forall e a. LuaError e => Pusher e a -> [a] -> LuaE e ()
pushList forall e. LuaError e => Pusher e (Tree SecInfo)
pushTocTree [Tree SecInfo]
subSecInfo
  forall e. LuaError e => Pusher e SecInfo
pushSecInfo SecInfo
secInfo
  forall e. LuaError e => StackIndex -> Integer -> LuaE e ()
rawseti (CInt -> StackIndex
nth CInt
2) Integer
0

pushSecInfo :: LuaError e => Pusher e SecInfo
pushSecInfo :: forall e. LuaError e => Pusher e SecInfo
pushSecInfo = forall e a.
LuaError e =>
[(Name, a -> LuaE e ())] -> a -> LuaE e ()
pushAsTable
  [ (Name
"title"  , forall e. LuaError e => Pusher e [Inline]
pushInlines forall b c a. (b -> c) -> (a -> b) -> a -> c
. SecInfo -> [Inline]
secTitle)
  , (Name
"number" , forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall e. LuaE e ()
pushnil forall e. Pusher e Text
pushText forall b c a. (b -> c) -> (a -> b) -> a -> c
. SecInfo -> Maybe Text
secNumber)
  , (Name
"id"     , forall e. Pusher e Text
pushText forall b c a. (b -> c) -> (a -> b) -> a -> c
. SecInfo -> Text
secId)
  , (Name
"path"   , forall e. Pusher e Text
pushText forall b c a. (b -> c) -> (a -> b) -> a -> c
. SecInfo -> Text
secPath)
  , (Name
"level"  , forall a e. (Integral a, Show a) => a -> LuaE e ()
pushIntegral forall b c a. (b -> c) -> (a -> b) -> a -> c
. SecInfo -> Int
secLevel)
  ]

peekMaybe :: LuaError e => Peeker e a -> Peeker e (Maybe a)
peekMaybe :: forall e a. LuaError e => Peeker e a -> Peeker e (Maybe a)
peekMaybe Peeker e a
p StackIndex
idx = forall e a. LuaE e a -> Peek e a
liftLua (forall e. StackIndex -> LuaE e Bool
isnoneornil StackIndex
idx) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
  Bool
True  -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a. Maybe a
Nothing
  Bool
False -> forall a. a -> Maybe a
Just forall (m :: * -> *) a b. Monad m => (a -> b) -> m a -> m b
<$!> Peeker e a
p StackIndex
idx

pushMaybe :: LuaError e => Pusher e a -> Pusher e (Maybe a)
pushMaybe :: forall e a. LuaError e => Pusher e a -> Pusher e (Maybe a)
pushMaybe = forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall e. LuaE e ()
pushnil