-- | Printer combinators for lining up multiple elements.
module HIndent.Pretty.Combinators.Lineup
  ( -- * Tuples
    hvTuple
  , hvTuple'
  , hTuple
  , vTuple
  , vTuple'
  , hPromotedTuple
  , -- * Unboxed tuples
    hvUnboxedTuple'
  , hUnboxedTuple
  , -- * Unboxed sums
    hvUnboxedSum'
  , -- * Records
    hvFields
  , hFields
  , vFields
  , vFields'
  , -- * Lists
    hList
  , vList
  , hvPromotedList
  , -- * Bars
    hvBarSep
  , hBarSep
  , vBarSep
  , -- * Commas
    hvCommaSep
  , hCommaSep
  , vCommaSep
  , -- * Others
    spaced
  , lined
  , blanklined
  , hDotSep
  , spacePrefixed
  , newlinePrefixed
  , prefixedLined
  , inter
  ) where

import Control.Monad
import Data.List
import HIndent.Pretty.Combinators.Indent
import HIndent.Pretty.Combinators.String
import HIndent.Pretty.Combinators.Switch
import HIndent.Pretty.Combinators.Wrap
import HIndent.Printer

-- | Applies 'hTuple' if the result fits in a line or 'vTuple' otherwise.
hvTuple :: [Printer ()] -> Printer ()
hvTuple :: [Printer ()] -> Printer ()
hvTuple = Printer () -> Printer () -> Printer ()
forall a. Printer a -> Printer a -> Printer a
(<-|>) (Printer () -> Printer () -> Printer ())
-> ([Printer ()] -> Printer ())
-> [Printer ()]
-> Printer ()
-> Printer ()
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Printer ()] -> Printer ()
hTuple ([Printer ()] -> Printer () -> Printer ())
-> ([Printer ()] -> Printer ()) -> [Printer ()] -> Printer ()
forall a b.
([Printer ()] -> a -> b)
-> ([Printer ()] -> a) -> [Printer ()] -> b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> [Printer ()] -> Printer ()
vTuple

-- | Applies 'hTuple'' if the result fits in a line or 'vTuple'' otherwise.
hvTuple' :: [Printer ()] -> Printer ()
hvTuple' :: [Printer ()] -> Printer ()
hvTuple' = Printer () -> Printer () -> Printer ()
forall a. Printer a -> Printer a -> Printer a
(<-|>) (Printer () -> Printer () -> Printer ())
-> ([Printer ()] -> Printer ())
-> [Printer ()]
-> Printer ()
-> Printer ()
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Printer ()] -> Printer ()
hTuple ([Printer ()] -> Printer () -> Printer ())
-> ([Printer ()] -> Printer ()) -> [Printer ()] -> Printer ()
forall a b.
([Printer ()] -> a -> b)
-> ([Printer ()] -> a) -> [Printer ()] -> b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> [Printer ()] -> Printer ()
vTuple'

-- | Runs printers to construct a tuple in a line.
hTuple :: [Printer ()] -> Printer ()
hTuple :: [Printer ()] -> Printer ()
hTuple = Printer () -> Printer ()
forall a. Printer a -> Printer a
parens (Printer () -> Printer ())
-> ([Printer ()] -> Printer ()) -> [Printer ()] -> Printer ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Printer ()] -> Printer ()
hCommaSep

-- | Runs printers to construct a tuple where elements are aligned
-- vertically.
vTuple :: [Printer ()] -> Printer ()
vTuple :: [Printer ()] -> Printer ()
vTuple = (String, String) -> [Printer ()] -> Printer ()
vCommaSepWrapped (String
"(", String
")")

-- | Similar to 'vTuple', but the closing parenthesis is in the last
-- element.
vTuple' :: [Printer ()] -> Printer ()
vTuple' :: [Printer ()] -> Printer ()
vTuple' = (String, String) -> [Printer ()] -> Printer ()
vCommaSepWrapped' (String
"(", String
")")

-- | Runs printers to construct a promoted tuple in a line.
hPromotedTuple :: [Printer ()] -> Printer ()
hPromotedTuple :: [Printer ()] -> Printer ()
hPromotedTuple = Printer () -> Printer ()
forall a. Printer a -> Printer a
promotedTupleParens (Printer () -> Printer ())
-> ([Printer ()] -> Printer ()) -> [Printer ()] -> Printer ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Printer ()] -> Printer ()
hCommaSep

