gemmula 1.0.0 → 1.0.1
raw patch · 4 files changed
+36/−37 lines, 4 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- ChangeLog.md +4/−0
- README.md +5/−4
- gemmula.cabal +3/−3
- src/Text/Gemini.hs +24/−30
ChangeLog.md view
@@ -1,6 +1,10 @@ # `gemmula` Change Log +## 1.0.1 (January 08, 2024)+* Improve code readability and quality.+* Clean up some documentations.+ ## 1.0.0 (December 19, 2023) * Change the stability to `stable`. * Use strict data types and functions instead of lazy ones.
README.md view
@@ -1,11 +1,12 @@ # [gemmula](https://hackage.haskell.org/package/gemmula)-A tiny and functional Gemtext (`text/gemini`) parser from and to Text. -Check the Section 5 of the [Gemini Protocol specification](https://geminiprotocol.net/docs/specification.gmi)-for more about the `text/gemini` filetype.+A tiny and functional Gemtext (`text/gemini`) parser from and back to Text. -The documentation is available at [Hackage](https://hackage.haskell.org/package/gemmula/docs/Text-Gemini.html).+Check the Section 5 of the [Gemini Protocol specification](https://geminiprotocol.net/docs/specification.gmi)+for more about the `text/gemini` filetype. +You can also check the [Gemini Protocol](https://geminiprotocol.net) capsule for more about the Gemini itself. +The documentation is available at [Hackage](https://hackage.haskell.org/package/gemmula/docs/Text-Gemini.html). You can find more information and related modules at the [Codeberg repository](https://codeberg.org/sena/gemmula).
gemmula.cabal view
@@ -1,8 +1,8 @@ name: gemmula-version: 1.0.0+version: 1.0.1 synopsis: A tiny Gemtext parser-description: gemmula is a tiny and functional text/gemini (also known as Gemtext)- parser that aims to parse a Gemtext document from and to Text,+description: gemmula is a tiny and functional Gemtext (unofficially text/gemini)+ parser that aims to parse a Gemtext document from and back to Text, according to the Section 5 of the Gemini Protocol specification at <https://geminiprotocol.net/docs/specification.gmi>. license: AGPL-3
src/Text/Gemini.hs view
@@ -9,9 +9,9 @@ -- Stability : stable -- Portability : portable ----- A tiny @text/gemini@ parser.+-- A tiny Gemtext (@text/gemini@) parser. ----- Parses Gemtext documents from and to 'Text'. See the Section 5 of the+-- Parses Gemtext documents from and back to 'Text'. See the Section 5 of the -- [Gemini Protocol specification](https://geminiprotocol.net/docs/specification.gmi). module Text.Gemini@@ -21,20 +21,19 @@ -- * Decoding from Text , decode , decodeLine- -- * Encoding to Text+ -- * Encoding as Text , encode , encodeItem ) where import Data.Text (Text) import qualified Data.Text as T-import Data.Maybe (maybeToList)+import Data.Maybe (fromMaybe) import Data.Char (isSpace)-import Data.List (foldl') import Data.Bool (bool) --- | A Gemtext document, in the form of an ordered list.+-- | A Gemtext document, in the form of an ordered list of 'GemItem's. type GemDocument = [GemItem] -- | A Gemtext item.@@ -47,7 +46,7 @@ deriving (Show, Eq) --- | Parse a @text/gemini@ file as 'GemDocument'.+-- | Parse a Gemtext file as 'GemDocument'. -- The text should be supplied as an LF-ending 'Text'. decode :: Text -> GemDocument decode = parse [] . T.lines@@ -62,29 +61,23 @@ | otherwise = parse (doc <> [decodeLine l]) ls parse doc [] = doc - -- List recursive parser with a list carried. Adds the line to- -- the list if it starts with list prefix. If the line doesn't- -- start with the prefix, will end the recursion and continue with- -- @parse@, with the final list added to the carried 'GemDocument'- -- as 'GemList'.+ -- List recursive parser. Continues with @parse@ when the line+ -- is no longer a list item, and adds the 'GemList' to the 'GemDocument'. parseList :: GemDocument -> [Text] -> [Text] -> GemDocument parseList doc glist (l:ls) | l `hasValueOf` "* " = parseList doc (glist <> [value 1 l]) ls | otherwise = parse (doc <> [GemList glist]) (l:ls) parseList doc glist [] = doc <> [GemList glist] - -- Preformatted recursive parser with lines carried. Adds the line to- -- the list if the ending delimiter hasn't been reached yet. If the line- -- is the ending with the delimiter, will end the recursion and continue- -- with @parse@, with the final list of lines added to the carried- -- 'GemDocument' as 'GemPre'.+ -- Preformatted recursive parser. Continues with @parse@ when the+ -- closing delimiter is reached, and adds the 'GemPre' to the 'GemDocument'. parsePre :: GemDocument -> [Text] -> Maybe Text -> [Text] -> GemDocument parsePre doc glines alt (l:ls) | "```" `T.isPrefixOf` l = parse (doc <> [GemPre glines alt]) ls | otherwise = parsePre doc (glines <> [l]) alt ls parsePre doc glines alt [] = doc <> [GemPre glines alt] --- | Parse a /single/ @text/gemini@ line as 'GemItem'.+-- | Parse a /single/ Gemtext line as 'GemItem'. -- -- Notes: --@@ -107,15 +100,15 @@ where (pre, text) = T.span (=='#') l --- | Encode parsed 'GemDocument' to a @text/gemini@ file.--- The output 'Text' uses LF-endings.+-- | Encode parsed 'GemDocument' as a Gemtext file.+-- The output 'Text' uses LF-endings. Uses the 'encodeItem' function below. encode :: GemDocument -> Text-encode = T.unlines . foldl' (\acc x -> acc <> [encodeItem x]) []+encode = T.unlines . map encodeItem --- | Encode a /single/ parsed 'GemItem' as @text/gemini@ text.+-- | Encode a /single/ parsed 'GemItem' as Gemtext text. -- The output 'Text' uses LF-endings and might be multiple lines. ----- /Beware/ that the final newline is always stripped, if any.+-- /Beware/ that the output text never ends with a newline. -- -- Notes: --@@ -124,12 +117,13 @@ -- * The link in the 'GemLink' should not have spaces. encodeItem :: GemItem -> Text encodeItem (GemText line) = escapePrefixes line-encodeItem (GemLink link desc) = T.unwords $ ["=>", link] <> maybeToList desc-encodeItem (GemHeading level text) = T.unwords [T.replicate (min level 3) "#", text]-encodeItem (GemList list) = T.stripEnd . T.unlines $ map (T.append "* ") list-encodeItem (GemQuote text) = T.unwords [">", text]-encodeItem (GemPre text alt) = T.stripEnd . T.unlines $ [T.concat (["```"] <> maybeToList alt)] <> text <> ["```"]+encodeItem (GemLink link desc) = "=> " <> link <> maybe "" (" " <>) desc+encodeItem (GemHeading level text) = T.replicate (min level 3) "#" <> " " <> text+encodeItem (GemList list) = T.intercalate "\n" $ map ("* " <>) list+encodeItem (GemQuote text) = "> " <> text+encodeItem (GemPre text alt) = T.intercalate "\n" $ ["```" <> fromMaybe "" alt] <> text <> ["```"] + -- Escape the line prefixes by adding a whitespace at the beginning for 'GemText'. escapePrefixes :: Text -> Text escapePrefixes line = bool line (T.cons ' ' line) escape@@ -144,11 +138,11 @@ not (T.null $ value (T.length prefix) line) -- Get the value of a line.--- Removes the prefix and strips.+-- Removes the prefix of given length and strips. value :: Int -> Text -> Text value prefix = T.strip . T.drop prefix -- @Nothing@ if the text is empty. optional :: Text -> Maybe Text-optional text = if T.null text then Nothing else Just text+optional text = bool (Just text) Nothing $ T.null text