{-# LANGUAGE CPP #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE TupleSections #-}
{-|
Module      : Text.Jira.Parser.Inline
Copyright   : © 2019–2021 Albert Krewinkel
License     : MIT

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

Parse Jira wiki inline markup.
-}
module Text.Jira.Parser.Inline
  ( inline
    -- * Inline component parsers
  , anchor
  , autolink
  , citation
  , colorInline
  , dash
  , emoji
  , entity
  , image
  , linebreak
  , link
  , monospaced
  , specialChar
  , str
  , styled
  , whitespace
    -- * Constants
  , specialChars
  ) where

import Control.Monad (guard, void)
import Data.Char (isAlphaNum, isAscii, isPunctuation, ord)
#if !MIN_VERSION_base(4,13,0)
import Data.Monoid ((<>), All (..))
#else
import Data.Monoid (All (..))
#endif
import Data.Text (append, pack)
import Text.Jira.Markup
import Text.Jira.Parser.Core
import Text.Jira.Parser.Shared
import Text.Parsec

-- | Parses any inline element.
inline :: JiraParser Inline
inline :: JiraParser Inline
inline = JiraParser String -> JiraParser ()
forall a. Show a => JiraParser a -> JiraParser ()
notFollowedBy' JiraParser String
forall u. ParsecT Text u Identity String
blockEnd JiraParser () -> JiraParser Inline -> JiraParser Inline
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> [JiraParser Inline] -> JiraParser Inline
forall s (m :: * -> *) t u a.
Stream s m t =>
[ParsecT s u m a] -> ParsecT s u m a
choice
  [ JiraParser Inline
whitespace
  , JiraParser Inline
emoji
  , JiraParser Inline
dash
  , JiraParser Inline
autolink
  , JiraParser Inline
str
  , JiraParser Inline
linebreak
  , JiraParser Inline
link
  , JiraParser Inline
image
  , JiraParser Inline
styled
  , JiraParser Inline
colorInline
  , JiraParser Inline
monospaced
  , JiraParser Inline
anchor
  , JiraParser Inline
citation
  , JiraParser Inline
entity
  , JiraParser Inline
specialChar
  ] JiraParser Inline -> String -> JiraParser Inline
forall s u (m :: * -> *) a.
ParsecT s u m a -> String -> ParsecT s u m a
<?> String
"inline"
  where
    blockEnd :: ParsecT Text u Identity String
blockEnd = Char -> ParsecT Text u Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'{' ParsecT Text u Identity Char
-> ParsecT Text u Identity String -> ParsecT Text u Identity String
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> [ParsecT Text u Identity String] -> ParsecT Text u Identity String
forall s (m :: * -> *) t u a.
Stream s m t =>
[ParsecT s u m a] -> ParsecT s u m a
choice ((String -> ParsecT Text u Identity String)
-> [String] -> [ParsecT Text u Identity String]
forall a b. (a -> b) -> [a] -> [b]
map String -> ParsecT Text u Identity String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string [String]
blockNames) ParsecT Text u Identity String
-> ParsecT Text u Identity Char -> ParsecT Text u Identity String
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Char -> ParsecT Text u Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'}'

-- | Characters which, depending on context, can have a special meaning.
specialChars :: String
specialChars :: String
specialChars = String
"_+-*^~|[]{}(?!&\\:;"

-- | Parses an in-paragraph newline as a @Linebreak@ element. Both newline
-- characters and double-backslash are recognized as line-breaks.
linebreak :: JiraParser Inline
linebreak :: JiraParser Inline
linebreak = (JiraParser Inline -> String -> JiraParser Inline
forall s u (m :: * -> *) a.
ParsecT s u m a -> String -> ParsecT s u m a
<?> String
"linebreak") (JiraParser Inline -> JiraParser Inline)
-> (JiraParser Inline -> JiraParser Inline)
-> JiraParser Inline
-> JiraParser Inline
forall b c a. (b -> c) -> (a -> b) -> a -> c
. JiraParser Inline -> JiraParser Inline
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (JiraParser Inline -> JiraParser Inline)
-> JiraParser Inline -> JiraParser Inline
forall a b. (a -> b) -> a -> b
$ do
  Bool -> JiraParser ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> JiraParser ())
-> (ParserState -> Bool) -> ParserState -> JiraParser ()
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
stateInMarkup (ParserState -> JiraParser ())
-> ParsecT Text ParserState Identity ParserState -> JiraParser ()
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
  [JiraParser ()] -> JiraParser ()
forall s (m :: * -> *) t u a.
Stream s m t =>
[ParsecT s u m a] -> ParsecT s u m a
choice [ ParsecT Text ParserState Identity Char -> JiraParser ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (ParsecT Text ParserState Identity Char -> JiraParser ())
-> ParsecT Text ParserState Identity Char -> JiraParser ()
forall a b. (a -> b) -> a -> b
$ ParsecT Text ParserState Identity Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
newline ParsecT Text ParserState Identity Char
-> JiraParser () -> ParsecT Text ParserState Identity Char
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* JiraParser () -> JiraParser ()
forall a. Show a => JiraParser a -> JiraParser ()
notFollowedBy' JiraParser ()
endOfPara
         , JiraParser String -> JiraParser ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (JiraParser String -> JiraParser ())
-> JiraParser String -> JiraParser ()
forall a b. (a -> b) -> a -> b
$ String -> JiraParser String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"\\\\" JiraParser String -> JiraParser () -> JiraParser String
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* ParsecT Text ParserState Identity Char -> JiraParser ()
forall a. Show a => JiraParser a -> JiraParser ()
notFollowedBy' (Char -> ParsecT Text ParserState Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'\\')
         ]
  JiraParser ()
updateLastSpcPos
  Inline -> JiraParser Inline
forall (m :: * -> *) a. Monad m => a -> m a
return Inline
Linebreak

-- | Parses whitespace and return a @Space@ element.
whitespace :: JiraParser Inline
whitespace :: JiraParser Inline
whitespace = Inline
Space Inline -> JiraParser () -> JiraParser Inline
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ ParsecT Text ParserState Identity Char -> JiraParser ()
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m ()
skipMany1 (Char -> ParsecT Text ParserState Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
' ') JiraParser Inline -> JiraParser () -> JiraParser Inline
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* JiraParser ()
updateLastSpcPos
  JiraParser Inline -> String -> JiraParser Inline
