packages feed

ronn 1.1.2.0 → 1.2.0.0

raw patch · 7 files changed

+215/−249 lines, 7 filesdep +prettyprinterPVP ok

version bump matches the API change (PVP)

Dependencies added: prettyprinter

API changes (from Hackage documentation)

- Ronn.AST: Definitions :: [Definition] -> Content
- Ronn.AST: Groups :: [Group] -> Content
- Ronn.AST: Header :: Text -> Group
- Ronn.AST: Lines :: [Line] -> Group
- Ronn.AST: Title :: ManRef -> [Part] -> Group
- Ronn.AST: [unwrap] :: Line -> [Part]
- Ronn.AST: data Group
- Ronn.AST: instance Data.String.IsString Ronn.AST.Group
- Ronn.AST: instance Data.String.IsString Ronn.AST.Line
- Ronn.AST: newtype Line
- Ronn.Render: ronnGroupToText :: Group -> Text
- Ronn.Render: ronnLineToText :: Line -> Text
- Ronn.Render: ronnPartToText :: Part -> Text
+ Ronn.AST: Defn :: Definition -> Content
+ Ronn.AST: Para :: [Part] -> Content
+ Ronn.AST: instance Prettyprinter.Internal.Pretty Ronn.AST.Content
+ Ronn.AST: instance Prettyprinter.Internal.Pretty Ronn.AST.Definition
+ Ronn.AST: instance Prettyprinter.Internal.Pretty Ronn.AST.Part
+ Ronn.AST: instance Prettyprinter.Internal.Pretty Ronn.AST.Section
+ Ronn.ManRef: instance Prettyprinter.Internal.Pretty Ronn.ManRef.ManRef
+ Ronn.ManRef: instance Prettyprinter.Internal.Pretty Ronn.ManRef.ManSection
+ Ronn.Render: ronnToDoc :: Ronn -> Doc ann
- Ronn.AST: Definition :: Part -> Line -> Maybe [Content] -> Definition
+ Ronn.AST: Definition :: Part -> [Part] -> Maybe [Content] -> Definition
- Ronn.AST: Line :: [Part] -> Line
+ Ronn.AST: Line :: [Part] -> Content
- Ronn.AST: [description] :: Definition -> Line
+ Ronn.AST: [description] :: Definition -> [Part]

Files

