uu-cco-0.1.0.0: src/CCO/Printing/Printer.hs
-------------------------------------------------------------------------------
-- |
-- Module : CCO.Printing.Printer
-- Copyright : (c) 2008 Utrecht University
-- License : All rights reserved
--
-- Maintainer : stefan@cs.uu.nl
-- Stability : provisional
-- Portability : portable
--
-- The 'Printer' class and two instances.
--
-- Instances of 'Printer' model low-level devices for outputting the basic
-- elements (text, whitespace, and line breaks) of pretty-printable documents.
--
-------------------------------------------------------------------------------
module CCO.Printing.Printer (
-- * The Printer class
Printer (..) -- superclasses: Monoid
-- * Printing to strings
, StringPrinter -- abstract, instances: Monoid, Printer
, printToString -- :: StringPrinter -> String
-- * Printing to the standard output channel
, IOPrinter -- abstract, instances: Monoid, Printer
, printToIO -- :: IOPrinter -> IO ()
) where
import CCO.Printing.Colour ( Colour (..) )
import Data.Monoid ( Monoid (..) )
import System.Console.ANSI ( ConsoleLayer (Foreground)
, ColorIntensity (Dull)
, SGR (Reset, SetColor)
, setSGR
)
import qualified System.Console.ANSI as A ( Color (..) )
-------------------------------------------------------------------------------
-- The Printer class
-------------------------------------------------------------------------------
-- | The @Printer@ class.
--
-- A minimal complete definition must supply the methods @ptext@, @ws@,
-- @newLine@, @width@, and @height@.
--
-- Instances of @Printer@ are also instances of 'Monoid' and should be in such
-- a way that 'mempty' prints the empty document and 'mappend' produces a
-- printer that runs its constituent printers consecutively.
--
-- Instances of @Printer@ should satisfy the following laws:
--
-- > width mempty == 0
-- > width (ptext txt) == length txt
-- > width (ws n) == n
-- > width newLine == 0
-- > width (beginColour c) == 0
-- > width endColour == 0
-- > width (pl `mappend` pr) == width pl + width pr
-- > height mempty == 0
-- > height (ptext txt) == 0
-- > height (ws n) == 0
-- > height newLine == 1
-- > height (beginColour c) == 0
-- > height endColour == 0
-- > height (pl `mappend` pr) == height pl + height pr
class Monoid a => Printer a where
-- | Prints a given single-line text.
ptext :: String -> a
-- | Prints the specifed amount of whitespace.
ws :: Int -> a
-- | Moves to the next line.
newLine :: a
-- | Select a foreground colour.
beginColour :: Colour -> a
-- | Select the previous foreground colour.
endColour :: a
-- | Produces the amount of horizontal space to be claimed.
width :: a -> Int
-- | Produces the number of new lines to be claimed.
height :: a -> Int
beginColour = mempty
endColour = mempty
-------------------------------------------------------------------------------
-- Printing to strings
-------------------------------------------------------------------------------
-- | The type of printers that produce 'String's.
data StringPrinter = SP !Int !Int (String -> String)
instance Monoid StringPrinter where
mempty = SP 0 0 id
mappend (SP wl hl accl) (SP wr hr accr) =
SP (wl + wr) (hl + hr) (accl . accr)
instance Printer StringPrinter where
ptext txt = SP (length txt) 0 (txt ++)
ws n = SP n 0 (take n spaces ++)
newLine = SP 0 1 ("\n" ++)
width (SP w _ _) = w
height (SP _ h _) = h
-- | Runs a 'StringPrinter'.
printToString :: StringPrinter -> String
printToString (SP _ _ acc) = acc ""
-------------------------------------------------------------------------------
-- Printing to the standard output channel
-------------------------------------------------------------------------------
-- | The type of printers that print to the standard output channel.
data IOPrinter = IOP !Int !Int ([Colour] -> (IO (), [Colour]))
instance Monoid IOPrinter where
mempty = IOP 0 0 (\cs -> (return (), cs))
mappend (IOP wl hl f) (IOP wr hr g) = IOP (wl + wr) (hl + hr) $ \cs ->
let (iol, cs') = f cs
(ior, cs'') = g cs'
in (iol >> ior, cs'')
instance Printer IOPrinter where
ptext txt = IOP (length txt) 0 (\cs -> (putStr txt, cs))
ws n = IOP n 0 (\cs -> (putStr (take n spaces), cs))
newLine = IOP 0 1 (\cs -> (putStrLn "", cs))
beginColour c = IOP 0 0 (\cs -> (setColour c, c : cs))
endColour = IOP 0 0 (\(_ : cs@(c : _)) -> (setColour c, cs))
width (IOP w _ _) = w
height (IOP _ h _) = h
-- | Sets the foreground colour.
setColour :: Colour -> IO ()
setColour Default = setSGR [Reset ]
setColour Black = setSGR [SetColor Foreground Dull A.Black ]
setColour Red = setSGR [SetColor Foreground Dull A.Red ]
setColour Green = setSGR [SetColor Foreground Dull A.Green ]
setColour Blue = setSGR [SetColor Foreground Dull A.Blue ]
setColour Yellow = setSGR [SetColor Foreground Dull A.Yellow ]
setColour Magenta = setSGR [SetColor Foreground Dull A.Magenta]
setColour Cyan = setSGR [SetColor Foreground Dull A.Cyan ]
setColour White = setSGR [SetColor Foreground Dull A.White ]
-- | Runs an 'IOPrinter'.
printToIO :: IOPrinter -> IO ()
printToIO (IOP _ _ f) = fst (f [Default])
-------------------------------------------------------------------------------
-- Utilities
-------------------------------------------------------------------------------
-- | An infinite supply of spaces.
spaces :: [Char]
spaces = ' ' : spaces