terminal-0.2.0.0: src/System/Terminal/MonadPrinter.hs
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleContexts #-}
module System.Terminal.MonadPrinter where
import Data.Text as T
import Prelude hiding (putChar)
-- | This class describes an environment that Unicode text can be printed to.
-- This might either be file or a terminal.
--
-- * Instances shall implement the concept of lines and line width.
-- * Instances shall implement the concept of a carriage that can be
-- set to the beginning of the next line.
-- * It is assumed that the carriage automatically moves to the beginning
-- of the next line if the end of the current line is reached.
-- * Instances shall be Unicode aware or must at least be able to print
-- a replacement character.
-- * Implementations must be aware of infinite lazy `Prelude.String`s and
-- long `Data.Text.Text`s. `String`s should be printed character wise as
-- evaluating them might trigger exceptions at any point. Long text should
-- be printed chunk wise in order to stay interruptible.
-- * Implementations must not use an unbounded output buffer. Print operations
-- shall block and be interruptible when the output buffer is full.
-- * Instances shall not pass control characters in text to the printer (not even line break).
-- Control characters shall be replaced with �. Text formatting shall be done
-- with the designated classes extending `MonadMarkupPrinter`.
-- Allowing control sequences would cause a dependency on certain terminal
-- types, but also pose an underrated security risk as modern terminals are
-- highly programmable and should not be fed with untrusted input.
class Monad m => MonadPrinter m where
-- | Move the carriage to the beginning of the next line.
putLn :: m ()
-- | Print a single character.
putChar :: Char -> m ()
-- | Print a `String`.
putString :: String -> m ()
putString = mapM_ putChar
-- | Print a `String` and an additional newline.
putStringLn :: String -> m ()
putStringLn s = putString s >> putLn
-- | Print a `Text`.
putText :: Text -> m ()
putText = putString . T.unpack
-- | Print a `Text` and an additional newline.
putTextLn :: Text -> m ()
putTextLn = putStringLn . T.unpack
-- | Flush the output buffer and make the all previous output actually
-- visible after a reasonably short amount of time.
--
-- * The operation may return before the buffer has actually been flushed.
flush :: m ()
flush = pure ()
-- | Get the current line width.
--
-- * The operation may return the last known line width and may not be
-- completely precise when I/O is asynchronous.
-- * This operations shall not block too long and rather be called more
-- often in order to adapt to changes in line width.
getLineWidth :: m Int
{-# MINIMAL putLn, putChar, putText, getLineWidth #-}
-- | This class introduces abstract constructors for text markup.
class MonadPrinter m => MonadMarkupPrinter m where
-- | This associated type represents all possible attributes that are
-- available in the current environment.
--
-- When writing polymorphic code against these monadic interfaces
-- the concrete instantiation of this type is usually unknown and class
-- instances are generally advised to not expose value constructors for
-- this type.
--
-- Instead, subclasses like `MonadFormattingPrinter` and `MonadColorPrinter`
-- offer abstract value constructors like `bold`, `underlined`, `inverted`
-- which are then given meaning by the concrete class instance.
data Attribute m
setAttribute :: Attribute m -> m ()
setAttribute _ = pure ()
-- | Reset an attribute so that it does no longer affect subsequent output.
--
-- * Binary attributes like `bold` or `underlined` shall just be reset to their opposite.
--
-- * For non-binary attributes like colors all of their possible values shall be treated
-- as equal, so that
--
-- @
-- `setAttribute` (`foreground` $ `bright` `blue`) >> `resetAttribute` (`foreground` `red`)
-- @
--
-- results in the foreground color attribute reset afterwards whereas after
--
-- @
-- `setAttribute` (`foreground` $ `bright` `blue`) >> `resetAttribute` (`background` `red`)
-- @
--
-- the foreground color is still set as `bright` `blue`.
--
resetAttribute :: Attribute m -> m ()
-- | Reset all attributes to their default.
resetAttributes :: m ()
-- | Shall determine wheter two attribute values would override each other
-- or can be applied independently.
--
-- * Shall obey the laws of equivalence.
resetsAttribute :: Attribute m -> Attribute m -> Bool
class MonadMarkupPrinter m => MonadFormattingPrinter m where
-- | This attribute makes text appear __bold__.
bold :: Attribute m
-- | This attribute makes text appear /italic/.
italic :: Attribute m
-- | This attribute makes text appear underlined.
underlined :: Attribute m
-- | This attribute swaps foreground and background (color).
--
-- * This operation is idempotent: Applying the attribute a second time
-- won't swap it back. Use `resetAttribute` instead.
inverted :: Attribute m
-- | This class offers abstract value constructors for
-- foreground and background coloring.
class MonadMarkupPrinter m => MonadColorPrinter m where
data Color m
black :: Color m
red :: Color m
green :: Color m
yellow :: Color m
blue :: Color m
magenta :: Color m
cyan :: Color m
white :: Color m
bright :: Color m -> Color m
-- | This attribute sets the __foreground__ color (the text color).
foreground :: Color m -> Attribute m
-- | This attribute sets the __background__ color.
background :: Color m -> Attribute m