Reader.hs 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. module Text.Ptolemy.Slackdown.Reader
  2. ( SlackdownOpts(..)
  3. , defaultOpts
  4. , inlineOpts
  5. , readSlackdown
  6. ) where
  7. import Control.Applicative (empty)
  8. import Data.Text (Text)
  9. import qualified Data.Text as T
  10. import qualified Data.Vector as V
  11. import Text.Megaparsec
  12. import Text.Megaparsec.Text
  13. import Text.Ptolemy.Core (PtolemyError, Document)
  14. import qualified Text.Ptolemy.Core as P
  15. data SlackdownOpts = SlackdownOpts
  16. { tdBlockElems :: Bool
  17. } deriving (Eq, Show)
  18. defaultOpts :: SlackdownOpts
  19. defaultOpts = SlackdownOpts
  20. { tdBlockElems = True
  21. }
  22. inlineOpts :: SlackdownOpts
  23. inlineOpts = SlackdownOpts
  24. { tdBlockElems = False
  25. }
  26. readSlackdown :: SlackdownOpts -> Text -> Either PtolemyError Document
  27. readSlackdown opts tx = case runParser (pSlackdown opts) "[]" tx of
  28. Right x -> Right x
  29. Left err -> Left (P.PtolemyError (show err))
  30. enables :: Bool -> Parser a -> Parser a
  31. enables True p = p
  32. enables False _ = empty
  33. pSlackdown :: SlackdownOpts -> Parser Document
  34. pSlackdown SlackdownOpts { tdBlockElems = blockElems } =
  35. P.vec <$> (many pBlock <* eof)
  36. where pBlock =
  37. blockElems `enables` (pCodeBlock <|> pQuote) <|>
  38. pLine
  39. pLine = (P.Plain . flip V.snoc P.LineBreak . P.vec) <$>
  40. manyTill pInline (char '\n')
  41. pQuote = (P.BlockQuote . P.vec) <$> some (char '>' *> pLine)
  42. pCodeBlock = (P.CodeBlock P.emptyAttr . T.concat) <$>
  43. (string "```\n" *> manyTill pPlainLine (string "```\n"))
  44. pPlainLine = T.pack <$> manyTill (noneOf ("\n\r" :: String))
  45. (char '\n')
  46. pInline = pWhitespace
  47. <|> pString
  48. <|> (P.Code P.emptyAttr . T.pack) <$>
  49. (char '`' *> many (satisfy (/= '`')) <* char '`')
  50. <|> P.Strong <$> pSurrounded '*'
  51. <|> P.Emph <$> pSurrounded '_'
  52. <|> P.Strikeout <$> pSurrounded '~'
  53. pWhitespace = (P.Space) <$ some (oneOf (" \t" :: String))
  54. pString = (P.Str . T.pack) <$> some (noneOf ("*_~` \t\r\n" :: String))
  55. pSurrounded :: Char -> Parser P.Chunk
  56. pSurrounded c = try (char c *> rest)
  57. where rest = P.vec <$> (many (notFollowedBy (char c) *> pInline)
  58. <* char c)