{-# LANGUAGE TupleSections #-}
{-# LANGUAGE OverloadedStrings #-}
-- | Compact pretty-printer.
--
-- == Examples
--
-- Assume that we want to pretty print S-Expressions, which can either be atom or a list of S-Expressions.
--
-- >>> data SExpr = SExpr [SExpr] | Atom String deriving Show
-- >>> let pretty :: SExpr -> Doc (); pretty (Atom s) = text s; pretty (SExpr xs) = text "(" <> (sep $ map pretty xs) <> text ")"
--
-- Using the above representation, the S-Expression @(a b c d)@ has the following encoding:
--
-- >>> let abcd = SExpr [Atom "a",Atom "b",Atom "c",Atom "d"]
--
-- The legible layouts of the @abcd@ S-Expression defined above would be either
--
-- >>> putStrLn $ render $ pretty abcd
-- (a b c d)
--
-- or
--
-- >>> putStrLn $ renderWith defaultOptions { optsPageWidth = 5 } $ pretty abcd
-- (a
--  b
--  c
--  d)
--
-- The @testData@ S-Expression is specially crafted to
-- demonstrate general shortcomings of both Hughes and Wadler libraries.
--
-- >>> let abcd4 = SExpr [abcd,abcd,abcd,abcd]
-- >>> let testData = SExpr [ SExpr [Atom "abcde", abcd4], SExpr [Atom "abcdefgh", abcd4]]
-- >>> putStrLn $ render $ pretty testData
-- ((abcde ((a b c d) (a b c d) (a b c d) (a b c d)))
--  (abcdefgh ((a b c d) (a b c d) (a b c d) (a b c d))))
--
-- on 20-column-wide page
--
-- >>> putStrLn $ renderWith defaultOptions { optsPageWidth = 20 } $ pretty testData
-- ((abcde ((a b c d)
--          (a b c d)
--          (a b c d)
--          (a b c d)))
--  (abcdefgh
--   ((a b c d)
--    (a b c d)
--    (a b c d)
--    (a b c d))))
--
-- Yet, neither Hughes' nor Wadler's library can deliver those results.
--
-- === Annotations
--
-- For example we can annotate every /car/ element of S-Expressions,
-- and in the rendering phase emphasise them by rendering them in uppercase.
--
-- >>> let pretty' :: SExpr -> Doc Any; pretty' (Atom s) = text s; pretty' (SExpr []) = text "()"; pretty' (SExpr (x:xs)) = text "(" <> (sep $ annotate (Any True) (pretty' x) : map pretty' xs) <> text ")"
-- >>> let render' = renderWith defaultOptions { optsAnnotate  = \a x -> if a == Any True then map toUpper x else x }
-- >>> putStrLn $ render' $ pretty' testData
-- ((ABCDE ((A B C D) (A B C D) (A B C D) (A B C D)))
--  (ABCDEFGH ((A B C D) (A b c d) (A b c d) (A b c d))))
--
module Text.PrettyPrint.Compact (
   -- * Documents
   Doc,

   -- * Basic combinators
   module Data.Monoid, text, flush, char,

   hang, hangWith, encloseSep, list, tupled, semiBraces,

   -- * Operators
   (<+>), ($$), (</>), (<//>), (<$$>),

   -- * List combinators
   hsep, sep, hcat, vcat, cat, punctuate,

   -- * Fill combiantors
   -- fillSep, fillCat,

   -- * Bracketing combinators
   enclose, squotes, dquotes, parens, angles, braces, brackets,

   -- * Character documents
   lparen, rparen, langle, rangle, lbrace, rbrace, lbracket, rbracket,
   squote, dquote, semi, colon, comma, space, dot, backslash, equals,

   -- * Primitive type documents
   string, int, integer, float, double, rational,
   bool,

   -- * Rendering
   renderWith,
   render,
   Options(..),
   defaultOptions,

   -- * Annotations
   annotate,

   -- * Undocumented
   -- column, nesting, width
   ) where

import Data.Monoid

import Text.PrettyPrint.Compact.Core as Text.PrettyPrint.Compact

-- | Render the 'Doc' into 'String' omitting all annotations.
render :: Annotation a => Doc a -> String
render :: forall a. Annotation a => Doc a -> String
render = Options a String -> ODoc a -> String
forall r a. (Monoid r, Annotation a) => Options a r -> ODoc a -> r
renderWith Options a String
forall a. Options a String
defaultOptions

defaultOptions :: Options a String
defaultOptions :: forall a. Options a String
defaultOptions = Options
    { optsAnnotate :: a -> String -> String
optsAnnotate = \a
_ String
s -> String
s
    , optsPageWidth :: Int
optsPageWidth = Int
80
    }

-- | The document @(list xs)@ comma separates the documents @xs@ and
-- encloses them in square brackets. The documents are rendered
-- horizontally if that fits the page. Otherwise they are aligned
-- vertically. All comma separators are put in front of the elements.
list :: Annotation a => [Doc a] -> Doc a
list :: forall a. Annotation a => [Doc a] -> Doc a
list            = Doc a -> Doc a -> Doc a -> [Doc a] -> Doc a
forall a.
Annotation a =>
Doc a -> Doc a -> Doc a -> [Doc a] -> Doc a
encloseSep Doc a
forall a. Annotation a => Doc a
lbracket Doc a
forall a. Annotation a => Doc a
rbracket Doc a
forall a. Annotation a => Doc a
comma

-- | The document @(tupled xs)@ comma separates the documents @xs@ and
-- encloses them in parenthesis. The documents are rendered
-- horizontally if that fits the page. Otherwise they are aligned
-- vertically. All comma separators are put in front of the elements.
tupled :: Annotation a => [Doc a] -> Doc a
tupled :: forall a. Annotation a => [Doc a] -> Doc a
tupled          = Doc a -> Doc a -> Doc a -> [Doc a] -> Doc a
forall a.
Annotation a =>
Doc a -> Doc a -> Doc a -> [Doc a] -> Doc a
encloseSep Doc a
forall a. Annotation a => Doc a
lparen   Doc a
forall a. Annotation a => Doc a
rparen  Doc a
forall a. Annotation a => Doc a
comma


-- | The document @(semiBraces xs)@ separates the documents @xs@ with
-- semi colons and encloses them in braces. The documents are rendered
-- horizontally if that fits the page. Otherwise they are aligned
-- vertically. All semi colons are put in front of the elements.
semiBraces :: Annotation a => [Doc a] -> Doc a
semiBraces :: forall a. Annotation a => [Doc a] -> Doc a
semiBraces      = Doc a -> Doc a -> Doc a -> [Doc a] -> Doc a
forall a.
Annotation a =>
Doc a -> Doc a -> Doc a -> [Doc a] -> Doc a
encloseSep Doc a
forall a. Annotation a => Doc a
lbrace   Doc a
forall a. Annotation a => Doc a
rbrace  Doc a
forall a. Annotation a => Doc a
semi

-- | The document @(enclosure l r sep xs)@ concatenates the documents
-- @xs@ separated by @sep@ and encloses the resulting document by @l@
-- and @r@. The documents are rendered horizontally if that fits the
-- page. Otherwise they are aligned vertically. All separators are put
-- in front of the elements. For example, the combinator 'list' can be
-- defined with @enclosure@:
--
-- > list xs = enclosure lbracket rbracket comma xs
-- > test    = text "list" <+> (list (map int [10,200,3000]))
--
-- Which is layed out with a page width of 20 as:
--
-- @
-- list [10,200,3000]
-- @
--
-- But when the page width is 15, it is layed out as:
--
-- @
-- list [10
--      ,200
--      ,3000]
-- @
encloseSep :: Annotation a => Doc a -> Doc a -> Doc a -> [Doc a] -> Doc a
encloseSep :: forall a.
Annotation a =>
Doc a -> Doc a -> Doc a -> [Doc a] -> Doc a
encloseSep Doc a
left Doc a
right Doc a
separator [Doc a]
ds
    = (Doc a -> Doc a -> Doc a
forall a. Semigroup a => a -> a -> a
<> Doc a
right) (Doc a -> Doc a) -> Doc a -> Doc a
forall a b. (a -> b) -> a -> b
$ case [Doc a]
ds of
        []  -> Doc a
left
        [Doc a
d] -> Doc a
left Doc a -> Doc a -> Doc a
forall a. Semigroup a => a -> a -> a
<> Doc a
d
        (Doc a
d:[Doc a]
ds') -> [Doc a] -> Doc a
forall a. Annotation a => [Doc a] -> Doc a
cat (Doc a
left Doc a -> Doc a -> Doc a
forall a. Semigroup a => a -> a -> a
<> Doc a
dDoc a -> [Doc a] -> [Doc a]
forall a. a -> [a] -> [a]
:(Doc a -> Doc a) -> [Doc a] -> [Doc a]
forall a b. (a -> b) -> [a] -> [b]
map (Doc a
separator Doc a -> Doc a -> Doc a
forall a. Semigroup a => a -> a -> a
<>) [Doc a]
ds')

-----------------------------------------------------------
-- punctuate p [d1,d2,...,dn] => [d1 <> p,d2 <> p, ... ,dn]
-----------------------------------------------------------


-- | @(punctuate p xs)@ concatenates all documents in @xs@ with
-- document @p@ except for the last document.
--
-- > someText = map text ["words","in","a","tuple"]
-- > test     = parens (align (cat (punctuate comma someText)))
--
-- This is layed out on a page width of 20 as:
--
-- @
-- (words,in,a,tuple)
-- @
--
-- But when the page width is 15, it is layed out as:
--
-- @
-- (words,
--  in,
--  a,
--  tuple)
-- @
--
-- (If you want put the commas in front of their elements instead of
-- at the end, you should use 'tupled' or, in general, 'encloseSep'.)
punctuate :: Annotation a => Doc a -> [Doc a] -> [Doc a]
punctuate :: forall a. Annotation a => Doc a -> [Doc a] -> [Doc a]
punctuate Doc a
_p []      = []
punctuate Doc a
_p [Doc a
d]     = [Doc a
d]
punctuate Doc a
p (Doc a
d:[Doc a]
ds)  = (Doc a
d Doc a -> Doc a -> Doc a
forall a. Semigroup a => a -> a -> a
<> Doc a
p) Doc a -> [Doc a] -> [Doc a]
forall a. a -> [a] -> [a]
: Doc a -> [Doc a] -> [Doc a]
forall a. Annotation a => Doc a -> [Doc a] -> [Doc a]
punctuate Doc a
p [Doc a]
ds


-----------------------------------------------------------
-- high-level combinators
-----------------------------------------------------------


-- | The document @(sep xs)@ concatenates all documents @xs@ either
-- horizontally with @(\<+\>)@, if it fits the page, or vertically
-- with @(\<$$\>)@. Documents on the left of horizontal concatenation
-- must fit on a single line.
--
sep :: Annotation a => [Doc a] -> Doc a
sep :: forall a. Annotation a => [Doc a] -> Doc a
sep [Doc a]
xs = String -> [(Int, Doc a)] -> Doc a
forall a. Monoid a => String -> [(Int, Doc a)] -> Doc a
groupingBy String
" " ((Doc a -> (Int, Doc a)) -> [Doc a] -> [(Int, Doc a)]
forall a b. (a -> b) -> [a] -> [b]
map (Int
0,) [Doc a]
xs)


-- -- | The document @(fillSep xs)@ concatenates documents @xs@
-- -- horizontally with @(\<+\>)@ as long as its fits the page, than
-- -- inserts a @line@ and continues doing that for all documents in
-- -- @xs@.
-- --
-- -- > fillSep xs  = foldr (\<\/\>) empty xs
-- fillSep :: Annotation a => [Doc a] -> Doc a
-- fillSep         = foldDoc (</>)

-- | The document @(hsep xs)@ concatenates all documents @xs@
-- horizontally with @(\<+\>)@.
hsep :: Annotation a => [Doc a] -> Doc a
hsep :: forall a. Annotation a => [Doc a] -> Doc a
hsep            = (Doc a -> Doc a -> Doc a) -> [Doc a] -> Doc a
forall a.
Annotation a =>
(Doc a -> Doc a -> Doc a) -> [Doc a] -> Doc a
foldDoc Doc a -> Doc a -> Doc a
forall a. Annotation a => Doc a -> Doc a -> Doc a
(<+>)

-- | The document @(cat xs)@ concatenates all documents @xs@ either
-- horizontally with @(\<\>)@, if it fits the page, or vertically with
-- @(\<$$\>)@.
--
cat :: Annotation a => [Doc a] -> Doc a
cat :: forall a. Annotation a => [Doc a] -> Doc a
cat [Doc a]
xs = String -> [(Int, Doc a)] -> Doc a
forall a. Monoid a => String -> [(Int, Doc a)] -> Doc a
groupingBy String
"" ((Doc a -> (Int, Doc a)) -> [Doc a] -> [(Int, Doc a)]
forall a b. (a -> b) -> [a] -> [b]
map (Int
0,) [Doc a]
xs)

-- -- | The document @(fillCat xs)@ concatenates documents @xs@
-- -- horizontally with @(\<\>)@ as long as its fits the page, than inserts
-- -- a @linebreak@ and continues doing that for all documents in @xs@.
-- --
-- -- > fillCat xs  = foldr (\<\/\/\>) empty xs
-- fillCat :: Annotation a => [Doc a] -> Doc a
-- fillCat         = foldDoc (<//>)

-- | The document @(hcat xs)@ concatenates all documents @xs@
-- horizontally with @(\<\>)@.
hcat :: Annotation a => [Doc a] -> Doc a
hcat :: forall a. Annotation a => [Doc a] -> Doc a
hcat            = (Doc a -> Doc a -> Doc a) -> [Doc a] -> Doc a
forall a.
Annotation a =>
(Doc a -> Doc a -> Doc a) -> [Doc a] -> Doc a
foldDoc Doc a -> Doc a -> Doc a
forall a. Semigroup a => a -> a -> a
(<>)

-- | The document @(vcat xs)@ concatenates all documents @xs@
-- vertically with @($$)@.
vcat :: Annotation a => [Doc a] -> Doc a
vcat :: forall a. Annotation a => [Doc a] -> Doc a
vcat            = (ODoc a -> ODoc a -> ODoc a) -> [ODoc a] -> ODoc a
forall a.
Annotation a =>
(Doc a -> Doc a -> Doc a) -> [Doc a] -> Doc a
foldDoc ODoc a -> ODoc a -> ODoc a
forall (d :: * -> *) a.
(Layout d, Monoid a, Semigroup (d a)) =>
d a -> d a -> d a
($$)

foldDoc :: Annotation a => (Doc a -> Doc a -> Doc a) -> [Doc a] -> Doc a
foldDoc :: forall a.
Annotation a =>
(Doc a -> Doc a -> Doc a) -> [Doc a] -> Doc a
foldDoc Doc a -> Doc a -> Doc a
_ []       = Doc a
forall a. Monoid a => a
mempty
foldDoc Doc a -> Doc a -> Doc a
f [Doc a]
ds       = (Doc a -> Doc a -> Doc a) -> [Doc a] -> Doc a
forall a. (a -> a -> a) -> [a] -> a
forall (t :: * -> *) a. Foldable t => (a -> a -> a) -> t a -> a
foldr1 Doc a -> Doc a -> Doc a
f [Doc a]
ds

-- | The document @(x \<+\> y)@ concatenates document @x@ and @y@ with a
-- @space@ in between.  (infixr 6)
(<+>) :: Annotation a => Doc a -> Doc a -> Doc a
Doc a
x <+> :: forall a. Annotation a => Doc a -> Doc a -> Doc a
<+> Doc a
y         = Doc a
x Doc a -> Doc a -> Doc a
forall a. Semigroup a => a -> a -> a
<> Doc a
forall a. Annotation a => Doc a
space Doc a -> Doc a -> Doc a
forall a. Semigroup a => a -> a -> a
<> Doc a
y

-- | The document @(x \<\/\> y)@ puts @x@ and @y@ either next to each other
-- (with a @space@ in between) or underneath each other. (infixr 5)
(</>) :: Annotation a => Doc a -> Doc a -> Doc a
Doc a
x </> :: forall a. Annotation a => Doc a -> Doc a -> Doc a
</> Doc a
y         = Int -> Doc a -> Doc a -> Doc a
forall a. Annotation a => Int -> Doc a -> Doc a -> Doc a
hang Int
0 Doc a
x Doc a
y

-- | The document @(x \<\/\/\> y)@ puts @x@ and @y@ either right next
-- to each other (if @x@ fits on a single line) or underneath each
-- other. (infixr 5)
(<//>) :: Annotation a => Doc a -> Doc a -> Doc a
Doc a
x <//> :: forall a. Annotation a => Doc a -> Doc a -> Doc a
<//> Doc a
y        = String -> Int -> Doc a -> Doc a -> Doc a
forall a. Annotation a => String -> Int -> Doc a -> Doc a -> Doc a
hangWith String
"" Int
0 Doc a
x Doc a
y

-- | The document @(x \<$$\> y)@ concatenates document @x@ and @y@ with
-- a linebreak in between. (infixr 5)
(<$$>) :: Annotation a => Doc a -> Doc a -> Doc a
<$$> :: forall a. Annotation a => Doc a -> Doc a -> Doc a
(<$$>) = ODoc a -> ODoc a -> ODoc a
forall (d :: * -> *) a.
(Layout d, Monoid a, Semigroup (d a)) =>
d a -> d a -> d a
($$)

-- | Document @(squotes x)@ encloses document @x@ with single quotes
-- \"'\".
squotes :: Annotation a => Doc a -> Doc a
squotes :: forall a. Annotation a => Doc a -> Doc a
squotes         = Doc a -> Doc a -> Doc a -> Doc a
forall a. Annotation a => Doc a -> Doc a -> Doc a -> Doc a
enclose Doc a
forall a. Annotation a => Doc a
squote Doc a
forall a. Annotation a => Doc a
squote

-- | Document @(dquotes x)@ encloses document @x@ with double quotes
-- '\"'.
dquotes :: Annotation a => Doc a -> Doc a
dquotes :: forall a. Annotation a => Doc a -> Doc a
dquotes         = Doc a -> Doc a -> Doc a -> Doc a
forall a. Annotation a => Doc a -> Doc a -> Doc a -> Doc a
enclose Doc a
forall a. Annotation a => Doc a
dquote Doc a
forall a. Annotation a => Doc a
dquote

-- | Document @(braces x)@ encloses document @x@ in braces, \"{\" and
-- \"}\".
braces :: Annotation a => Doc a -> Doc a
braces :: forall a. Annotation a => Doc a -> Doc a
braces          = Doc a -> Doc a -> Doc a -> Doc a
forall a. Annotation a => Doc a -> Doc a -> Doc a -> Doc a
enclose Doc a
forall a. Annotation a => Doc a
lbrace Doc a
forall a. Annotation a => Doc a
rbrace

-- | Document @(parens x)@ encloses document @x@ in parenthesis, \"(\"
-- and \")\".
parens :: Annotation a => Doc a -> Doc a
parens :: forall a. Annotation a => Doc a -> Doc a
parens          = Doc a -> Doc a -> Doc a -> Doc a
forall a. Annotation a => Doc a -> Doc a -> Doc a -> Doc a
enclose Doc a
forall a. Annotation a => Doc a
lparen Doc a
forall a. Annotation a => Doc a
rparen

-- | Document @(angles x)@ encloses document @x@ in angles, \"\<\" and
-- \"\>\".
angles :: Annotation a => Doc a -> Doc a
angles :: forall a. Annotation a => Doc a -> Doc a
angles          = Doc a -> Doc a -> Doc a -> Doc a
forall a. Annotation a => Doc a -> Doc a -> Doc a -> Doc a
enclose Doc a
forall a. Annotation a => Doc a
langle Doc a
forall a. Annotation a => Doc a
rangle

-- | Document @(brackets x)@ encloses document @x@ in square brackets,
-- \"[\" and \"]\".
brackets :: Annotation a => Doc a -> Doc a
brackets :: forall a. Annotation a => Doc a -> Doc a
brackets        = Doc a -> Doc a -> Doc a -> Doc a
forall a. Annotation a => Doc a -> Doc a -> Doc a -> Doc a
enclose Doc a
forall a. Annotation a => Doc a
lbracket Doc a
forall a. Annotation a => Doc a
rbracket

-- | The document @(enclose l r x)@ encloses document @x@ between
-- documents @l@ and @r@ using @(\<\>)@.
enclose :: Annotation a => Doc a -> Doc a -> Doc a -> Doc a
enclose :: forall a. Annotation a => Doc a -> Doc a -> Doc a -> Doc a
enclose Doc a
l Doc a
r Doc a
x   = Doc a
l Doc a -> Doc a -> Doc a
forall a. Semigroup a => a -> a -> a
<> Doc a
x Doc a -> Doc a -> Doc a
forall a. Semigroup a => a -> a -> a
<> Doc a
r

char :: Annotation a => Char -> Doc a
char :: forall a. Annotation a => Char -> Doc a
char Char
x = String -> ODoc a
forall a. Monoid a => String -> ODoc a
forall (d :: * -> *) a. (Layout d, Monoid a) => String -> d a
text [Char
x]

-- | The document @lparen@ contains a left parenthesis, \"(\".
lparen :: Annotation a => Doc a
lparen :: forall a. Annotation a => Doc a
lparen          = Char -> Doc a
forall a. Annotation a => Char -> Doc a
char Char
'('
-- | The document @rparen@ contains a right parenthesis, \")\".
rparen :: Annotation a => Doc a
rparen :: forall a. Annotation a => Doc a
rparen          = Char -> Doc a
forall a. Annotation a => Char -> Doc a
char Char
')'
-- | The document @langle@ contains a left angle, \"\<\".
langle :: Annotation a => Doc a
langle :: forall a. Annotation a => Doc a
langle          = Char -> Doc a
forall a. Annotation a => Char -> Doc a
char Char
'<'
-- | The document @rangle@ contains a right angle, \">\".
rangle :: Annotation a => Doc a
rangle :: forall a. Annotation a => Doc a
rangle          = Char -> Doc a
forall a. Annotation a => Char -> Doc a
char Char
'>'
-- | The document @lbrace@ contains a left brace, \"{\".
lbrace :: Annotation a => Doc a
lbrace :: forall a. Annotation a => Doc a
lbrace          = Char -> Doc a
forall a. Annotation a => Char -> Doc a
char Char
'{'
-- | The document @rbrace@ contains a right brace, \"}\".
rbrace :: Annotation a => Doc a
rbrace :: forall a. Annotation a => Doc a
rbrace          = Char -> Doc a
forall a. Annotation a => Char -> Doc a
char Char
'}'
-- | The document @lbracket@ contains a left square bracket, \"[\".
lbracket :: Annotation a => Doc a
lbracket :: forall a. Annotation a => Doc a
lbracket        = Char -> Doc a
forall a. Annotation a => Char -> Doc a
char Char
'['
-- | The document @rbracket@ contains a right square bracket, \"]\".
rbracket :: Annotation a => Doc a
rbracket :: forall a. Annotation a => Doc a
rbracket        = Char -> Doc a
forall a. Annotation a => Char -> Doc a
char Char
']'


-- | The document @squote@ contains a single quote, \"'\".
squote :: Annotation a => Doc a
squote :: forall a. Annotation a => Doc a
squote          = Char -> Doc a
forall a. Annotation a => Char -> Doc a
char Char
'\''
-- | The document @dquote@ contains a double quote, '\"'.
dquote :: Annotation a => Doc a
dquote :: forall a. Annotation a => Doc a
dquote          = Char -> Doc a
forall a. Annotation a => Char -> Doc a
char Char
'"'
-- | The document @semi@ contains a semi colon, \";\".
semi :: Annotation a => Doc a
semi :: forall a. Annotation a => Doc a
semi            = Char -> Doc a
forall a. Annotation a => Char -> Doc a
char Char
';'
-- | The document @colon@ contains a colon, \":\".
colon :: Annotation a => Doc a
colon :: forall a. Annotation a => Doc a
colon           = Char -> Doc a
forall a. Annotation a => Char -> Doc a
char Char
':'
-- | The document @comma@ contains a comma, \",\".
comma :: Annotation a => Doc a
comma :: forall a. Annotation a => Doc a
comma           = Char -> Doc a
forall a. Annotation a => Char -> Doc a
char Char
','

-- | The document @dot@ contains a single dot, \".\".
dot :: Annotation a => Doc a
dot :: forall a. Annotation a => Doc a
dot             = Char -> Doc a
forall a. Annotation a => Char -> Doc a
char Char
'.'
-- | The document @backslash@ contains a back slash, \"\\\".
backslash :: Annotation a => Doc a
backslash :: forall a. Annotation a => Doc a
backslash       = Char -> Doc a
forall a. Annotation a => Char -> Doc a
char Char
'\\'
-- | The document @equals@ contains an equal sign, \"=\".
equals :: Annotation a => Doc a
equals :: forall a. Annotation a => Doc a
equals          = Char -> Doc a
forall a. Annotation a => Char -> Doc a
char Char
'='

-----------------------------------------------------------
-- Combinators for prelude types
-----------------------------------------------------------

-- string is like "text" but replaces '\n' by "line"

-- | The document @(string s)@ concatenates all characters in @s@
-- using @line@ for newline characters and @char@ for all other
-- characters. It is used instead of 'text' whenever the text contains
-- newline characters.
string :: Annotation a => String -> Doc a
string :: forall a. Monoid a => String -> ODoc a
string = [Doc a] -> Doc a
forall a. Annotation a => [Doc a] -> Doc a
vcat ([Doc a] -> Doc a) -> (String -> [Doc a]) -> String -> Doc a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> Doc a) -> [String] -> [Doc a]
forall a b. (a -> b) -> [a] -> [b]
map String -> Doc a
forall a. Monoid a => String -> ODoc a
forall (d :: * -> *) a. (Layout d, Monoid a) => String -> d a
text ([String] -> [Doc a]) -> (String -> [String]) -> String -> [Doc a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
lines

bool :: Annotation a => Bool -> Doc a
bool :: forall a. Annotation a => Bool -> Doc a
bool Bool
b          = String -> ODoc a
forall a. Monoid a => String -> ODoc a
forall (d :: * -> *) a. (Layout d, Monoid a) => String -> d a
text (Bool -> String
forall a. Show a => a -> String
show Bool
b)

-- | The document @(int i)@ shows the literal integer @i@ using
-- 'text'.
int :: Annotation a => Int -> Doc a
int :: forall a. Annotation a => Int -> Doc a
int Int
i           = String -> ODoc a
forall a. Monoid a => String -> ODoc a
forall (d :: * -> *) a. (Layout d, Monoid a) => String -> d a
text (Int -> String
forall a. Show a => a -> String
show Int
i)

-- | The document @(integer i)@ shows the literal integer @i@ using
-- 'text'.
integer :: Annotation a => Integer -> Doc a
integer :: forall a. Annotation a => Integer -> Doc a
integer Integer
i       = String -> ODoc a
forall a. Monoid a => String -> ODoc a
forall (d :: * -> *) a. (Layout d, Monoid a) => String -> d a
text (Integer -> String
forall a. Show a => a -> String
show Integer
i)

-- | The document @(float f)@ shows the literal float @f@ using
-- 'text'.
float :: Annotation a => Float -> Doc a
float :: forall a. Annotation a => Float -> Doc a
float Float
f         = String -> ODoc a
forall a. Monoid a => String -> ODoc a
forall (d :: * -> *) a. (Layout d, Monoid a) => String -> d a
text (Float -> String
forall a. Show a => a -> String
show Float
f)

-- | The document @(double d)@ shows the literal double @d@ using
-- 'text'.
double :: Annotation a => Double -> Doc a
double :: forall a. Annotation a => Double -> Doc a
double Double
d        = String -> ODoc a
forall a. Monoid a => String -> ODoc a
forall (d :: * -> *) a. (Layout d, Monoid a) => String -> d a
text (Double -> String
forall a. Show a => a -> String
show Double
d)

-- | The document @(rational r)@ shows the literal rational @r@ using
-- 'text'.
rational :: Annotation a => Rational -> Doc a
rational :: forall a. Annotation a => Rational -> Doc a
rational Rational
r      = String -> ODoc a
forall a. Monoid a => String -> ODoc a
forall (d :: * -> *) a. (Layout d, Monoid a) => String -> d a
text (Rational -> String
forall a. Show a => a -> String
show Rational
r)



-- | The hang combinator implements hanging indentation. The document
-- @(hang i x y)@ either @x@ and @y@ concatenated with @\<+\>@ or @y@
-- below @x@ with an additional indentation of @i@.

hang :: Annotation a => Int -> Doc a -> Doc a -> Doc a
hang :: forall a. Annotation a => Int -> Doc a -> Doc a -> Doc a
hang = String -> Int -> Doc a -> Doc a -> Doc a
forall a. Annotation a => String -> Int -> Doc a -> Doc a -> Doc a
hangWith String
" "


-- | The hang combinator implements hanging indentation. The document
-- @(hang separator i x y)@ either @x@ and @y@ concatenated with @\<\>
-- text separator \<\>@ or @y@ below @x@ with an additional
-- indentation of @i@.
hangWith :: Annotation a => String -> Int -> Doc a -> Doc a -> Doc a
hangWith :: forall a. Annotation a => String -> Int -> Doc a -> Doc a -> Doc a
hangWith String
separator Int
n Doc a
x Doc a
y = String -> [(Int, Doc a)] -> Doc a
forall a. Monoid a => String -> [(Int, Doc a)] -> Doc a
groupingBy String
separator [(Int
0,Doc a
x), (Int
n,Doc a
y)]

space :: Annotation a => Doc a
space :: forall a. Annotation a => Doc a
space = String -> ODoc a
forall a. Monoid a => String -> ODoc a
forall (d :: * -> *) a. (Layout d, Monoid a) => String -> d a
text String
" "

-- $setup
-- >>> import Data.Monoid
-- >>> import Data.Char