ansi-terminal (empty) → 0.1
raw patch · 10 files changed
+954/−0 lines, 10 filesdep +Win32dep +basedep +unixsetup-changed
Dependencies added: Win32, base, unix
Files
- LICENSE +22/−0
- Setup.lhs +4/−0
- System/Console/ANSI.hs +20/−0
- System/Console/ANSI/Common.hs +31/−0
- System/Console/ANSI/Example.hs +250/−0
- System/Console/ANSI/Unix.hs +78/−0
- System/Console/ANSI/Windows.hs +6/−0
- System/Console/ANSI/Windows/Emulator.hs +195/−0
- System/Console/ANSI/Windows/Foreign.hs +266/−0
- ansi-terminal.cabal +82/−0
+ LICENSE view
@@ -0,0 +1,22 @@+Copyright (c) 2008, Maximilian Bolingbroke+All rights reserved.++Redistribution and use in source and binary forms, with or without modification, are permitted+provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright notice, this list of+ conditions and the following disclaimer.+ * Redistributions in binary form must reproduce the above copyright notice, this list of+ conditions and the following disclaimer in the documentation and/or other materials+ provided with the distribution.+ * Neither the name of Maximilian Bolingbroke nor the names of other contributors may be used to+ endorse or promote products derived from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER+IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT+OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.lhs view
@@ -0,0 +1,4 @@+#! /usr/bin/env runhaskell++> import Distribution.Simple+> main = defaultMain
+ System/Console/ANSI.hs view
@@ -0,0 +1,20 @@+#if defined(WINDOWS)+module System.Console.ANSI (+ module System.Console.ANSI.Windows+ ) where++import System.Console.ANSI.Windows++#elif defined(UNIX)++module System.Console.ANSI (+ module System.Console.ANSI.Unix+ ) where++import System.Console.ANSI.Unix++#else++#error Unsupported platform for the ansi-terminal package++#endif
+ System/Console/ANSI/Common.hs view
@@ -0,0 +1,31 @@+module System.Console.ANSI.Common where++data ANSIColor = Black+ | Red+ | Green+ | Yellow+ | Blue+ | Magenta+ | Cyan+ | White+ deriving (Bounded, Enum, Show)++data ANSISGR = Reset+ | BoldIntensity+ | FaintIntensity -- ^ Not widely supported: sometimes treated as conceal+ | NormalIntensity+ | Italic -- ^ Not widely supported: sometimes treated as swapping foreground and background+ | SingleUnderline+ | DoubleUnderline -- ^ Not widely supported+ | NoUnderline+ | SlowBlink+ | RapidBlink+ | NoBlink+ | Conceal -- ^ Not widely supported+ | Reveal+ | SwapForegroundBackground+ | DontSwapForegroundBackground+ | ForegroundNormalIntensity ANSIColor+ | ForegroundHighIntensity ANSIColor+ | BackgroundNormalIntensity ANSIColor+ | BackgroundHighIntensity ANSIColor
+ System/Console/ANSI/Example.hs view
@@ -0,0 +1,250 @@+module Main (+ main+ ) where++import System.Console.ANSI++import System.IO++import Control.Concurrent+import Control.Monad+++examples :: [IO ()]+examples = [ cursorMovementExample+ , lineChangeExample+ , setPositionExample+ , clearExample+ , scrollExample+ , sgrExample+ , cursorVisibilityExample+ ]++main :: IO ()+main = mapM_ (\example -> resetScreen >> example) examples++resetScreen :: IO ()+resetScreen = clearScreen >> setSGR Reset >> setPosition 0 0++pause :: IO ()+pause = do+ hFlush stdout+ -- 1 second pause+ threadDelay 1000000++cursorMovementExample :: IO ()+cursorMovementExample = do+ putStrLn "Line One"+ putStr "Line Two"+ pause+ -- Line One+ -- Line Two+ + cursorUp 1+ putStr " - Extras"+ pause+ -- Line One - Extras+ -- Line Two+ + cursorBackward 2+ putStr "zz"+ pause+ -- Line One - Extrzz+ -- Line Two+ + cursorForward 2+ putStr "- And More"+ pause+ -- Line One - Extrzz - And More+ -- Line Two+ + cursorDown 1+ putStr "Disconnected"+ pause+ -- Line One - Extrzz - And More+ -- Line Two Disconnected++lineChangeExample :: IO ()+lineChangeExample = do+ putStrLn "Line One"+ putStr "Line Two"+ pause+ -- Line One+ -- Line Two+ + previousLine 1+ putStr "New Line One"+ pause+ -- New Line One+ -- Line Two+ + nextLine 1+ putStr "New Line Two"+ pause+ -- New Line One+ -- New Line Two++setPositionExample :: IO ()+setPositionExample = do+ putStrLn "Line One"+ putStrLn "Line Two"+ pause+ -- Line One+ -- Line Two+ + setPosition 0 5+ putStr "Foo"+ pause+ -- Line Foo+ -- Line Two+ + setPosition 1 5+ putStr "Bar"+ pause+ -- Line Foo+ -- Line Bar+ + setColumn 1+ putStr "oaf"+ pause+ -- Line Foo+ -- Loaf Bar++clearExample :: IO ()+clearExample = do+ putStrLn "Line One"+ putStrLn "Line Two"+ pause+ -- Line One+ -- Line Two+ + setPosition 0 4+ clearFromCursorToScreenEnd+ pause+ -- Line+ + + resetScreen+ putStrLn "Line One"+ putStrLn "Line Two"+ pause+ -- Line One+ -- Line Two+ + setPosition 1 4+ clearFromCursorToScreenBeginning+ pause+ --+ -- Two+ + + resetScreen+ putStrLn "Line One"+ putStrLn "Line Two"+ pause+ -- Line One+ -- Line Two+ + setPosition 0 4+ clearFromCursorToLineEnd+ pause+ -- Line+ -- Line Two+ + setPosition 1 4+ clearFromCursorToLineBeginning+ pause+ -- Line+ -- Two+ + clearLine+ pause+ -- Line+ + clearScreen+ pause+ --++scrollExample :: IO ()+scrollExample = do+ putStrLn "Line One"+ putStrLn "Line Two"+ putStrLn "Line Three"+ pause+ -- Line One+ -- Line Two+ -- Line Three+ + scrollPageDown 2+ pause+ --+ --+ -- Line One+ -- Line Two+ -- Line Three+ + scrollPageUp 3+ pause+ -- Line Two+ -- Line Three++sgrExample :: IO ()+sgrExample = do+ let colors = enumFromTo minBound maxBound :: [ANSIColor]+ forM_ [ForegroundNormalIntensity, ForegroundHighIntensity, BackgroundNormalIntensity, BackgroundHighIntensity] $ \color_way -> do+ resetScreen+ forM_ colors $ \color -> do+ setSGR Reset+ setSGR (color_way color)+ putStrLn (show color)+ pause+ -- All the colors, 4 times in sequence+ + let named_styles = [ (BoldIntensity, "Bold")+ , (FaintIntensity, "Faint")+ , (NormalIntensity, "Normal")+ , (Italic, "Italic")+ , (SingleUnderline, "Single Underline")+ , (DoubleUnderline, "Double Underline")+ , (NoUnderline, "No Underline")+ , (SlowBlink, "Slow Blink")+ , (RapidBlink, "Rapid Blink")+ , (NoBlink, "No Blink")+ , (Conceal, "Conceal")+ , (Reveal, "Reveal")+ ]+ forM_ named_styles $ \(style, name) -> do+ resetScreen+ setSGR style+ putStrLn name+ pause+ -- Text describing a style displayed in that style in sequence+ + setSGR (ForegroundHighIntensity Red)+ setSGR (BackgroundHighIntensity Blue)+ + clearScreen >> setPosition 0 0+ setSGR DontSwapForegroundBackground+ putStr "Red-On-Blue"+ pause+ -- Red-On-Blue+ + clearScreen >> setPosition 0 0+ setSGR SwapForegroundBackground+ putStr "Blue-On-Red"+ pause+ -- Blue-On-Red++cursorVisibilityExample :: IO ()+cursorVisibilityExample = do+ putStr "Cursor Demo"+ pause+ -- Cursor Demo|+ + hideCursor+ pause+ -- Cursor Demo+ + showCursor+ pause+ -- Cursor Demo|
+ System/Console/ANSI/Unix.hs view
@@ -0,0 +1,78 @@+module System.Console.ANSI.Unix (+#include "Exports-Include.hs"+ ) where++import System.Console.ANSI.Common++import Data.List+++#include "Common-Include.hs"+++-- | The reference I used for the escape characters in this module was http://en.wikipedia.org/wiki/ANSI_escape_sequences+csi :: [Int] -> String -> IO ()+csi args code = putStr $ "\ESC[" ++ concat (intersperse ";" (map show args)) ++ code+++cursorUp n = csi [n] "A"+cursorDown n = csi [n] "B"+cursorForward n = csi [n] "C"+cursorBackward n = csi [n] "D"++nextLine n = csi [n] "E"+previousLine n = csi [n] "F"++setColumn n = csi [n + 1] "G"++setPosition n m = csi [n + 1, m + 1] "H"++clearFromCursorToScreenEnd = csi [0] "J"+clearFromCursorToScreenBeginning = csi [1] "J"+clearScreen = csi [2] "J"++clearFromCursorToLineEnd = csi [0] "K"+clearFromCursorToLineBeginning = csi [1] "K"+clearLine = csi [2] "K"++scrollPageUp n = csi [n] "S"+scrollPageDown n = csi [n] "T"++setSGR sgr = csi [ansiSGRToCode sgr] "m"++hideCursor = csi [] "?25l"+showCursor = csi [] "?25h"+++ansiColorToCode :: ANSIColor -> Int+ansiColorToCode color = case color of+ Black -> 0+ Red -> 1+ Green -> 2+ Yellow -> 3+ Blue -> 4+ Magenta -> 5+ Cyan -> 6+ White -> 7++ansiSGRToCode :: ANSISGR -> Int+ansiSGRToCode sgr = case sgr of+ Reset -> 0+ BoldIntensity -> 1+ FaintIntensity -> 2+ NormalIntensity -> 22+ Italic -> 3+ SingleUnderline -> 4+ DoubleUnderline -> 21+ NoUnderline -> 24+ SlowBlink -> 5+ RapidBlink -> 6+ NoBlink -> 25+ Conceal -> 8+ Reveal -> 28+ SwapForegroundBackground -> 7+ DontSwapForegroundBackground -> 27+ ForegroundNormalIntensity color -> 30 + ansiColorToCode color+ ForegroundHighIntensity color -> 90 + ansiColorToCode color+ BackgroundNormalIntensity color -> 40 + ansiColorToCode color+ BackgroundHighIntensity color -> 100 + ansiColorToCode color
+ System/Console/ANSI/Windows.hs view
@@ -0,0 +1,6 @@+module System.Console.ANSI.Windows (+#include "Exports-Include.hs"+ ) where++import System.Console.ANSI.Common+import System.Console.ANSI.Windows.Emulator
+ System/Console/ANSI/Windows/Emulator.hs view
@@ -0,0 +1,195 @@+module System.Console.ANSI.Windows.Emulator where++import System.Console.ANSI.Common+import System.Console.ANSI.Windows.Foreign++import Data.Bits+++#include "Common-Include.hs"+++screenRectangle :: IO SMALL_RECT+screenRectangle = do+ handle <- getStdHandle sTD_OUTPUT_HANDLE+ fmap csbi_window $ getConsoleScreenBufferInfo handle+++adjustCursorPosition :: (SHORT -> SHORT -> SHORT) -> (SHORT -> SHORT -> SHORT) -> IO ()+adjustCursorPosition change_x change_y = do+ handle <- getStdHandle sTD_OUTPUT_HANDLE+ screen_buffer_info <- getConsoleScreenBufferInfo handle+ let window = csbi_window screen_buffer_info+ (COORD x y) = csbi_cursor_position screen_buffer_info+ cursor_pos' = COORD (change_x (rect_left window) x) (change_y (rect_top window) y)+ setConsoleCursorPosition handle cursor_pos'++cursorUp n = adjustCursorPosition (\_ x -> x) (\_ y -> y - fromIntegral n)+cursorDown n = adjustCursorPosition (\_ x -> x) (\_ y -> y + fromIntegral n)+cursorForward n = adjustCursorPosition (\_ x -> x + fromIntegral n) (\_ y -> y)+cursorBackward n = adjustCursorPosition (\_ x -> x - fromIntegral n) (\_ y -> y)+++adjustLine :: (SHORT -> SHORT -> SHORT) -> IO ()+adjustLine change_y = do+ adjustCursorPosition (\window_left _ -> window_left) change_y++nextLine n = adjustLine (\_ y -> y + fromIntegral n)+previousLine n = adjustLine (\_ y -> y - fromIntegral n)+++setColumn x = adjustCursorPosition (\window_left _ -> window_left + fromIntegral x) (\_ y -> y)++setPosition y x = adjustCursorPosition (\window_left _ -> window_left + fromIntegral x) (\window_top _ -> window_top + fromIntegral y)+++clearChar :: WCHAR+clearChar = charToWCHAR ' '++clearAttribute :: WORD+clearAttribute = 0++clearScreenFraction :: (SMALL_RECT -> COORD -> (DWORD, COORD)) -> IO ()+clearScreenFraction fraction_finder = do+ handle <- getStdHandle sTD_OUTPUT_HANDLE+ screen_buffer_info <- getConsoleScreenBufferInfo handle+ + let window = csbi_window screen_buffer_info+ cursor_pos = csbi_cursor_position screen_buffer_info+ (fill_length, fill_cursor_pos) = fraction_finder window cursor_pos+ + fillConsoleOutputCharacter handle clearChar fill_length fill_cursor_pos+ fillConsoleOutputAttribute handle clearAttribute fill_length fill_cursor_pos+ return ()++clearFromCursorToScreenEnd = clearScreenFraction go+ where+ go window cursor_pos = (fromIntegral fill_length, cursor_pos)+ where+ size_x = rect_width window+ size_y = rect_bottom window - coord_y cursor_pos+ line_remainder = size_x - coord_x cursor_pos+ fill_length = size_x * size_y + line_remainder++clearFromCursorToScreenBeginning = clearScreenFraction go+ where+ go window cursor_pos = (fromIntegral fill_length, rect_top_left window)+ where+ size_x = rect_width window+ size_y = coord_y cursor_pos - rect_top window+ line_remainder = coord_x cursor_pos+ fill_length = size_x * size_y + line_remainder++clearScreen = clearScreenFraction go+ where+ go window _ = (fromIntegral fill_length, rect_top_left window)+ where+ size_x = rect_width window+ size_y = rect_height window+ fill_length = size_x * size_y++clearFromCursorToLineEnd = clearScreenFraction go+ where+ go window cursor_pos = (fromIntegral (rect_right window - coord_x cursor_pos), cursor_pos)++clearFromCursorToLineBeginning = clearScreenFraction go+ where+ go window cursor_pos = (fromIntegral (coord_x cursor_pos), cursor_pos { coord_x = rect_left window })++clearLine = clearScreenFraction go+ where+ go window cursor_pos = (fromIntegral (rect_width window), cursor_pos { coord_x = rect_left window })+++scrollPage :: Int -> IO ()+scrollPage new_origin_y = do+ handle <- getStdHandle sTD_OUTPUT_HANDLE+ screen_buffer_info <- getConsoleScreenBufferInfo handle+ let fill = CHAR_INFO clearChar clearAttribute+ window = csbi_window screen_buffer_info+ origin = COORD (rect_left window) (rect_top window + fromIntegral new_origin_y)+ scrollConsoleScreenBuffer handle window Nothing origin fill++scrollPageUp n = scrollPage (negate n)+scrollPageDown n = scrollPage n+++{-# INLINE applyANSIColorToAttribute #-}+applyANSIColorToAttribute :: WORD -> WORD -> WORD -> ANSIColor -> WORD -> WORD+applyANSIColorToAttribute rED gREEN bLUE color attribute = case color of+ Black -> attribute'+ Red -> attribute' .|. rED+ Green -> attribute' .|. gREEN+ Yellow -> attribute' .|. rED .|. gREEN+ Blue -> attribute' .|. bLUE+ Magenta -> attribute' .|. rED .|. bLUE+ Cyan -> attribute' .|. gREEN .|. bLUE+ White -> attribute' .|. wHITE+ where+ wHITE = rED .|. gREEN .|. bLUE+ attribute' = attribute .&. (complement wHITE)++applyForegroundANSIColorToAttribute, applyBackgroundANSIColorToAttribute :: ANSIColor -> WORD -> WORD+applyForegroundANSIColorToAttribute = applyANSIColorToAttribute fOREGROUND_RED fOREGROUND_GREEN fOREGROUND_BLUE+applyBackgroundANSIColorToAttribute = applyANSIColorToAttribute bACKGROUND_RED bACKGROUND_GREEN bACKGROUND_BLUE++swapForegroundBackgroundColors :: WORD -> WORD+swapForegroundBackgroundColors attribute = clean_attribute .|. foreground_attribute' .|. background_attribute'+ where+ foreground_attribute = attribute .&. fOREGROUND_INTENSE_WHITE+ background_attribute = attribute .&. bACKGROUND_INTENSE_WHITE+ clean_attribute = attribute .&. complement (fOREGROUND_INTENSE_WHITE .|. bACKGROUND_INTENSE_WHITE)+ foreground_attribute' = background_attribute `shiftR` 4+ background_attribute' = foreground_attribute `shiftL` 4++applyANSISGRToAttribute :: ANSISGR -> WORD -> WORD+applyANSISGRToAttribute sgr attribute = case sgr of+ Reset -> fOREGROUND_WHITE+ BoldIntensity -> attribute .|. iNTENSITY+ FaintIntensity -> attribute .&. (complement iNTENSITY) -- Not supported+ NormalIntensity -> attribute .&. (complement iNTENSITY)+ Italic -> attribute -- Not supported+ SingleUnderline -> attribute .|. cOMMON_LVB_UNDERSCORE -- Not supported, since cOMMON_LVB_UNDERSCORE seems to have no effect+ DoubleUnderline -> attribute .|. cOMMON_LVB_UNDERSCORE -- Not supported, since cOMMON_LVB_UNDERSCORE seems to have no effect+ NoUnderline -> attribute .&. (complement cOMMON_LVB_UNDERSCORE)+ SlowBlink -> attribute -- Not supported+ RapidBlink -> attribute -- Not supported+ NoBlink -> attribute+ Conceal -> attribute -- Not supported+ Reveal -> attribute+ -- The cOMMON_LVB_REVERSE_VIDEO doesn't actually appear to have any affect on the colors being displayed, so the emulator+ -- just uses it to carry information and implements the color-swapping behaviour itself. Bit of a hack, I guess :-)+ SwapForegroundBackground ->+ -- Check if the color-swapping flag is already set+ if attribute .&. cOMMON_LVB_REVERSE_VIDEO /= 0+ then attribute+ else swapForegroundBackgroundColors attribute .|. cOMMON_LVB_REVERSE_VIDEO+ DontSwapForegroundBackground ->+ -- Check if the color-swapping flag is already not set+ if attribute .&. cOMMON_LVB_REVERSE_VIDEO == 0+ then attribute+ else swapForegroundBackgroundColors attribute .&. (complement cOMMON_LVB_REVERSE_VIDEO)+ ForegroundNormalIntensity color -> applyForegroundANSIColorToAttribute color (attribute .&. (complement fOREGROUND_INTENSITY))+ ForegroundHighIntensity color -> applyForegroundANSIColorToAttribute color (attribute .|. fOREGROUND_INTENSITY)+ BackgroundNormalIntensity color -> applyBackgroundANSIColorToAttribute color (attribute .&. (complement bACKGROUND_INTENSITY))+ BackgroundHighIntensity color -> applyBackgroundANSIColorToAttribute color (attribute .|. bACKGROUND_INTENSITY)+ where+ iNTENSITY = fOREGROUND_INTENSITY .|. bACKGROUND_INTENSITY++setSGR sgr = do+ handle <- getStdHandle sTD_OUTPUT_HANDLE+ screen_buffer_info <- getConsoleScreenBufferInfo handle+ let attribute = csbi_attributes screen_buffer_info+ attribute' = applyANSISGRToAttribute sgr attribute+ setConsoleTextAttribute handle attribute'+++changeCursorVisibility :: Bool -> IO ()+changeCursorVisibility cursor_visible = do+ handle <- getStdHandle sTD_OUTPUT_HANDLE+ cursor_info <- getConsoleCursorInfo handle+ setConsoleCursorInfo handle (cursor_info { cci_cursor_visible = cursor_visible })++hideCursor = changeCursorVisibility False+showCursor = changeCursorVisibility True+
+ System/Console/ANSI/Windows/Foreign.hs view
@@ -0,0 +1,266 @@+-- | "System.Win32.Console" is really very impoverished, so I have had to do all the FFI myself.+module System.Console.ANSI.Windows.Foreign (+ -- Re-exports from Win32.Types+ BOOL, WORD, DWORD, WCHAR, HANDLE, SHORT,+ + charToWCHAR,+ + COORD(..), SMALL_RECT(..), rect_top, rect_bottom, rect_left, rect_right, rect_width, rect_height,+ CONSOLE_CURSOR_INFO(..), CONSOLE_SCREEN_BUFFER_INFO(..), CHAR_INFO(..),+ + sTD_INPUT_HANDLE, sTD_OUTPUT_HANDLE, sTD_ERROR_HANDLE,+ + fOREGROUND_BLUE, fOREGROUND_GREEN, fOREGROUND_RED, fOREGROUND_INTENSITY, fOREGROUND_WHITE, fOREGROUND_INTENSE_WHITE,+ bACKGROUND_BLUE, bACKGROUND_GREEN, bACKGROUND_RED, bACKGROUND_INTENSITY, bACKGROUND_WHITE, bACKGROUND_INTENSE_WHITE,+ cOMMON_LVB_REVERSE_VIDEO, cOMMON_LVB_UNDERSCORE,+ + getStdHandle,+ getConsoleScreenBufferInfo,+ getConsoleCursorInfo,+ + setConsoleTextAttribute,+ setConsoleCursorPosition,+ setConsoleCursorInfo,+ + fillConsoleOutputAttribute,+ fillConsoleOutputCharacter,+ scrollConsoleScreenBuffer+ ) where++import Foreign.C.Types+import Foreign.Marshal+import Foreign.Ptr+import Foreign.Storable++import Data.Bits+import Data.Char++import System.Win32.Types+++-- Some Windows types missing from System.Win32+type SHORT = CShort+type WCHAR = CWchar++charToWCHAR :: Char -> WCHAR+charToWCHAR char = fromIntegral (ord char)+++-- This is a FFI hack. Some of the API calls take a Coord, but that isn't a built-in FFI type so I can't+-- use it directly. Instead, I use UNPACKED_COORD and marshal COORDs into this manually. Note that we CAN'T+-- just use two SHORTs directly because they get expanded to 4 bytes each instead of just boing 2 lots of 2+-- bytes by the stdcall convention, so linking fails.+type UNPACKED_COORD = CInt++-- Field packing order determined experimentally: I couldn't immediately find a specification for Windows+-- struct layout anywhere.+unpackCOORD :: COORD -> UNPACKED_COORD+unpackCOORD (COORD x y) = (fromIntegral y) `shiftL` (sizeOf x * 8) .|. (fromIntegral x)+++peekAndOffset :: Storable a => Ptr a -> IO (a, Ptr b)+peekAndOffset ptr = do+ item <- peek ptr+ return (item, ptr `plusPtr` sizeOf item)++pokeAndOffset :: Storable a => Ptr a -> a -> IO (Ptr b)+pokeAndOffset ptr item = do+ poke ptr item+ return (ptr `plusPtr` sizeOf item)+++data COORD = COORD {+ coord_x :: SHORT,+ coord_y :: SHORT+ }++instance Show COORD where+ show (COORD x y) = "(" ++ show x ++ ", " ++ show y ++ ")"++instance Storable COORD where+ sizeOf ~(COORD x y) = sizeOf x + sizeOf y+ alignment ~(COORD x _) = alignment x+ peek ptr = do+ let ptr' = castPtr ptr :: Ptr SHORT+ x <- peekElemOff ptr' 0+ y <- peekElemOff ptr' 1+ return (COORD x y)+ poke ptr (COORD x y) = do+ let ptr' = castPtr ptr :: Ptr SHORT+ pokeElemOff ptr' 0 x+ pokeElemOff ptr' 1 y+++data SMALL_RECT = SMALL_RECT {+ rect_top_left :: COORD,+ rect_bottom_right :: COORD+ }++rect_top, rect_left, rect_bottom, rect_right :: SMALL_RECT -> SHORT+rect_top = coord_y . rect_top_left+rect_left = coord_x . rect_top_left+rect_bottom = coord_y . rect_bottom_right+rect_right = coord_x . rect_bottom_right++rect_width, rect_height :: SMALL_RECT -> SHORT+rect_width rect = rect_right rect - rect_left rect + 1+rect_height rect = rect_bottom rect - rect_top rect + 1++instance Show SMALL_RECT where+ show (SMALL_RECT tl br) = show tl ++ "-" ++ show br++instance Storable SMALL_RECT where+ sizeOf ~(SMALL_RECT tl br) = sizeOf tl + sizeOf br+ alignment ~(SMALL_RECT tl _) = alignment tl+ peek ptr = do+ let ptr' = castPtr ptr :: Ptr COORD+ tl <- peekElemOff ptr' 0+ br <- peekElemOff ptr' 1+ return (SMALL_RECT tl br)+ poke ptr (SMALL_RECT tl br) = do+ let ptr' = castPtr ptr :: Ptr COORD+ pokeElemOff ptr' 0 tl+ pokeElemOff ptr' 1 br+++data CONSOLE_CURSOR_INFO = CONSOLE_CURSOR_INFO {+ cci_cursor_size :: DWORD,+ cci_cursor_visible :: BOOL+ }+ deriving (Show)++instance Storable CONSOLE_CURSOR_INFO where+ sizeOf ~(CONSOLE_CURSOR_INFO size visible) = sizeOf size + sizeOf visible+ alignment ~(CONSOLE_CURSOR_INFO size _) = alignment size+ peek ptr = do+ (size, ptr') <- peekAndOffset (castPtr ptr)+ visible <- peek ptr'+ return (CONSOLE_CURSOR_INFO size visible)+ poke ptr (CONSOLE_CURSOR_INFO size visible) = do+ ptr' <- pokeAndOffset (castPtr ptr) size+ poke ptr' visible+++data CONSOLE_SCREEN_BUFFER_INFO = CONSOLE_SCREEN_BUFFER_INFO {+ csbi_size :: COORD,+ csbi_cursor_position :: COORD,+ csbi_attributes :: WORD,+ csbi_window :: SMALL_RECT,+ csbi_maximum_window_size :: COORD+ }+ deriving (Show)++instance Storable CONSOLE_SCREEN_BUFFER_INFO where+ sizeOf ~(CONSOLE_SCREEN_BUFFER_INFO size cursor_position attributes window maximum_window_size)+ = sizeOf size + sizeOf cursor_position + sizeOf attributes + sizeOf window + sizeOf maximum_window_size+ alignment ~(CONSOLE_SCREEN_BUFFER_INFO size _ _ _ _) = alignment size+ peek ptr = do+ (size, ptr1) <- peekAndOffset (castPtr ptr)+ (cursor_position, ptr2) <- peekAndOffset ptr1+ (attributes, ptr3) <- peekAndOffset ptr2+ (window, ptr4) <- peekAndOffset ptr3+ maximum_window_size <- peek ptr4+ return (CONSOLE_SCREEN_BUFFER_INFO size cursor_position attributes window maximum_window_size)+ poke ptr (CONSOLE_SCREEN_BUFFER_INFO size cursor_position attributes window maximum_window_size) = do+ ptr1 <- pokeAndOffset (castPtr ptr) size+ ptr2 <- pokeAndOffset ptr1 cursor_position+ ptr3 <- pokeAndOffset ptr2 attributes+ ptr4 <- pokeAndOffset ptr3 window+ poke ptr4 maximum_window_size+++data CHAR_INFO = CHAR_INFO {+ ci_char :: WCHAR,+ ci_attributes :: WORD+ }+ deriving (Show)++instance Storable CHAR_INFO where+ sizeOf ~(CHAR_INFO char attributes) = sizeOf char + sizeOf attributes+ alignment ~(CHAR_INFO char _) = alignment char+ peek ptr = do+ (char, ptr') <- peekAndOffset (castPtr ptr)+ attributes <- peek ptr'+ return (CHAR_INFO char attributes)+ poke ptr (CHAR_INFO char attributes) = do+ ptr' <- pokeAndOffset (castPtr ptr) char+ poke ptr' attributes+++sTD_INPUT_HANDLE, sTD_OUTPUT_HANDLE, sTD_ERROR_HANDLE :: DWORD+sTD_INPUT_HANDLE = -10+sTD_OUTPUT_HANDLE = -11+sTD_ERROR_HANDLE = -12++fOREGROUND_BLUE, fOREGROUND_GREEN, fOREGROUND_RED, fOREGROUND_INTENSITY,+ bACKGROUND_BLUE, bACKGROUND_GREEN, bACKGROUND_RED, bACKGROUND_INTENSITY,+ cOMMON_LVB_REVERSE_VIDEO, cOMMON_LVB_UNDERSCORE :: WORD+fOREGROUND_BLUE = 0x1+fOREGROUND_GREEN = 0x2+fOREGROUND_RED = 0x4+fOREGROUND_INTENSITY = 0x8+bACKGROUND_BLUE = 0x10+bACKGROUND_GREEN = 0x20+bACKGROUND_RED= 0x40+bACKGROUND_INTENSITY = 0x80+cOMMON_LVB_REVERSE_VIDEO = 0x4000+cOMMON_LVB_UNDERSCORE = 0x8000++fOREGROUND_WHITE, bACKGROUND_WHITE, fOREGROUND_INTENSE_WHITE, bACKGROUND_INTENSE_WHITE :: WORD+fOREGROUND_WHITE = fOREGROUND_RED .|. fOREGROUND_GREEN .|. fOREGROUND_BLUE+bACKGROUND_WHITE = bACKGROUND_RED .|. bACKGROUND_GREEN .|. bACKGROUND_BLUE+fOREGROUND_INTENSE_WHITE = fOREGROUND_WHITE .|. fOREGROUND_INTENSITY+bACKGROUND_INTENSE_WHITE = bACKGROUND_WHITE .|. bACKGROUND_INTENSITY+++foreign import stdcall unsafe "windows.h GetStdHandle" getStdHandle :: DWORD -> IO HANDLE+foreign import stdcall unsafe "windows.h GetConsoleScreenBufferInfo" cGetConsoleScreenBufferInfo :: HANDLE -> Ptr CONSOLE_SCREEN_BUFFER_INFO -> IO BOOL+foreign import stdcall unsafe "windows.h GetConsoleCursorInfo" cGetConsoleCursorInfo :: HANDLE -> Ptr CONSOLE_CURSOR_INFO -> IO BOOL++foreign import stdcall unsafe "windows.h SetConsoleTextAttribute" cSetConsoleTextAttribute :: HANDLE -> WORD -> IO BOOL+foreign import stdcall unsafe "windows.h SetConsoleCursorPosition" cSetConsoleCursorPosition :: HANDLE -> UNPACKED_COORD -> IO BOOL+foreign import stdcall unsafe "windows.h SetConsoleCursorInfo" cSetConsoleCursorInfo :: HANDLE -> Ptr CONSOLE_CURSOR_INFO -> IO BOOL++foreign import stdcall unsafe "windows.h FillConsoleOutputAttribute" cFillConsoleOutputAttribute :: HANDLE -> WORD -> DWORD -> UNPACKED_COORD -> Ptr DWORD -> IO BOOL+foreign import stdcall unsafe "windows.h FillConsoleOutputCharacterW" cFillConsoleOutputCharacter :: HANDLE -> TCHAR -> DWORD -> UNPACKED_COORD -> Ptr DWORD -> IO BOOL+foreign import stdcall unsafe "windows.h ScrollConsoleScreenBufferW" cScrollConsoleScreenBuffer :: HANDLE -> Ptr SMALL_RECT -> Ptr SMALL_RECT -> UNPACKED_COORD -> Ptr CHAR_INFO -> IO BOOL+++getConsoleScreenBufferInfo :: HANDLE -> IO CONSOLE_SCREEN_BUFFER_INFO+getConsoleScreenBufferInfo handle = alloca $ \ptr_console_screen_buffer_info -> do+ failIfFalse_ "getConsoleScreenBufferInfo" $ cGetConsoleScreenBufferInfo handle ptr_console_screen_buffer_info+ peek ptr_console_screen_buffer_info++getConsoleCursorInfo :: HANDLE -> IO CONSOLE_CURSOR_INFO+getConsoleCursorInfo handle = alloca $ \ptr_console_cursor_info -> do+ failIfFalse_ "getConsoleCursorInfo" $ cGetConsoleCursorInfo handle ptr_console_cursor_info+ peek ptr_console_cursor_info+++setConsoleTextAttribute :: HANDLE -> WORD -> IO ()+setConsoleTextAttribute handle attributes = failIfFalse_ "setConsoleTextAttribute" $ cSetConsoleTextAttribute handle attributes++setConsoleCursorPosition :: HANDLE -> COORD -> IO ()+setConsoleCursorPosition handle cursor_position = failIfFalse_ "setConsoleCursorPosition" $ cSetConsoleCursorPosition handle (unpackCOORD cursor_position)++setConsoleCursorInfo :: HANDLE -> CONSOLE_CURSOR_INFO -> IO ()+setConsoleCursorInfo handle console_cursor_info = with console_cursor_info $ \ptr_console_cursor_info -> do+ failIfFalse_ "setConsoleCursorInfo" $ cSetConsoleCursorInfo handle ptr_console_cursor_info+++fillConsoleOutputAttribute :: HANDLE -> WORD -> DWORD -> COORD -> IO DWORD+fillConsoleOutputAttribute handle attribute fill_length write_origin = alloca $ \ptr_chars_written -> do+ failIfFalse_ "fillConsoleOutputAttribute" $ cFillConsoleOutputAttribute handle attribute fill_length (unpackCOORD write_origin) ptr_chars_written+ peek ptr_chars_written++fillConsoleOutputCharacter :: HANDLE -> TCHAR -> DWORD -> COORD -> IO DWORD+fillConsoleOutputCharacter handle char fill_length write_origin = alloca $ \ptr_chars_written -> do+ failIfFalse_ "fillConsoleOutputCharacter" $ cFillConsoleOutputCharacter handle char fill_length (unpackCOORD write_origin) ptr_chars_written+ peek ptr_chars_written++scrollConsoleScreenBuffer :: HANDLE -> SMALL_RECT -> Maybe SMALL_RECT -> COORD -> CHAR_INFO -> IO ()+scrollConsoleScreenBuffer handle scroll_rectangle mb_clip_rectangle destination_origin fill + = with scroll_rectangle $ \ptr_scroll_rectangle ->+ maybeWith with mb_clip_rectangle $ \ptr_clip_rectangle ->+ with fill $ \ptr_fill ->+ failIfFalse_ "scrollConsoleScreenBuffer" $ cScrollConsoleScreenBuffer handle ptr_scroll_rectangle ptr_clip_rectangle (unpackCOORD destination_origin) ptr_fill
+ ansi-terminal.cabal view
@@ -0,0 +1,82 @@+Name: ansi-terminal+Version: 0.1+Cabal-Version: >= 1.2+Category: User Interfaces+Synopsis: Simple ANSI terminal support, with Windows compatibility+Description: ANSI terminal support for Haskell: allows cursor movement, screen clearing, color output and showing or hiding the cursor+License: BSD3+License-File: LICENSE+Author: Max Bolingbroke+Maintainer: batterseapower@hotmail.com+Homepage: http://bsp.lighthouseapp.com/projects/16235-ansi-terminal/overview+Build-Type: Simple++Flag SplitBase+ Description: Choose the new smaller, split-up base package+ Default: True++Flag Example+ Description: Build the example application+ Default: False+++Library+ Exposed-Modules: System.Console.ANSI+ + Other-Modules: System.Console.ANSI.Common+ + Cpp-Options: -Iincludes+ + if os(windows)+ Build-Depends: Win32 >= 2.0+ Cpp-Options: -DWINDOWS+ Extra-Libraries: "kernel32"+ Other-Modules: System.Console.ANSI.Windows+ System.Console.ANSI.Windows.Foreign+ System.Console.ANSI.Windows.Emulator+ else+ -- We assume any non-Windows platform is Unix+ Build-Depends: unix >= 2.3.0.0+ Cpp-Options: -DUNIX+ Other-Modules: System.Console.ANSI.Unix+ + if flag(splitBase)+ Build-Depends: base >= 3+ else+ Build-Depends: base < 3+ + Extensions: CPP+ ForeignFunctionInterface+ + Ghc-Options: -Wall++Executable ansi-terminal-example+ Main-Is: System/Console/ANSI/Example.hs+ + Cpp-Options: -Iincludes+ + if os(windows)+ Build-Depends: Win32 >= 2.0+ Cpp-Options: -DWINDOWS+ Extra-Libraries: "kernel32"+ Other-Modules: System.Console.ANSI.Windows+ System.Console.ANSI.Windows.Foreign+ System.Console.ANSI.Windows.Emulator+ else+ -- We assume any non-Windows platform is Unix+ Build-Depends: unix >= 2.3.0.0+ Cpp-Options: -DUNIX+ Other-Modules: System.Console.ANSI.Unix+ + if flag(splitBase)+ Build-Depends: base >= 3+ else+ Build-Depends: base < 3+ + Extensions: CPP+ ForeignFunctionInterface+ + Ghc-Options: -Wall+ + if !flag(example)+ Buildable: False