-- Copyright 2009-2010 Corey O'Connor {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE TypeFamilies #-} module Graphics.Vty.Terminal.Debug ( DebugTerminal(..) , DebugDisplay(..) , terminal_instance , dehandle ) where import Graphics.Vty.DisplayRegion import Graphics.Vty.Terminal.Generic import Control.Applicative import Control.Monad.Trans import Control.Monad.State.Strict import qualified Data.ByteString.UTF8 as BS import qualified Data.ByteString as BSCore import Data.IORef import qualified Data.Sequence as Seq import qualified Data.String.UTF8 as UTF8 import Data.Word import Foreign.Marshal.Array ( peekArray ) import Foreign.Ptr ( plusPtr ) import Foreign.Storable ( poke ) import System.IO import Unsafe.Coerce -- | The debug display terminal produces a string representation of the requested picture. There is -- *not* an isomorphism between the string representation and the picture. The string -- representation is a simplification of the picture that is only useful in debugging VTY without -- considering terminal specific issues. -- -- The debug implementation is useful in manually determining if the sequence of terminal operations -- matches the expected sequence. So requirement of the produced representation is simplicity in -- parsing the text representation and determining how the picture was mapped to terminal -- operations. -- -- All terminals support the operations specified in the Terminal class defined in -- Graphics.Vty.Terminal. As an instance of the Terminal class is also an instance of the Monad -- class there exists a monoid that defines it's algebra. The string representation is a sequence of -- identifiers where each identifier is the name of an operation in the algebra. data DebugTerminal = DebugTerminal { debug_terminal_last_output :: IORef (UTF8.UTF8 BS.ByteString) , debug_terminal_bounds :: DisplayRegion } instance Terminal DebugTerminal where terminal_ID _t = "debug_terminal" release_terminal _t = return () reserve_display _t = return () release_display _t = return () display_bounds t = return $ debug_terminal_bounds t display_terminal_instance t r c = return $ c (DebugDisplay r) output_byte_buffer t out_buffer buffer_size = liftIO $ do putStrLn $ "output_byte_buffer ?? " ++ show buffer_size peekArray (fromEnum buffer_size) out_buffer >>= return . UTF8.fromRep . BSCore.pack >>= writeIORef (debug_terminal_last_output t) output_handle t = return stdout data DebugDisplay = DebugDisplay { debug_display_bounds :: DisplayRegion } terminal_instance :: ( Applicative m, MonadIO m ) => DisplayRegion -> m TerminalHandle terminal_instance r = do output_ref <- liftIO $ newIORef undefined new_terminal_handle $ DebugTerminal output_ref r dehandle :: TerminalHandle -> DebugTerminal dehandle (TerminalHandle t _) = unsafeCoerce t instance DisplayTerminal DebugDisplay where -- | Provide the current bounds of the output terminal. context_region d = debug_display_bounds d -- | A cursor move is always visualized as the single character 'M' move_cursor_required_bytes _d _x _y = 1 -- | A cursor move is always visualized as the single character 'M' serialize_move_cursor _d _x _y ptr = do liftIO $ poke ptr (toEnum $ fromEnum 'M') return $ ptr `plusPtr` 1 -- | Show cursor is always visualized as the single character 'S' show_cursor_required_bytes _d = 1 -- | Show cursor is always visualized as the single character 'S' serialize_show_cursor _d ptr = do liftIO $ poke ptr (toEnum $ fromEnum 'S') return $ ptr `plusPtr` 1 -- | Hide cursor is always visualized as the single character 'H' hide_cursor_required_bytes _d = 1 -- | Hide cursor is always visualized as the single character 'H' serialize_hide_cursor _d ptr = do liftIO $ poke ptr (toEnum $ fromEnum 'H') return $ ptr `plusPtr` 1 -- | An attr change is always visualized as the single character 'A' attr_required_bytes _d _fattr _diffs _attr = 1 -- | An attr change is always visualized as the single character 'A' serialize_set_attr _d _fattr _diffs _attr ptr = do liftIO $ poke ptr (toEnum $ fromEnum 'A') return $ ptr `plusPtr` 1 default_attr_required_bytes _d = 1 serialize_default_attr _d ptr = do liftIO $ poke ptr (toEnum $ fromEnum 'D') return $ ptr `plusPtr` 1