-- | Runs printers to construct an unboxed tuple. The elements are aligned
-- either in a line or vertically.
hvUnboxedTuple' :: [Printer ()] -> Printer ()
hvUnboxedTuple' :: [Printer ()] -> Printer ()
hvUnboxedTuple' = Printer () -> Printer () -> Printer ()
forall a. Printer a -> Printer a -> Printer a
(<-|>) (Printer () -> Printer () -> Printer ())
-> ([Printer ()] -> Printer ())
-> [Printer ()]
-> Printer ()
-> Printer ()
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Printer ()] -> Printer ()
hUnboxedTuple ([Printer ()] -> Printer () -> Printer ())
-> ([Printer ()] -> Printer ()) -> [Printer ()] -> Printer ()
forall a b.
([Printer ()] -> a -> b)
-> ([Printer ()] -> a) -> [Printer ()] -> b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> [Printer ()] -> Printer ()
vUnboxedTuple'

-- | Runs printers to construct an unboxed tuple in a line.
hUnboxedTuple :: [Printer ()] -> Printer ()
hUnboxedTuple :: [Printer ()] -> Printer ()
hUnboxedTuple = Printer () -> Printer ()
forall a. Printer a -> Printer a
unboxedParens (Printer () -> Printer ())
-> ([Printer ()] -> Printer ()) -> [Printer ()] -> Printer ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Printer ()] -> Printer ()
hCommaSep

-- | Runs printers to construct an unboxed tuple where the elements are
-- aligned vertically.
vUnboxedTuple' :: [Printer ()] -> Printer ()
vUnboxedTuple' :: [Printer ()] -> Printer ()
vUnboxedTuple' = (String, String) -> [Printer ()] -> Printer ()
vCommaSepWrapped' (String
"(#", String
" #)")

-- | Runs printers to construct an unboxed sum. The elements are aligned
-- either in a line or vertically.
--
-- The enclosing parenthesis will be printed on the same line as the last
-- element.
hvUnboxedSum' :: [Printer ()] -> Printer ()
hvUnboxedSum' :: [Printer ()] -> Printer ()
hvUnboxedSum' = Printer () -> Printer () -> Printer ()
forall a. Printer a -> Printer a -> Printer a
(<-|>) (Printer () -> Printer () -> Printer ())
-> ([Printer ()] -> Printer ())
-> [Printer ()]
-> Printer ()
-> Printer ()
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Printer ()] -> Printer ()
hUnboxedSum ([Printer ()] -> Printer () -> Printer ())
-> ([Printer ()] -> Printer ()) -> [Printer ()] -> Printer ()
forall a b.
([Printer ()] -> a -> b)
-> ([Printer ()] -> a) -> [Printer ()] -> b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> [Printer ()] -> Printer ()
vUnboxedSum'

-- | Runs printers to construct an unboxed sum in a line.
hUnboxedSum :: [Printer ()] -> Printer ()
hUnboxedSum :: [Printer ()] -> Printer ()
hUnboxedSum = Printer () -> Printer ()
forall a. Printer a -> Printer a
unboxedParens (Printer () -> Printer ())
-> ([Printer ()] -> Printer ()) -> [Printer ()] -> Printer ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Printer ()] -> Printer ()
hBarSep

-- | Runs printers to construct an unboxed sum where the elements are
-- aligned vertically.
--
-- The enclosing parenthesis will be printed on the same line as the last
-- element.
vUnboxedSum' :: [Printer ()] -> Printer ()
vUnboxedSum' :: [Printer ()] -> Printer ()
vUnboxedSum' = Char -> (String, String) -> [Printer ()] -> Printer ()
vWrappedLineup' Char
'|' (String
"(#", String
" #)")

-- | Applies 'hFields' if the result fits in a line or 'vFields' otherwise.
hvFields :: [Printer ()] -> Printer ()
hvFields :: [Printer ()] -> Printer ()
hvFields = Printer () -> Printer () -> Printer ()
forall a. Printer a -> Printer a -> Printer a
(<-|>) (Printer () -> Printer () -> Printer ())
-> ([Printer ()] -> Printer ())
-> [Printer ()]
-> Printer ()
-> Printer ()
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Printer ()] -> Printer ()
hFields ([Printer ()] -> Printer () -> Printer ())
-> ([Printer ()] -> Printer ()) -> [Printer ()] -> Printer ()
forall a b.
([Printer ()] -> a -> b)
-> ([Printer ()] -> a) -> [Printer ()] -> b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> [Printer ()] -> Printer ()
vFields

