diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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)
 
diff --git a/ronn.cabal b/ronn.cabal
--- a/ronn.cabal
+++ b/ronn.cabal
@@ -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)
diff --git a/src/Ronn.hs b/src/Ronn.hs
--- a/src/Ronn.hs
+++ b/src/Ronn.hs
@@ -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
     }
diff --git a/src/Ronn/AST.hs b/src/Ronn/AST.hs
--- a/src/Ronn/AST.hs
+++ b/src/Ronn/AST.hs
@@ -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]
diff --git a/src/Ronn/ManRef.hs b/src/Ronn/ManRef.hs
--- a/src/Ronn/ManRef.hs
+++ b/src/Ronn/ManRef.hs
@@ -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
diff --git a/src/Ronn/Render.hs b/src/Ronn/Render.hs
--- a/src/Ronn/Render.hs
+++ b/src/Ronn/Render.hs
@@ -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)
diff --git a/tests/Ronn/RenderSpec.hs b/tests/Ronn/RenderSpec.hs
--- a/tests/Ronn/RenderSpec.hs
+++ b/tests/Ronn/RenderSpec.hs
@@ -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 =
