packages feed

uuagc-0.9.5: src/Pretty.hs

{-# OPTIONS_GHC -fglasgow-exts #-}
-- Layer on top of the original UU.Pretty class
module Pretty
  ( (>|<)
  , (>-<)
  , (>#<)
  , text
  , empty
  , indent
  , pp_block
  , hlist
  , vlist
  , vlist_sep
  , fill
  , pp_parens
  , hv_sp
  , ppWithLineNr
  , disp
  , PP_Doc
  , PP (..)
  ) where

import qualified UU.Pretty as U
import Data.List(intersperse)


--
-- Type classes and data types that mimic UU.Pretty
--

class Show a => PP a where
  pp :: a -> PP_Doc
  pp = text . show

  ppList :: [a] -> PP_Doc
  ppList as = if null as
              then empty
              else foldr (>|<) empty . map pp $ as

instance PP PP_Doc where
  pp = id

instance Show PP_Doc where
  show (PP_Doc f) = let (doc, _, _) = f 1
                    in show doc

instance PP String where
  pp = text

instance PP Char where
  pp = text . (\c -> [c])


newtype PP_Doc = PP_Doc (Int -> (U.PP_Doc, Int, Bool))

fromInternal :: PP a => a -> Int -> (U.PP_Doc, Int, Bool)
fromInternal x l
  = let (PP_Doc f) = pp x
    in f l


--
-- Layer on top of primitive combinators
--

infixr 3 >|<
infixr 2 >-<
infixr 3 >#<

(>|<) :: (PP a, PP b) => a -> b -> PP_Doc
x >|< y
  = PP_Doc $
      \l -> let (p, n, s) = fromInternal x l
                (q, m, t) = fromInternal y n
            in  (p U.>|< q, m, s && t)

(>-<) :: (PP a, PP b) => a -> b -> PP_Doc
x >-< y
  = PP_Doc $
      \l -> let (p, n, s) = fromInternal x l
                (q, m, t) = fromInternal y (if s then n else n+1)
             in (p U.>-< q, if t then m-1 else m, s && t)

text :: String -> PP_Doc
text s
  = let ls = lines s
        ls' | null ls   = [""]
            | otherwise = ls
    in vlist (map ppLine ls')
  where
    ppLine txt
      = PP_Doc $
          \l -> (U.text txt, l, False)

empty :: PP_Doc
empty
  = PP_Doc $
      \l -> (U.empty, l, True)


--
-- Layer on top of the higher-level combinators
-- (shameless copy of their definition)
--

(>#<) :: (PP a, PP b) => a -> b -> PP_Doc
l >#< r = l >|< " " >|< r

hlist :: PP a => [a] -> PP_Doc
hlist = foldr (>|<) empty

vlist :: PP a => [a] -> PP_Doc
vlist = foldr (>-<) empty

vlist_sep :: (PP a, PP b) => a -> [b] -> PP_Doc
vlist_sep sep lst
  = vlist (intersperse (pp sep) (map pp lst))

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 >|< ')'


--
-- Layer on top of the higher-level "smart" combinators
-- (dump alternative implementation)
--

indent :: PP a => Int -> a -> PP_Doc
indent n p = foldr (>#<) (pp p) (replicate n empty)

fill :: PP a => [a] -> PP_Doc
fill = foldr (>#<) empty

hv_sp :: PP a => [a] -> PP_Doc
hv_sp = foldr (>#<) empty


-- Special combinator that exposes the line number
ppWithLineNr :: (Int -> PP_Doc) -> PP_Doc
ppWithLineNr f
  = PP_Doc $
      \l -> fromInternal (f l) l

-- Render function
disp :: PP a => a -> Int -> String -> String
disp p n = let (doc, _, _) = fromInternal (pp p) 1
            in U.disp doc n