module Pretty
( PP_Doc, PP(..)
, disp
, (>|<), (>-<)
, (>#<)
, ppWithLineNr
, hlist, vlist, hv
, fill
, indent
, pp_block
, vlist_sep
, pp_parens
, pp_braces
, hv_sp
, empty, empty1, text
, isEmpty
)
where
import Data.List(intersperse)
data Doc
= Emp
| Emp1
| Str !String
| Hor Doc !Doc
| Ver Doc !Doc
| Ind !Int Doc
| Line (Int -> Doc)
type PP_Doc = Doc
infixr 3 >|<, >#<
infixr 2 >-<
(>|<) :: (PP a, PP b) => a -> b -> PP_Doc
l >|< r = pp l `Hor` pp r
(>-<) :: (PP a, PP b) => a -> b -> PP_Doc
l >-< r | isEmpty a = b
| isEmpty b = a
| otherwise = a `Ver` b
where a = pp l
b = pp r
(>#<) :: (PP a, PP b) => a -> b -> PP_Doc
l >#< r | isEmpty a = b
| isEmpty b = a
| otherwise = a >|< " " >|< b
where a = pp l
b = pp r
indent :: PP a => Int -> a -> PP_Doc
indent i d = Ind i $ pp d
text :: String -> PP_Doc
text s
= let ls = lines s
ls' | null ls = [""]
| otherwise = ls
in vlist (map Str ls')
empty :: PP_Doc
empty = Emp
empty1 :: PP_Doc
empty1 = Emp1
ppWithLineNr :: PP a => (Int -> a) -> PP_Doc
ppWithLineNr f = Line (pp . f)
hlist, vlist :: PP a => [a] -> PP_Doc
vlist [] = empty
vlist as = foldr (>-<) empty as
hlist [] = empty
hlist as = foldr (>|<) empty as
hv :: PP a => [a] -> PP_Doc
hv = vlist
hv_sp :: PP a => [a] -> PP_Doc
hv_sp = foldr (>#<) empty
fill :: PP a => [a] -> PP_Doc
fill = hlist
pp_block:: (PP a, PP b, PP c) => a -> b -> c -> [PP_Doc] -> PP_Doc
pp_block o c s as = pp o >|< hlist (intersperse (pp s) as) >|< pp c
pp_parens :: PP a => a -> PP_Doc
pp_parens p = '(' >|< p >|< ')'
pp_braces :: PP a => a -> PP_Doc
pp_braces p = '{' >-< p >-< '}'
vlist_sep :: (PP a, PP b) => a -> [b] -> PP_Doc
vlist_sep sep lst
= vlist (intersperse (pp sep) (map pp lst))
class Show a => PP a where
pp :: a -> PP_Doc
pp = text . show
ppList :: [a] -> PP_Doc
ppList as = hlist as
instance PP Doc where
pp = id
instance PP Char where
pp c = text [c]
ppList = text
instance PP a => PP [a] where
pp = ppList
instance Show Doc where
show p = disp p 200 ""
instance PP Int where
pp = text . show
instance PP Float where
pp = text . show
isEmpty :: PP_Doc -> Bool
isEmpty Emp = True
isEmpty Emp1 = False
isEmpty (Ver d1 d2) = isEmpty d1 && isEmpty d2
isEmpty (Hor d1 d2) = isEmpty d1 && isEmpty d2
isEmpty (Ind _ d ) = isEmpty d
isEmpty _ = False
disp :: PP_Doc -> Int -> ShowS
disp d0 _ s0
= r
where (r,_,_) = put 0 1 d0 s0
put p l d s
= case d of
Emp -> (s,p,l)
Emp1 -> (s,p,l)
Str s' -> (s' ++ s,p + length s',l)
Ind i d1 -> (ind ++ r',p', l')
where (r',p',l') = put (p+i) l d1 s
ind = replicate i ' '
Hor d1 d2 -> (r1,p2,l2)
where (r1,p1,l1) = put p l d1 r2
(r2,p2,l2) = put p1 l1 d2 s
Ver d1 d2 | isEmpty d1
-> put p l d2 s
Ver d1 d2 | isEmpty d2
-> put p l d1 s
Ver d1 d2 -> (r1,p2,l2)
where (r1,_ ,l1) = put p l d1 $ "\n" ++ ind ++ r2
(r2,p2,l2) = put p (l1+1) d2 s
ind = replicate p ' '
Line f -> (r',p',l')
where (r',p',l') = put p l (f l) s