hs-term-emulator-0.1.0.0: src/System/Terminal/Emulator/Attrs.hs
module System.Terminal.Emulator.Attrs where
import Control.Lens
import Data.Bits
import Data.Word (Word32)
import qualified System.Console.ANSI.Types as SGR
-- | Attrs:
--
-- 00000000 00000000 000000000000uuii
-- ^^ fg ^^ ^^ bg ^^ ^^^^^^^^^^^^^^^^
--
-- ii : ConsoleIntensity (00 = Normal, 01 = Bold, 10 = Faint)
-- uu : Underlining (00 = NoUnderline, 01 = SingleUnderline, 10 = DoubleUnderline)
type Attrs = Word32
blankAttrs :: Attrs
blankAttrs = 0
{-# INLINE blankAttrs #-}
type Cell = (Char, Attrs)
cellChar :: Lens' Cell Char
cellChar = lens fst (\(_, attrs) c -> (c, attrs))
{-# INLINE cellChar #-}
cellAttrs :: Lens' Cell Attrs
cellAttrs = lens snd (\(char, _) attrs -> (char, attrs))
{-# INLINE cellAttrs #-}
attrsFg :: Lens' Attrs (Maybe (SGR.ColorIntensity, SGR.Color))
attrsFg = lens getter setter
where
getter :: Attrs -> Maybe (SGR.ColorIntensity, SGR.Color)
getter attrs = intToColor (shiftR attrs 24 .&. 0x000000FF)
setter :: Attrs -> Maybe (SGR.ColorIntensity, SGR.Color) -> Attrs
setter attrs color = (attrs .&. 0x00FFFFFF) .|. shiftL (colorToInt color) 24
{-# INLINE getter #-}
{-# INLINE setter #-}
{-# INLINE attrsFg #-}
attrsBg :: Lens' Attrs (Maybe (SGR.ColorIntensity, SGR.Color))
attrsBg = lens getter setter
where
getter :: Attrs -> Maybe (SGR.ColorIntensity, SGR.Color)
getter attrs = intToColor (shiftR attrs 16 .&. 0x000000FF)
setter :: Attrs -> Maybe (SGR.ColorIntensity, SGR.Color) -> Attrs
setter attrs color = (attrs .&. 0xFF00FFFF) .|. shiftL (colorToInt color) 16
{-# INLINE getter #-}
{-# INLINE setter #-}
{-# INLINE attrsBg #-}
attrsIntensity :: Lens' Attrs SGR.ConsoleIntensity
attrsIntensity = lens getter setter
where
getter :: Attrs -> SGR.ConsoleIntensity
getter attrs
| attrs .&. 0x00000003 == 0 = SGR.NormalIntensity
| attrs .&. 0x00000003 == 1 = SGR.BoldIntensity
| otherwise = SGR.FaintIntensity
setter :: Attrs -> SGR.ConsoleIntensity -> Attrs
setter attrs intensity = ((attrs .&. 0xFFFFFFFC) .|. consoleIntensityToInt intensity)
{-# INLINE getter #-}
{-# INLINE setter #-}
{-# INLINE attrsIntensity #-}
attrsUnderline :: Lens' Attrs SGR.Underlining
attrsUnderline = lens getter setter
where
getter :: Attrs -> SGR.Underlining
getter attrs
| (shiftR attrs 2) .&. 0x00000003 == 0 = SGR.NoUnderline
| (shiftR attrs 2) .&. 0x00000003 == 1 = SGR.SingleUnderline
| otherwise = SGR.DoubleUnderline
setter :: Attrs -> SGR.Underlining -> Attrs
setter attrs underlining = ((attrs .&. 0xFFFFFFF3) .|. shiftL (underliningToInt underlining) 2)
{-# INLINE getter #-}
{-# INLINE setter #-}
{-# INLINE attrsUnderline #-}
intToColor :: Word32 -> Maybe (SGR.ColorIntensity, SGR.Color)
intToColor 0 = Nothing
intToColor 1 = Just (SGR.Dull, SGR.Black)
intToColor 2 = Just (SGR.Dull, SGR.Red)
intToColor 3 = Just (SGR.Dull, SGR.Green)
intToColor 4 = Just (SGR.Dull, SGR.Yellow)
intToColor 5 = Just (SGR.Dull, SGR.Blue)
intToColor 6 = Just (SGR.Dull, SGR.Magenta)
intToColor 7 = Just (SGR.Dull, SGR.Cyan)
intToColor 8 = Just (SGR.Dull, SGR.White)
intToColor 9 = Just (SGR.Vivid, SGR.Black)
intToColor 10 = Just (SGR.Vivid, SGR.Red)
intToColor 11 = Just (SGR.Vivid, SGR.Green)
intToColor 12 = Just (SGR.Vivid, SGR.Yellow)
intToColor 13 = Just (SGR.Vivid, SGR.Blue)
intToColor 14 = Just (SGR.Vivid, SGR.Magenta)
intToColor 15 = Just (SGR.Vivid, SGR.Cyan)
intToColor 16 = Just (SGR.Vivid, SGR.White)
intToColor i = error $ "intToColor: invalid int: " <> show i
{-# INLINE intToColor #-}
colorToInt :: Maybe (SGR.ColorIntensity, SGR.Color) -> Word32
colorToInt Nothing = 0
colorToInt (Just (SGR.Dull, SGR.Black)) = 1
colorToInt (Just (SGR.Dull, SGR.Red)) = 2
colorToInt (Just (SGR.Dull, SGR.Green)) = 3
colorToInt (Just (SGR.Dull, SGR.Yellow)) = 4
colorToInt (Just (SGR.Dull, SGR.Blue)) = 5
colorToInt (Just (SGR.Dull, SGR.Magenta)) = 6
colorToInt (Just (SGR.Dull, SGR.Cyan)) = 7
colorToInt (Just (SGR.Dull, SGR.White)) = 8
colorToInt (Just (SGR.Vivid, SGR.Black)) = 9
colorToInt (Just (SGR.Vivid, SGR.Red)) = 10
colorToInt (Just (SGR.Vivid, SGR.Green)) = 11
colorToInt (Just (SGR.Vivid, SGR.Yellow)) = 12
colorToInt (Just (SGR.Vivid, SGR.Blue)) = 13
colorToInt (Just (SGR.Vivid, SGR.Magenta)) = 14
colorToInt (Just (SGR.Vivid, SGR.Cyan)) = 15
colorToInt (Just (SGR.Vivid, SGR.White)) = 16
{-# INLINE colorToInt #-}
consoleIntensityToInt :: SGR.ConsoleIntensity -> Word32
consoleIntensityToInt SGR.NormalIntensity = 0
consoleIntensityToInt SGR.BoldIntensity = 1
consoleIntensityToInt SGR.FaintIntensity = 2
{-# INLINE consoleIntensityToInt #-}
underliningToInt :: SGR.Underlining -> Word32
underliningToInt SGR.NoUnderline = 0
underliningToInt SGR.SingleUnderline = 1
underliningToInt SGR.DoubleUnderline = 2
{-# INLINE underliningToInt #-}