module Parsing.ParseInline (inline) where
import Data.Maybe
import Text.Parsec
import qualified Data.Map.Strict as M
import AST
import Parsing.State
import Parsing.Text
import Parsing.TextUtils
import Parsing.Utils
import Parsing.ParseHtml
nestedBold :: Parser Inline
nestedBold = suppressErr (try (string "****")) >> fail "cannot have empty or nested bold nodes"
bold :: Parser Inline
bold = do
state <- getState
let currentParserStack = inlineParserStack state
failIf $ elem "bold" currentParserStack
s <- betweenWithErrors' "**" "**" "bold"
$ withModifiedState (many1 inline) $ \s -> s {inlineParserStack=("bold" : currentParserStack)}
return $ Bold s
italics :: Parser Inline
italics = do
state <- getState
let currentParserStack = inlineParserStack state
failIf $ elem "italics" currentParserStack
s <- between
(try ((char' '*' <?> "\"*\" (italics)") >> suppressErr (notFollowedBy (char '*'))))
(char' '*' <?> "closing \"*\" (italics)")
((withModifiedState (many1 inline) $ \s -> s {inlineParserStack=("italics" : currentParserStack)}) <?>
if elem "bold" currentParserStack
then "content in italics node or extra \"*\" to close bold node"
else "content in italics node")
return $ Italics s
code :: Parser Inline
code = fmap Code $ betweenWithErrors' "`" "`" "code" $ many1 $ escapableNoneOf "`"
footnoteRef :: Parser Inline
footnoteRef = do
identifier <- betweenWithErrors' "^[" "]" "footnote reference" $ many1 $ escapableNoneOf "[]"
state <- getState
let f = footnoteIndices state
let maybeIndex = M.lookup identifier f
if isJust maybeIndex
then fail $ "repeated footnote identifier: " ++ (show $ fromJust maybeIndex)
else return ()
let index = M.size f
let f' = M.insert identifier index f
putState $ state {footnoteIndices=f'}
return $ FootnoteRef index
link :: Parser Inline
link = do
state <- getState
let currentParserStack = inlineParserStack state
lookAhead (char '[' <?> "\"[\" (link text)")
if elem "link" currentParserStack
then fail "links cannot be nested"
else return ()
text <- betweenWithErrors' "[" "]" "link text" $ withModifiedState (many1 inline) $ \s -> s {inlineParserStack=("link" : currentParserStack)}
href <- betweenWithErrors' "(" ")" "link href" $ many $ escapableNoneOf "()"
return $ Link {text=text, href=href}
inline :: Parser Inline
inline = choice [nestedBold, bold, italics, code, footnoteRef, link, fmap InlineHtml html, fmap Plaintext plaintext]