{-# LINE 1 "CMarkGFM.hsc" #-}
{-# LANGUAGE CPP, ForeignFunctionInterface, GeneralizedNewtypeDeriving,
{-# LINE 2 "CMarkGFM.hsc" #-}
    DeriveGeneric, DeriveDataTypeable, FlexibleContexts #-}

module CMarkGFM (
    commonmarkToHtml
  , commonmarkToXml
  , commonmarkToMan
  , commonmarkToLaTeX
  , commonmarkToNode
  , registerPlugins
  , nodeToHtml
  , nodeToXml
  , nodeToMan
  , nodeToLaTeX
  , nodeToCommonmark
  , optSourcePos
  , optHardBreaks
  , optSmart
  , optSafe
  , extStrikethrough
  , extTable
  , extAutolink
  , extTagfilter
  , Node(..)
  , NodeType(..)
  , PosInfo(..)
  , DelimType(..)
  , ListType(..)
  , ListAttributes(..)
  , Url
  , Title
  , Level
  , Info
  , TableCellAlignment(..)
  , CMarkOption
  , CMarkExtension
  ) where

import Foreign
import Foreign.C.Types
import Foreign.C.String (CString, withCString)
import qualified System.IO.Unsafe as Unsafe
import Data.Maybe (fromMaybe)
import GHC.Generics (Generic)
import Data.Maybe (catMaybes)
import Data.Data (Data)
import Data.Typeable (Typeable)
import Data.Text (Text, empty)
import qualified Data.Text.Foreign as TF
import qualified Data.ByteString as B
import Data.Text.Encoding (encodeUtf8)
import Control.Applicative ((<$>), (<*>))


{-# LINE 55 "CMarkGFM.hsc" #-}

{-# LINE 56 "CMarkGFM.hsc" #-}

-- | Register core extensions.  This should be done once at program start.
registerPlugins :: IO ()
registerPlugins = c_cmark_register_plugin c_core_extensions_registration

-- | Frees a cmark linked list, produced by extsToLlist.
freeLlist :: LlistPtr a -> IO ()
freeLlist = c_cmark_llist_free c_CMARK_DEFAULT_MEM_ALLOCATOR

-- | Converts a list of resolved extension pointers to a single cmark
-- linked list, which can be passed to functions requiring a list of
-- extensions.
extsToLlist :: [ExtensionPtr] -> IO (LlistPtr ExtensionPtr)
extsToLlist [] = return nullPtr
extsToLlist (h:t) = do
  t' <- extsToLlist t
  c_cmark_llist_append c_CMARK_DEFAULT_MEM_ALLOCATOR t' (castPtr h)

-- | Resolves a CMarkExtension to its pointer.
resolveExt :: CMarkExtension -> IO (Maybe ExtensionPtr)
resolveExt e = do
  p <- withCString (unCMarkExtension e) c_cmark_find_syntax_extension
  return (if p == nullPtr then Nothing else Just p)

-- | Convert CommonMark formatted text to Html, using cmark's
-- built-in renderer.
commonmarkToHtml :: [CMarkOption] -> [CMarkExtension] -> Text -> Text
commonmarkToHtml opts exts =
  commonmarkToX render_html opts exts Nothing
  where exts' = Unsafe.unsafePerformIO $ fmap catMaybes $ mapM resolveExt exts
        render_html n o _ = Unsafe.unsafePerformIO $ do
          llist <- extsToLlist exts'
          let r = c_cmark_render_html n o llist
          freeLlist llist
          return r

-- | Convert CommonMark formatted text to CommonMark XML, using cmark's
-- built-in renderer.
commonmarkToXml :: [CMarkOption] -> [CMarkExtension] -> Text -> Text
commonmarkToXml opts exts = commonmarkToX render_xml opts exts Nothing
  where render_xml n o _ = c_cmark_render_xml n o

-- | Convert CommonMark formatted text to groff man, using cmark's
-- built-in renderer.
commonmarkToMan :: [CMarkOption] -> [CMarkExtension] -> Maybe Int -> Text -> Text
commonmarkToMan = commonmarkToX c_cmark_render_man

-- | Convert CommonMark formatted text to latex, using cmark's
-- built-in renderer.
commonmarkToLaTeX :: [CMarkOption] -> [CMarkExtension] -> Maybe Int -> Text -> Text
commonmarkToLaTeX = commonmarkToX c_cmark_render_latex

-- | Convert CommonMark formatted text to a structured 'Node' tree,
-- which can be transformed or rendered using Haskell code.
commonmarkToNode :: [CMarkOption] -> [CMarkExtension] -> Text -> Node
commonmarkToNode opts exts s = Unsafe.unsafePerformIO $ do
  exts' <- fmap catMaybes $ mapM resolveExt exts
  parser <- c_cmark_parser_new (combineOptions opts)
  mapM_ (c_cmark_parser_attach_syntax_extension parser) exts'
  TF.withCStringLen s $! \(ptr, len) ->
             c_cmark_parser_feed parser ptr len
  nptr <- c_cmark_parser_finish parser
  c_cmark_parser_free parser
  fptr <- newForeignPtr c_cmark_node_free nptr
  withForeignPtr fptr toNode

nodeToHtml :: [CMarkOption] -> [CMarkExtension] -> Node -> Text
nodeToHtml opts exts =
  nodeToX render_html opts Nothing
  where exts' = Unsafe.unsafePerformIO $ fmap catMaybes $ mapM resolveExt exts
        render_html n o _ = Unsafe.unsafePerformIO $ do
          llist <- extsToLlist exts'
          let r = c_cmark_render_html n o llist
          freeLlist llist
          return r

nodeToXml :: [CMarkOption] -> Node -> Text
nodeToXml opts = nodeToX render_xml opts Nothing
  where render_xml n o _ = c_cmark_render_xml n o

nodeToMan :: [CMarkOption] -> Maybe Int -> Node -> Text
nodeToMan = nodeToX c_cmark_render_man

nodeToLaTeX :: [CMarkOption] -> Maybe Int -> Node -> Text
nodeToLaTeX = nodeToX c_cmark_render_latex

nodeToCommonmark :: [CMarkOption] -> Maybe Int -> Node -> Text
nodeToCommonmark = nodeToX c_cmark_render_commonmark

type Renderer = NodePtr -> CInt -> Int -> IO CString

nodeToX :: Renderer -> [CMarkOption] -> Maybe Int -> Node -> Text
nodeToX renderer opts mbWidth node = Unsafe.unsafePerformIO $ do
  nptr <- fromNode node
  fptr <- newForeignPtr c_cmark_node_free nptr
  withForeignPtr fptr $ \ptr -> do
    cstr <- renderer ptr (combineOptions opts) (fromMaybe 0 mbWidth)
    TF.peekCStringLen (cstr, c_strlen cstr)

commonmarkToX :: Renderer
              -> [CMarkOption]
              -> [CMarkExtension]
              -> Maybe Int
              -> Text
              -> Text
commonmarkToX renderer opts exts mbWidth s = Unsafe.unsafePerformIO $
  TF.withCStringLen s $ \(ptr, len) -> do
    let opts' = combineOptions opts
    exts' <- fmap catMaybes $ mapM resolveExt exts
    parser <- c_cmark_parser_new opts'
    mapM_ (c_cmark_parser_attach_syntax_extension parser) exts'
    c_cmark_parser_feed parser ptr len
    nptr <- c_cmark_parser_finish parser
    c_cmark_parser_free parser
    fptr <- newForeignPtr c_cmark_node_free nptr
    withForeignPtr fptr $ \p -> do
      str <- renderer p opts' (fromMaybe 0 mbWidth)
      t <- TF.peekCStringLen $! (str, c_strlen str)
      return t

data ParserPhantom
type ParserPtr = Ptr ParserPhantom

data NodePhantom
type NodePtr = Ptr NodePhantom

data LlistPhantom a
type LlistPtr a = Ptr (LlistPhantom a)

data MemPhantom
type MemPtr = Ptr MemPhantom

data PluginPhantom
type PluginPtr = Ptr PluginPhantom

data ExtensionPhantom
type ExtensionPtr = Ptr ExtensionPhantom

data Node = Node (Maybe PosInfo) NodeType [Node]
     deriving (Show, Read, Eq, Ord, Typeable, Data, Generic)

data DelimType =
    PERIOD_DELIM
  | PAREN_DELIM
  deriving (Show, Read, Eq, Ord, Typeable, Data, Generic)

data ListType =
    BULLET_LIST
  | ORDERED_LIST
  deriving (Show, Read, Eq, Ord, Typeable, Data, Generic)

data ListAttributes = ListAttributes{
    listType     :: ListType
  , listTight    :: Bool
  , listStart    :: Int
  , listDelim    :: DelimType
  } deriving (Show, Read, Eq, Ord, Typeable, Data, Generic)

type Url = Text

type Title = Text

type Level = Int

type Info = Text

type OnEnter = Text

type OnExit = Text

data TableCellAlignment = None | Left | Center | Right
     deriving (Show, Read, Eq, Ord, Typeable, Data, Generic)

data NodeType =
    DOCUMENT
  | THEMATIC_BREAK
  | PARAGRAPH
  | BLOCK_QUOTE
  | HTML_BLOCK Text
  | CUSTOM_BLOCK OnEnter OnExit
  | CODE_BLOCK Info Text
  | HEADING Level
  | LIST ListAttributes
  | ITEM
  | TEXT Text
  | SOFTBREAK
  | LINEBREAK
  | HTML_INLINE Text
  | CUSTOM_INLINE OnEnter OnExit
  | CODE Text
  | EMPH
  | STRONG
  | LINK Url Title
  | IMAGE Url Title
  | STRIKETHROUGH
  | TABLE [TableCellAlignment]
  | TABLE_ROW
  | TABLE_CELL
  deriving (Show, Read, Eq, Ord, Typeable, Data, Generic)

data PosInfo = PosInfo{ startLine   :: Int
                      , startColumn :: Int
                      , endLine     :: Int
                      , endColumn   :: Int
                      }
  deriving (Show, Read, Eq, Ord, Typeable, Data, Generic)

newtype CMarkOption = CMarkOption { unCMarkOption :: CInt }

-- | Combine a list of options into a single option, using bitwise or.
combineOptions :: [CMarkOption] -> CInt
combineOptions = foldr ((.|.) . unCMarkOption) 0

-- | Include a @data-sourcepos@ attribute on block elements.
optSourcePos :: CMarkOption
optSourcePos = CMarkOption 2
{-# LINE 272 "CMarkGFM.hsc" #-}

-- | Render @softbreak@ elements as hard line breaks.
optHardBreaks :: CMarkOption
optHardBreaks = CMarkOption 4
{-# LINE 276 "CMarkGFM.hsc" #-}

-- | Convert straight quotes to curly, @---@ to em-dash, @--@ to en-dash.
optSmart :: CMarkOption
optSmart = CMarkOption 1024
{-# LINE 280 "CMarkGFM.hsc" #-}

-- | Suppress rendering of raw HTML and potentially dangerous URLs in links
-- and images.
optSafe :: CMarkOption
optSafe = CMarkOption 8
{-# LINE 285 "CMarkGFM.hsc" #-}

newtype CMarkExtension = CMarkExtension { unCMarkExtension :: String }

extStrikethrough :: CMarkExtension
extStrikethrough = CMarkExtension "strikethrough"

extTable :: CMarkExtension
extTable = CMarkExtension "table"

extAutolink :: CMarkExtension
extAutolink = CMarkExtension "autolink"

extTagfilter :: CMarkExtension
extTagfilter = CMarkExtension "tagfilter"

ptrToNodeType :: NodePtr -> IO NodeType
ptrToNodeType ptr = do
  nodeType <- c_cmark_node_get_type ptr
  case nodeType of
       32769
{-# LINE 305 "CMarkGFM.hsc" #-}
         -> return DOCUMENT
       32778
{-# LINE 307 "CMarkGFM.hsc" #-}
         -> return THEMATIC_BREAK
       32776
{-# LINE 309 "CMarkGFM.hsc" #-}
         -> return PARAGRAPH
       32770
{-# LINE 311 "CMarkGFM.hsc" #-}
         -> return BLOCK_QUOTE
       32774
{-# LINE 313 "CMarkGFM.hsc" #-}
         -> HTML_BLOCK <$> literal
       32775
{-# LINE 315 "CMarkGFM.hsc" #-}
         -> CUSTOM_BLOCK <$> onEnter <*> onExit
       32773
{-# LINE 317 "CMarkGFM.hsc" #-}
         -> CODE_BLOCK <$> info
                       <*> literal
       32771
{-# LINE 320 "CMarkGFM.hsc" #-}
         -> LIST <$> listAttr
       32772
{-# LINE 322 "CMarkGFM.hsc" #-}
         -> return ITEM
       32777
{-# LINE 324 "CMarkGFM.hsc" #-}
         -> HEADING <$> level
       49159
{-# LINE 326 "CMarkGFM.hsc" #-}
         -> return EMPH
       49160
{-# LINE 328 "CMarkGFM.hsc" #-}
         -> return STRONG
       49161
{-# LINE 330 "CMarkGFM.hsc" #-}
         -> LINK <$> url <*> title
       49162
{-# LINE 332 "CMarkGFM.hsc" #-}
         -> IMAGE <$> url <*> title
       49153
{-# LINE 334 "CMarkGFM.hsc" #-}
         -> TEXT <$> literal
       49156
{-# LINE 336 "CMarkGFM.hsc" #-}
         -> CODE <$> literal
       49157
{-# LINE 338 "CMarkGFM.hsc" #-}
         -> HTML_INLINE <$> literal
       49158
{-# LINE 340 "CMarkGFM.hsc" #-}
         -> CUSTOM_INLINE <$> onEnter <*> onExit
       49154
{-# LINE 342 "CMarkGFM.hsc" #-}
         -> return SOFTBREAK
       49155
{-# LINE 344 "CMarkGFM.hsc" #-}
         -> return LINEBREAK
       _ -> if nodeType == fromIntegral (Unsafe.unsafePerformIO $ peek c_CMARK_NODE_STRIKETHROUGH) then
              return STRIKETHROUGH
            else if nodeType == fromIntegral (Unsafe.unsafePerformIO $ peek c_CMARK_NODE_TABLE) then
              TABLE <$> alignments
            else if nodeType == fromIntegral (Unsafe.unsafePerformIO $ peek c_CMARK_NODE_TABLE_ROW) then
              return TABLE_ROW
            else if nodeType == fromIntegral (Unsafe.unsafePerformIO $ peek c_CMARK_NODE_TABLE_CELL) then
              return TABLE_CELL
            else
              error $ "Unknown node type " ++ (show nodeType)
  where literal   = c_cmark_node_get_literal ptr >>= totext
        level     = c_cmark_node_get_heading_level ptr
        onEnter    = c_cmark_node_get_on_enter ptr >>= totext
        onExit     = c_cmark_node_get_on_exit  ptr >>= totext
        listAttr  = do
          listtype <- c_cmark_node_get_list_type ptr
          listdelim <- c_cmark_node_get_list_delim ptr
          tight <- c_cmark_node_get_list_tight ptr
          start <- c_cmark_node_get_list_start ptr
          return ListAttributes{
            listType  = case listtype of
                             (2) -> ORDERED_LIST
{-# LINE 367 "CMarkGFM.hsc" #-}
                             (1)  -> BULLET_LIST
{-# LINE 368 "CMarkGFM.hsc" #-}
                             _                           -> BULLET_LIST
          , listDelim  = case listdelim of
                             (1) -> PERIOD_DELIM
{-# LINE 371 "CMarkGFM.hsc" #-}
                             (2)  -> PAREN_DELIM
{-# LINE 372 "CMarkGFM.hsc" #-}
                             _                           -> PERIOD_DELIM
          , listTight  = tight
          , listStart  = start
          }
        url       = c_cmark_node_get_url ptr >>= totext
        title     = c_cmark_node_get_title ptr >>= totext
        info      = c_cmark_node_get_fence_info ptr >>= totext
        alignments = do
          ncols <- c_cmarkextensions_get_table_columns ptr
          cols <- c_cmarkextensions_get_table_alignments ptr
          mapM (fmap ucharToAlignment . peekElemOff cols) [0..(fromIntegral ncols) - 1]
        ucharToAlignment (CUChar 108) = CMarkGFM.Left
        ucharToAlignment (CUChar 99)  = CMarkGFM.Center
        ucharToAlignment (CUChar 114) = CMarkGFM.Right
        ucharToAlignment _            = None

getPosInfo :: NodePtr -> IO (Maybe PosInfo)
getPosInfo ptr = do
  startline <- c_cmark_node_get_start_line ptr
  endline <- c_cmark_node_get_end_line ptr
  startcol <- c_cmark_node_get_start_column ptr
  endcol <- c_cmark_node_get_end_column ptr
  if startline + endline + startcol + endcol == 0
     then return Nothing
     else return $ Just PosInfo{ startLine = startline
                               , startColumn = startcol
                               , endLine = endline
                               , endColumn = endcol }

toNode :: NodePtr -> IO Node
toNode ptr = do
  let handleNodes ptr' =
        if ptr' == nullPtr
           then return []
           else do
              x  <- toNode ptr'
              xs <- c_cmark_node_next ptr' >>= handleNodes
              return $! (x:xs)
  nodeType <- ptrToNodeType ptr
  children <- c_cmark_node_first_child ptr >>= handleNodes
  posinfo <- getPosInfo ptr
  return $! Node posinfo nodeType children

fromNode :: Node -> IO NodePtr
fromNode (Node _ nodeType children) = do
  node <- case nodeType of
            DOCUMENT    -> c_cmark_node_new (32769)
{-# LINE 419 "CMarkGFM.hsc" #-}
            THEMATIC_BREAK -> c_cmark_node_new (32778)
{-# LINE 420 "CMarkGFM.hsc" #-}
            PARAGRAPH   -> c_cmark_node_new (32776)
{-# LINE 421 "CMarkGFM.hsc" #-}
            BLOCK_QUOTE -> c_cmark_node_new (32770)
{-# LINE 422 "CMarkGFM.hsc" #-}
            HTML_BLOCK literal -> do
                     n <- c_cmark_node_new (32774)
{-# LINE 424 "CMarkGFM.hsc" #-}
                     c_cmark_node_set_literal n =<< fromtext literal
                     return n
            CUSTOM_BLOCK onEnter onExit -> do
                     n <- c_cmark_node_new (32775)
{-# LINE 428 "CMarkGFM.hsc" #-}
                     c_cmark_node_set_on_enter n =<< fromtext onEnter
                     c_cmark_node_set_on_exit  n =<< fromtext onExit
                     return n
            CODE_BLOCK info literal -> do
                     n <- c_cmark_node_new (32773)
{-# LINE 433 "CMarkGFM.hsc" #-}
                     c_cmark_node_set_literal n =<< fromtext literal
                     c_cmark_node_set_fence_info n =<< fromtext info
                     return n
            LIST attr   -> do
                     n <- c_cmark_node_new (32771)
{-# LINE 438 "CMarkGFM.hsc" #-}
                     c_cmark_node_set_list_type n $ case listType attr of
                         ORDERED_LIST -> 2
{-# LINE 440 "CMarkGFM.hsc" #-}
                         BULLET_LIST  -> 1
{-# LINE 441 "CMarkGFM.hsc" #-}
                     c_cmark_node_set_list_delim n $ case listDelim attr of
                         PERIOD_DELIM -> 1
{-# LINE 443 "CMarkGFM.hsc" #-}
                         PAREN_DELIM  -> 2
{-# LINE 444 "CMarkGFM.hsc" #-}
                     c_cmark_node_set_list_tight n $ listTight attr
                     c_cmark_node_set_list_start n $ listStart attr
                     return n
            ITEM        -> c_cmark_node_new (32772)
{-# LINE 448 "CMarkGFM.hsc" #-}
            HEADING lev  -> do
                     n <- c_cmark_node_new (32777)
{-# LINE 450 "CMarkGFM.hsc" #-}
                     c_cmark_node_set_heading_level n lev
                     return n
            EMPH        -> c_cmark_node_new (49159)
{-# LINE 453 "CMarkGFM.hsc" #-}
            STRONG      -> c_cmark_node_new (49160)
{-# LINE 454 "CMarkGFM.hsc" #-}
            LINK url title -> do
                     n <- c_cmark_node_new (49161)
{-# LINE 456 "CMarkGFM.hsc" #-}
                     c_cmark_node_set_url n =<< fromtext url
                     c_cmark_node_set_title n =<< fromtext title
                     return n
            IMAGE url title -> do
                     n <- c_cmark_node_new (49162)
{-# LINE 461 "CMarkGFM.hsc" #-}
                     c_cmark_node_set_url n =<< fromtext url
                     c_cmark_node_set_title n =<< fromtext title
                     return n
            TEXT literal -> do
                     n <- c_cmark_node_new (49153)
{-# LINE 466 "CMarkGFM.hsc" #-}
                     c_cmark_node_set_literal n =<< fromtext literal
                     return n
            CODE literal -> do
                     n <- c_cmark_node_new (49156)
{-# LINE 470 "CMarkGFM.hsc" #-}
                     c_cmark_node_set_literal n =<< fromtext literal
                     return n
            HTML_INLINE literal -> do
                     n <- c_cmark_node_new (49157)
{-# LINE 474 "CMarkGFM.hsc" #-}
                     c_cmark_node_set_literal n =<< fromtext literal
                     return n
            CUSTOM_INLINE onEnter onExit -> do
                     n <- c_cmark_node_new (49158)
{-# LINE 478 "CMarkGFM.hsc" #-}
                     c_cmark_node_set_on_enter n =<< fromtext onEnter
                     c_cmark_node_set_on_exit  n =<< fromtext onExit
                     return n
            SOFTBREAK   -> c_cmark_node_new (49154)
{-# LINE 482 "CMarkGFM.hsc" #-}
            LINEBREAK   -> c_cmark_node_new (49155)
{-# LINE 483 "CMarkGFM.hsc" #-}
            STRIKETHROUGH -> c_cmark_node_new (fromIntegral . Unsafe.unsafePerformIO $ peek c_CMARK_NODE_STRIKETHROUGH)
            TABLE _       -> error "constructing table not supported"
            TABLE_ROW     -> error "constructing table row not supported"
            TABLE_CELL    -> error "constructing table cell not supported"
  mapM_ (\child -> fromNode child >>= c_cmark_node_append_child node) children
  return node

totext :: CString -> IO Text
totext str
  | str == nullPtr = return empty
  | otherwise      = TF.peekCStringLen (str, c_strlen str)

fromtext :: Text -> IO CString
fromtext t = B.useAsCString (encodeUtf8 t) return

foreign import ccall "string.h strlen"
    c_strlen :: CString -> Int

foreign import ccall "cmark.h cmark_node_new"
    c_cmark_node_new :: Int -> IO NodePtr

foreign import ccall "cmark.h cmark_render_html"
    c_cmark_render_html :: NodePtr -> CInt -> LlistPtr ExtensionPtr -> IO CString

foreign import ccall "cmark.h cmark_render_xml"
    c_cmark_render_xml :: NodePtr -> CInt -> IO CString

foreign import ccall "cmark.h cmark_render_man"
    c_cmark_render_man :: NodePtr -> CInt -> Int -> IO CString

foreign import ccall "cmark.h cmark_render_latex"
    c_cmark_render_latex :: NodePtr -> CInt -> Int -> IO CString

foreign import ccall "cmark.h cmark_render_commonmark"
    c_cmark_render_commonmark :: NodePtr -> CInt -> Int -> IO CString

foreign import ccall "cmark.h cmark_parser_new"
    c_cmark_parser_new :: CInt -> IO ParserPtr

foreign import ccall "cmark.h cmark_parser_feed"
    c_cmark_parser_feed :: ParserPtr -> CString -> Int -> IO ()

foreign import ccall "cmark.h cmark_parser_finish"
    c_cmark_parser_finish :: ParserPtr -> IO NodePtr

foreign import ccall "cmark.h cmark_parser_free"
    c_cmark_parser_free :: ParserPtr -> IO ()

foreign import ccall "cmark.h cmark_node_get_type"
    c_cmark_node_get_type :: NodePtr -> IO Int

foreign import ccall "cmark.h cmark_node_first_child"
    c_cmark_node_first_child :: NodePtr -> IO NodePtr

foreign import ccall "cmark.h cmark_node_next"
    c_cmark_node_next :: NodePtr -> IO NodePtr

foreign import ccall "cmark.h cmark_node_get_literal"
    c_cmark_node_get_literal :: NodePtr -> IO CString

foreign import ccall "cmark.h cmark_node_get_url"
    c_cmark_node_get_url :: NodePtr -> IO CString

foreign import ccall "cmark.h cmark_node_get_title"
    c_cmark_node_get_title :: NodePtr -> IO CString

foreign import ccall "cmark.h cmark_node_get_heading_level"
    c_cmark_node_get_heading_level :: NodePtr -> IO Int

foreign import ccall "cmark.h cmark_node_get_list_type"
    c_cmark_node_get_list_type :: NodePtr -> IO Int

foreign import ccall "cmark.h cmark_node_get_list_tight"
    c_cmark_node_get_list_tight :: NodePtr -> IO Bool

foreign import ccall "cmark.h cmark_node_get_list_start"
    c_cmark_node_get_list_start :: NodePtr -> IO Int

foreign import ccall "cmark.h cmark_node_get_list_delim"
    c_cmark_node_get_list_delim :: NodePtr -> IO Int

foreign import ccall "cmark.h cmark_node_get_fence_info"
    c_cmark_node_get_fence_info :: NodePtr -> IO CString

foreign import ccall "cmark.h cmark_node_get_start_line"
    c_cmark_node_get_start_line :: NodePtr -> IO Int

foreign import ccall "cmark.h cmark_node_get_start_column"
    c_cmark_node_get_start_column :: NodePtr -> IO Int

foreign import ccall "cmark.h cmark_node_get_end_line"
    c_cmark_node_get_end_line :: NodePtr -> IO Int

foreign import ccall "cmark.h cmark_node_get_end_column"
    c_cmark_node_get_end_column :: NodePtr -> IO Int

foreign import ccall "cmark.h cmark_node_get_on_enter"
    c_cmark_node_get_on_enter :: NodePtr -> IO CString

foreign import ccall "cmark.h cmark_node_get_on_exit"
    c_cmark_node_get_on_exit :: NodePtr -> IO CString

foreign import ccall "cmark.h cmark_node_append_child"
    c_cmark_node_append_child :: NodePtr -> NodePtr -> IO Int

foreign import ccall "cmark.h cmark_node_set_literal"
    c_cmark_node_set_literal :: NodePtr -> CString -> IO Int

foreign import ccall "cmark.h cmark_node_set_url"
    c_cmark_node_set_url :: NodePtr -> CString -> IO Int

foreign import ccall "cmark.h cmark_node_set_title"
    c_cmark_node_set_title :: NodePtr -> CString -> IO Int

foreign import ccall "cmark.h cmark_node_set_heading_level"
    c_cmark_node_set_heading_level :: NodePtr -> Int -> IO Int

foreign import ccall "cmark.h cmark_node_set_list_type"
    c_cmark_node_set_list_type :: NodePtr -> Int -> IO Int

foreign import ccall "cmark.h cmark_node_set_list_tight"
    c_cmark_node_set_list_tight :: NodePtr -> Bool -> IO Int

foreign import ccall "cmark.h cmark_node_set_list_start"
    c_cmark_node_set_list_start :: NodePtr -> Int -> IO Int

foreign import ccall "cmark.h cmark_node_set_list_delim"
    c_cmark_node_set_list_delim :: NodePtr -> Int -> IO Int

foreign import ccall "cmark.h cmark_node_set_fence_info"
    c_cmark_node_set_fence_info :: NodePtr -> CString -> IO Int

foreign import ccall "cmark.h cmark_node_set_on_enter"
    c_cmark_node_set_on_enter :: NodePtr -> CString -> IO Int

foreign import ccall "cmark.h cmark_node_set_on_exit"
    c_cmark_node_set_on_exit :: NodePtr -> CString -> IO Int

foreign import ccall "cmark.h &cmark_node_free"
    c_cmark_node_free :: FunPtr (NodePtr -> IO ())

foreign import ccall "registry.h cmark_register_plugin"
    c_cmark_register_plugin :: FunPtr (PluginPtr -> IO Int) -> IO ()

foreign import ccall "core-extensions.h &core_extensions_registration"
    c_core_extensions_registration :: FunPtr (PluginPtr -> IO Int)

foreign import ccall "cmark_extension_api.h cmark_find_syntax_extension"
    c_cmark_find_syntax_extension :: CString -> IO ExtensionPtr

foreign import ccall "cmark.h cmark_llist_append"
    c_cmark_llist_append :: MemPtr -> LlistPtr a -> Ptr () -> IO (LlistPtr a)

foreign import ccall "cmark.h cmark_llist_free"
    c_cmark_llist_free :: MemPtr -> LlistPtr a -> IO ()

foreign import ccall "cmark.h &CMARK_DEFAULT_MEM_ALLOCATOR"
    c_CMARK_DEFAULT_MEM_ALLOCATOR :: MemPtr

foreign import ccall "cmark_extension_api.h cmark_parser_attach_syntax_extension"
    c_cmark_parser_attach_syntax_extension :: ParserPtr -> ExtensionPtr -> IO ()

foreign import ccall "strikethrough.h &CMARK_NODE_STRIKETHROUGH"
    c_CMARK_NODE_STRIKETHROUGH :: Ptr CUShort

foreign import ccall "table.h &CMARK_NODE_TABLE"
    c_CMARK_NODE_TABLE :: Ptr CUShort

foreign import ccall "table.h &CMARK_NODE_TABLE_ROW"
    c_CMARK_NODE_TABLE_ROW :: Ptr CUShort

foreign import ccall "table.h &CMARK_NODE_TABLE_CELL"
    c_CMARK_NODE_TABLE_CELL :: Ptr CUShort

foreign import ccall "core-extensions.h cmarkextensions_get_table_columns"
    c_cmarkextensions_get_table_columns :: NodePtr -> IO CUShort

foreign import ccall "core-extensions.h cmarkextensions_get_table_alignments"
    c_cmarkextensions_get_table_alignments :: NodePtr -> IO (Ptr CUChar)