module Parsing.ParseBlock where
import Text.Parsec
import AST
import Parsing.State
import Parsing.TextUtils
import Parsing.Utils
import Parsing.ParseHtml
import Parsing.ParseInline
hardRule :: Parser Block
hardRule = do
try (string "---") <?> "\"---\" (hard rule)"
many (char '-')
many1 (char '\n')
return HardRule
paragraph :: Parser Block
paragraph = fmap Paragraph $ many1 inline
header :: Parser Block
header = do
hashes <- (many1 $ char' '#') <?> "\"#\" (header)"
many1 $ oneOf " \t"
text <- many1 inline
return $ Header (length hashes) text
listItem :: Bool -> Int -> Parser ListItem
listItem ordered depth = fmap ListItem $ do
let identifier = replicate depth ' ' ++ if ordered
then "- "
else "* "
let errMsg = "\"" ++ identifier ++ "\" " ++ if ordered
then "(ordered list item)"
else "(unordered list item)"
try (string' identifier) <?> errMsg
many1 inline
list :: Bool -> Int -> Parser List
list ordered depth = do
first <- listItem ordered depth
remainder <- many (listItem ordered depth
<|> fmap SubList (list True (depth + 1))
<|> fmap SubList (list False (depth + 1)))
return $ List ordered $ first : remainder
listBlock :: Parser Block
listBlock = fmap ListBlock (list True 1 <|> list False 1)
blockQuoteLineStart :: Parser String
blockQuoteLineStart = try (string "> ") <?> "\"> \" (blockquote)"
blockQuote :: Parser Block
blockQuote = fmap BlockQuote $ do
blockQuoteLineStart
withModifiedState (many1 inline) $ \s -> s {prevCharIsNewline=False, skipPrefix=(blockQuoteLineStart >> many (char ' '))}
blockCodeLineStart :: Parser String
blockCodeLineStart = try (string "\t" <|> string " ") <?> "\" \" or tab (code block)"
blockCode :: Parser Block
blockCode = fmap (BlockCode . unlines) $ many1 $ blockCodeLineStart >> manyTill (noneOf "\n") (char' '\n')
blockHtml :: Parser Block
blockHtml = fmap BlockHtml html
tableRow :: Parser [[Inline]]
tableRow = manyTill ((char' '|' <?> "\"|\" (table cell)") >> many1 inline) (try $ string' "|\n")
tableSeparator :: Parser ()
tableSeparator = optional $ do
sepBy1 (char '+' <?> "\"+\" (table)") $ many1 (char '-')
char' '\n'
table :: Parser Block
table = do
tableSeparator
rows <- many1 $ tableRow
tableSeparator
rows2 <- many $ tableRow
let headerRows = if null rows2
then Nothing
else Just $ map (TableRow . map TableHeaderCell) rows
let bodyRows = map (TableRow . map TableBodyCell) $ if null rows2 then rows else rows2
if null rows2
then return ()
else tableSeparator
return $ Table headerRows bodyRows
block :: Parser Block
block = between
(many $ char '\n')
(many $ char '\n')
(choice [blockHtml, hardRule, header, listBlock, blockQuote, table, blockCode, paragraph])