forall s u (m :: * -> *) a.
ParsecT s u m a -> String -> ParsecT s u m a
<?> String
"whitespace"

-- | Parses a simple, markup-less string into a @Str@ element.
str :: JiraParser Inline
str :: JiraParser Inline
str = Text -> Inline
Str (Text -> Inline) -> ([String] -> Text) -> [String] -> Inline
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
pack (String -> Text) -> ([String] -> String) -> [String] -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> String
forall a. Monoid a => [a] -> a
mconcat
  ([String] -> Inline)
-> ParsecT Text ParserState Identity [String] -> JiraParser Inline
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> JiraParser String -> ParsecT Text ParserState Identity [String]
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
many1 (JiraParser String
alphaNums JiraParser String -> JiraParser String -> JiraParser String
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> JiraParser String
forall u. ParsecT Text u Identity String
otherNonSpecialChars)
  JiraParser Inline -> String -> JiraParser Inline
forall s u (m :: * -> *) a.
ParsecT s u m a -> String -> ParsecT s u m a
<?> String
"string"
  where
    nonStrChars :: String
nonStrChars = String
" \n" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
specialChars
    alphaNums :: JiraParser String
alphaNums = ParsecT Text ParserState Identity Char -> JiraParser String
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
many1 ParsecT Text ParserState Identity Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
alphaNum JiraParser String -> JiraParser () -> JiraParser String
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* JiraParser ()
updateLastStrPos
    otherNonSpecialChars :: ParsecT Text u Identity String
otherNonSpecialChars = ParsecT Text u Identity Char -> ParsecT Text u Identity String
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
many1 (ParsecT Text u Identity Char -> ParsecT Text u Identity String)
-> ((Char -> Bool) -> ParsecT Text u Identity Char)
-> (Char -> Bool)
-> ParsecT Text u Identity String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> ParsecT Text u Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
(Char -> Bool) -> ParsecT s u m Char
satisfy ((Char -> Bool) -> ParsecT Text u Identity String)
-> (Char -> Bool) -> ParsecT Text u Identity String
forall a b. (a -> b) -> a -> b
$ \Char
c ->
      Bool -> Bool
not (Char -> Bool
isAlphaNum Char
c Bool -> Bool -> Bool
|| Char
c Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` String
nonStrChars)

-- | Parses an HTML entity into an @'Entity'@ element.
entity :: JiraParser Inline
entity :: JiraParser Inline
entity = Text -> Inline
Entity (Text -> Inline) -> (String -> Text) -> String -> Inline
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
pack
  (String -> Inline) -> JiraParser String -> JiraParser Inline
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> JiraParser String -> JiraParser String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (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 String -> JiraParser String
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> (JiraParser String
forall u. ParsecT Text u Identity String
numerical JiraParser String -> JiraParser String -> JiraParser String
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> JiraParser String
forall u. ParsecT Text u Identity String
named) JiraParser String
-> ParsecT Text ParserState Identity Char -> JiraParser String
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
';')
  where
    numerical :: ParsecT Text u Identity String
numerical = (:) (Char -> String -> String)
-> ParsecT Text u Identity Char
-> ParsecT Text u Identity (String -> String)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Char -> ParsecT Text u Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'#' ParsecT Text u Identity (String -> String)
-> ParsecT Text u Identity String -> ParsecT Text u Identity String
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> ParsecT Text u Identity Char -> ParsecT Text u Identity String
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
many1 ParsecT Text u Identity Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
digit
    named :: ParsecT Text u Identity String
named = ParsecT Text u Identity Char -> ParsecT Text u Identity String
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
many1 ParsecT Text u Identity Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
letter

-- | Parses textual representation of an icon into an @'Emoji'@ element.
emoji :: JiraParser Inline
emoji :: JiraParser Inline
emoji = JiraParser Inline -> JiraParser Inline
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (Icon -> Inline
Emoji (Icon -> Inline)
-> ParsecT Text ParserState Identity Icon -> JiraParser Inline
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT Text ParserState Identity Icon
forall u. Parsec Text u Icon
icon JiraParser Inline -> JiraParser () -> JiraParser Inline
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* ParsecT Text ParserState Identity Char -> JiraParser ()
forall a. Show a => JiraParser a -> JiraParser ()
notFollowedBy' ParsecT Text ParserState Identity Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
letter JiraParser Inline -> String -> JiraParser Inline
forall s u (m :: * -> *) a.
ParsecT s u m a -> String -> ParsecT s u m a
<?> String
"emoji")

-- | Parses ASCII representation of en-dash or em-dash.
dash :: JiraParser Inline
dash :: JiraParser Inline
dash = JiraParser Inline -> JiraParser Inline
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (JiraParser Inline -> JiraParser Inline)
-> JiraParser Inline -> JiraParser Inline
forall a b. (a -> b) -> a -> b
$ do
  Bool -> JiraParser ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> JiraParser ())
-> ParsecT Text ParserState Identity Bool -> JiraParser ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< ParsecT Text ParserState Identity Bool
notAfterString
  String
_ <- String -> JiraParser String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"--"
  [JiraParser Inline] -> JiraParser Inline
forall s (m :: * -> *) t u a.
Stream s m t =>
[ParsecT s u m a] -> ParsecT s u m a
choice [ Text -> Inline
Str Text
"—" Inline
-> ParsecT Text ParserState Identity Char -> JiraParser Inline
forall (f :: * -> *) a b. Functor 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
'-'   -- em dash
         , Inline -> JiraParser Inline
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Text -> Inline
Str Text
"–")          -- en dash
         ] JiraParser Inline -> JiraParser () -> JiraParser Inline
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* JiraParser () -> JiraParser ()
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a
lookAhead (ParsecT Text ParserState Identity Char -> JiraParser ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (Char -> ParsecT Text ParserState Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
' ') JiraParser () -> JiraParser () -> JiraParser ()
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> JiraParser ()
forall s (m :: * -> *) t u.
(Stream s m t, Show t) =>
ParsecT s u m ()
eof)

-- | Parses a special character symbol as a @Str@.
specialChar :: JiraParser Inline
specialChar :: JiraParser Inline
specialChar = Char -> Inline
SpecialChar (Char -> Inline)
-> ParsecT Text ParserState Identity Char -> JiraParser Inline
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (ParsecT Text ParserState Identity Char
forall u. ParsecT Text u Identity Char
escapedChar ParsecT Text ParserState Identity Char
-> ParsecT Text ParserState Identity Char
-> ParsecT Text ParserState Identity Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT Text ParserState Identity Char
plainSpecialChar)
  JiraParser Inline -> String -> JiraParser Inline
forall s u (m :: * -> *) a.
ParsecT s u m a -> String -> ParsecT s u m a
<?> String
"special char"
  where
    escapedChar :: ParsecT Text u Identity Char
escapedChar = ParsecT Text u Identity Char -> ParsecT Text u Identity Char
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (Char -> ParsecT Text u Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'\\' ParsecT Text u Identity Char
-> ParsecT Text u Identity Char -> ParsecT Text u Identity Char
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> (Char -> Bool) -> ParsecT Text u Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
(Char -> Bool) -> ParsecT s u m Char
satisfy Char -> Bool
isPunctuation)

    plainSpecialChar :: ParsecT Text ParserState Identity Char
plainSpecialChar = do
      Char -> All
inTablePred <- do
        Bool
b <- ParserState -> Bool
stateInTable (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
        (Char -> All) -> ParsecT Text ParserState Identity (Char -> All)
forall (m :: * -> *) a. Monad m => a -> m a
return ((Char -> All) -> ParsecT Text ParserState Identity (Char -> All))
-> (Char -> All) -> ParsecT Text ParserState Identity (Char -> All)
forall a b. (a -> b) -> a -> b
$ if Bool
b then Bool -> All
All (Bool -> All) -> (Char -> Bool) -> Char -> All
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'|') else Char -> All
forall a. Monoid a => a
mempty
      Char -> All
inLinkPred  <- do
        Bool
b <- ParserState -> Bool
stateInLink  (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
        (Char -> All) -> ParsecT Text ParserState Identity (Char -> All)
forall (m :: * -> *) a. Monad m => a -> m a
return ((Char -> All) -> ParsecT Text ParserState Identity (Char -> All))
-> (Char -> All) -> ParsecT Text ParserState Identity (Char -> All)
forall a b. (a -> b) -> a -> b
$ if Bool
b then Bool -> All
All (Bool -> All) -> (Char -> Bool) -> Char -> All
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` (String
"]^|\n" :: String)) else Char -> All
forall a. Monoid a => a
mempty
      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 Char)