-- | Runs printers to construct a record in a line.
hFields :: [Printer ()] -> Printer ()
hFields :: [Printer ()] -> Printer ()
hFields = Printer () -> Printer ()
forall a. Printer a -> Printer a
braces (Printer () -> Printer ())
-> ([Printer ()] -> Printer ()) -> [Printer ()] -> Printer ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Printer ()] -> Printer ()
hCommaSep

-- | Runs printers to construct a record where elements are aligned
-- vertically.
vFields :: [Printer ()] -> Printer ()
vFields :: [Printer ()] -> Printer ()
vFields = (String, String) -> [Printer ()] -> Printer ()
vCommaSepWrapped (String
"{", String
"}")

-- | Similar to 'vFields', but the closing brace is in the same line as the
-- last element.
vFields' :: [Printer ()] -> Printer ()
vFields' :: [Printer ()] -> Printer ()
vFields' = (String, String) -> [Printer ()] -> Printer ()
vCommaSepWrapped' (String
"{", String
"}")

-- | Runs printers to construct a list in a line.
hList :: [Printer ()] -> Printer ()
hList :: [Printer ()] -> Printer ()
hList = Printer () -> Printer ()
forall a. Printer a -> Printer a
brackets (Printer () -> Printer ())
-> ([Printer ()] -> Printer ()) -> [Printer ()] -> Printer ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Printer ()] -> Printer ()
hCommaSep

-- | Runs printers to construct a list where elements are aligned
-- vertically.
vList :: [Printer ()] -> Printer ()
vList :: [Printer ()] -> Printer ()
vList = (String, String) -> [Printer ()] -> Printer ()
vCommaSepWrapped (String
"[", String
"]")

-- | Runs printers to construct a promoted list where elements are aligned
-- in a line or vertically.
hvPromotedList :: [Printer ()] -> Printer ()
hvPromotedList :: [Printer ()] -> Printer ()
hvPromotedList = Printer () -> Printer () -> Printer ()
forall a. Printer a -> Printer a -> Printer a
(<-|>) (Printer () -> Printer () -> Printer ())
-> ([Printer ()] -> Printer ())
-> [Printer ()]
-> Printer ()
-> Printer ()
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Printer ()] -> Printer ()
hPromotedList ([Printer ()] -> Printer () -> Printer ())
-> ([Printer ()] -> Printer ()) -> [Printer ()] -> Printer ()
forall a b.
([Printer ()] -> a -> b)
-> ([Printer ()] -> a) -> [Printer ()] -> b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> [Printer ()] -> Printer ()
vPromotedList

-- | Runs printers to construct a promoted list in a line.
hPromotedList :: [Printer ()] -> Printer ()
hPromotedList :: [Printer ()] -> Printer ()
hPromotedList = Printer () -> Printer ()
forall a. Printer a -> Printer a
promotedListBrackets (Printer () -> Printer ())
-> ([Printer ()] -> Printer ()) -> [Printer ()] -> Printer ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Printer ()] -> Printer ()
hCommaSep

-- | Runs printers to construct a promoted list where elements are aligned
-- vertically.
vPromotedList :: [Printer ()] -> Printer ()
vPromotedList :: [Printer ()] -> Printer ()
vPromotedList = (String, String) -> [Printer ()] -> Printer ()
vCommaSepWrapped (String
"'[", String
" ]")

-- | Runs printers in a line with a space as the separator.
spaced :: [Printer ()] -> Printer ()
spaced :: [Printer ()] -> Printer ()
spaced = Printer () -> [Printer ()] -> Printer ()
inter Printer ()
space

-- | Runs printers line by line.
lined :: [Printer ()] -> Printer ()
lined :: [Printer ()] -> Printer ()
lined = Printer () -> [Printer ()] -> Printer ()
inter Printer ()
newline

-- | Runs printers with a blank line as the separator.
blanklined :: [Printer ()] -> Printer ()
blanklined :: [Printer ()] -> Printer ()
blanklined = Printer () -> [Printer ()] -> Printer ()
inter Printer ()
blankline

