module Reflow.Parser where

import Data.Monoid ((<>))
import Data.Text (Text)
import qualified Data.Text as T
import Text.ParserCombinators.Parsec

import Reflow.Types

parseFile :: Text -> [Content]
parseFile t = either (const []) id $ parse parseContent "content" (T.unpack t)

parseContent :: Parser [Content]
parseContent = many (quoted <|> codeBlock <|> normal) <* eof

normal :: Parser Content
normal = Normal <$> singleLine

quoted :: Parser Content
quoted = do
    q <- quoteChar
    l <- singleLine
    return $ Quoted (q <> l)

codeBlock :: Parser Content
codeBlock = do
    s <- codeBlockChar
    c <- codeBlockContents
    e <- codeBlockChar
    eol
    return $ CodeBlock $ s <> c <> e

singleLine :: Parser Text
singleLine = T.pack <$> manyTill anyChar (try eol)

quoteChar :: Parser Text
quoteChar = T.pack <$> (string ">")

codeBlockChar :: Parser Text
codeBlockChar = T.pack <$> (string "```")

codeBlockContents :: Parser Text
codeBlockContents = T.pack <$> manyTill anyChar (lookAhead codeBlockChar)

eol :: Parser String
eol = try (string "\n\r")
    <|> try (string "\r\n")
    <|> string "\n"
    <|> string "\r"
    <?> "end of line"

module Reflow.Parser where

import Data.Monoid ((<>))
import Data.Text (Text, pack)
import Text.Parsec
import Text.Parsec.Text (Parser)

import Reflow.Types

parseFile :: Text -> [Content]
parseFile t = either (const []) id $ parse parseContent "content" t

parseContent :: Parser [Content]
parseContent = many (quoted <|> codeBlock <|> normal) <* eof

normal :: Parser Content
normal = Normal <$> singleLine

quoted :: Parser Content
quoted = do
    q <- quoteChar
    l <- singleLine
    return $ Quoted (q <> l)

codeBlock :: Parser Content
codeBlock = do
    s <- codeBlockChar
    c <- codeBlockContents
    e <- codeBlockChar
    eol
    return $ CodeBlock $ s <> c <> e

singleLine :: Parser Text
singleLine = pack <$> manyTill anyChar (try eol)

quoteChar :: Parser Text
quoteChar = pack <$> (string ">")

codeBlockChar :: Parser Text
codeBlockChar = pack <$> (string "```")

codeBlockContents :: Parser Text
codeBlockContents = pack <$> manyTill anyChar (lookAhead codeBlockChar)

eol :: Parser String
eol = try (string "\n\r")
    <|> try (string "\r\n")
    <|> string "\n"
    <|> string "\r"
    <?> "end of line"

Make parsing Data.Text.Text slightly nicer
Make parsing Data.Text.Text slightly nicer

Parsec has had support for parsing Text Since version 3.1.2, so we don't need
`T.unpack text` as long as we also import `Text.Parsec.Text`.

This also means that the code only requires `(Text, pack)` from `Data.Text`, so
import only those (unqualified).
