-- | -- Module : Basement.Terminal.ANSI -- License : BSD-style -- Maintainer : Vincent Hanquez -- -- ANSI Terminal escape for cursor and attributes manipulations -- -- On Unix system, it should be supported by most terminal emulators. -- -- On Windows system, all escape sequences are empty for maximum -- compatibility purpose, and easy implementation. newer version -- of Windows 10 supports ANSI escape now, but we'll need -- some kind of detection. -- {-# LANGUAGE CPP #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE OverloadedStrings #-} module Basement.Terminal.ANSI ( -- * Types Escape , Displacement , ColorComponent , GrayComponent , RGBComponent -- * Simple ANSI escape factory functions , cursorUp , cursorDown , cursorForward , cursorBack , cursorNextLine , cursorPrevLine , cursorHorizontalAbsolute , cursorPosition , eraseScreenFromCursor , eraseScreenToCursor , eraseScreenAll , eraseLineFromCursor , eraseLineToCursor , eraseLineAll , scrollUp , scrollDown , sgrReset , sgrForeground , sgrBackground , sgrForegroundGray24 , sgrBackgroundGray24 , sgrForegroundColor216 , sgrBackgroundColor216 ) where import Basement.String import Basement.Bounded import Basement.Imports import Basement.Numerical.Multiplicative import Basement.Numerical.Additive #ifndef mingw32_HOST_OS #define SUPPORT_ANSI_ESCAPE #endif type Escape = String type Displacement = Word64 -- | Simple color component on 8 color terminal (maximum compatibility) type ColorComponent = Zn64 8 -- | Gray color compent on 256colors terminals type GrayComponent = Zn64 24 -- | Color compent on 256colors terminals type RGBComponent = Zn64 6 cursorUp, cursorDown, cursorForward, cursorBack , cursorNextLine, cursorPrevLine , cursorHorizontalAbsolute :: Displacement -> Escape cursorUp n = csi1 n "A" cursorDown n = csi1 n "B" cursorForward n = csi1 n "C" cursorBack n = csi1 n "D" cursorNextLine n = csi1 n "E" cursorPrevLine n = csi1 n "F" cursorHorizontalAbsolute n = csi1 n "G" cursorPosition :: Displacement -> Displacement -> Escape cursorPosition row col = csi2 row col "H" eraseScreenFromCursor , eraseScreenToCursor , eraseScreenAll , eraseLineFromCursor , eraseLineToCursor , eraseLineAll :: Escape eraseScreenFromCursor = csi1 0 "J" eraseScreenToCursor = csi1 1 "J" eraseScreenAll = csi1 2 "J" eraseLineFromCursor = csi1 0 "K" eraseLineToCursor = csi1 1 "K" eraseLineAll = csi1 2 "K" scrollUp, scrollDown :: Displacement -> Escape scrollUp n = csi1 n "S" scrollDown n = csi1 n "T" -- | All attribute off sgrReset :: Escape sgrReset = csi1 0 "m" -- | 8 Colors + Bold attribute for foreground sgrForeground :: ColorComponent -> Bool -> Escape sgrForeground n bold | bold = csi2 (30+unZn64 n) 1 "m" | otherwise = csi1 (30+unZn64 n) "m" -- | 8 Colors + Bold attribute for background sgrBackground :: ColorComponent -> Bool -> Escape sgrBackground n bold | bold = csi2 (40+unZn64 n) 1 "m" | otherwise = csi1 (40+unZn64 n) "m" -- 256 colors mode sgrForegroundGray24, sgrBackgroundGray24 :: GrayComponent -> Escape sgrForegroundGray24 v = csi3 38 5 (0xE8 + unZn64 v) "m" sgrBackgroundGray24 v = csi3 48 5 (0xE8 + unZn64 v) "m" sgrForegroundColor216 :: RGBComponent -- ^ Red component -> RGBComponent -- ^ Green component -> RGBComponent -- ^ Blue component -> Escape sgrForegroundColor216 r g b = csi3 38 5 (0x10 + 36 * unZn64 r + 6 * unZn64 g + unZn64 b) "m" sgrBackgroundColor216 :: RGBComponent -- ^ Red component -> RGBComponent -- ^ Green component -> RGBComponent -- ^ Blue component -> Escape sgrBackgroundColor216 r g b = csi3 48 5 (0x10 + 36 * unZn64 r + 6 * unZn64 g + unZn64 b) "m" #ifdef SUPPORT_ANSI_ESCAPE csi0 :: String -> String csi0 suffix = mconcat ["\ESC[", suffix] csi1 :: Displacement -> String -> String csi1 p1 suffix = mconcat ["\ESC[", pshow p1, suffix] csi2 :: Displacement -> Displacement -> String -> String csi2 p1 p2 suffix = mconcat ["\ESC[", pshow p1, ";", pshow p2, suffix] csi3 :: Displacement -> Displacement -> Displacement -> String -> String csi3 p1 p2 p3 suffix = mconcat ["\ESC[", pshow p1, ";", pshow p2, ";", pshow p3, suffix] pshow = show #else csi0 :: String -> String csi0 _ = "" csi1 :: Displacement -> String -> String csi1 _ _ = "" csi2 :: Displacement -> Displacement -> String -> String csi2 _ _ _ = "" csi3 :: Displacement -> Displacement -> Displacement -> String -> String csi3 _ _ _ _ = "" #endif