{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE LambdaCase #-}
{-# OPTIONS_GHC -Wno-name-shadowing #-}

module Text.PrettyPrint.Avh4.Block
  ( -- * Line
    Line,
    space,
    string7,
    char7,
    stringUtf8,
    lineFromBuilder,
    commentByteString,

    -- * Block
    Block,

    -- ** convert to
    render,

    -- ** create
    blankLine,
    line,
    mustBreak,

    -- ** combine
    stack,
    stackForce,
    andThen,
    indent,
    prefix,
    addSuffix,
    joinMustBreak,
    prefixOrIndent,
    rowOrStack,
    rowOrStackForce,
    rowOrIndent,
    rowOrIndentForce,
  )
where

import Data.ByteString (ByteString)
import qualified Data.ByteString as ByteString
import qualified Data.ByteString.Builder as B
import Data.List.NonEmpty (NonEmpty ((:|)))
import qualified Data.List.NonEmpty as NonEmpty
import Data.Semigroup (sconcat)
import Text.PrettyPrint.Avh4.Indent (Indent)
import qualified Text.PrettyPrint.Avh4.Indent as Indent

-- | A `Line` is ALWAYS just one single line of text,
-- and can always be combined horizontally with other `Line`s.
--
-- - `Space` is a single horizontal space,
-- - `Blank` is a line with no content.
-- - `Text` brings any text into the data structure. (Uses `ByteString.Builder` for the possibility of optimal performance)
-- - `Row` joins multiple elements onto one line.
data Line
  = Text B.Builder
  | Row Line Line
  | Space
  | Blank

instance Semigroup Line where
  Line
a <> :: Line -> Line -> Line
<> Line
b = Line -> Line -> Line
Row Line
a Line
b

-- | Creates a @Line@ from the given @Char@.
-- You must guarantee that the given character is a valid 7-bit ASCII character,
-- and is not a space character (use `space` instead).
char7 :: Char -> Line
char7 :: Char -> Line
char7 = Builder -> Line
Text forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Builder
B.char7

-- | Creates a @Line@ from the given @String@.
-- You must guarantee that all characters in the @String@ are valid 7-bit ASCII characters,
-- and that the string does not start or end with spaces (use `space` instead).
string7 :: String -> Line
string7 :: String -> Line
string7 = Builder -> Line
Text forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Builder
B.string7

-- | If you know the String only contains ASCII characters, then use `string7` instead for better performance.
stringUtf8 :: String -> Line
stringUtf8 :: String -> Line
stringUtf8 = Builder -> Line
Text forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Builder
B.stringUtf8

-- | You must guarantee that the content of the Builder does not contain newlines and does not start with whitespace.
lineFromBuilder :: B.Builder -> Line
lineFromBuilder :: Builder -> Line
lineFromBuilder = Builder -> Line
Text

{-# INLINE mkTextByteString #-}
mkTextByteString :: ByteString -> Line
mkTextByteString :: ByteString -> Line
mkTextByteString = Builder -> Line
Text forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Builder
B.byteString

commentByteString :: ByteString -> Line
commentByteString :: ByteString -> Line
commentByteString ByteString
bs =
  if ByteString -> Bool
ByteString.null ByteString
bs
    then Line
Blank
    else ByteString -> Line
mkTextByteString ByteString
bs

-- | A @Line@ containing a single space.  You **must** use this to create
-- space characters if the spaces will ever be at the start or end of a line that is joined in the context of indentation changes.
space :: Line
space :: Line
space =
  Line
Space

data Indented a
  = Indented Indent a
  deriving (forall a b. a -> Indented b -> Indented a
forall a b. (a -> b) -> Indented a -> Indented b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: forall a b. a -> Indented b -> Indented a
$c<$ :: forall a b. a -> Indented b -> Indented a
fmap :: forall a b. (a -> b) -> Indented a -> Indented b
$cfmap :: forall a b. (a -> b) -> Indented a -> Indented b
Functor)

-- | `Block` contains Lines (at least one; it can't be empty).
--
-- Block either:
--
--  - can appear in the middle of a line
--      (Stack someLine [], thus can be joined without problems), or
--  - has to appear on its own
--      (Stack someLine moreLines OR MustBreak someLine).
--
-- Types of Blocks:
--
-- - `SingleLine` is a single line, and the indentation level for the line.
-- - `MustBreak` is a single line (and its indentation level)) that cannot have anything joined to its right side.
--  Notably, it is used for `--` comments.
-- - `Stack` contains two or more lines, and the indentation level for each.
--
-- Sometimes (see `prefix`) the first line of Stack
--  gets different treatment than the other lines.
data Block
  = SingleLine (Indented Line)
  | Stack (Indented Line) (Indented Line) [Indented Line]
  | MustBreak (Indented Line)

-- | A blank line (taking up one vertical space), with no text content.
blankLine :: Block
blankLine :: Block
blankLine =
  Line -> Block
line Line
Blank

-- | Promote a @Line@ into a @Block@.
line :: Line -> Block
line :: Line -> Block
line =
  Indented Line -> Block
SingleLine forall b c a. (b -> c) -> (a -> b) -> a -> c
. Line -> Indented Line
mkIndentedLine

-- | Promote a @Line@ into a @Block@ that will always have a newline at the end of it,
-- meaning that this @Line@ will never have another @Line@ joined to its right side.
mustBreak :: Line -> Block
mustBreak :: Line -> Block
mustBreak =
  Indented Line -> Block
MustBreak forall b c a. (b -> c) -> (a -> b) -> a -> c
. Line -> Indented Line
mkIndentedLine

mkIndentedLine :: Line -> Indented Line
mkIndentedLine :: Line -> Indented Line
mkIndentedLine Line
Space = forall a. Indent -> a -> Indented a
Indented (Word -> Indent
Indent.spaces Word
1) Line
Blank
mkIndentedLine (Row Line
Space Line
next) =
  let (Indented Indent
i Line
rest') = Line -> Indented Line
mkIndentedLine Line
next
   in forall a. Indent -> a -> Indented a
Indented (Word -> Indent
Indent.spaces Word
1 forall a. Semigroup a => a -> a -> a
<> Indent
i) Line
rest'
mkIndentedLine Line
other = forall a. Indent -> a -> Indented a
Indented forall a. Monoid a => a
mempty Line
other

-- | A binary version of `stack`.
--
-- TODO: This function needs a better name.
stackForce :: Block -> Block -> Block
stackForce :: Block -> Block -> Block
stackForce Block
b1 Block
b2 =
  let (Indented Line
line1first, [Indented Line]
line1rest) = Block -> (Indented Line, [Indented Line])
destructure Block
b1
      (Indented Line
line2first, [Indented Line]
line2rest) = Block -> (Indented Line, [Indented Line])
destructure Block
b2
   in case [Indented Line]
line1rest forall a. [a] -> [a] -> [a]
++ Indented Line
line2first forall a. a -> [a] -> [a]
: [Indented Line]
line2rest of
        [] ->
          forall a. HasCallStack => String -> a
error String
"the list will contain at least line2first"
        Indented Line
first : [Indented Line]
rest ->
          Indented Line -> Indented Line -> [Indented Line] -> Block
Stack Indented Line
line1first Indented Line
first [Indented Line]
rest

-- | An alternate style for `stack`.
--
-- @a & andThen [b, c]@ is the same as @stack [a, b, c]@
andThen :: [Block] -> Block -> Block
andThen :: [Block] -> Block -> Block
andThen [Block]
rest Block
first =
  forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl Block -> Block -> Block
stackForce Block
first [Block]
rest

-- | A vertical stack of @Block@s.  The left edges of all the @Block@s will be aligned.
stack :: NonEmpty Block -> Block
stack :: NonEmpty Block -> Block
stack = forall (t :: * -> *) a. Foldable t => (a -> a -> a) -> t a -> a
foldr1 Block -> Block -> Block
stackForce

joinMustBreak :: Block -> Block -> Block
joinMustBreak :: Block -> Block -> Block
joinMustBreak Block
inner Block
eol =
  case (Block
inner, Block
eol) of
    (SingleLine (Indented Indent
i1 Line
inner'), SingleLine (Indented Indent
_ Line
eol')) ->
      Indented Line -> Block
SingleLine forall a b. (a -> b) -> a -> b
$
        forall a. Indent -> a -> Indented a
Indented Indent
i1 forall a b. (a -> b) -> a -> b
$
          Line
inner' forall a. Semigroup a => a -> a -> a
<> Line
space forall a. Semigroup a => a -> a -> a
<> Line
eol'
    (SingleLine (Indented Indent
i1 Line
inner'), MustBreak (Indented Indent
_ Line
eol')) ->
      Indented Line -> Block
MustBreak forall a b. (a -> b) -> a -> b
$
        forall a. Indent -> a -> Indented a
Indented Indent
i1 forall a b. (a -> b) -> a -> b
$
          Line
inner' forall a. Semigroup a => a -> a -> a
<> Line
space forall a. Semigroup a => a -> a -> a
<> Line
eol'
    (Block, Block)
_ ->
      Block -> Block -> Block
stackForce Block
inner Block
eol

{-# INLINE prefixOrIndent #-}
prefixOrIndent :: Maybe Line -> Line -> Block -> Block
prefixOrIndent :: Maybe Line -> Line -> Block -> Block
prefixOrIndent Maybe Line
joiner Line
a Block
b =
  let join :: Line -> Line -> Line
join Line
a Line
b =
        case Maybe Line
joiner of
          Maybe Line
Nothing -> Line
a forall a. Semigroup a => a -> a -> a
<> Line
b
          Just Line
j -> Line
a forall a. Semigroup a => a -> a -> a
<> Line
j forall a. Semigroup a => a -> a -> a
<> Line
b
   in case Block
b of
        SingleLine (Indented Indent
_ Line
b') ->
          Line -> Block
line forall a b. (a -> b) -> a -> b
$ Line -> Line -> Line
join Line
a Line
b'
        MustBreak (Indented Indent
_ Line
b') ->
          Line -> Block
mustBreak forall a b. (a -> b) -> a -> b
$ Line -> Line -> Line
join Line
a Line
b'
        Block
_ ->
          Block -> Block -> Block
stackForce (Line -> Block
line Line
a) (Block -> Block
indent Block
b)

mapLines :: (Indented Line -> Indented Line) -> Block -> Block
mapLines :: (Indented Line -> Indented Line) -> Block -> Block
mapLines Indented Line -> Indented Line
fn =
  (Indented Line -> Indented Line)
-> (Indented Line -> Indented Line) -> Block -> Block
mapFirstLine Indented Line -> Indented Line
fn Indented Line -> Indented Line
fn

mapFirstLine :: (Indented Line -> Indented Line) -> (Indented Line -> Indented Line) -> Block -> Block
mapFirstLine :: (Indented Line -> Indented Line)
-> (Indented Line -> Indented Line) -> Block -> Block
mapFirstLine Indented Line -> Indented Line
firstFn Indented Line -> Indented Line
restFn Block
b =
  case Block
b of
    SingleLine Indented Line
l1 ->
      Indented Line -> Block
SingleLine (Indented Line -> Indented Line
firstFn Indented Line
l1)
    Stack Indented Line
l1 Indented Line
l2 [Indented Line]
ls ->
      Indented Line -> Indented Line -> [Indented Line] -> Block
Stack (Indented Line -> Indented Line
firstFn Indented Line
l1) (Indented Line -> Indented Line
restFn Indented Line
l2) (forall a b. (a -> b) -> [a] -> [b]
map Indented Line -> Indented Line
restFn [Indented Line]
ls)
    MustBreak Indented Line
l1 ->
      Indented Line -> Block
MustBreak (Indented Line -> Indented Line
firstFn Indented Line
l1)

mapLastLine :: (Indented Line -> Indented Line) -> Block -> Block
mapLastLine :: (Indented Line -> Indented Line) -> Block -> Block
mapLastLine Indented Line -> Indented Line
lastFn = \case
  SingleLine Indented Line
l1 ->
    Indented Line -> Block
SingleLine (Indented Line -> Indented Line
lastFn Indented Line
l1)
  Stack Indented Line
l1 Indented Line
l2 [] ->
    Indented Line -> Indented Line -> [Indented Line] -> Block
Stack Indented Line
l1 (Indented Line -> Indented Line
lastFn Indented Line
l2) []
  Stack Indented Line
l1 Indented Line
l2 [Indented Line]
ls ->
    Indented Line -> Indented Line -> [Indented Line] -> Block
Stack Indented Line
l1 Indented Line
l2 (forall a. [a] -> [a]
init [Indented Line]
ls forall a. [a] -> [a] -> [a]
++ [Indented Line -> Indented Line
lastFn forall a b. (a -> b) -> a -> b
$ forall a. [a] -> a
last [Indented Line]
ls])
  MustBreak Indented Line
l1 ->
    Indented Line -> Block
MustBreak (Indented Line -> Indented Line
lastFn Indented Line
l1)

-- | Makes a new @Block@ with the contents of the input @Block@ indented by one additional level.
indent :: Block -> Block
indent :: Block -> Block
indent =
  (Indented Line -> Indented Line) -> Block -> Block
mapLines (\(Indented Indent
i Line
l) -> forall a. Indent -> a -> Indented a
Indented (Indent
Indent.tab forall a. Semigroup a => a -> a -> a
<> Indent
i) Line
l)

-- | This is the same as `rowOrStackForce` @False@.
{-# INLINE rowOrStack #-}
rowOrStack :: Maybe Line -> NonEmpty Block -> Block
rowOrStack :: Maybe Line -> NonEmpty Block -> Block
rowOrStack = Bool -> Maybe Line -> NonEmpty Block -> Block
rowOrStackForce Bool
False

-- | If all given @Block@s are single-line and the @Bool@ is @False@,
-- then makes a new single-line @Block@, with the @Maybe Line@ interspersed.
-- Otherwise, makes a vertical `stack` of the given @Block@s.
{-# INLINE rowOrStackForce #-}
rowOrStackForce :: Bool -> Maybe Line -> NonEmpty Block -> Block
rowOrStackForce :: Bool -> Maybe Line -> NonEmpty Block -> Block
rowOrStackForce Bool
_ Maybe Line
_ (Block
single :| []) = Block
single
rowOrStackForce Bool
forceMultiline (Just Line
joiner) NonEmpty Block
blocks =
  case forall (t :: * -> *).
Traversable t =>
t Block -> Either (t Block) (t Line)
allSingles NonEmpty Block
blocks of
    Right NonEmpty Line
lines
      | Bool -> Bool
not Bool
forceMultiline ->
          Line -> Block
line forall a b. (a -> b) -> a -> b
$ forall a. Semigroup a => NonEmpty a -> a
sconcat forall a b. (a -> b) -> a -> b
$ forall a. a -> NonEmpty a -> NonEmpty a
NonEmpty.intersperse Line
joiner NonEmpty Line
lines
    Either (NonEmpty Block) (NonEmpty Line)
_ ->
      NonEmpty Block -> Block
stack NonEmpty Block
blocks
rowOrStackForce Bool
forceMultiline Maybe Line
Nothing NonEmpty Block
blocks =
  case forall (t :: * -> *).
Traversable t =>
t Block -> Either (t Block) (t Line)
allSingles NonEmpty Block
blocks of
    Right NonEmpty Line
lines
      | Bool -> Bool
not Bool
forceMultiline ->
          Line -> Block
line forall a b. (a -> b) -> a -> b
$ forall a. Semigroup a => NonEmpty a -> a
sconcat NonEmpty Line
lines
    Either (NonEmpty Block) (NonEmpty Line)
_ ->
      NonEmpty Block -> Block
stack NonEmpty Block
blocks

-- | Same as `rowOrIndentForce` @False@.
{-# INLINE rowOrIndent #-}
rowOrIndent :: Maybe Line -> NonEmpty Block -> Block
rowOrIndent :: Maybe Line -> NonEmpty Block -> Block
rowOrIndent = Bool -> Maybe Line -> NonEmpty Block -> Block
rowOrIndentForce Bool
False

-- | This is the same as `rowOrStackForce`, but all non-first lines in
-- the resulting block are indented one additional level.
{-# INLINE rowOrIndentForce #-}
rowOrIndentForce :: Bool -> Maybe Line -> NonEmpty Block -> Block
rowOrIndentForce :: Bool -> Maybe Line -> NonEmpty Block -> Block
rowOrIndentForce Bool
_ Maybe Line
_ (Block
single :| []) = Block
single
rowOrIndentForce Bool
forceMultiline (Just Line
joiner) blocks :: NonEmpty Block
blocks@(Block
b1 :| [Block]
rest) =
  case forall (t :: * -> *).
Traversable t =>
t Block -> Either (t Block) (t Line)
allSingles NonEmpty Block
blocks of
    Right NonEmpty Line
lines
      | Bool -> Bool
not Bool
forceMultiline ->
          Line -> Block
line forall a b. (a -> b) -> a -> b
$ forall a. Semigroup a => NonEmpty a -> a
sconcat forall a b. (a -> b) -> a -> b
$ forall a. a -> NonEmpty a -> NonEmpty a
NonEmpty.intersperse Line
joiner NonEmpty Line
lines
    Either (NonEmpty Block) (NonEmpty Line)
_ ->
      NonEmpty Block -> Block
stack (Block
b1 forall a. a -> [a] -> NonEmpty a
:| (Block -> Block
indent forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Block]
rest))
rowOrIndentForce Bool
forceMultiline Maybe Line
Nothing blocks :: NonEmpty Block
blocks@(Block
b1 :| [Block]
rest) =
  case forall (t :: * -> *).
Traversable t =>
t Block -> Either (t Block) (t Line)
allSingles NonEmpty Block
blocks of
    Right NonEmpty Line
lines
      | Bool -> Bool
not Bool
forceMultiline ->
          Line -> Block
line forall a b. (a -> b) -> a -> b
$ forall a. Semigroup a => NonEmpty a -> a
sconcat NonEmpty Line
lines
    Either (NonEmpty Block) (NonEmpty Line)
_ ->
      NonEmpty Block -> Block
stack (Block
b1 forall a. a -> [a] -> NonEmpty a
:| (Block -> Block
indent forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Block]
rest))

{-# DEPRECATED isLine "Rewrite to avoid inspecting the child blocks" #-}
isLine :: Block -> Either Block Line
isLine :: Block -> Either Block Line
isLine Block
b =
  case Block
b of
    SingleLine (Indented Indent
_ Line
l) ->
      forall a b. b -> Either a b
Right Line
l
    Block
_ ->
      forall a b. a -> Either a b
Left Block
b

destructure :: Block -> (Indented Line, [Indented Line])
destructure :: Block -> (Indented Line, [Indented Line])
destructure Block
b =
  case Block
b of
    SingleLine Indented Line
l1 ->
      (Indented Line
l1, [])
    Stack Indented Line
l1 Indented Line
l2 [Indented Line]
rest ->
      (Indented Line
l1, Indented Line
l2 forall a. a -> [a] -> [a]
: [Indented Line]
rest)
    MustBreak Indented Line
l1 ->
      (Indented Line
l1, [])

allSingles :: Traversable t => t Block -> Either (t Block) (t Line)
allSingles :: forall (t :: * -> *).
Traversable t =>
t Block -> Either (t Block) (t Line)
allSingles t Block
blocks =
  case forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM Block -> Either Block Line
isLine t Block
blocks of
    Right t Line
lines' ->
      forall a b. b -> Either a b
Right t Line
lines'
    Either Block (t Line)
_ ->
      forall a b. a -> Either a b
Left t Block
blocks

-- | Adds the prefix to the first line,
-- and pads the other lines with spaces of the given length.
-- You are responsible for making sure that the given length is the actual length of the content of the given @Line@.
--
-- NOTE: An exceptional case that we haven't really designed for is if the first line of the input Block is indented.
--
-- EXAMPLE:
--
-- @
-- abcde
-- xyz
-- ----->
-- myPrefix abcde
--         xyz
-- @
prefix :: Word -> Line -> Block -> Block
prefix :: Word -> Line -> Block -> Block
prefix Word
prefixLength Line
pref =
  let padLineWithSpaces :: Indented a -> Indented a
padLineWithSpaces (Indented Indent
i a
l) = forall a. Indent -> a -> Indented a
Indented (Word -> Indent
Indent.spaces Word
prefixLength forall a. Semigroup a => a -> a -> a
<> Indent
i) a
l

      addPrefixToLine :: Line -> Line
addPrefixToLine Line
Blank = Line -> Line
stripEnd Line
pref
      addPrefixToLine Line
l = Line
pref forall a. Semigroup a => a -> a -> a
<> Line
l
   in (Indented Line -> Indented Line)
-> (Indented Line -> Indented Line) -> Block -> Block
mapFirstLine (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Line -> Line
addPrefixToLine) forall {a}. Indented a -> Indented a
padLineWithSpaces

stripEnd :: Line -> Line
stripEnd :: Line -> Line
stripEnd = \case
  Line
Space -> Line
Blank
  Row Line
r1 Line
r2 ->
    case (Line -> Line
stripEnd Line
r1, Line -> Line
stripEnd Line
r2) of
      (Line
r1', Line
Blank) -> Line
r1'
      (Line
Blank, Line
r2') -> Line
r2'
      (Line
r1', Line
r2') -> Line -> Line -> Line
Row Line
r1' Line
r2'
  Text Builder
t -> Builder -> Line
Text Builder
t
  Line
Blank -> Line
Blank

-- | Adds the given suffix to then end of the last line of the @Block@.
addSuffix :: Line -> Block -> Block
addSuffix :: Line -> Block -> Block
addSuffix Line
suffix =
  (Indented Line -> Indented Line) -> Block -> Block
mapLastLine forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall a. Semigroup a => a -> a -> a
<> Line
suffix)

renderIndentedLine :: Indented Line -> B.Builder
renderIndentedLine :: Indented Line -> Builder
renderIndentedLine (Indented Indent
i Line
line') =
  Indent -> Line -> Builder
renderLine Indent
i Line
line' forall a. Semigroup a => a -> a -> a
<> Char -> Builder
B.char7 Char
'\n'

spaces :: Int -> B.Builder
spaces :: Int -> Builder
spaces Int
i =
  ByteString -> Builder
B.byteString (Int -> Word8 -> ByteString
ByteString.replicate Int
i Word8
0x20 {- space -})

renderLine :: Indent -> Line -> B.Builder
renderLine :: Indent -> Line -> Builder
renderLine Indent
i = \case
  Text Builder
text ->
    Int -> Builder
spaces (forall n. Num n => Indent -> n
Indent.width Indent
i) forall a. Semigroup a => a -> a -> a
<> Builder
text
  Line
Space ->
    Int -> Builder
spaces (Int
1 forall a. Num a => a -> a -> a
+ forall n. Num n => Indent -> n
Indent.width Indent
i)
  Row Line
left Line
right ->
    Indent -> Line -> Builder
renderLine Indent
i Line
left forall a. Semigroup a => a -> a -> a
<> Indent -> Line -> Builder
renderLine forall a. Monoid a => a
mempty Line
right
  Line
Blank ->
    forall a. Monoid a => a
mempty

-- | Converts a @Block@ into a `Data.ByteString.Builder.Builder`.
--
-- You can then write to a file with `Data.ByteString.Builder.writeFile`,
-- or convert to @Text@ with @Data.Text.Encoding.decodeUtf8@ . `Data.ByteString.Builder.toLazyByteString`
render :: Block -> B.Builder
render :: Block -> Builder
render = \case
  SingleLine Indented Line
line' ->
    Indented Line -> Builder
renderIndentedLine Indented Line
line'
  Stack Indented Line
l1 Indented Line
l2 [Indented Line]
rest ->
    forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap Indented Line -> Builder
renderIndentedLine (Indented Line
l1 forall a. a -> [a] -> [a]
: Indented Line
l2 forall a. a -> [a] -> [a]
: [Indented Line]
rest)
  MustBreak Indented Line
line' ->
    Indented Line -> Builder
renderIndentedLine Indented Line
line'