-> String -> ParsecT Text ParserState Identity Char
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
filter (All -> Bool
getAll (All -> Bool) -> (Char -> All) -> Char -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> All
inTablePred (Char -> All) -> (Char -> All) -> Char -> All
forall a. Semigroup a => a -> a -> a
<> Char -> All
inLinkPred)) String
specialChars


--
-- Anchors, links and images
--

-- | Parses an anchor into an @Anchor@ element.
anchor :: JiraParser Inline
anchor :: JiraParser Inline
anchor = Text -> Inline
Anchor (Text -> Inline) -> (String -> Text) -> String -> Inline
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
pack (String -> Text) -> (String -> String) -> String -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
filter (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
' ')
  (String -> Inline) -> JiraParser String -> JiraParser Inline
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> JiraParser String -> JiraParser String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (String -> JiraParser String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"{anchor:" JiraParser String -> JiraParser String -> JiraParser String
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
noneOf String
"\n" ParsecT Text ParserState Identity Char
-> ParsecT Text ParserState Identity Char -> JiraParser String
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` Char -> ParsecT Text ParserState Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'}')

-- | Parse image into an @Image@ element.
image :: JiraParser Inline
image :: JiraParser Inline
image = JiraParser Inline -> JiraParser Inline
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (JiraParser Inline -> JiraParser Inline)
-> JiraParser Inline -> JiraParser Inline
forall a b. (a -> b) -> a -> b
$ do
  -- does not use @url@, as is may contain relative locations.
  URL
src <- 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
-> ParsecT Text ParserState Identity URL
-> ParsecT Text ParserState Identity URL
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> (Text -> URL
URL (Text -> URL) -> (String -> Text) -> String -> URL
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
pack (String -> URL)
-> JiraParser String -> ParsecT Text ParserState Identity URL
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT Text ParserState Identity Char -> JiraParser String
forall s (m :: * -> *) t u a.
Stream s m t =>
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
noneOf String
"\r\t\n|]!"))
  [Parameter]
params <- [Parameter]
-> ParsecT Text ParserState Identity [Parameter]
-> ParsecT Text ParserState Identity [Parameter]
forall s (m :: * -> *) t a u.
Stream s m t =>
a -> ParsecT s u m a -> ParsecT s u m a
option [] (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
-> ParsecT Text ParserState Identity [Parameter]
-> ParsecT Text ParserState Identity [Parameter]
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> (ParsecT Text ParserState Identity [Parameter]
forall u. ParsecT Text u Identity [Parameter]
thumbnail ParsecT Text ParserState Identity [Parameter]
-> ParsecT Text ParserState Identity [Parameter]
-> ParsecT Text ParserState Identity [Parameter]
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT Text ParserState Identity Parameter
forall u. ParsecT Text u Identity Parameter
imgParams ParsecT Text ParserState Identity Parameter
-> JiraParser () -> ParsecT Text ParserState Identity [Parameter]
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]
`sepBy` JiraParser ()
comma))
  Char
_ <- Char -> ParsecT Text ParserState Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'!'
  Inline -> JiraParser Inline
forall (m :: * -> *) a. Monad m => a -> m a
return (Inline -> JiraParser Inline) -> Inline -> JiraParser Inline
forall a b. (a -> b) -> a -> b
$ [Parameter] -> URL -> Inline
Image [Parameter]
params URL
src
  where
    thumbnail :: ParsecT Text u Identity [Parameter]
thumbnail = [Text -> Text -> Parameter
Parameter Text
"thumbnail" Text
""] [Parameter]
-> ParsecT Text u Identity String
-> ParsecT Text u Identity [Parameter]
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ ParsecT Text u Identity String -> ParsecT Text u Identity String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (String -> ParsecT Text u Identity String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"thumbnail")
    imgParams :: ParsecT Text u Identity Parameter
imgParams = ParsecT Text u Identity Parameter
-> ParsecT Text u Identity Parameter
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (Text -> Text -> Parameter
Parameter (Text -> Text -> Parameter)
-> ParsecT Text u Identity Text
-> ParsecT Text u Identity (Text -> Parameter)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT Text u Identity Text
forall u. ParsecT Text u Identity Text
key ParsecT Text u Identity (Text -> Parameter)
-> ParsecT Text u Identity Text
-> ParsecT Text u Identity Parameter
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Char -> ParsecT Text u Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'=' ParsecT Text u Identity Char
-> ParsecT Text u Identity Text -> ParsecT Text u Identity Text
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> ParsecT Text u Identity Text
forall u. ParsecT Text u Identity Text
value))
    key :: ParsecT Text u Identity Text
key       = String -> Text
pack (String -> Text)
-> ParsecT Text u Identity String -> ParsecT Text u Identity Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT Text u Identity Char -> ParsecT Text u Identity String
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
many1 (String -> ParsecT Text u Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
noneOf String
",\"'\t\n\r |{}=!")
    value :: ParsecT Text u Identity Text
value     = String -> Text
pack (String -> Text)
-> ParsecT Text u Identity String -> ParsecT Text u Identity Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (ParsecT Text u Identity String -> ParsecT Text u Identity String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try ParsecT Text u Identity String
forall u. ParsecT Text u Identity String
quotedValue ParsecT Text u Identity String
-> ParsecT Text u Identity String -> ParsecT Text u Identity String
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT Text u Identity String
forall u. ParsecT Text u Identity String
unquotedValue)
    comma :: JiraParser ()
comma     = 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 () -> JiraParser ()
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> JiraParser ()
skipSpaces
    quotedValue :: ParsecT Text u Identity String
quotedValue = Char -> ParsecT Text u Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'"' ParsecT Text u Identity Char
-> ParsecT Text u Identity String -> ParsecT Text u Identity String
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> ParsecT Text u Identity Char
-> ParsecT Text u Identity Char -> ParsecT Text u Identity String
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 (String -> ParsecT Text u Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
noneOf String
"\n\r") (Char -> ParsecT Text u Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'"')
    unquotedValue :: ParsecT Text u Identity String
unquotedValue = ParsecT Text u Identity Char -> ParsecT Text u Identity String
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
many1 (String -> ParsecT Text u Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
noneOf String
",\"'\n\r|{}=!")

-- | Parse link into a @Link@ element.
link :: JiraParser Inline
link :: JiraParser Inline
link = JiraParser Inline -> JiraParser Inline
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (JiraParser Inline -> JiraParser Inline)
-> JiraParser Inline -> JiraParser Inline
forall a b. (a -> b) -> a -> b
$ do
  Bool -> JiraParser ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> JiraParser ())
-> (ParserState -> Bool) -> ParserState -> JiraParser ()
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
stateInLink (ParserState -> JiraParser ())
-> ParsecT Text ParserState Identity ParserState -> JiraParser ()
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 Inline -> JiraParser Inline
forall a.
(Bool -> ParserState -> ParserState)
-> JiraParser a -> JiraParser a
withStateFlag (\Bool
b ParserState
st -> ParserState
st { stateInLink :: Bool
stateInLink = Bool
b }) (JiraParser Inline -> JiraParser Inline)
-> JiraParser Inline -> JiraParser Inline
forall a b. (a -> b) -> a -> b
$ do
    Char
_ <- Char -> ParsecT Text ParserState Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'['
    ([Inline]
alias, Char
sep) <- ([Inline], Char)
-> ParsecT Text ParserState Identity ([Inline], Char)
-> ParsecT Text ParserState Identity ([Inline], Char)
forall s (m :: * -> *) t a u.
Stream s m t =>
a -> ParsecT s u m a -> ParsecT s u m a
option ([], Char
'|') (ParsecT Text ParserState Identity ([Inline], Char)
 -> ParsecT Text ParserState Identity ([Inline], Char))
-> (ParsecT Text ParserState Identity ([Inline], Char)
    -> ParsecT Text ParserState Identity ([Inline], Char))
-> ParsecT Text ParserState Identity ([Inline], Char)
-> ParsecT Text ParserState Identity ([Inline], Char)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParsecT Text ParserState Identity ([Inline], Char)
-> ParsecT Text ParserState Identity ([Inline], Char)
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT Text ParserState Identity ([Inline], Char)
 -> ParsecT Text ParserState Identity ([Inline], Char))
-> ParsecT Text ParserState Identity ([Inline], Char)
-> ParsecT Text ParserState Identity ([Inline], Char)
forall a b. (a -> b) -> a -> b
$ (,) ([Inline] -> Char -> ([Inline], Char))
-> ParsecT Text ParserState Identity [Inline]
-> ParsecT Text ParserState Identity (Char -> ([Inline], Char))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> JiraParser Inline -> ParsecT Text ParserState Identity [Inline]
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many JiraParser Inline
inline ParsecT Text ParserState Identity (Char -> ([Inline], Char))
-> ParsecT Text ParserState Identity Char
-> ParsecT Text ParserState Identity ([Inline], Char)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> String -> ParsecT Text ParserState Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf String
"^|"
    (LinkType
linkType, URL
linkURL) <-
      if Char
sep Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'|'
      then (LinkType
Email,) (URL -> (LinkType, URL))
-> ParsecT Text ParserState Identity URL
-> ParsecT Text ParserState Identity (LinkType, URL)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT Text ParserState Identity URL
email ParsecT Text ParserState Identity (LinkType, URL)
-> ParsecT Text ParserState Identity (LinkType, URL)
-> ParsecT Text ParserState Identity (LinkType, URL)
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|>
           (LinkType
External,) (URL -> (LinkType, URL))
-> ParsecT Text ParserState Identity URL
-> ParsecT Text ParserState Identity (LinkType, URL)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT Text ParserState Identity URL
anchorLink ParsecT Text ParserState Identity (LinkType, URL)
-> ParsecT Text ParserState Identity (LinkType, URL)
-> ParsecT Text ParserState Identity (LinkType, URL)
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|>
           (LinkType
User,) (URL -> (LinkType, URL))
-> ParsecT Text ParserState Identity URL
-> ParsecT Text ParserState Identity (LinkType, URL)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT Text ParserState Identity URL
userLink ParsecT Text ParserState Identity (LinkType, URL)
-> ParsecT Text ParserState Identity (LinkType, URL)
-> ParsecT Text ParserState Identity (LinkType, URL)
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|>
           ParsecT Text ParserState Identity (LinkType, URL)
externalLink
      else (LinkType
Attachment,) (URL -> (LinkType, URL))
-> (String -> URL) -> String -> (LinkType, URL)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> URL
URL (Text -> URL) -> (String -> Text) -> String -> URL
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
pack (String -> (LinkType, URL))
-> JiraParser String
-> ParsecT Text ParserState Identity (LinkType, URL)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
           ParsecT Text ParserState Identity Char -> JiraParser String
forall s (m :: * -> *) t u a.
Stream s m t =>
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
noneOf String
"\t\r\f\n]|:;/\\")
    Char
_ <- Char -> ParsecT Text ParserState Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
']'
    Inline -> JiraParser Inline
forall (m :: * -> *) a. Monad m => a -> m a
return (Inline -> JiraParser Inline) -> Inline -> JiraParser Inline
forall a b. (a -> b) -> a -> b
$ LinkType -> [Inline] -> URL -> Inline
Link LinkType
linkType [Inline]
alias URL
linkURL

-- | Parse a plain URL or mail address as @'AutoLink'@ element.
autolink :: JiraParser Inline
autolink :: JiraParser Inline
autolink = do
  Bool -> JiraParser ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> JiraParser ())
-> (ParserState -> Bool) -> ParserState -> JiraParser ()
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
stateInLink (ParserState -> JiraParser ())
-> ParsecT Text ParserState Identity ParserState -> JiraParser ()
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
  URL -> Inline
AutoLink (URL -> Inline)
-> ParsecT Text ParserState Identity URL -> JiraParser Inline
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (ParsecT Text ParserState Identity URL
email' ParsecT Text ParserState Identity URL
-> ParsecT Text ParserState Identity URL
-> ParsecT Text ParserState Identity URL
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> Bool -> ParsecT Text ParserState Identity URL
url Bool
True) JiraParser Inline -> String -> JiraParser Inline
forall s u (m :: * -> *) a.
ParsecT s u m a -> String -> ParsecT s u m a
<?> String
"email or other URL"
    where email' :: ParsecT Text ParserState Identity URL
email' = (\(URL Text
e) -> Text -> URL
URL (Text
"mailto:" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
e)) (URL -> URL)
-> ParsecT Text ParserState Identity URL
-> ParsecT Text ParserState Identity URL
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT Text ParserState Identity URL
email

-- | Parse a URL with scheme @file@, @ftp@, @http@, @https@, @irc@,
-- @nntp@, or @news@; ignores @file@ if @isAutoLink@ is false.
url :: Bool {-^ isAutoLink -} -> JiraParser URL
url :: Bool -> ParsecT Text ParserState Identity URL
url Bool
isAutoLink = ParsecT Text ParserState Identity URL
-> ParsecT Text ParserState Identity URL
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT Text ParserState Identity URL
 -> ParsecT Text ParserState Identity URL)
-> ParsecT Text ParserState Identity URL
-> ParsecT Text ParserState Identity URL
forall a b. (a -> b) -> a -> b
$ do
  let urlChar' :: ParsecT Text ParserState Identity Char
urlChar' = if Bool
isAutoLink then ParsecT Text ParserState Identity Char
urlPathChar else ParsecT Text ParserState Identity Char
urlChar ParsecT Text ParserState Identity Char
-> ParsecT Text ParserState Identity Char
-> ParsecT Text ParserState Identity Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> Char -> ParsecT Text ParserState Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
' '
  Text
urlScheme <- ParsecT Text ParserState Identity Text
forall u. ParsecT Text u Identity Text
scheme
  Text
sep <- String -> Text
pack (String -> Text)
-> JiraParser String -> ParsecT Text ParserState Identity Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> JiraParser String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"://"
  Text
rest <- String -> Text
pack (String -> Text)
-> JiraParser String -> ParsecT Text ParserState Identity Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT Text ParserState Identity Char -> JiraParser String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many ParsecT Text ParserState Identity Char
urlChar'
  URL -> ParsecT Text ParserState Identity URL
forall (m :: * -> *) a. Monad m => a -> m a
return (URL -> ParsecT Text ParserState Identity URL)
-> URL -> ParsecT Text ParserState Identity URL
forall a b. (a -> b) -> a -> b
$ Text -> URL
URL (Text
urlScheme Text -> Text -> Text
`append` Text
sep Text -> Text -> Text
`append` Text
rest)
  where
    scheme :: ParsecT Text u Identity Text
scheme = do
      Char
first <- ParsecT Text u Identity Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
letter
      case Char
first of
        Char
'f' -> (Text
"file" Text
-> ParsecT Text u Identity String -> ParsecT Text u Identity Text
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ (Bool -> ParsecT Text u Identity ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Bool
not Bool
isAutoLink) ParsecT Text u Identity ()
-> ParsecT Text u Identity String -> ParsecT Text u Identity String
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> String -> ParsecT Text u Identity String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"ile")) ParsecT Text u Identity Text
-> ParsecT Text u Identity Text -> ParsecT Text u Identity Text
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|>
               (Text
"ftp" Text
-> ParsecT Text u Identity String -> ParsecT Text u Identity Text
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ String -> ParsecT Text u Identity String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"tp")
        Char
'h' -> String -> ParsecT Text u Identity String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"ttp" ParsecT Text u Identity String
-> ParsecT Text u Identity Text -> ParsecT Text u Identity Text
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Text
-> ParsecT Text u Identity Text -> ParsecT Text u Identity Text
forall s (m :: * -> *) t a u.
Stream s m t =>
a -> ParsecT s u m a -> ParsecT s u m a
option Text
"http" (Text
"https" Text
-> ParsecT Text u Identity Char -> ParsecT Text u Identity Text
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Char -> ParsecT Text u Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
's')
        Char
'i' -> Text
"irc" Text
-> ParsecT Text u Identity String -> ParsecT Text u Identity Text
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ String -> ParsecT Text u Identity String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"rc"
        Char
'n' -> (Text
"nntp" Text
-> ParsecT Text u Identity String -> ParsecT Text u Identity Text
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ String -> ParsecT Text u Identity String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"ntp") ParsecT Text u Identity Text
-> ParsecT Text u Identity Text -> ParsecT Text u Identity Text
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> (Text
"news" Text
-> ParsecT Text u Identity String -> ParsecT Text u Identity Text
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ String -> ParsecT Text u Identity String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"ews")
        Char
_   -> String -> ParsecT Text u Identity Text
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"not looking at a known scheme"

-- | Parses an email URI, returns the mail address without schema.
email :: JiraParser URL
email :: ParsecT Text ParserState Identity URL
email = Text -> URL
URL (Text -> URL) -> (String -> Text) -> String -> URL
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
pack (String -> URL)
-> JiraParser String -> ParsecT Text ParserState Identity URL
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> JiraParser String -> JiraParser String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (String -> JiraParser String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"mailto:" JiraParser String -> JiraParser String -> JiraParser String
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> ParsecT Text ParserState Identity Char -> JiraParser String
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
many1 ParsecT Text ParserState Identity Char
urlChar)

-- | Parses the link to an anchor name.
anchorLink :: JiraParser URL
anchorLink :: ParsecT Text ParserState Identity URL
anchorLink = Text -> URL
URL (Text -> URL) -> (String -> Text) -> String -> URL
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
pack (String -> URL)
-> JiraParser String -> ParsecT Text ParserState Identity URL
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ((:) (Char -> String -> String)
-> ParsecT Text ParserState Identity Char
-> ParsecT Text ParserState Identity (String -> String)
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
'#' ParsecT Text ParserState Identity (String -> String)
-> JiraParser String -> JiraParser String
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> ParsecT Text ParserState Identity Char -> JiraParser String
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
many1 ParsecT Text ParserState Identity Char
urlChar)

-- | Parses a user-identifying resource name
userLink :: JiraParser URL
userLink :: ParsecT Text ParserState Identity URL
userLink = Text -> URL
URL (Text -> URL) -> (String -> Text) -> String -> URL
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
pack (String -> URL)
-> JiraParser String -> ParsecT Text ParserState Identity URL
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
'~' ParsecT Text ParserState Identity Char
-> JiraParser String -> JiraParser String
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> ParsecT Text ParserState Identity Char -> JiraParser String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many (String -> ParsecT Text ParserState Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
noneOf String
"|]\n\r"))

-- | Parses an external link, i.e., either a plain link to an external
-- website, or a \"smart\" link or card.
externalLink :: JiraParser (LinkType, URL)
externalLink :: ParsecT Text ParserState Identity (LinkType, URL)
externalLink = do
  URL
url' <- Bool -> ParsecT Text ParserState Identity URL
url Bool
False
  Maybe LinkType
mSmartType <- ParsecT Text ParserState Identity LinkType
-> ParsecT Text ParserState Identity (Maybe LinkType)
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m (Maybe a)
optionMaybe (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
-> ParsecT Text ParserState Identity LinkType
-> ParsecT Text ParserState Identity LinkType
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> ParsecT Text ParserState Identity LinkType
smartLinkType)
  (LinkType, URL)
-> ParsecT Text ParserState Identity (LinkType, URL)
forall (m :: * -> *) a. Monad m => a -> m a
return ((LinkType, URL)
 -> ParsecT Text ParserState Identity (LinkType, URL))
-> (LinkType, URL)
-> ParsecT Text ParserState Identity (LinkType, URL)
forall a b. (a -> b) -> a -> b
$ case Maybe LinkType
mSmartType of
    Maybe LinkType
Nothing -> (LinkType
External, URL
url')
    Just LinkType
st -> (LinkType
st, URL
url')

-- | Finds the type of a "smart" link.
smartLinkType :: JiraParser LinkType
smartLinkType :: ParsecT Text ParserState Identity LinkType
smartLinkType = String -> JiraParser String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"smart-" JiraParser String
-> ParsecT Text ParserState Identity LinkType
-> ParsecT Text ParserState Identity LinkType
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> [ParsecT Text ParserState Identity LinkType]
-> ParsecT Text ParserState Identity LinkType
forall s (m :: * -> *) t u a.
Stream s m t =>
[ParsecT s u m a] -> ParsecT s u m a
choice
  [ LinkType
SmartLink LinkType
-> JiraParser String -> ParsecT Text ParserState Identity LinkType
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ String -> JiraParser String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"link"
  , LinkType
SmartCard LinkType
-> JiraParser String -> ParsecT Text ParserState Identity LinkType
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ String -> JiraParser String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"card"
  ]

-- | Parses a character which is allowed in URLs
urlChar :: JiraParser Char
urlChar :: ParsecT Text ParserState Identity Char
urlChar = (Char -> Bool) -> ParsecT Text ParserState Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
(Char -> Bool) -> ParsecT s u m Char
satisfy ((Char -> Bool) -> ParsecT Text ParserState Identity Char)
-> (Char -> Bool) -> ParsecT Text ParserState Identity Char
forall a b. (a -> b) -> a -> b
$ \case
  Char
']' -> Bool
False    -- "]"
  Char
'|' -> Bool
False    -- "|"
  Char
x   -> Char -> Int
ord Char
x Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
32 Bool -> Bool -> Bool
&& Char -> Int
ord Char
x Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
126 -- excludes space

-- | Parses a character in an URL path.
urlPathChar :: JiraParser Char
urlPathChar :: ParsecT Text ParserState Identity Char
urlPathChar = (Char -> Bool) -> ParsecT Text ParserState Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
(Char -> Bool) -> ParsecT s u m Char
satisfy ((Char -> Bool) -> ParsecT Text ParserState Identity Char)
-> (Char -> Bool) -> ParsecT Text ParserState Identity Char
forall a b. (a -> b) -> a -> b
$ \case
  Char
'!' -> Bool
True
  Char
'#' -> Bool
True
  Char
'$' -> Bool
True
  Char
'%' -> Bool
True
  Char
'&' -> Bool
True
  Char
'\''-> Bool
True
  Char
'(' -> Bool
True
  Char
')' -> Bool
True
  Char
'*' -> Bool
True
  Char
'+' -> Bool
True
  Char
',' -> Bool
True
  Char
'-' -> Bool
True
  Char
'.' -> Bool
True
  Char
'/' -> Bool
True
  Char
':' -> Bool
True
  Char
';' -> Bool
True
  Char
'=' -> Bool
True
  Char
'?' -> Bool
True
  Char
'@' -> Bool
True
  Char
'\\'-> Bool
True
  Char
'_' -> Bool
True
  Char
'~' -> Bool
True
  Char
x   -> Char -> Bool
isAlphaNum Char
x Bool -> Bool -> Bool
&& Char -> Bool
isAscii Char
x

--
-- Color
--

-- | Text in a different color.
colorInline :: JiraParser Inline
colorInline :: JiraParser Inline
colorInline = JiraParser Inline -> JiraParser Inline
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (JiraParser Inline -> JiraParser Inline)
-> JiraParser Inline -> JiraParser Inline
forall a b. (a -> b) -> a -> b
$ do
  String
name <- String -> JiraParser String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"{color:" JiraParser String -> JiraParser String -> JiraParser String
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> JiraParser String
forall u. ParsecT Text u Identity String
colorName JiraParser String
-> ParsecT Text ParserState Identity Char -> JiraParser String
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
'}'
  [Inline]
content <- JiraParser Inline
inline JiraParser Inline
-> JiraParser String -> 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` JiraParser String -> JiraParser String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (String -> JiraParser String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"{color}")
  Inline -> JiraParser Inline
forall (m :: * -> *) a. Monad m => a -> m a
return (Inline -> JiraParser Inline) -> Inline -> JiraParser Inline
forall a b. (a -> b) -> a -> b
$ ColorName -> [Inline] -> Inline
ColorInline (Text -> ColorName
ColorName (Text -> ColorName) -> Text -> ColorName
forall a b. (a -> b) -> a -> b
$ String -> Text
pack String
name) [Inline]
content

--
-- Markup
--

-- | Parses styled text
styled :: JiraParser Inline
styled :: JiraParser Inline
styled = (JiraParser Inline
simpleStyled JiraParser Inline -> JiraParser Inline -> JiraParser Inline
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> JiraParser Inline
forceStyled) JiraParser Inline -> String -> JiraParser Inline
forall s u (m :: * -> *) a.
ParsecT s u m a -> String -> ParsecT s u m a
<?> String
"styled text"
  where
    simpleStyled :: JiraParser Inline
simpleStyled = JiraParser Inline -> JiraParser Inline
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (JiraParser Inline -> JiraParser Inline)
-> JiraParser Inline -> JiraParser Inline
forall a b. (a -> b) -> a -> b
$ do
      Char
styleChar <- ParsecT Text ParserState Identity Char
-> ParsecT Text ParserState Identity Char
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a
lookAhead (ParsecT Text ParserState Identity Char
 -> ParsecT Text ParserState Identity Char)
-> ParsecT Text ParserState Identity Char
-> ParsecT Text ParserState Identity Char
forall a b. (a -> b) -> a -> b
$ String -> ParsecT Text ParserState Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf String
"-_+*~^"
      [Inline]
content   <- ParsecT Text ParserState Identity [Inline]
-> ParsecT Text ParserState Identity [Inline]
forall a. JiraParser a -> JiraParser a
noNewlines (ParsecT Text ParserState Identity [Inline]
 -> ParsecT Text ParserState Identity [Inline])
-> ParsecT Text ParserState Identity [Inline]
-> ParsecT Text ParserState Identity [Inline]
forall a b. (a -> b) -> a -> b
$ Char
styleChar Char
-> JiraParser Inline -> ParsecT Text ParserState Identity [Inline]
forall a. Char -> JiraParser a -> JiraParser [a]
`delimitingMany` JiraParser Inline
inline
      let style :: InlineStyle
style = Char -> InlineStyle
delimiterStyle Char
styleChar
      Inline -> JiraParser Inline
forall (m :: * -> *) a. Monad m => a -> m a
return (Inline -> JiraParser Inline) -> Inline -> JiraParser Inline
forall a b. (a -> b) -> a -> b
$ InlineStyle -> [Inline] -> Inline
Styled InlineStyle
style [Inline]
content

    forceStyled :: JiraParser Inline
forceStyled = JiraParser Inline -> JiraParser Inline
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (JiraParser Inline -> JiraParser Inline)
-> JiraParser Inline -> JiraParser Inline
forall a b. (a -> b) -> a -> b
$ do
      Char
styleChar <- 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
-> ParsecT Text ParserState Identity Char
-> ParsecT Text ParserState Identity Char
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
"-_+*~^" ParsecT Text ParserState Identity Char
-> ParsecT Text ParserState Identity Char
-> ParsecT Text ParserState Identity Char
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
'}'
      let closing :: ParsecT Text u Identity String
closing = ParsecT Text u Identity String -> ParsecT Text u Identity String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT Text u Identity String -> ParsecT Text u Identity String)
-> ParsecT Text u Identity String -> ParsecT Text u Identity String
forall a b. (a -> b) -> a -> b
$ String -> ParsecT Text u Identity String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string [Char
'{', Char
styleChar, Char
'}']
      let style :: InlineStyle
