{-# OPTIONS -Wall #-} -------------------------------------------------------------------------------- -- | -- Module : ZMidi.Core.Internal.SimpleFormat -- Copyright : (c) Stephen Tetley 2010-2012 -- License : BSD3 -- -- Maintainer : Stephen Tetley -- Stability : unstable -- Portability : As per dependencies. -- -- Simple line-oriented formatting combinators. -- -------------------------------------------------------------------------------- module ZMidi.Core.Internal.SimpleFormat ( Doc , width , output , cat , sep , char , text , repeatChar , padl , padr , hex2 , hex4 , integral ) where import Data.Monoid import Data.Word import Numeric -- | Strings are represented as Hughes lists -- -- ShowS is a Hughes list representation specialized to Strings -- type H a = [a] -> [a] type HString = H Char -- | Make a HString of spaces. -- spaceH :: Int -> HString spaceH n = showString $ replicate n ' ' fromH :: H a -> [a] fromH = ($ []) -- | Docs represent a single line - they should not contain -- newlines. -- data Doc = Doc { -- | Width of the doc. width :: !Int, -- | Internal representation. doch :: HString } -- | Make a literal Doc from a String. -- doc :: String -> Doc doc s = Doc (length s) (showString s) -- | Unwrap a Doc making a String. -- output :: Doc -> String output = fromH . doch instance Monoid Doc where mempty = Doc 0 id Doc i1 f1 `mappend` Doc i2 f2 = Doc (i1+i2) (f1 . f2) infixr 6 `cat` -- | Concatenate - no space. -- cat :: Doc -> Doc -> Doc cat = mappend infixr 6 `sep` -- | Concatenate - with space. -- sep :: Doc -> Doc -> Doc sep (Doc i1 f1) (Doc i2 f2) = Doc (1+i1+i2) (f1 . (' ':) . f2) -- | Make a Doc from a Char. -- char :: Char -> Doc char c = Doc 1 (c:) -- | Make a Doc from a String. -- text :: String -> Doc text = doc -- | Repeat the Char /n/ times to make a Doc. -- repeatChar :: Int -> Char -> Doc repeatChar n c = Doc n (showString $ replicate n c) -- | Pad the left with space. -- padl :: Int -> Doc -> Doc padl i d@(Doc n f) | i > n = Doc i (spaceH (i-n) . f) | otherwise = d -- | Pad the right with space. -- padr :: Int -> Doc -> Doc padr i d@(Doc n f) | i > n = Doc i (f . spaceH (i-n)) | otherwise = d -- | Show as a two digit hex number. -- hex2 :: Word8 -> Doc hex2 n | n < 0x10 = Doc 2 (('0' :) . showHex n) | otherwise = Doc 2 (showHex n) -- | Show as a four digit hex number. -- hex4 :: Word16 -> Doc hex4 n | n < 0x10 = Doc 4 (('0':) . ('0':) . ('0':) . showHex n) | n < 0x100 = Doc 4 (('0':) . ('0':) . showHex n) | n < 0x1000 = Doc 4 (('0':) . showHex n) | otherwise = Doc 4 (showHex n) -- | Show an Integral value as a base 10 number. -- integral :: (Show a, Integral a) => a -> Doc integral = doc . show