CHANGELOG.md view
@@ -1,4 +1,10 @@-## [_Unreleased_](https://github.com/pbrisbin/ronn/compare/ronn-v1.1.1.0...main)+## [_Unreleased_](https://github.com/pbrisbin/ronn/compare/ronn-v1.2.0.0...main)++## [v1.2.0.0](https://github.com/pbrisbin/ronn/compare/ronn-v1.1.2.0...ronn-v1.2.0.0)++- Simplify AST, distinguish lines from paragraphs+- Reflow paragraphs (`Para`) at 80 columns+- Don't print empty trailing line  ## [v1.1.2.0](https://github.com/pbrisbin/ronn/compare/ronn-v1.1.1.0...ronn-v1.1.2.0) 
ronn.cabal view
@@ -1,6 +1,6 @@ cabal-version:   1.18 name:            ronn-version:         1.1.2.0+version:         1.2.0.0 license:         AGPL-3 maintainer:      Pat Brisbin homepage:        https://github.com/pbrisbin/ronn#readme@@ -44,6 +44,7 @@      build-depends:         base >=4.16.4.0 && <5,+        prettyprinter >=1.7.1,         text >=1.2.5.0      if impl(ghc >=9.8)
src/Ronn.hs view
@@ -71,22 +71,22 @@ seeAlsoSection refs =   oneLineSection     "SEE ALSO"-    [ mconcat $-        intersperse ", " $-          map Ref $-            sort refs+    [ mconcat+        $ intersperse ", "+        $ map Ref+        $ sort refs     ]  oneLineSection :: Text -> [Part] -> Section oneLineSection name ps =   Section     { name-    , content = [Groups [Lines [Line ps]]]+    , content = [Line ps]     }  definitionsSection :: Text -> [Definition] -> Section definitionsSection name definitions =   Section     { name-    , content = [Definitions definitions]+    , content = map Defn definitions     }
src/Ronn/AST.hs view
@@ -11,8 +11,6 @@   , Section (..)   , Content (..)   , Definition (..)-  , Group (..)-  , Line (..)   , Part (..)      -- * References@@ -25,6 +23,8 @@  import Data.String (IsString (..)) import Data.Text (Text, pack)+import Data.Text qualified as T+import Prettyprinter import Ronn.ManRef  data Ronn = Ronn@@ -38,47 +38,55 @@   , content :: [Content]   } +instance Pretty Section where+  pretty s = vsep $ ("##" <+> pretty s.name) : map pretty s.content+ data Content-  = Definitions [Definition]-  | Groups [Group]+  = -- | Reflowed line+    Para [Part]+  | -- | Unbroken line+    Line [Part]+  | -- | Single definition+    Defn Definition  instance IsString Content where-  fromString = Groups . pure . fromString+  fromString = Para . pure . fromString +instance Pretty Content where+  pretty =+    (hardline <>) . \case+      Para ps -> reflow ps+      Line ps -> hsep $ map pretty ps+      Defn dn -> pretty dn+ data Definition = Definition   { name :: Part-  , description :: Line+  , description :: [Part]   -- ^ A line of nested description is required   , content :: Maybe [Content]   -- ^ More content can be optionally nested   } -data Group-  = Title ManRef [Part]-  | Header Text-  | Lines [Line]--instance IsString Group where-  fromString = Lines . pure . fromString--newtype Line = Line-  { unwrap :: [Part]-  }--instance IsString Line where-  fromString = Line . pure . fromString+instance Pretty Definition where+  pretty d =+    indent 2+      $ "*"+        <+> align+          ( vsep+              [ pretty d.name <> ":"+              , reflow d.description+              ]+          )+        <> maybe mempty (nest 2 . foldMap ((hardline <>) . pretty)) d.content  data Part   = -- | 'Concat' joins 'Part's without automaticaly inserting a space     ---    -- The following expressions are equivalent:-    ---    -- - @'ronnLineToText' $ 'Line' [p1, p2]@-    -- - @'ronnLineToText' $ 'Line' ['Concat' [p1, " ", p2]]@-    -- - @'ronnLineToText' $ 'Line' [p1 <> " " <> p2]@+    -- - @'pretty' [p1, p2]@ (may be broken for reflow)+    -- - @'pretty' ['Concat' [p1, " ", p2]]@ (never broken)     ---    -- Using the 'Semigroup' instance should be preferred, in case the AST-    -- changes in the future.+    -- '(<>)' is implemented with 'Concat' and should be preferred, to avoid+    -- unnecessary nesting.     Concat [Part]   | Code Part   | UserInput Part@@ -101,3 +109,27 @@  instance Monoid Part where   mempty = Concat []++instance Pretty Part where+  pretty = \case+    Concat ps -> foldMap pretty ps+    Code p -> "`" <> pretty p <> "`"+    UserInput p -> "`" <> pretty p <> "`"+    Strong p -> "**" <> pretty p <> "**"+    Variable p -> "<" <> pretty p <> ">"+    Ephasis p -> "_" <> pretty p <> "_"+    Brackets p -> "[" <> pretty p <> "]"+    Parens p -> "(" <> pretty p <> ")"+    Ref ref -> "**" <> pretty ref <> "**"+    Raw t -> pretty t++-- | Reflow a paragraph by tokenizing words and inserting softlines+--+-- This function will split any 'Raw' parts into multiple 'Raw' parts, one per+-- word, so that 'fillSep' will insert softlines between them.+reflow :: [Part] -> Doc ann+reflow = fillSep . map pretty . concatMap reword+ where+  reword = \case+    Raw t -> map Raw $ T.words t+    p -> [p]
src/Ronn/ManRef.hs view
@@ -17,6 +17,7 @@  import Data.Ord import Data.Text+import Prettyprinter (Pretty (..), parens)  data ManRef = ManRef   { name :: Text@@ -27,6 +28,9 @@ instance Ord ManRef where   compare a b = comparing (.section) a b <> comparing (.name) a b +instance Pretty ManRef where+  pretty (ManRef n s) = pretty n <> parens (pretty s)+ data ManSection   = ManSection1   | ManSection2@@ -37,6 +41,9 @@   | ManSection7   | ManSection8   deriving stock (Eq, Ord, Bounded, Enum, Show)++instance Pretty ManSection where+  pretty = pretty . manSectionNumber  manSectionNumber :: ManSection -> Int manSectionNumber = (+ 1) . fromEnum
src/Ronn/Render.hs view
@@ -8,101 +8,31 @@ -- Portability : POSIX module Ronn.Render   ( ronnToText--    -- * Rendering sub-parts, mostly useful in tests-  , ronnGroupToText-  , ronnLineToText-  , ronnPartToText+  , ronnToDoc   ) where  import Prelude -import Data.Text (Text, pack)-import Data.Text qualified as T+import Data.Text (Text)+import Prettyprinter+import Prettyprinter.Render.Text (renderStrict) import Ronn.AST  ronnToText :: Ronn -> Text-ronnToText ronn =-  T.unlines $-    map ronnGroupToText $-      Title ronn.name ronn.description-        : concatMap ronnSectionToGroups ronn.sections--ronnSectionToGroups :: Section -> [Group]-ronnSectionToGroups section =-  Header section.name : concatMap (ronnContentToGroups 0) section.content--ronnContentToGroups :: Int -> Content -> [Group]-ronnContentToGroups indentLevel = \case-  Definitions defns ->-    concatMap (ronnDefinitionToGroups $ indentLevel + 2) defns-  Groups gs -> map (indentRonnGroup indentLevel) gs--ronnDefinitionToGroups :: Int -> Definition -> [Group]-ronnDefinitionToGroups indentLevel defn =-  [ Lines-      [ indentRonnLine indentLevel $ Line ["* " <> defn.name <> ":"]-      , indentRonnLine nextIndentLevel defn.description-      ]-  ]-    <> nested- where-  nested = maybe [] (concatMap $ ronnContentToGroups nextIndentLevel) defn.content-  nextIndentLevel = indentLevel + 2--ronnGroupToText :: Group -> Text-ronnGroupToText = T.unlines . map ronnLineToText . ronnGroupToLines--ronnGroupToLines :: Group -> [Line]-ronnGroupToLines = \case-  Title ref description ->-    let nameLine = ronnNameLine ref description-    in  [ nameLine-        , Line [Raw $ T.replicate (ronnLineLength nameLine) "="]-        ]-  Header name -> [Line ["##", Raw name]]-  Lines ls -> ls--ronnNameLine :: ManRef -> [Part] -> Line-ronnNameLine ref =-  Line . (Raw (manRefToText ref) :) . ("--" :)--ronnLineToText :: Line -> Text-ronnLineToText = T.unwords . map ronnPartToText . (.unwrap)--ronnPartToText :: Part -> Text-ronnPartToText = \case-  Concat xs -> mconcat $ map ronnPartToText xs-  Code x -> "`" <> ronnPartToText x <> "`"-  UserInput x -> "`" <> ronnPartToText x <> "`"-  Strong x -> "**" <> ronnPartToText x <> "**"-  Variable x -> "<" <> ronnPartToText x <> ">"-  Ephasis x -> "_" <> ronnPartToText x <> "_"-  Brackets x -> "[" <> ronnPartToText x <> "]"-  Parens x -> "(" <> ronnPartToText x <> ")"-  Ref ref -> ronnPartToText $ Strong $ Raw $ manRefToText ref-  Raw x -> x--manRefToText :: ManRef -> Text-manRefToText ref =-  ref.name-    <> "("-    <> pack (show $ manSectionNumber ref.section)-    <> ")"+ronnToText = renderStrict . layoutPretty defaultLayoutOptions . ronnToDoc -ronnLineLength :: Line -> Int-ronnLineLength = T.length . ronnLineToText+ronnToDoc :: Ronn -> Doc ann+ronnToDoc ronn =+  (<> hardline) -- ensure doc ends in final newline+    $ vsep+    $ punctuate hardline+    $ prettyTitle ronn+      : map pretty ronn.sections -indentRonnGroup :: Int -> Group -> Group-indentRonnGroup indentLevel = \case-  g@Title {} -> g-  g@Header {} -> g-  Lines ls -> Lines $ map (indentRonnLine indentLevel) ls+prettyTitle :: Ronn -> Doc ann+prettyTitle ronn =+  underline '='+    $ pretty ronn.name <+> "--" <+> hsep (map pretty ronn.description) --- | Prepends the given number of spaces to the first 'Part' of the line-indentRonnLine :: Int -> Line -> Line-indentRonnLine n = \case-  Line [] -> Line []-  Line (p : ps) -> Line $ (spaces <> p) : ps- where-  spaces = Raw $ pack $ replicate n ' '+underline :: Char -> Doc ann -> Doc ann+underline c x = width x $ \w -> hardline <> pretty (replicate w c)
tests/Ronn/RenderSpec.hs view
@@ -23,134 +23,124 @@ spec :: Spec spec = do   describe "ronnToText" $ do-    specify "a complete example" $-      ronnGolden $-        Ronn-          { name = ManRef "ronn" ManSection1-          , description = ["example ronn man-page"]-          , sections =-              [ Section-                  { name = "SYNOPSIS"-                  , content =-                      [ Groups-                          [ Lines-                              [ Line-                                  [ Code "ronn"-                                  , Brackets $ Code "-h"-                                  , Brackets $ Code "--help"-                                  , Brackets $ mconcat [Code "--debug", "\\|", Code "--trace"]-                                  , Brackets $ mconcat [Code "-o", " ", Variable "FILE"]-                                  , Brackets $ mconcat [Code "--output", "=", Variable "FILE"]-                                  , Variable "INPUT"-                                  ]-                              ]-                          ]-                      ]-                  }-              , Section-                  { name = "DESCRIPTION"-                  , content =-                      [ Groups-                          [ Lines-                              [ Line -- test unwords-like behavior-                                  [ "This is an"-                                  , "example man-page to show"-                                  , "how rendering the AST looks."-                                  ]-                              ]-                          ]-                      ]-                  }-              , Section-                  { name = "OPTIONS"-                  , content =-                      [ Definitions-                          [ Definition-                              { name =-                                  mconcat-                                    [ Code "-h"-                                    , ", "-                                    , Code "--help"-                                    ]-                              , description = "Display this help"-                              , content = Nothing-                              }-                          , Definition-                              { name = Code "--debug"-                              , description = "Enable debug"-                              , content = Nothing-                              }-                          , Definition-                              { name = Code "--trace"-                              , description = "Enable trace"-                              , content = Nothing-                              }-                          , Definition-                              { name =-                                  mconcat-                                    [ Code "-o"-                                    , ", "-                                    , Code "--output"-                                    , "="-                                    , Variable "FILE"-                                    ]-                              , description = Line ["Output to", Variable "FILE"]-                              , content = Nothing-                              }-                          , Definition-                              { name = Variable "INPUT"-                              , description = "Source input"-                              , content = Nothing-                              }-                          ]-                      ]-                  }-              , Section-                  { name = "ENVIRONMENT"-                  , content =-                      [ Definitions-                          [ Definition-                              { name = Code "HOME"-                              , description = "User's HOME directory"-                              , content =-                                  Just-                                    [ "Some further details:"-                                    , Definitions-                                        [ Definition-                                            { name = "foo"-                                            , description = "The foo"-                                            , content = Nothing-                                            }-                                        , Definition-                                            { name = "bar"-                                            , description = "The bar"-                                            , content = Nothing-                                            }-                                        ]-                                    ]-                              }-                          ]+    specify "a complete example"+      $ ronnGolden+      $ Ronn+        { name = ManRef "ronn" ManSection1+        , description = ["example ronn man-page"]+        , sections =+            [ Section+                { name = "SYNOPSIS"+                , content =+                    [ Line+                        [ Code "ronn"+                        , Brackets $ Code "-h"+                        , Brackets $ Code "--help"+                        , Brackets $ mconcat [Code "--debug", "\\|", Code "--trace"]+                        , Brackets $ mconcat [Code "-o", " ", Variable "FILE"]+                        , Brackets $ mconcat [Code "--output", "=", Variable "FILE"]+                        , Variable "INPUT"+                        ]+                    ]+                }+            , Section+                { name = "DESCRIPTION"+                , content =+                    [ Para+                        [ "This is an"+                        , "example man-page to show"+                        , "how rendering the AST looks."+                        , "This description wouldn't normally be this"+                        , "long, but we want to verify the"+                        , "implementation reflows long lines."+                        ]+                    ]+                }+            , Section+                { name = "OPTIONS"+                , content =+                    map+                      Defn+                      [ Definition+                          { name =+                              mconcat+                                [ Code "-h"+                                , ", "+                                , Code "--help"+                                ]+                          , description = ["Display this help"]+                          , content = Nothing+                          }+                      , Definition+                          { name = Code "--debug"+                          , description = ["Enable debug"]+                          , content = Nothing+                          }+                      , Definition+                          { name = Code "--trace"+                          , description = ["Enable trace"]+                          , content = Nothing+                          }+                      , Definition+                          { name =+                              mconcat+                                [ Code "-o"+                                , ", "+                                , Code "--output"+                                , "="+                                , Variable "FILE"+                                ]+                          , description = ["Output to", Variable "FILE"]+                          , content = Nothing+                          }+                      , Definition+                          { name = Variable "INPUT"+                          , description = ["Source input"]+                          , content = Nothing+                          }                       ]-                  }-              , Section-                  { name = "SEE ALSO"-                  , content =-                      [ Groups-                          [ Lines-                              [ Line-                                  [ mconcat $-                                      intersperse-                                        (Raw ", ")-                                        [ Ref $ ManRef "markdown" ManSection7-                                        , Ref $ ManRef "roff" ManSection7-                                        ]-                                  ]+                }+            , Section+                { name = "ENVIRONMENT"+                , content =+                    [ Defn+                        Definition+                          { name = Code "HOME"+                          , description = ["User's HOME directory"]+                          , content =+                              Just+                                [ "Some further details:"+                                , Defn+                                    Definition+                                      { name = "foo"+                                      , description = ["The foo"]+                                      , content = Nothing+                                      }+                                , Defn+                                    Definition+                                      { name = "bar"+                                      , description = ["The bar"]+                                      , content = Nothing+                                      }+                                ]+                          }+                    ]+                }+            , Section+                { name = "SEE ALSO"+                , content =+                    [ Para+                        [ mconcat+                            $ intersperse+                              (Raw ", ")+                              [ Ref $ ManRef "markdown" ManSection7+                              , Ref $ ManRef "roff" ManSection7                               ]-                          ]-                      ]-                  }-              ]-          }+                        ]+                    ]+                }+            ]+        }  ronnGolden :: Ronn -> Golden Text ronnGolden ronn =