symantic-document-0.1.2.20180831: Language/Symantic/Document/Term.hs
module Language.Symantic.Document.Term
( module Language.Symantic.Document.Sym
, module Language.Symantic.Document.Term
) where
import Control.Applicative (Applicative(..))
import Data.Bool
import Data.Function (($), (.), id)
import Data.Maybe (Maybe(..))
import Data.Monoid (Monoid(..))
import Data.Ord (Ord(..))
import Data.Semigroup (Semigroup(..))
import Data.String (IsString(..))
import GHC.Exts (IsList(..))
import Prelude (pred, fromIntegral, Num(..))
import System.Console.ANSI
import qualified Data.List as List
import qualified Data.Text.Lazy as TL
import qualified Data.Text.Lazy.Builder as TLB
import Language.Symantic.Document.Sym
-- * Type 'Reader'
data Reader
= Reader
{ reader_indent :: !Indent -- ^ Current indentation level, used by 'newline'.
, reader_newline :: Term -- ^ How to display 'newline'.
, reader_sgr :: ![SGR] -- ^ Active ANSI codes.
, reader_breakable :: !(Maybe Column) -- ^ 'Column' after which to break, or 'Nothing'
, reader_colorable :: !Bool -- ^ Whether colors are activated or not.
, reader_decorable :: !Bool -- ^ Whether decorations are activated or not.
}
-- | Default 'Reader'.
defReader :: Reader
defReader = Reader
{ reader_indent = 0
, reader_newline = newlineWithIndent
, reader_sgr = []
, reader_breakable = Nothing
, reader_colorable = True
, reader_decorable = True
}
-- * Type 'State'
type State = Column
-- | Default 'State'.
defState :: State
defState = 0
-- * Type 'Term'
newtype Term
= Term
{ unTerm :: Reader ->
State ->
(State -> TLB.Builder -> TLB.Builder) -> -- normal continuation
(State -> TLB.Builder -> TLB.Builder) -> -- should-break continuation
TLB.Builder }
-- | Render a 'Term' into a 'TL.Text'.
textTerm :: Term -> TL.Text
textTerm = TLB.toLazyText . runTerm
-- | Render a 'Term' into a 'TLB.Builder'.
runTerm :: Term -> TLB.Builder
runTerm (Term t) = t defReader defState oko oko
where oko _st = id
instance IsList Term where
type Item Term = Term
fromList = mconcat
toList = pure
instance Semigroup Term where
x <> y = Term $ \ro st ok ko ->
unTerm x ro st
(\sx tx -> unTerm y ro sx
(\sy ty -> ok sy (tx<>ty))
(\sy ty -> ko sy (tx<>ty)))
(\sx tx -> unTerm y ro sx
(\sy ty -> ko sy (tx<>ty))
(\sy ty -> ko sy (tx<>ty)))
instance Monoid Term where
mempty = empty
mappend = (<>)
instance IsString Term where
fromString = string
writeH :: Column -> TLB.Builder -> Term
writeH len t =
Term $ \ro st ok ko ->
let newCol = st + len in
(case reader_breakable ro of
Just breakCol | breakCol < newCol -> ko
_ -> ok)
newCol t
instance Textable Term where
empty = Term $ \_ro st ok _ko -> ok st mempty
charH t = writeH (Nat 1) (TLB.singleton t)
stringH t = writeH (length t) (fromString t)
textH t = writeH (length t) (TLB.fromText t)
ltextH t = writeH (length t) (TLB.fromLazyText t)
replicate cnt t | cnt <= 0 = empty
| otherwise = t <> replicate (pred cnt) t
newline = Term $ \ro -> unTerm (reader_newline ro) ro
instance Indentable Term where
align t = Term $ \ro st -> unTerm t ro{reader_indent=st} st
withNewline nl t = Term $ \ro -> unTerm t ro{reader_newline=nl}
withIndent ind t = Term $ \ro -> unTerm t ro{reader_indent=ind}
incrIndent ind t = Term $ \ro -> unTerm t ro{reader_indent=reader_indent ro + ind}
column f = Term $ \ro st -> unTerm (f st) ro st
indent f = Term $ \ro -> unTerm (f (reader_indent ro)) ro
newlineWithoutIndent = Term $ \_ro _st ok _ko ->
ok 0 $ TLB.singleton '\n'
newlineWithIndent = Term $ \ro _st ok _ko ->
ok (reader_indent ro) $
TLB.singleton '\n' <>
fromString (List.replicate (fromIntegral $ reader_indent ro) ' ')
instance Breakable Term where
breakable f = Term $ \ro -> unTerm (f (reader_breakable ro)) ro
withBreakable b t = Term $ \ro -> unTerm t ro{reader_breakable=b}
ifBreak y x = Term $ \ro st ok ko ->
unTerm x ro st ok $
case reader_breakable ro of
Nothing -> ko
Just{} -> (\_sx _tx -> unTerm y ro st ok ko)
breakpoint onNoBreak onBreak t = Term $ \ro st ok ko ->
unTerm (onNoBreak <> t) ro st ok $
case reader_breakable ro of
Nothing -> ko
Just{} -> (\_sp _tp -> unTerm (onBreak <> t) ro st ok ko)
writeSGR :: (Reader -> Bool) -> SGR -> Term -> Term
writeSGR isOn s (Term t) =
Term $ \ro ->
if isOn ro
then unTerm (o <> m <> c) ro
else t ro
where
o = Term $ \_ro st ok _ko -> ok st $ fromString $ setSGRCode [s]
m = Term $ \ro -> t ro{reader_sgr=s:reader_sgr ro}
c = Term $ \ro st ok _ko -> ok st $ fromString $ setSGRCode $ Reset:List.reverse (reader_sgr ro)
instance Colorable Term where
colorable f = Term $ \ro -> unTerm (f (reader_colorable ro)) ro
withColorable b t = Term $ \ro -> unTerm t ro{reader_colorable=b}
reverse = writeSGR reader_colorable $ SetSwapForegroundBackground True
black = writeSGR reader_colorable $ SetColor Foreground Dull Black
red = writeSGR reader_colorable $ SetColor Foreground Dull Red
green = writeSGR reader_colorable $ SetColor Foreground Dull Green
yellow = writeSGR reader_colorable $ SetColor Foreground Dull Yellow
blue = writeSGR reader_colorable $ SetColor Foreground Dull Blue
magenta = writeSGR reader_colorable $ SetColor Foreground Dull Magenta
cyan = writeSGR reader_colorable $ SetColor Foreground Dull Cyan
white = writeSGR reader_colorable $ SetColor Foreground Dull White
blacker = writeSGR reader_colorable $ SetColor Foreground Vivid Black
redder = writeSGR reader_colorable $ SetColor Foreground Vivid Red
greener = writeSGR reader_colorable $ SetColor Foreground Vivid Green
yellower = writeSGR reader_colorable $ SetColor Foreground Vivid Yellow
bluer = writeSGR reader_colorable $ SetColor Foreground Vivid Blue
magentaer = writeSGR reader_colorable $ SetColor Foreground Vivid Magenta
cyaner = writeSGR reader_colorable $ SetColor Foreground Vivid Cyan
whiter = writeSGR reader_colorable $ SetColor Foreground Vivid White
onBlack = writeSGR reader_colorable $ SetColor Background Dull Black
onRed = writeSGR reader_colorable $ SetColor Background Dull Red
onGreen = writeSGR reader_colorable $ SetColor Background Dull Green
onYellow = writeSGR reader_colorable $ SetColor Background Dull Yellow
onBlue = writeSGR reader_colorable $ SetColor Background Dull Blue
onMagenta = writeSGR reader_colorable $ SetColor Background Dull Magenta
onCyan = writeSGR reader_colorable $ SetColor Background Dull Cyan
onWhite = writeSGR reader_colorable $ SetColor Background Dull White
onBlacker = writeSGR reader_colorable $ SetColor Background Vivid Black
onRedder = writeSGR reader_colorable $ SetColor Background Vivid Red
onGreener = writeSGR reader_colorable $ SetColor Background Vivid Green
onYellower = writeSGR reader_colorable $ SetColor Background Vivid Yellow
onBluer = writeSGR reader_colorable $ SetColor Background Vivid Blue
onMagentaer = writeSGR reader_colorable $ SetColor Background Vivid Magenta
onCyaner = writeSGR reader_colorable $ SetColor Background Vivid Cyan
onWhiter = writeSGR reader_colorable $ SetColor Background Vivid White
instance Decorable Term where
decorable f = Term $ \ro -> unTerm (f (reader_decorable ro)) ro
withDecorable b t = Term $ \ro -> unTerm t ro{reader_decorable=b}
bold = writeSGR reader_decorable $ SetConsoleIntensity BoldIntensity
underline = writeSGR reader_decorable $ SetUnderlining SingleUnderline
italic = writeSGR reader_decorable $ SetItalicized True