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

    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 = DocumentedTypeWithList e Chunk Void -> Peeker e Chunk
    forall e a itemtype.
    LuaError e =>
    DocumentedTypeWithList e a itemtype -> Peeker e a
    peekUD DocumentedTypeWithList e Chunk Void
    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 = DocumentedTypeWithList e Chunk Void -> Chunk -> LuaE e ()
    forall e a itemtype.
    LuaError e =>
    DocumentedTypeWithList e a itemtype -> a -> LuaE e ()
    pushUD DocumentedTypeWithList e Chunk Void
    forall e. LuaError e => DocumentedType e Chunk
    typeChunk

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

      , Name
    -> Text
    -> (Pusher e Text, Chunk -> Text)
    -> (Peeker e Text, Chunk -> Text -> Chunk)
    -> Member e (DocumentedFunction e) Chunk
    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"
        (Pusher e Text
    forall e. Pusher e Text
    pushText, Chunk -> Text
    chunkId)
        (Peeker e Text
    forall e. Peeker e Text
    peekText, \Chunk
    chunk Text
    ident -> Chunk
    chunk{ chunkId = ident })

      , Name
    -> Text
    -> (Pusher e Int, Chunk -> Int)
    -> (Peeker e Int, Chunk -> Int -> Chunk)
    -> Member e (DocumentedFunction e) Chunk
    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"
        (Pusher e Int
    forall a e. (Integral a, Show a) => a -> LuaE e ()
    pushIntegral, Chunk -> Int
    chunkLevel)
        (Peeker e Int
    forall a e. (Integral a, Read a) => Peeker e a
    peekIntegral, \Chunk
    chunk Int
    level -> Chunk
    chunk{ chunkLevel = level })

      , Name
    -> Text
    -> (Pusher e Int, Chunk -> Int)
    -> (Peeker e Int, Chunk -> Int -> Chunk)
    -> Member e (DocumentedFunction e) Chunk
    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"
        (Pusher e Int
    forall a e. (Integral a, Show a) => a -> LuaE e ()
    pushIntegral, Chunk -> Int
    chunkNumber)
        (Peeker e Int
    forall a e. (Integral a, Read a) => Peeker e a
    peekIntegral, \Chunk
    chunk Int
    number -> Chunk
    chunk{ chunkNumber = number })

      , Name
    -> Text
    -> (Pusher e (Maybe Text), Chunk -> Maybe Text)
    -> (Peeker e (Maybe Text), Chunk -> Maybe Text -> Chunk)
    -> Member e (DocumentedFunction e) Chunk
    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"
        (Pusher e Text -> Pusher e (Maybe Text)
    forall e a. LuaError e => Pusher e a -> Pusher e (Maybe a)
    pushMaybe Pusher e Text
    forall e. Pusher e Text
    pushText, Chunk -> Maybe Text
    chunkSectionNumber)
        (Peeker e Text -> Peeker e (Maybe Text)
    forall e a. LuaError e => Peeker e a -> Peeker e (Maybe a)
    peekMaybe Peeker e Text
    forall e. Peeker e Text
    peekText, \Chunk
    chunk Maybe Text
    secnum -> Chunk
    chunk{ chunkSectionNumber = secnum })

      , Name
    -> Text
    -> (Pusher e String, Chunk -> String)
    -> (Peeker e String, Chunk -> String -> Chunk)
    -> Member e (DocumentedFunction e) Chunk
    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"
        (Pusher e String
    forall e. String -> LuaE e ()
    pushString, Chunk -> String
    chunkPath)
        (Peeker e String
    forall e. Peeker e String
    peekString, \Chunk
    chunk String
    path -> Chunk
    chunk{ chunkPath = path })

      , Name
    -> Text
    -> (Pusher e (Maybe Chunk), Chunk -> Maybe Chunk)
    -> (Peeker e (Maybe Chunk), Chunk -> Maybe Chunk -> Chunk)
    -> Member e (DocumentedFunction e) Chunk
    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"
        (Pusher e Chunk -> Pusher e (Maybe Chunk)
    forall e a. LuaError e => Pusher e a -> Pusher e (Maybe a)
    pushMaybe Pusher e Chunk
    forall e. LuaError e => Pusher e Chunk
    pushChunk, Chunk -> Maybe Chunk
    chunkUp)
        (Peeker e Chunk -> Peeker e (Maybe Chunk)
    forall e a. LuaError e => Peeker e a -> Peeker e (Maybe a)
    peekMaybe Peeker e Chunk
    forall e. LuaError e => Peeker e Chunk
    peekChunk, \Chunk
    chunk Maybe Chunk
    up -> Chunk
    chunk{ chunkUp = up })

      , Name
    -> Text
    -> (Pusher e (Maybe Chunk), Chunk -> Maybe Chunk)
    -> (Peeker e (Maybe Chunk), Chunk -> Maybe Chunk -> Chunk)
    -> Member e (DocumentedFunction e) Chunk
    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"
        (Pusher e Chunk -> Pusher e (Maybe Chunk)
    forall e a. LuaError e => Pusher e a -> Pusher e (Maybe a)
    pushMaybe Pusher e Chunk
    forall e. LuaError e => Pusher e Chunk
    pushChunk, Chunk -> Maybe Chunk
    chunkPrev)
        (Peeker e Chunk -> Peeker e (Maybe Chunk)
    forall e a. LuaError e => Peeker e a -> Peeker e (Maybe a)
    peekMaybe Peeker e Chunk
    forall e. LuaError e => Peeker e Chunk
    peekChunk, \Chunk
    chunk Maybe Chunk
    prev -> Chunk
    chunk{ chunkPrev = prev })

      , Name
    -> Text
    -> (Pusher e (Maybe Chunk), Chunk -> Maybe Chunk)
    -> (Peeker e (Maybe Chunk), Chunk -> Maybe Chunk -> Chunk)
    -> Member e (DocumentedFunction e) Chunk
    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"
        (Pusher e Chunk -> Pusher e (Maybe Chunk)
    forall e a. LuaError e => Pusher e a -> Pusher e (Maybe a)
    pushMaybe Pusher e Chunk
    forall e. LuaError e => Pusher e Chunk
    pushChunk, Chunk -> Maybe Chunk
    chunkNext)
        (Peeker e Chunk -> Peeker e (Maybe Chunk)
    forall e a. LuaError e => Peeker e a -> Peeker e (Maybe a)
    peekMaybe Peeker e Chunk
    forall e. LuaError e => Peeker e Chunk
    peekChunk, \Chunk
    chunk Maybe Chunk
    next' -> Chunk
    chunk{ chunkNext = next' })

      , Name
    -> Text
    -> (Pusher e Bool, Chunk -> Bool)
    -> (Peeker e Bool, Chunk -> Bool -> Chunk)
    -> Member e (DocumentedFunction e) Chunk
    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" Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <>
          Text
    "even if the chunk has no section number" )
        (Pusher e Bool
    forall e. Pusher e Bool
    pushBool, Chunk -> Bool
    chunkUnlisted)
        (Peeker e Bool
    forall e. Peeker e Bool
    peekBool, \Chunk
    chunk Bool
    unlisted -> Chunk
    chunk { chunkUnlisted = unlisted })

      , Name
    -> Text
    -> (Pusher e [Block], Chunk -> [Block])
    -> (Peeker e [Block], Chunk -> [Block] -> Chunk)
    -> Member e (DocumentedFunction e) Chunk
    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"
        (Pusher e [Block]
    forall e. LuaError e => Pusher e [Block]
    pushBlocks, Chunk -> [Block]
    chunkContents)
        (Peeker e [Block]
    forall e. LuaError e => Peeker e [Block]
    peekBlocksFuzzy, \Chunk
    chunk [Block]
    blks -> Chunk
    chunk{ chunkContents = blks })
      ]

    -- | Retrieves a 'ChunkedDoc' from the Lua stack.
    peekChunkedDoc :: LuaError e => Peeker e ChunkedDoc
    peekChunkedDoc :: forall e. LuaError e => Peeker e ChunkedDoc
    peekChunkedDoc = DocumentedTypeWithList e ChunkedDoc Void -> Peeker e ChunkedDoc
    forall e a itemtype.
    LuaError e =>
    DocumentedTypeWithList e a itemtype -> Peeker e a
    peekUD DocumentedTypeWithList e ChunkedDoc Void
    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 = DocumentedTypeWithList e ChunkedDoc Void -> ChunkedDoc -> LuaE e ()
    forall e a itemtype.
    LuaError e =>
    DocumentedTypeWithList e a itemtype -> a -> LuaE e ()
    pushUD DocumentedTypeWithList e ChunkedDoc Void
    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 = Name
    -> [(Operation, DocumentedFunction e)]
    -> [Member e (DocumentedFunction e) ChunkedDoc]
    -> DocumentedType e ChunkedDoc
    forall e a.
    LuaError e =>
    Name
    -> [(Operation, DocumentedFunction e)]
    -> [Member e (DocumentedFunction e) a]
    -> DocumentedType e a
    deftype Name
    "ChunkedDoc"
      []
      [ Name
    -> Text
    -> (Pusher e [Chunk], ChunkedDoc -> [Chunk])
    -> Member e (DocumentedFunction e) 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"
        (Pusher e Chunk -> Pusher e [Chunk]
    forall e a. LuaError e => Pusher e a -> [a] -> LuaE e ()
    pushList Pusher e Chunk
    forall e. LuaError e => Pusher e Chunk
    pushChunk, ChunkedDoc -> [Chunk]
    chunkedChunks)

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

      , Name
    -> Text
    -> (Pusher e (Tree SecInfo), ChunkedDoc -> Tree SecInfo)
    -> Member e (DocumentedFunction e) ChunkedDoc
    forall e b a fn.
    Name -> Text -> (Pusher e b, a -> b) -> Member e fn a
    readonly Name
    "toc"
        Text
    "table of contents information"
        (Pusher e (Tree SecInfo)
    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
      Pusher e (Tree SecInfo) -> [Tree SecInfo] -> LuaE e ()
    forall e a. LuaError e => Pusher e a -> [a] -> LuaE e ()
    pushList Pusher e (Tree SecInfo)
    forall e. LuaError e => Pusher e (Tree SecInfo)
    pushTocTree [Tree SecInfo]
    subSecInfo
      Pusher e SecInfo
    forall e. LuaError e => Pusher e SecInfo
    pushSecInfo SecInfo
    secInfo
      StackIndex -> Integer -> LuaE e ()
    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 = [(Name, SecInfo -> LuaE e ())] -> SecInfo -> LuaE e ()
    forall e a.
    LuaError e =>
    [(Name, a -> LuaE e ())] -> a -> LuaE e ()
    pushAsTable
      [ (Name
    "title"  , Pusher e [Inline]
    forall e. LuaError e => Pusher e [Inline]
    pushInlines Pusher e [Inline] -> (SecInfo -> [Inline]) -> SecInfo -> LuaE e ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . SecInfo -> [Inline]
    secTitle)
      , (Name
    "number" , LuaE e () -> (Text -> LuaE e ()) -> Maybe Text -> LuaE e ()
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe LuaE e ()
    forall e. LuaE e ()
    pushnil Text -> LuaE e ()
    forall e. Pusher e Text
    pushText (Maybe Text -> LuaE e ())
    -> (SecInfo -> Maybe Text) -> SecInfo -> LuaE e ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . SecInfo -> Maybe Text
    secNumber)
      , (Name
    "id"     , Text -> LuaE e ()
    forall e. Pusher e Text
    pushText (Text -> LuaE e ()) -> (SecInfo -> Text) -> SecInfo -> LuaE e ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . SecInfo -> Text
    secId)
      , (Name
    "path"   , Text -> LuaE e ()
    forall e. Pusher e Text
    pushText (Text -> LuaE e ()) -> (SecInfo -> Text) -> SecInfo -> LuaE e ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . SecInfo -> Text
    secPath)
      , (Name
    "level"  , Int -> LuaE e ()
    forall a e. (Integral a, Show a) => a -> LuaE e ()
    pushIntegral (Int -> LuaE e ()) -> (SecInfo -> Int) -> SecInfo -> LuaE e ()
    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 = LuaE e Bool -> Peek e Bool
    forall e a. LuaE e a -> Peek e a
    liftLua (StackIndex -> LuaE e Bool
    forall e. StackIndex -> LuaE e Bool
    isnoneornil StackIndex
    idx) Peek e Bool -> (Bool -> Peek e (Maybe a)) -> Peek e (Maybe a)
    forall a b. Peek e a -> (a -> Peek e b) -> Peek e b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= \case
      Bool
    True  -> Maybe a -> Peek e (Maybe a)
    forall a. a -> Peek e a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure Maybe a
    forall a. Maybe a
    Nothing
      Bool
    False -> a -> Maybe a
    forall a. a -> Maybe a
    Just (a -> Maybe a) -> Peek e a -> Peek e (Maybe a)
    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 = LuaE e () -> (a -> LuaE e ()) -> Maybe a -> LuaE e ()
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe LuaE e ()
    forall e. LuaE e ()
    pushnil