style   = Char -> InlineStyle
delimiterStyle Char
styleChar
      [Inline]
content   <- ParsecT Text ParserState Identity [Inline]
-> ParsecT Text ParserState Identity [Inline]
forall a. JiraParser a -> JiraParser a
noNewlines (ParsecT Text ParserState Identity [Inline]
 -> ParsecT Text ParserState Identity [Inline])
-> ParsecT Text ParserState Identity [Inline]
-> ParsecT Text ParserState Identity [Inline]
forall a b. (a -> b) -> a -> b
$ JiraParser Inline
-> JiraParser String -> 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 JiraParser Inline
inline JiraParser String
forall u. ParsecT Text u Identity String
closing
      Inline -> JiraParser Inline
forall (m :: * -> *) a. Monad m => a -> m a
return (Inline -> JiraParser Inline) -> Inline -> JiraParser Inline
forall a b. (a -> b) -> a -> b
$ InlineStyle -> [Inline] -> Inline
Styled InlineStyle
style [Inline]
content

-- | Makes sure that the wrapped parser does not parse inline
-- linebreaks.
noNewlines :: JiraParser a -> JiraParser a
noNewlines :: JiraParser a -> JiraParser a
noNewlines = (Bool -> ParserState -> ParserState)
-> JiraParser a -> JiraParser a
forall a.
(Bool -> ParserState -> ParserState)
-> JiraParser a -> JiraParser a
withStateFlag (\Bool
b ParserState
st -> ParserState
st { stateInMarkup :: Bool
stateInMarkup = Bool
b })

