{-|
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 = 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
  ] forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* JiraParser ()
skipWhitespace

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

-- | Parses a header line into a @Header@.
header :: JiraParser Block
header :: JiraParser Block
header = (forall s u (m :: * -> *) a.
ParsecT s u m a -> String -> ParsecT s u m a
<?> String
"header") forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try forall a b. (a -> b) -> a -> b
$ do
  Int
level <- Char -> Int
digitToInt forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'h' forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf String
"123456" forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'.')
  [Inline]
content <- forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m ()
skipMany (forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
' ') forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> JiraParser Inline
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` (forall (f :: * -> *) a. Functor f => f a -> f ()
void forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
newline forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> forall s (m :: * -> *) t u.
(Stream s m t, Show t) =>
ParsecT s u m ()
eof)
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Int -> [Inline] -> Block
Header Int
level ([Inline] -> [Inline]
normalizeInlines [Inline]
content)

-- | Parses a list into @List@.
list :: JiraParser Block
list :: JiraParser Block
list = (forall s u (m :: * -> *) a.
ParsecT s u m a -> String -> ParsecT s u m a
<?> String
"list") forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try forall a b. (a -> b) -> a -> b
$ do
  forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParserState -> Bool
stateInList forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall (m :: * -> *) s u. Monad m => ParsecT s u m u
getState
  forall a.
(Bool -> ParserState -> ParserState)
-> JiraParser a -> JiraParser a
withStateFlag (\Bool
b ParserState
st -> ParserState
st { stateInList :: Bool
stateInList = Bool
b }) 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 = forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try forall a b. (a -> b) -> a -> b
$ Int -> JiraParser ()
atDepth Int
depth 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 = forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try forall a b. (a -> b) -> a -> b
$ do
      Char
bulletChar <- ParsecT Text ParserState Identity Char
anyBulletMarker
      [Block]
first <- Int -> JiraParser [Block]
firstItemAtDepth Int
depth
      [[Block]]
rest  <- forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many (forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try forall a b. (a -> b) -> a -> b
$ Int -> ParsecT Text ParserState Identity Char -> JiraParser [Block]
listItemAtDepth Int
depth (forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
bulletChar))
      forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ ListStyle -> [[Block]] -> Block
List (Char -> ListStyle
style Char
bulletChar) ([Block]
firstforall a. a -> [a] -> [a]
:[[Block]]
rest)

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

    atDepth :: Int -> JiraParser ()
    atDepth :: Int -> JiraParser ()
atDepth Int
depth = forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try forall a b. (a -> b) -> a -> b
$ JiraParser ()
skipSpaces forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* 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 = forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try forall a b. (a -> b) -> a -> b
$ Int -> JiraParser [Block]
listContent (Int
depth forall a. Num a => a -> a -> a
+ Int
1) forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|>
      do
        [Block]
blocks <- Int -> JiraParser [Block]
nonListContent Int
depth
        [Block]
nestedLists <- forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many forall a b. (a -> b) -> a -> b
$ Int -> JiraParser Block
listAtDepth (Int
depth forall a. Num a => a -> a -> a
+ Int
1)
        forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ [Block]
blocks forall a. [a] -> [a] -> [a]
++ [Block]
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 -> JiraParser ()
atDepth Int
depth forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*>
      (forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT Text ParserState Identity Char
bulletChar forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Int -> JiraParser [Block]
nonListContent Int
depth) forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|>
       forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT Text ParserState Identity Char
anyBulletMarker 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
        Block
first <- Int -> JiraParser Block
listAtDepth' Int
depth
        [Block]
rest <- forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many (Int -> JiraParser Block
listAtDepth Int
depth)
        forall (m :: * -> *) a. Monad m => a -> m a
return (Block
first forall a. a -> [a] -> [a]
: [Block]
rest)

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

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

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

-- | Parses a table cell.
cell :: JiraParser Cell
cell :: JiraParser Cell
cell = forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try forall a b. (a -> b) -> a -> b
$ do
  [Block] -> Cell
mkCell <- JiraParser ([Block] -> Cell)
cellStart
  [Block]
bs     <- forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many JiraParser Block
block
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ [Block] -> Cell
mkCell [Block]
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 = forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try
  forall a b. (a -> b) -> a -> b
$  JiraParser ()
skipSpaces
  forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'|'
  forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> 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 forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
many1 (forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'|'))
  forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* JiraParser ()
skipSpaces
  forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* forall a. Show a => JiraParser a -> JiraParser ()
notFollowedBy' 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 = forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try forall a b. (a -> b) -> a -> b
$ do
  (Maybe Text
langName, [Parameter]
params) <- forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"{code" forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> ParsecT Text ParserState Identity (Maybe Text, [Parameter])
parameters forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'}' forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* JiraParser ()
blankline
  let lang :: Language
lang = forall b a. b -> (a -> b) -> Maybe a -> b
maybe Language
defaultLanguage Text -> Language
Language Maybe Text
langName
  String
content <- forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
anyChar 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` forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"{code}" forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> JiraParser ()
blankline)
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Language -> [Parameter] -> Text -> Block
Code Language
lang [Parameter]
params (String -> Text
pack String
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 = forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try forall a b. (a -> b) -> a -> b
$ JiraParser Block
singleLineBq 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 forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall a. a -> [a] -> [a]
:[]) forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Inline] -> Block
Para forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
                   (forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"bq." forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m ()
skipMany (forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
' ') forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*>
                    JiraParser Inline
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` (forall (f :: * -> *) a. Functor f => f a -> f ()
void forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
newline forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> forall s (m :: * -> *) t u.
(Stream s m t, Show t) =>
ParsecT s u m ()
eof))
    multiLineBq :: JiraParser Block
multiLineBq = [Block] -> Block
BlockQuote forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
                  (forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"{quote}"
                   forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m ()
optional JiraParser ()
blankline
                   forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m ()
skipMany (forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
' ')
                   forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> JiraParser Block
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` forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (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 forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$
  forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"----" forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> JiraParser ()
blankline)

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

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

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

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