-- | Applies 'hBarSep' if the result fits in a line or 'vBarSep' otherwise.
hvBarSep :: [Printer ()] -> Printer ()
hvBarSep :: [Printer ()] -> Printer ()
hvBarSep = Printer () -> Printer () -> Printer ()
forall a. Printer a -> Printer a -> Printer a
(<-|>) (Printer () -> Printer () -> Printer ())
-> ([Printer ()] -> Printer ())
-> [Printer ()]
-> Printer ()
-> Printer ()
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Printer ()] -> Printer ()
hBarSep ([Printer ()] -> Printer () -> Printer ())
-> ([Printer ()] -> Printer ()) -> [Printer ()] -> Printer ()
forall a b.
([Printer ()] -> a -> b)
-> ([Printer ()] -> a) -> [Printer ()] -> b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> [Printer ()] -> Printer ()
vBarSep

-- | Runs printers in a line with a bar as the separator.
hBarSep :: [Printer ()] -> Printer ()
hBarSep :: [Printer ()] -> Printer ()
hBarSep = Printer () -> [Printer ()] -> Printer ()
inter (HasCallStack => String -> Printer ()
String -> Printer ()
string String
" | ")

-- | Runs printers where each line except the first one has @| @ as
-- a prefix.
vBarSep :: [Printer ()] -> Printer ()
vBarSep :: [Printer ()] -> Printer ()
vBarSep = String -> [Printer ()] -> Printer ()
prefixedLined String
"| "

-- | Applies 'hCommaSep' if the result fits in a line or 'vCommaSep'
-- otherwise.
hvCommaSep :: [Printer ()] -> Printer ()
hvCommaSep :: [Printer ()] -> Printer ()
hvCommaSep = Printer () -> Printer () -> Printer ()
forall a. Printer a -> Printer a -> Printer a
(<-|>) (Printer () -> Printer () -> Printer ())
-> ([Printer ()] -> Printer ())
-> [Printer ()]
-> Printer ()
-> Printer ()
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Printer ()] -> Printer ()
hCommaSep ([Printer ()] -> Printer () -> Printer ())
-> ([Printer ()] -> Printer ()) -> [Printer ()] -> Printer ()
forall a b.
([Printer ()] -> a -> b)
-> ([Printer ()] -> a) -> [Printer ()] -> b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> [Printer ()] -> Printer ()
vCommaSep

-- | Runs printers in a line with a comma as the separator.
hCommaSep :: [Printer ()] -> Printer ()
hCommaSep :: [Printer ()] -> Printer ()
hCommaSep = Printer () -> [Printer ()] -> Printer ()
inter (HasCallStack => String -> Printer ()
String -> Printer ()
string String
", ")

-- | Runs printers with each line except the first one has @, @ as
-- a prefix.
vCommaSep :: [Printer ()] -> Printer ()
vCommaSep :: [Printer ()] -> Printer ()
vCommaSep = String -> [Printer ()] -> Printer ()
prefixedLined String
", "

-- | Prints elements separated by comma  in vertical with the given prefix
-- and suffix.
vCommaSepWrapped :: (String, String) -> [Printer ()] -> Printer ()
vCommaSepWrapped :: (String, String) -> [Printer ()] -> Printer ()
vCommaSepWrapped = Char -> (String, String) -> [Printer ()] -> Printer ()
vWrappedLineup Char
','

-- | Similar to 'vCommaSepWrapped' but the suffix is in the same line as the last
-- element.
vCommaSepWrapped' :: (String, String) -> [Printer ()] -> Printer ()
vCommaSepWrapped' :: (String, String) -> [Printer ()] -> Printer ()
vCommaSepWrapped' = Char -> (String, String) -> [Printer ()] -> Printer ()
vWrappedLineup' Char
','

-- | Runs printers with a dot as the separator.
hDotSep :: [Printer ()] -> Printer ()
hDotSep :: [Printer ()] -> Printer ()
hDotSep = Printer () -> [Printer ()] -> Printer ()
inter (HasCallStack => String -> Printer ()
String -> Printer ()
string String
".")

-- | Prints each element after a space like.
spacePrefixed :: [Printer ()] -> Printer ()
spacePrefixed :: [Printer ()] -> Printer ()
spacePrefixed = (Printer () -> Printer ()) -> [Printer ()] -> Printer ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (Printer ()
space Printer () -> Printer () -> Printer ()
forall a b. Printer a -> Printer b -> Printer b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>)