-- | Returns the markup kind from the delimiting markup character.
delimiterStyle :: Char -> InlineStyle
delimiterStyle :: Char -> InlineStyle
delimiterStyle = \case
  Char
'*' -> InlineStyle
Strong
  Char
'+' -> InlineStyle
Insert
  Char
'-' -> InlineStyle
Strikeout
  Char
'^' -> InlineStyle
Superscript
  Char
'_' -> InlineStyle
Emphasis
  Char
'~' -> InlineStyle
Subscript
  Char
c   -> String -> InlineStyle
forall a. HasCallStack => String -> a
error (String
"Unknown delimiter character: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ [Char
c])

-- | Parses monospaced text into @Monospaced@.
monospaced :: JiraParser Inline
monospaced :: JiraParser Inline
monospaced = [Inline] -> Inline
Monospaced
  ([Inline] -> Inline)
-> ParsecT Text ParserState Identity [Inline] -> JiraParser Inline
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> JiraParser String
-> JiraParser String
-> JiraParser Inline
-> ParsecT Text ParserState Identity [Inline]
forall closing opening a.
Show closing =>
JiraParser opening
-> JiraParser closing -> JiraParser a -> JiraParser [a]
enclosed (JiraParser String -> JiraParser String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (JiraParser String -> JiraParser String)
-> JiraParser String -> JiraParser String
forall a b. (a -> b) -> a -> b
$ String -> JiraParser String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"{{") (JiraParser String -> JiraParser String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (JiraParser String -> JiraParser String)
-> JiraParser String -> JiraParser String
forall a b. (a -> b) -> a -> b
$ String -> JiraParser String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"}}") JiraParser Inline
inline
  JiraParser Inline -> String -> JiraParser Inline
