    {-|
    Module      : Text.Jira.Parser.Block
    Copyright   : © 2019–2023 Albert Krewinkel
    License     : MIT

    Maintainer  : Albert Krewinkel <tarleb@zeitkraut.de>
    Stability   : alpha
    Portability : portable

    Parse Jira wiki blocks.
    -}
    module Text.Jira.Parser.Block
      ( block
        -- * Parsers for block types
      , blockQuote
      , code
      , color
      , header
      , horizontalRule
      , list
      , noformat
      , panel
      , para
      , table
      ) where

    import Control.Monad (guard, void, when)
    import Data.Char (digitToInt)
    import Data.Text (pack)
    import Text.Jira.Markup
    import Text.Jira.Parser.Core
    import Text.Jira.Parser.Inline
    import Text.Jira.Parser.Shared (colorName)
    import Text.Parsec

    -- | Parses any block element.
    block :: JiraParser Block
    block :: JiraParser Block
    block = [JiraParser Block] -> JiraParser Block
    forall s (m :: * -> *) t u a.
    Stream s m t =>
    [ParsecT s u m a] -> ParsecT s u m a
    choice
      [ JiraParser Block
    header
      , JiraParser Block
    list
      , JiraParser Block
    table
      , JiraParser Block
    blockQuote
      , JiraParser Block
    horizontalRule
      , JiraParser Block
    code
      , JiraParser Block
    noformat
      , JiraParser Block
    panel
      , JiraParser Block
    color
      , JiraParser Block
    para
      ] JiraParser Block
    -> ParsecT Text ParserState Identity () -> JiraParser Block
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity a
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
    <* ParsecT Text ParserState Identity ()
    skipWhitespace

    -- | Parses a paragraph into a @Para@.
    para :: JiraParser Block
    para :: JiraParser Block
    para = (JiraParser Block -> String -> JiraParser Block
    forall s u (m :: * -> *) a.
    ParsecT s u m a -> String -> ParsecT s u m a
    <?> String
    "para") (JiraParser Block -> JiraParser Block)
    -> (JiraParser Block -> JiraParser Block)
    -> JiraParser Block
    -> JiraParser Block
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . JiraParser Block -> JiraParser Block
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
    try (JiraParser Block -> JiraParser Block)
    -> JiraParser Block -> JiraParser Block
    forall a b. (a -> b) -> a -> b
    $ do
      isInList <- ParserState -> Bool
    stateInList (ParserState -> Bool)
    -> ParsecT Text ParserState Identity ParserState
    -> ParsecT Text ParserState Identity Bool
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> ParsecT Text ParserState Identity ParserState
    forall (m :: * -> *) s u. Monad m => ParsecT s u m u
    getState
      when isInList $ do
        notFollowedBy' blankline
        notFollowedBy' horizontalRule
      Para . normalizeInlines <$> many1 inline

    -- | Parses a header line into a @Header@.
    header :: JiraParser Block
    header :: JiraParser Block
    header = (JiraParser Block -> String -> JiraParser Block
    forall s u (m :: * -> *) a.
    ParsecT s u m a -> String -> ParsecT s u m a
    <?> String
    "header") (JiraParser Block -> JiraParser Block)
    -> (JiraParser Block -> JiraParser Block)
    -> JiraParser Block
    -> JiraParser Block
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . JiraParser Block -> JiraParser Block
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
    try (JiraParser Block -> JiraParser Block)
    -> JiraParser Block -> JiraParser Block
    forall a b. (a -> b) -> a -> b
    $ do
      level <- Char -> Int
    digitToInt (Char -> Int)
    -> ParsecT Text ParserState Identity Char
    -> ParsecT Text ParserState Identity Int
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> (Char -> ParsecT Text ParserState Identity Char
    forall s (m :: * -> *) u.
    Stream s m Char =>
    Char -> ParsecT s u m Char
    char Char
    'h' ParsecT Text ParserState Identity Char
    -> ParsecT Text ParserState Identity Char
    -> ParsecT Text ParserState Identity Char
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity b
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> String -> ParsecT Text ParserState Identity Char
    forall s (m :: * -> *) u.
    Stream s m Char =>
    String -> ParsecT s u m Char
    oneOf String
    "123456" ParsecT Text ParserState Identity Char
    -> ParsecT Text ParserState Identity Char
    -> ParsecT Text ParserState Identity Char
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity a
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
    <* Char -> ParsecT Text ParserState Identity Char
    forall s (m :: * -> *) u.
    Stream s m Char =>
    Char -> ParsecT s u m Char
    char Char
    '.')
      content <- skipMany (char ' ') *> inline `manyTill` (void newline <|> eof)
      return $ Header level (normalizeInlines content)

    -- | Parses a list into @List@.
    list :: JiraParser Block
    list :: JiraParser Block
    list = (JiraParser Block -> String -> JiraParser Block
    forall s u (m :: * -> *) a.
    ParsecT s u m a -> String -> ParsecT s u m a
    <?> String
    "list") (JiraParser Block -> JiraParser Block)
    -> (JiraParser Block -> JiraParser Block)
    -> JiraParser Block
    -> JiraParser Block
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . JiraParser Block -> JiraParser Block
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
    try (JiraParser Block -> JiraParser Block)
    -> JiraParser Block -> JiraParser Block
    forall a b. (a -> b) -> a -> b
    $ do
      Bool -> ParsecT Text ParserState Identity ()
    forall (f :: * -> *). Alternative f => Bool -> f ()
    guard (Bool -> ParsecT Text ParserState Identity ())
    -> (ParserState -> Bool)
    -> ParserState
    -> ParsecT Text ParserState Identity ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Bool -> Bool
    not (Bool -> Bool) -> (ParserState -> Bool) -> ParserState -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ParserState -> Bool
    stateInList (ParserState -> ParsecT Text ParserState Identity ())
    -> ParsecT Text ParserState Identity ParserState
    -> ParsecT Text ParserState Identity ()
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< ParsecT Text ParserState Identity ParserState
    forall (m :: * -> *) s u. Monad m => ParsecT s u m u
    getState
      (Bool -> ParserState -> ParserState)
    -> JiraParser Block -> JiraParser Block
    forall a.
    (Bool -> ParserState -> ParserState)
    -> JiraParser a -> JiraParser a
    withStateFlag (\Bool
    b ParserState
    st -> ParserState
    st { stateInList = b }) (JiraParser Block -> JiraParser Block)
    -> JiraParser Block -> JiraParser Block
    forall a b. (a -> b) -> a -> b
    $
        Int -> JiraParser Block
    listAtDepth Int
    0
      where
        listAtDepth :: Int -> JiraParser Block
        listAtDepth :: Int -> JiraParser Block
    listAtDepth Int
    depth = JiraParser Block -> JiraParser Block
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
    try (JiraParser Block -> JiraParser Block)
    -> JiraParser Block -> JiraParser Block
    forall a b. (a -> b) -> a -> b
    $ Int -> ParsecT Text ParserState Identity ()
    atDepth Int
    depth ParsecT Text ParserState Identity ()
    -> JiraParser Block -> JiraParser Block
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity b
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> Int -> JiraParser Block
    listAtDepth' Int
    depth

        listAtDepth' :: Int -> JiraParser Block
        listAtDepth' :: Int -> JiraParser Block
    listAtDepth' Int
    depth = JiraParser Block -> JiraParser Block
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
    try (JiraParser Block -> JiraParser Block)
    -> JiraParser Block -> JiraParser Block
    forall a b. (a -> b) -> a -> b
    $ do
          bulletChar <- ParsecT Text ParserState Identity Char
    anyBulletMarker
          first <- firstItemAtDepth depth
          rest  <- many (try $ listItemAtDepth depth (char bulletChar))
          return $ List (style bulletChar) (first:rest)

        style :: Char -> ListStyle
        style :: Char -> ListStyle
    style Char
    c = case Char
    c of
          Char
    '-' -> ListStyle
    SquareBullets
          Char
    '*' -> ListStyle
    CircleBullets
          Char
    '#' -> ListStyle
    Enumeration
          Char
    _   -> String -> ListStyle
    forall a. HasCallStack => String -> a
    error (String
    "the impossible happened: unknown style for bullet " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ [Char
    c])

        atDepth :: Int -> JiraParser ()
        atDepth :: Int -> ParsecT Text ParserState Identity ()
    atDepth Int
    depth = ParsecT Text ParserState Identity ()
    -> ParsecT Text ParserState Identity ()
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
    try (ParsecT Text ParserState Identity ()
     -> ParsecT Text ParserState Identity ())
    -> ParsecT Text ParserState Identity ()
    -> ParsecT Text ParserState Identity ()
    forall a b. (a -> b) -> a -> b
    $ ParsecT Text ParserState Identity ()
    skipSpaces ParsecT Text ParserState Identity ()
    -> ParsecT Text ParserState Identity String
    -> ParsecT Text ParserState Identity ()
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity a
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
    <* Int
    -> ParsecT Text ParserState Identity Char
    -> ParsecT Text ParserState Identity String
    forall s (m :: * -> *) t u a.
    Stream s m t =>
    Int -> ParsecT s u m a -> ParsecT s u m [a]
    count Int
    depth ParsecT Text ParserState Identity Char
    anyBulletMarker

        firstItemAtDepth :: Int -> JiraParser [Block]
        firstItemAtDepth :: Int -> JiraParser [Block]
    firstItemAtDepth Int
    depth = JiraParser [Block] -> JiraParser [Block]
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
    try (JiraParser [Block] -> JiraParser [Block])
    -> JiraParser [Block] -> JiraParser [Block]
    forall a b. (a -> b) -> a -> b
    $ Int -> JiraParser [Block]
    listContent (Int
    depth Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    1) JiraParser [Block] -> JiraParser [Block] -> JiraParser [Block]
    forall s u (m :: * -> *) a.
    ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
    <|>
          do
            blocks <- Int -> JiraParser [Block]
    nonListContent Int
    depth
            nestedLists <- try . many $ listAtDepth (depth + 1)
            return $ blocks ++ nestedLists

        listItemAtDepth :: Int -> JiraParser Char -> JiraParser [Block]
        listItemAtDepth :: Int -> ParsecT Text ParserState Identity Char -> JiraParser [Block]
    listItemAtDepth Int
    depth ParsecT Text ParserState Identity Char
    bulletChar = Int -> ParsecT Text ParserState Identity ()
    atDepth Int
    depth ParsecT Text ParserState Identity ()
    -> JiraParser [Block] -> JiraParser [Block]
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity b
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *>
          (JiraParser [Block] -> JiraParser [Block]
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
    try (ParsecT Text ParserState Identity Char
    bulletChar ParsecT Text ParserState Identity Char
    -> JiraParser [Block] -> JiraParser [Block]
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity b
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> Int -> JiraParser [Block]
    nonListContent Int
    depth) JiraParser [Block] -> JiraParser [Block] -> JiraParser [Block]
    forall s u (m :: * -> *) a.
    ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
    <|>
           JiraParser [Block] -> JiraParser [Block]
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
    try (ParsecT Text ParserState Identity Char
    anyBulletMarker ParsecT Text ParserState Identity Char
    -> JiraParser [Block] -> JiraParser [Block]
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity b
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> Int -> JiraParser [Block]
    listContent Int
    depth))

        listContent :: Int -> JiraParser [Block]
        listContent :: Int -> JiraParser [Block]
    listContent Int
    depth = do
            first <- Int -> JiraParser Block
    listAtDepth' Int
    depth
            rest <- many (listAtDepth depth)
            return (first : rest)

        anyBulletMarker :: JiraParser Char
        anyBulletMarker :: ParsecT Text ParserState Identity Char
    anyBulletMarker = String -> ParsecT Text ParserState Identity Char
    forall s (m :: * -> *) u.
    Stream s m Char =>
    String -> ParsecT s u m Char
    oneOf String
    "*-#"

        nonListContent :: Int -> JiraParser [Block]
        nonListContent :: Int -> JiraParser [Block]
    nonListContent Int
    depth = JiraParser [Block] -> JiraParser [Block]
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
    try (JiraParser [Block] -> JiraParser [Block])
    -> JiraParser [Block] -> JiraParser [Block]
    forall a b. (a -> b) -> a -> b
    $
          let nonListBlock :: JiraParser Block
    nonListBlock = do
                ParsecT Text ParserState Identity String
    -> ParsecT Text ParserState Identity ()
    forall a.
    Show a =>
    JiraParser a -> ParsecT Text ParserState Identity ()
    notFollowedBy' (ParsecT Text ParserState Identity ()
    skipSpaces ParsecT Text ParserState Identity ()
    -> ParsecT Text ParserState Identity String
    -> ParsecT Text ParserState Identity String
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity b
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> ParsecT Text ParserState Identity Char
    -> ParsecT Text ParserState Identity String
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
    many1 (String -> ParsecT Text ParserState Identity Char
    forall s (m :: * -> *) u.
    Stream s m Char =>
    String -> ParsecT s u m Char
    oneOf String
    "#-*"))
                JiraParser Block
    block
          in Char -> ParsecT Text ParserState Identity Char
    forall s (m :: * -> *) u.
    Stream s m Char =>
    Char -> ParsecT s u m Char
    char Char
    ' ' ParsecT Text ParserState Identity Char
    -> JiraParser [Block] -> JiraParser [Block]
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity b
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> do
            first   <- JiraParser Block
    block
            nonList <- many nonListBlock
            lists   <- many (listAtDepth (depth + 1))
            return (first : nonList ++ lists)

    -- | Parses a table into a @Table@ element.
    table :: JiraParser Block
    table :: JiraParser Block
    table = do
      Bool -> ParsecT Text ParserState Identity ()
    forall (f :: * -> *). Alternative f => Bool -> f ()
    guard (Bool -> ParsecT Text ParserState Identity ())
    -> (ParserState -> Bool)
    -> ParserState
    -> ParsecT Text ParserState Identity ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Bool -> Bool
    not (Bool -> Bool) -> (ParserState -> Bool) -> ParserState -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ParserState -> Bool
    stateInTable (ParserState -> ParsecT Text ParserState Identity ())
    -> ParsecT Text ParserState Identity ParserState
    -> ParsecT Text ParserState Identity ()
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< ParsecT Text ParserState Identity ParserState
    forall (m :: * -> *) s u. Monad m => ParsecT s u m u
    getState
      (Bool -> ParserState -> ParserState)
    -> JiraParser Block -> JiraParser Block
    forall a.
    (Bool -> ParserState -> ParserState)
    -> JiraParser a -> JiraParser a
    withStateFlag (\Bool
    b ParserState
    st -> ParserState
    st { stateInTable = b }) (JiraParser Block -> JiraParser Block)
    -> JiraParser Block -> JiraParser Block
    forall a b. (a -> b) -> a -> b
    $
        [Row] -> Block
    Table ([Row] -> Block)
    -> ParsecT Text ParserState Identity [Row] -> JiraParser Block
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> ParsecT Text ParserState Identity Row
    -> ParsecT Text ParserState Identity [Row]
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
    many1 ParsecT Text ParserState Identity Row
    row

    -- | Parses a table row.
    row :: JiraParser Row
    row :: ParsecT Text ParserState Identity Row
    row = ([Cell] -> Row)
    -> ParsecT Text ParserState Identity [Cell]
    -> ParsecT Text ParserState Identity Row
    forall a b.
    (a -> b)
    -> ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap [Cell] -> Row
    Row (ParsecT Text ParserState Identity [Cell]
     -> ParsecT Text ParserState Identity Row)
    -> (ParsecT Text ParserState Identity [Cell]
        -> ParsecT Text ParserState Identity [Cell])
    -> ParsecT Text ParserState Identity [Cell]
    -> ParsecT Text ParserState Identity Row
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ParsecT Text ParserState Identity [Cell]
    -> ParsecT Text ParserState Identity [Cell]
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
    try (ParsecT Text ParserState Identity [Cell]
     -> ParsecT Text ParserState Identity Row)
    -> ParsecT Text ParserState Identity [Cell]
    -> ParsecT Text ParserState Identity Row
    forall a b. (a -> b) -> a -> b
    $
      ParsecT Text ParserState Identity Cell
    -> ParsecT Text ParserState Identity [Cell]
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
    many1 ParsecT Text ParserState Identity Cell
    cell ParsecT Text ParserState Identity [Cell]
    -> ParsecT Text ParserState Identity ()
    -> ParsecT Text ParserState Identity [Cell]
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity a
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
    <* ParsecT Text ParserState Identity Char
    -> ParsecT Text ParserState Identity ()
    forall s (m :: * -> *) t u a.
    Stream s m t =>
    ParsecT s u m a -> ParsecT s u m ()
    optional (ParsecT Text ParserState Identity Char
    -> ParsecT Text ParserState Identity ()
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m ()
    skipMany (String -> ParsecT Text ParserState Identity Char
    forall s (m :: * -> *) u.
    Stream s m Char =>
    String -> ParsecT s u m Char
    oneOf String
    " |") ParsecT Text ParserState Identity ()
    -> ParsecT Text ParserState Identity Char
    -> ParsecT Text ParserState Identity Char
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity b
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> ParsecT Text ParserState Identity Char
    forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
    newline)

    -- | Parses a table cell.
    cell :: JiraParser Cell
    cell :: ParsecT Text ParserState Identity Cell
    cell = ParsecT Text ParserState Identity Cell
    -> ParsecT Text ParserState Identity Cell
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
    try (ParsecT Text ParserState Identity Cell
     -> ParsecT Text ParserState Identity Cell)
    -> ParsecT Text ParserState Identity Cell
    -> ParsecT Text ParserState Identity Cell
    forall a b. (a -> b) -> a -> b
    $ do
      mkCell <- JiraParser ([Block] -> Cell)
    cellStart
      bs     <- many block
      return $ mkCell bs

    -- | Parses the beginning of a table cell and returns a function which
    -- constructs a cell of the appropriate type when given the cell's content.
    cellStart :: JiraParser ([Block] -> Cell)
    cellStart :: JiraParser ([Block] -> Cell)
    cellStart = JiraParser ([Block] -> Cell) -> JiraParser ([Block] -> Cell)
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
    try
      (JiraParser ([Block] -> Cell) -> JiraParser ([Block] -> Cell))
    -> JiraParser ([Block] -> Cell) -> JiraParser ([Block] -> Cell)
    forall a b. (a -> b) -> a -> b
    $  ParsecT Text ParserState Identity ()
    skipSpaces
      ParsecT Text ParserState Identity ()
    -> ParsecT Text ParserState Identity Char
    -> ParsecT Text ParserState Identity Char
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity b
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> Char -> ParsecT Text ParserState Identity Char
    forall s (m :: * -> *) u.
    Stream s m Char =>
    Char -> ParsecT s u m Char
    char Char
    '|'
      ParsecT Text ParserState Identity Char
    -> JiraParser ([Block] -> Cell) -> JiraParser ([Block] -> Cell)
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity b
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> ([Block] -> Cell)
    -> JiraParser ([Block] -> Cell) -> JiraParser ([Block] -> Cell)
    forall s (m :: * -> *) t a u.
    Stream s m t =>
    a -> ParsecT s u m a -> ParsecT s u m a
    option [Block] -> Cell
    BodyCell ([Block] -> Cell
    HeaderCell ([Block] -> Cell)
    -> ParsecT Text ParserState Identity String
    -> JiraParser ([Block] -> Cell)
    forall a b.
    a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity a
    forall (f :: * -> *) a b. Functor f => a -> f b -> f a
    <$ ParsecT Text ParserState Identity Char
    -> ParsecT Text ParserState Identity String
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
    many1 (Char -> ParsecT Text ParserState Identity Char
    forall s (m :: * -> *) u.
    Stream s m Char =>
    Char -> ParsecT s u m Char
    char Char
    '|'))
      JiraParser ([Block] -> Cell)
    -> ParsecT Text ParserState Identity ()
    -> JiraParser ([Block] -> Cell)
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity a
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
    <* ParsecT Text ParserState Identity ()
    skipSpaces
      JiraParser ([Block] -> Cell)
    -> ParsecT Text ParserState Identity ()
    -> JiraParser ([Block] -> Cell)
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity a
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
    <* ParsecT Text ParserState Identity Char
    -> ParsecT Text ParserState Identity ()
    forall a.
    Show a =>
    JiraParser a -> ParsecT Text ParserState Identity ()
    notFollowedBy' ParsecT Text ParserState Identity Char
    forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
    newline

    -- | Parses a code block into a @Code@ element.
    code :: JiraParser Block
    code :: JiraParser Block
    code = JiraParser Block -> JiraParser Block
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
    try (JiraParser Block -> JiraParser Block)
    -> JiraParser Block -> JiraParser Block
    forall a b. (a -> b) -> a -> b
    $ do
      (langName, params) <- String -> ParsecT Text ParserState Identity String
    forall s (m :: * -> *) u.
    Stream s m Char =>
    String -> ParsecT s u m String
    string String
    "{code" ParsecT Text ParserState Identity String
    -> ParsecT Text ParserState Identity (Maybe Text, [Parameter])
    -> ParsecT Text ParserState Identity (Maybe Text, [Parameter])
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity b
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> ParsecT Text ParserState Identity (Maybe Text, [Parameter])
    parameters ParsecT Text ParserState Identity (Maybe Text, [Parameter])
    -> ParsecT Text ParserState Identity Char
    -> ParsecT Text ParserState Identity (Maybe Text, [Parameter])
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity a
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
    <* Char -> ParsecT Text ParserState Identity Char
    forall s (m :: * -> *) u.
    Stream s m Char =>
    Char -> ParsecT s u m Char
    char Char
    '}' ParsecT Text ParserState Identity (Maybe Text, [Parameter])
    -> ParsecT Text ParserState Identity ()
    -> ParsecT Text ParserState Identity (Maybe Text, [Parameter])
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity a
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
    <* ParsecT Text ParserState Identity ()
    blankline
      let lang = Language -> (Text -> Language) -> Maybe Text -> Language
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe Language
    defaultLanguage Text -> Language
    Language Maybe Text
    langName
      content <- anyChar `manyTill` try (string "{code}" *> blankline)
      return $ Code lang params (pack content)
      where
        defaultLanguage :: Language
    defaultLanguage = Text -> Language
    Language (String -> Text
    pack String
    "java")

    -- | Parses a block quote into a @'Quote'@ element.
    blockQuote :: JiraParser Block
    blockQuote :: JiraParser Block
    blockQuote = JiraParser Block -> JiraParser Block
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
    try (JiraParser Block -> JiraParser Block)
    -> JiraParser Block -> JiraParser Block
    forall a b. (a -> b) -> a -> b
    $ JiraParser Block
    singleLineBq JiraParser Block -> JiraParser Block -> JiraParser Block
    forall s u (m :: * -> *) a.
    ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
    <|> JiraParser Block
    multiLineBq
      where
        singleLineBq :: JiraParser Block
    singleLineBq = [Block] -> Block
    BlockQuote ([Block] -> Block) -> ([Inline] -> [Block]) -> [Inline] -> Block
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Block -> [Block] -> [Block]
    forall a. a -> [a] -> [a]
    :[]) (Block -> [Block]) -> ([Inline] -> Block) -> [Inline] -> [Block]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Inline] -> Block
    Para ([Inline] -> Block)
    -> ParsecT Text ParserState Identity [Inline] -> JiraParser Block
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$>
                       (String -> ParsecT Text ParserState Identity String
    forall s (m :: * -> *) u.
    Stream s m Char =>
    String -> ParsecT s u m String
    string String
    "bq." ParsecT Text ParserState Identity String
    -> ParsecT Text ParserState Identity ()
    -> ParsecT Text ParserState Identity ()
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity b
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> ParsecT Text ParserState Identity Char
    -> ParsecT Text ParserState Identity ()
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m ()
    skipMany (Char -> ParsecT Text ParserState Identity Char
    forall s (m :: * -> *) u.
    Stream s m Char =>
    Char -> ParsecT s u m Char
    char Char
    ' ') ParsecT Text ParserState Identity ()
    -> ParsecT Text ParserState Identity [Inline]
    -> ParsecT Text ParserState Identity [Inline]
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity b
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *>
                        ParsecT Text ParserState Identity Inline
    inline ParsecT Text ParserState Identity Inline
    -> ParsecT Text ParserState Identity ()
    -> ParsecT Text ParserState Identity [Inline]
    forall s (m :: * -> *) t u a end.
    Stream s m t =>
    ParsecT s u m a -> ParsecT s u m end -> ParsecT s u m [a]
    `manyTill` (ParsecT Text ParserState Identity Char
    -> ParsecT Text ParserState Identity ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void ParsecT Text ParserState Identity Char
    forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
    newline ParsecT Text ParserState Identity ()
    -> ParsecT Text ParserState Identity ()
    -> ParsecT Text ParserState Identity ()
    forall s u (m :: * -> *) a.
    ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
    <|> ParsecT Text ParserState Identity ()
    forall s (m :: * -> *) t u.
    (Stream s m t, Show t) =>
    ParsecT s u m ()
    eof))
        multiLineBq :: JiraParser Block
    multiLineBq = [Block] -> Block
    BlockQuote ([Block] -> Block) -> JiraParser [Block] -> JiraParser Block
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$>
                      (String -> ParsecT Text ParserState Identity String
    forall s (m :: * -> *) u.
    Stream s m Char =>
    String -> ParsecT s u m String
    string String
    "{quote}"
                       ParsecT Text ParserState Identity String
    -> ParsecT Text ParserState Identity ()
    -> ParsecT Text ParserState Identity ()
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity b
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> ParsecT Text ParserState Identity ()
    -> ParsecT Text ParserState Identity ()
    forall s (m :: * -> *) t u a.
    Stream s m t =>
    ParsecT s u m a -> ParsecT s u m ()
    optional ParsecT Text ParserState Identity ()
    blankline
                       ParsecT Text ParserState Identity ()
    -> ParsecT Text ParserState Identity ()
    -> ParsecT Text ParserState Identity ()
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity b
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> ParsecT Text ParserState Identity Char
    -> ParsecT Text ParserState Identity ()
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m ()
    skipMany (Char -> ParsecT Text ParserState Identity Char
    forall s (m :: * -> *) u.
    Stream s m Char =>
    Char -> ParsecT s u m Char
    char Char
    ' ')
                       ParsecT Text ParserState Identity ()
    -> JiraParser [Block] -> JiraParser [Block]
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity b
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> JiraParser Block
    block JiraParser Block
    -> ParsecT Text ParserState Identity String -> JiraParser [Block]
    forall s (m :: * -> *) t u a end.
    Stream s m t =>
    ParsecT s u m a -> ParsecT s u m end -> ParsecT s u m [a]
    `manyTill` ParsecT Text ParserState Identity String
    -> ParsecT Text ParserState Identity String
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
    try (String -> ParsecT Text ParserState Identity String
    forall s (m :: * -> *) u.
    Stream s m Char =>
    String -> ParsecT s u m String
    string String
    "{quote}"))

    -- | Parses four consecutive hyphens as @'HorizontalRule'@.
    horizontalRule :: JiraParser Block
    horizontalRule :: JiraParser Block
    horizontalRule = Block
    HorizontalRule Block -> ParsecT Text ParserState Identity () -> JiraParser Block
    forall a b.
    a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity a
    forall (f :: * -> *) a b. Functor f => a -> f b -> f a
    <$
      ParsecT Text ParserState Identity ()
    -> ParsecT Text ParserState Identity ()
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
    try (String -> ParsecT Text ParserState Identity String
    forall s (m :: * -> *) u.
    Stream s m Char =>
    String -> ParsecT s u m String
    string String
    "----" ParsecT Text ParserState Identity String
    -> ParsecT Text ParserState Identity ()
    -> ParsecT Text ParserState Identity ()
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity b
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> ParsecT Text ParserState Identity ()
    blankline)

    -- | Parses a preformatted text into a @NoFormat@ element.
    noformat :: JiraParser Block
    noformat :: JiraParser Block
    noformat = JiraParser Block -> JiraParser Block
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
    try (JiraParser Block -> JiraParser Block)
    -> JiraParser Block -> JiraParser Block
    forall a b. (a -> b) -> a -> b
    $ do
      (_, params) <- String -> ParsecT Text ParserState Identity String
    forall s (m :: * -> *) u.
    Stream s m Char =>
    String -> ParsecT s u m String
    string String
    "{noformat" ParsecT Text ParserState Identity String
    -> ParsecT Text ParserState Identity (Maybe Text, [Parameter])
    -> ParsecT Text ParserState Identity (Maybe Text, [Parameter])
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity b
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> ParsecT Text ParserState Identity (Maybe Text, [Parameter])
    parameters ParsecT Text ParserState Identity (Maybe Text, [Parameter])
    -> ParsecT Text ParserState Identity Char
    -> ParsecT Text ParserState Identity (Maybe Text, [Parameter])
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity a
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
    <* Char -> ParsecT Text ParserState Identity Char
    forall s (m :: * -> *) u.
    Stream s m Char =>
    Char -> ParsecT s u m Char
    char Char
    '}'
      optional newline
      content <- anyChar `manyTill` try (string "{noformat}" *> optional blankline)
      return $ NoFormat params (pack content)

    -- | Parses a preformatted text into a @NoFormat@ element.
    panel :: JiraParser Block
    panel :: JiraParser Block
    panel = JiraParser Block -> JiraParser Block
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
    try (JiraParser Block -> JiraParser Block)
    -> JiraParser Block -> JiraParser Block
    forall a b. (a -> b) -> a -> b
    $ do
      (_, params) <- String -> ParsecT Text ParserState Identity String
    forall s (m :: * -> *) u.
    Stream s m Char =>
    String -> ParsecT s u m String
    string String
    "{panel" ParsecT Text ParserState Identity String
    -> ParsecT Text ParserState Identity (Maybe Text, [Parameter])
    -> ParsecT Text ParserState Identity (Maybe Text, [Parameter])
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity b
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> ParsecT Text ParserState Identity (Maybe Text, [Parameter])
    parameters ParsecT Text ParserState Identity (Maybe Text, [Parameter])
    -> ParsecT Text ParserState Identity Char
    -> ParsecT Text ParserState Identity (Maybe Text, [Parameter])
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity a
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
    <* Char -> ParsecT Text ParserState Identity Char
    forall s (m :: * -> *) u.
    Stream s m Char =>
    Char -> ParsecT s u m Char
    char Char
    '}' ParsecT Text ParserState Identity (Maybe Text, [Parameter])
    -> ParsecT Text ParserState Identity Char
    -> ParsecT Text ParserState Identity (Maybe Text, [Parameter])
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity a
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
    <* ParsecT Text ParserState Identity Char
    forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
    newline
      content <- block `manyTill` try (string "{panel}" *> blankline)
      return $ Panel params content

    -- | Parses colored text into a @'Color'@ element.
    color :: JiraParser Block
    color :: JiraParser Block
    color= JiraParser Block -> JiraParser Block
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
    try (JiraParser Block -> JiraParser Block)
    -> JiraParser Block -> JiraParser Block
    forall a b. (a -> b) -> a -> b
    $ do
      name <- String -> ParsecT Text ParserState Identity String
    forall s (m :: * -> *) u.
    Stream s m Char =>
    String -> ParsecT s u m String
    string String
    "{color:" ParsecT Text ParserState Identity String
    -> ParsecT Text ParserState Identity String
    -> ParsecT Text ParserState Identity String
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity b
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> ParsecT Text ParserState Identity String
    forall u. Parsec Text u String
    colorName ParsecT Text ParserState Identity String
    -> ParsecT Text ParserState Identity Char
    -> ParsecT Text ParserState Identity String
    forall a b.
    ParsecT Text ParserState Identity a
    -> ParsecT Text ParserState Identity b
    -> ParsecT Text ParserState Identity a
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
    <* Char -> ParsecT Text ParserState Identity Char
    forall s (m :: * -> *) u.
    Stream s m Char =>
    Char -> ParsecT s u m Char
    char Char
    '}'
      content <- block `manyTill` try (string "{color}" *> blankline)
      return $ Color (ColorName $ pack name) content

    -- | Skip whitespace till we reach the next block
    skipWhitespace :: JiraParser ()
    skipWhitespace :: ParsecT Text ParserState Identity ()
    skipWhitespace = ParsecT Text ParserState Identity ()
    -> ParsecT Text ParserState Identity ()
    forall s (m :: * -> *) t u a.
    Stream s m t =>
    ParsecT s u m a -> ParsecT s u m ()
    optional (ParsecT Text ParserState Identity ()
     -> ParsecT Text ParserState Identity ())
    -> ParsecT Text ParserState Identity ()
    -> ParsecT Text ParserState Identity ()
    forall a b. (a -> b) -> a -> b
    $ do
      isInList  <- ParserState -> Bool
    stateInList  (ParserState -> Bool)
    -> ParsecT Text ParserState Identity ParserState
    -> ParsecT Text ParserState Identity Bool
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> ParsecT Text ParserState Identity ParserState
    forall (m :: * -> *) s u. Monad m => ParsecT s u m u
    getState
      isInTable <- stateInTable <$> getState
      case (isInList, isInTable) of
        (Bool
    True, Bool
    _) -> ParsecT Text ParserState Identity ()
    blankline
        (Bool
    _, Bool
    True) -> ParsecT Text ParserState Identity ()
    skipSpaces
        (Bool, Bool)
    _         -> ParsecT Text ParserState Identity ()
    -> ParsecT Text ParserState Identity ()
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m ()
    skipMany ParsecT Text ParserState Identity ()
    blankline