|
@@ -0,0 +1,73 @@
|
|
|
+module Text.Ptolemy.Slackdown.Reader
|
|
|
+ ( SlackdownOpts(..)
|
|
|
+ , defaultOpts
|
|
|
+ , inlineOpts
|
|
|
+ , readSlackdown
|
|
|
+ ) where
|
|
|
+
|
|
|
+import Control.Applicative (empty)
|
|
|
+import Data.Text (Text)
|
|
|
+import qualified Data.Text as T
|
|
|
+import qualified Data.Vector as V
|
|
|
+import Text.Megaparsec
|
|
|
+import Text.Megaparsec.Text
|
|
|
+import Text.Ptolemy.Core (PtolemyError, Document)
|
|
|
+import qualified Text.Ptolemy.Core as P
|
|
|
+
|
|
|
+data SlackdownOpts = SlackdownOpts
|
|
|
+ { tdBlockElems :: Bool
|
|
|
+ } deriving (Eq, Show)
|
|
|
+
|
|
|
+defaultOpts :: SlackdownOpts
|
|
|
+defaultOpts = SlackdownOpts
|
|
|
+ { tdBlockElems = True
|
|
|
+ }
|
|
|
+
|
|
|
+inlineOpts :: SlackdownOpts
|
|
|
+inlineOpts = SlackdownOpts
|
|
|
+ { tdBlockElems = False
|
|
|
+ }
|
|
|
+
|
|
|
+readSlackdown :: SlackdownOpts -> Text -> Either PtolemyError Document
|
|
|
+readSlackdown opts tx = case runParser (pSlackdown opts) "[]" tx of
|
|
|
+ Right x -> Right x
|
|
|
+ Left err -> Left (P.PtolemyError (show err))
|
|
|
+
|
|
|
+enables :: Bool -> Parser a -> Parser a
|
|
|
+enables True p = p
|
|
|
+enables False _ = empty
|
|
|
+
|
|
|
+pSlackdown :: SlackdownOpts -> Parser Document
|
|
|
+pSlackdown SlackdownOpts { tdBlockElems = blockElems } =
|
|
|
+ P.vec <$> (many pBlock <* eof)
|
|
|
+ where pBlock =
|
|
|
+ blockElems `enables` (pCodeBlock <|> pQuote) <|>
|
|
|
+ pLine
|
|
|
+
|
|
|
+ pLine = (P.Plain . flip V.snoc P.LineBreak . P.vec) <$>
|
|
|
+ manyTill pInline (char '\n')
|
|
|
+
|
|
|
+ pQuote = (P.BlockQuote . P.vec) <$> some (char '>' *> pLine)
|
|
|
+
|
|
|
+ pCodeBlock = (P.CodeBlock P.emptyAttr . T.concat) <$>
|
|
|
+ (string "```\n" *> manyTill pPlainLine (string "```\n"))
|
|
|
+
|
|
|
+ pPlainLine = T.pack <$> manyTill (noneOf ("\n\r" :: String))
|
|
|
+ (char '\n')
|
|
|
+
|
|
|
+ pInline = pWhitespace
|
|
|
+ <|> pString
|
|
|
+ <|> (P.Code P.emptyAttr . T.pack) <$>
|
|
|
+ (char '`' *> many (satisfy (/= '`')) <* char '`')
|
|
|
+ <|> P.Strong <$> pSurrounded '*'
|
|
|
+ <|> P.Emph <$> pSurrounded '_'
|
|
|
+ <|> P.Strikeout <$> pSurrounded '~'
|
|
|
+
|
|
|
+ pWhitespace = (P.Space) <$ some (oneOf (" \t" :: String))
|
|
|
+
|
|
|
+ pString = (P.Str . T.pack) <$> some (noneOf ("*_~` \t\r\n" :: String))
|
|
|
+
|
|
|
+ pSurrounded :: Char -> Parser P.Chunk
|
|
|
+ pSurrounded c = try (char c *> rest)
|
|
|
+ where rest = P.vec <$> (many (notFollowedBy (char c) *> pInline)
|
|
|
+ <* char c)
|