forall s u (m :: * -> *) a.
ParsecT s u m a -> String -> ParsecT s u m a
<?> String
"monospaced"

citation :: JiraParser Inline
citation :: JiraParser Inline
citation = [Inline] -> Inline
Citation
  ([Inline] -> Inline)
-> ParsecT Text ParserState Identity [Inline] -> JiraParser Inline
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> JiraParser String
-> JiraParser String
-> JiraParser Inline
-> ParsecT Text ParserState Identity [Inline]
forall closing opening a.
Show closing =>
JiraParser opening
-> JiraParser closing -> JiraParser a -> JiraParser [a]
enclosed (JiraParser String -> JiraParser String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (JiraParser String -> JiraParser String)
-> JiraParser String -> JiraParser String
forall a b. (a -> b) -> a -> b
$ String -> JiraParser String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"??") (JiraParser String -> JiraParser String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (JiraParser String -> JiraParser String)
-> JiraParser String -> JiraParser String
forall a b. (a -> b) -> a -> b
$ String -> JiraParser String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"??") JiraParser Inline
inline
  JiraParser Inline -> String -> JiraParser Inline
forall s u (m :: * -> *) a.
ParsecT s u m a -> String -> ParsecT s u m a
<?> String
"citation"

--
-- Helpers
--

-- | Parse text delimited by a character.
delimitingMany :: Char -> JiraParser a -> JiraParser [a]
delimitingMany :: Char -> JiraParser a -> JiraParser [a]
delimitingMany Char
c = ParsecT Text ParserState Identity Char
-> ParsecT Text ParserState Identity Char
-> JiraParser a
-> JiraParser [a]
forall closing opening a.
Show closing =>
JiraParser opening
-> JiraParser closing -> JiraParser a -> JiraParser [a]
enclosed (Char -> ParsecT Text ParserState Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
c) (Char -> ParsecT Text ParserState Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
c)