-- | Prints each element after a new line.
newlinePrefixed :: [Printer ()] -> Printer ()
newlinePrefixed :: [Printer ()] -> Printer ()
newlinePrefixed = (Printer () -> Printer ()) -> [Printer ()] -> Printer ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (Printer ()
newline Printer () -> Printer () -> Printer ()
forall a b. Printer a -> Printer b -> Printer b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>)

-- | Runs printers with a prefix. The prefix is printed before the indent.
prefixedLined :: String -> [Printer ()] -> Printer ()
prefixedLined :: String -> [Printer ()] -> Printer ()
prefixedLined String
_ [] = () -> Printer ()
forall a. a -> Printer a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
prefixedLined String
pref (Printer ()
x:[Printer ()]
xs) = do
  Printer ()
x
  [Printer ()] -> (Printer () -> Printer ()) -> Printer ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [Printer ()]
xs ((Printer () -> Printer ()) -> Printer ())
-> (Printer () -> Printer ()) -> Printer ()
forall a b. (a -> b) -> a -> b
$ \Printer ()
p -> do
    Printer ()
newline
    String -> Printer () -> Printer ()
prefixed String
pref Printer ()
p

-- | Prints elements in vertical with the given prefix, suffix, and
-- separator.
vWrappedLineup :: Char -> (String, String) -> [Printer ()] -> Printer ()
vWrappedLineup :: Char -> (String, String) -> [Printer ()] -> Printer ()
vWrappedLineup Char
sep (String
prefix, String
suffix) [Printer ()]
ps =
  HasCallStack => String -> Printer ()
String -> Printer ()
string String
prefix Printer () -> Printer () -> Printer ()
forall a b. Printer a -> Printer b -> Printer b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
  Printer ()
space Printer () -> Printer () -> Printer ()
forall a. Printer () -> Printer a -> Printer a
|=> do
    String -> [Printer ()] -> Printer ()
prefixedLined [Char
sep, Char
' '] [Printer ()]
ps
    Printer ()
newline
    Int64 -> Printer () -> Printer ()
forall a. Int64 -> Printer a -> Printer a
indentedWithSpace (-(Int -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
prefix) Int64 -> Int64 -> Int64
forall a. Num a => a -> a -> a
+ Int64
1)) (Printer () -> Printer ()) -> Printer () -> Printer ()
forall a b. (a -> b) -> a -> b
$ HasCallStack => String -> Printer ()
String -> Printer ()
string String
suffix

-- | Similar to 'vWrappedLineup' but the suffix is in the same line as the
-- last element.
vWrappedLineup' :: Char -> (String, String) -> [Printer ()] -> Printer ()
vWrappedLineup' :: Char -> (String, String) -> [Printer ()] -> Printer ()
vWrappedLineup' Char
_ (String
prefix, String
suffix) [Printer ()
x] =
  [Printer ()] -> Printer ()
spaced [HasCallStack => String -> Printer ()
String -> Printer ()
string String
prefix, Printer ()
x, HasCallStack => String -> Printer ()
String -> Printer ()
string String
suffix]
vWrappedLineup' Char
sep (String
prefix, String
suffix) [Printer ()]
ps =
  HasCallStack => String -> Printer ()
String -> Printer ()
string String
prefix Printer () -> Printer () -> Printer ()
forall a b. Printer a -> Printer b -> Printer b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
  Printer ()
space Printer () -> Printer () -> Printer ()
forall a. Printer () -> Printer a -> Printer a
|=> do
    String -> [Printer ()] -> Printer ()
prefixedLined [Char
sep, Char
' '] [Printer ()]
ps
    HasCallStack => String -> Printer ()
String -> Printer ()
string String
suffix

-- Inserts the first printer between each element of the list passed as the
-- second argument and runs them.
inter :: Printer () -> [Printer ()] -> Printer ()
inter :: Printer () -> [Printer ()] -> Printer ()
inter Printer ()
separator = [Printer ()] -> Printer ()
forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, Monad m) =>
t (m a) -> m ()
sequence_ ([Printer ()] -> Printer ())
-> ([Printer ()] -> [Printer ()]) -> [Printer ()] -> Printer ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Printer () -> [Printer ()] -> [Printer ()]
forall a. a -> [a] -> [a]
intersperse Printer ()
separator