enclosed :: Show closing
         => JiraParser opening -> JiraParser closing
         -> JiraParser a
         -> JiraParser [a]
enclosed :: JiraParser opening
-> JiraParser closing -> JiraParser a -> JiraParser [a]
enclosed JiraParser opening
opening JiraParser closing
closing JiraParser a
parser = JiraParser [a] -> JiraParser [a]
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (JiraParser [a] -> JiraParser [a])
-> JiraParser [a] -> JiraParser [a]
forall a b. (a -> b) -> a -> b
$ do
  Bool -> JiraParser ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> JiraParser ())
-> ParsecT Text ParserState Identity Bool -> JiraParser ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< ParsecT Text ParserState Identity Bool
notAfterString
  JiraParser opening
opening JiraParser opening -> JiraParser () -> JiraParser ()
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> ParsecT Text ParserState Identity Char -> JiraParser ()
forall s (m :: * -> *) t a u.
(Stream s m t, Show a) =>
ParsecT s u m a -> ParsecT s u m ()
notFollowedBy ParsecT Text ParserState Identity Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
space JiraParser () -> JiraParser [a] -> JiraParser [a]
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> JiraParser a -> JiraParser closing -> JiraParser [a]
forall end a.
Show end =>
JiraParser a -> JiraParser end -> JiraParser [a]
many1Till JiraParser a
parser JiraParser closing
closing'
  where
    closing' :: JiraParser closing
closing' = JiraParser closing -> JiraParser closing
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (JiraParser closing -> JiraParser closing)
-> JiraParser closing -> JiraParser closing
forall a b. (a -> b) -> a -> b
$ do
      Bool -> JiraParser ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> JiraParser ()) -> (Bool -> Bool) -> Bool -> JiraParser ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> Bool
not (Bool -> JiraParser ())
-> ParsecT Text ParserState Identity Bool -> JiraParser ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< ParsecT Text ParserState Identity Bool
afterSpace
      JiraParser closing
closing JiraParser closing -> JiraParser () -> JiraParser closing
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* JiraParser () -> JiraParser ()
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a
lookAhead JiraParser ()
forall u. ParsecT Text u Identity ()
wordBoundary
    wordBoundary :: ParsecT Text u Identity ()
wordBoundary = ParsecT Text u Identity Char -> ParsecT Text u Identity ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void ((Char -> Bool) -> ParsecT Text u Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
(Char -> Bool) -> ParsecT s u m Char
satisfy (Bool -> Bool
not (Bool -> Bool) -> (Char -> Bool) -> Char -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Bool
isAlphaNum)) ParsecT Text u Identity ()
-> ParsecT Text u Identity () -> ParsecT Text u Identity ()
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT Text u Identity ()
forall s (m :: * -> *) t u.
(Stream s m t, Show t) =>
ParsecT s u m ()
eof