@@ -18,6 +18,7 @@ import Graphics.Vty.DisplayRegion
1818import Graphics.Vty.DisplayAttributes
1919
2020import Control.Monad ( liftM )
21+import Control.Monad.Trans
2122
2223import Data.Array
2324import qualified Data.ByteString.Internal as BSCore
@@ -34,7 +35,7 @@ data TerminalHandle where
3435terminal_state :: TerminalHandle -> TerminalState
3536terminal_state (TerminalHandle _ s) = s
3637
37−new_terminal_handle :: forall t. Terminal t => t -> IO TerminalHandle
38+new_terminal_handle :: forall m t. ( MonadIO m, Terminal t ) => t -> m TerminalHandle
3839new_terminal_handle t = liftM (TerminalHandle t) initial_terminal_state
3940
4041data TerminalState = TerminalState
@@ -42,14 +43,14 @@ data TerminalState = TerminalState
4243 current_attr :: Maybe FixedAttr
4344 }
4445
45−initial_terminal_state :: IO TerminalState
46+initial_terminal_state :: MonadIO m => m TerminalState
4647initial_terminal_state = return $ TerminalState Nothing
4748
4849class Terminal t where
4950 -- | Text identifier for the terminal. Used for debugging.
5051 terminal_ID :: t -> String
5152 -- |
52− release_terminal :: t -> IO ()
53+ release_terminal :: MonadIO m => t -> m ()
5354 -- | Clear the display and initialize the terminal to some initial display state.
5455 --
5556 -- The expectation of a program is that the display starts in some initial state.
@@ -61,25 +62,26 @@ class Terminal t where
6162 -- access to a display such that:
6263 -- - The previous state cannot be determined
6364 -- - When exclusive access to a display is release the display returns to the previous state.
64− reserve_display :: t -> IO ()
65+ reserve_display :: MonadIO m => t -> m ()
6566
6667 -- | Return the display to the state before reserve_display
6768 -- If no previous state then set the display state to the initial state.
68− release_display :: t -> IO ()
69+ release_display :: MonadIO m => t -> m ()
6970
7071 -- | Returns the current display bounds.
71− display_bounds :: t -> IO DisplayRegion
72+ display_bounds :: MonadIO m => t -> m DisplayRegion
7273
7374 -- Internal method used to provide the DisplayTerminal instance to the DisplayHandle
7475 -- constructor.
75− display_terminal_instance :: t
76+ display_terminal_instance :: MonadIO m
77+ => t
7678 -> DisplayRegion
7779 -> (forall d. DisplayTerminal d => d -> DisplayHandle)
78− -> IO DisplayHandle
80+ -> m DisplayHandle
7981
8082 -- | Output the byte buffer of the specified size to the terminal device. The size is equal to
8183 -- end_ptr - start_ptr
82− output_byte_buffer :: t -> OutputBuffer -> Word -> IO ()
84+ output_byte_buffer :: MonadIO m => t -> OutputBuffer -> Word -> m ()
8385
8486instance Terminal TerminalHandle where
8587 terminal_ID (TerminalHandle t _) = terminal_ID t
@@ -96,7 +98,7 @@ data DisplayHandle where
9698-- | Acquire display access to the given region of the display.
9799-- Currently all regions have the upper left corner of (0,0) and the lower right corner at
98100-- (max display_width provided_width, max display_height provided_height)
99−display_context :: TerminalHandle -> DisplayRegion -> IO DisplayHandle
101+display_context :: MonadIO m => TerminalHandle -> DisplayRegion -> m DisplayHandle
100102display_context t b = do
101103 s <- initial_display_state
102104 let c d = DisplayHandle d t s
@@ -106,8 +108,8 @@ data DisplayState = DisplayState
106108 { previous_output_ref :: IORef (Maybe SpanOpSequence)
107109 }
108110
109−initial_display_state :: IO DisplayState
110−initial_display_state = liftM DisplayState $ newIORef Nothing
111+initial_display_state :: MonadIO m => m DisplayState
112+initial_display_state = liftM DisplayState $ liftIO $ newIORef Nothing
111113
112114class DisplayTerminal d where
113115 -- | Provide the bounds of the display context.
@@ -119,13 +121,13 @@ class DisplayTerminal d where
119121 -- | sets the output position to the specified row and column. Where the number of bytes
120122 -- required for the control codes can be specified seperate from the actual byte sequence.
121123 move_cursor_required_bytes :: d -> Word -> Word -> Word
122− serialize_move_cursor :: d -> Word -> Word -> OutputBuffer -> IO OutputBuffer
124+ serialize_move_cursor :: MonadIO m => d -> Word -> Word -> OutputBuffer -> m OutputBuffer
123125
124126 show_cursor_required_bytes :: d -> Word
125− serialize_show_cursor :: d -> OutputBuffer -> IO OutputBuffer
127+ serialize_show_cursor :: MonadIO m => d -> OutputBuffer -> m OutputBuffer
126128
127129 hide_cursor_required_bytes :: d -> Word
128− serialize_hide_cursor :: d -> OutputBuffer -> IO OutputBuffer
130+ serialize_hide_cursor :: MonadIO m => d -> OutputBuffer -> m OutputBuffer
129131
130132 -- | Assure the specified output attributes will be applied to all the following text until the
131133 -- next output attribute change. Where the number of bytes required for the control codes can
@@ -139,11 +141,11 @@ class DisplayTerminal d where
139141 -- In addition it may be possible to optimize the state changes based off the currently applied
140142 -- display attributes.
141143 attr_required_bytes :: d -> FixedAttr -> Attr -> DisplayAttrDiff -> Word
142− serialize_set_attr :: d -> FixedAttr -> Attr -> DisplayAttrDiff -> OutputBuffer -> IO OutputBuffer
144+ serialize_set_attr :: MonadIO m => d -> FixedAttr -> Attr -> DisplayAttrDiff -> OutputBuffer -> m OutputBuffer
143145
144146 -- | Reset the display attributes to the default display attributes
145147 default_attr_required_bytes :: d -> Word
146− serialize_default_attr :: d -> OutputBuffer -> IO OutputBuffer
148+ serialize_default_attr :: MonadIO m => d -> OutputBuffer -> m OutputBuffer
147149
148150
149151instance DisplayTerminal DisplayHandle where
@@ -167,10 +169,10 @@ utf8_text_required_bytes str =
167169 in toEnum src_bytes_length
168170
169171-- | All terminals serialize UTF8 text to the terminal device exactly as serialized in memory.
170−serialize_utf8_text :: UTF8 BSCore.ByteString -> OutputBuffer -> IO OutputBuffer
172+serialize_utf8_text :: MonadIO m => UTF8 BSCore.ByteString -> OutputBuffer -> m OutputBuffer
171173serialize_utf8_text str dest_ptr =
172174 let (src_fptr, src_ptr_offset, src_bytes_length) = BSCore.toForeignPtr (toRep str)
173− in withForeignPtr src_fptr $ \src_ptr -> do
175+ in liftIO $ withForeignPtr src_fptr $ \src_ptr -> do
174176 let src_ptr' = src_ptr `plusPtr` src_ptr_offset
175177 BSCore.memcpy dest_ptr src_ptr' (toEnum src_bytes_length)
176178 return (dest_ptr `plusPtr` src_bytes_length)
@@ -191,7 +193,7 @@ serialize_utf8_text str dest_ptr =
191193--
192194-- todo: specify possible IO exceptions.
193195-- abstract from IO monad to a MonadIO instance.
194−output_picture :: DisplayHandle -> Picture -> IO ()
196+output_picture :: MonadIO m => DisplayHandle -> Picture -> m ()
195197output_picture (DisplayHandle d t s) pic = do
196198 let !r = context_region d
197199 let !ops = spans_for_pic pic r
@@ -199,7 +201,7 @@ output_picture (DisplayHandle d t s) pic = do
199201 -- Diff the previous output against the requested output. Differences are currently on a per-row
200202 -- basis.
201203 diffs :: [Bool]
202− <- readIORef (previous_output_ref s)
204+ <- liftIO ( readIORef (previous_output_ref s) )
203205 >>= \mprevious_ops -> case mprevious_ops of
204206 Nothing
205207 -> return $ replicate ( fromEnum $ region_height $ effected_region ops )
@@ -221,7 +223,7 @@ output_picture (DisplayHandle d t s) pic = do
221223 + move_cursor_required_bytes d x y
222224
223225 -- ... then serialize
224− allocaBytes (fromEnum total) $ \start_ptr -> do
226+ liftIO $ allocaBytes (fromEnum total) $ \start_ptr -> do
225227 ptr <- serialize_hide_cursor d start_ptr
226228 ptr' <- serialize_default_attr d ptr
227229 ptr'' <- serialize_output_ops d ptr' initial_attr diffs ops
@@ -237,7 +239,7 @@ output_picture (DisplayHandle d t s) pic = do
237239 | toEnum count > total -> fail $ "End pointer past end of buffer by " ++ show (toEnum count - total)
238240 | otherwise -> output_byte_buffer t start_ptr (toEnum count)
239241 -- Cache the output spans.
240− writeIORef (previous_output_ref s) (Just ops)
242+ liftIO $ writeIORef (previous_output_ref s) (Just ops)
241243 return ()
242244
243245required_bytes :: DisplayTerminal d => d -> FixedAttr -> [Bool] -> SpanOpSequence -> Word
@@ -272,13 +274,13 @@ span_op_required_bytes d fattr (AttributeChange attr) =
272274 in (c, fattr')
273275span_op_required_bytes _d fattr (TextSpan _ _ str) = (utf8_text_required_bytes str, fattr)
274276
275−serialize_output_ops :: DisplayTerminal d
277+serialize_output_ops :: ( MonadIO m, DisplayTerminal d )
276278 => d
277279 -> OutputBuffer
278280 -> FixedAttr
279281 -> [Bool]
280282 -> SpanOpSequence
281− -> IO OutputBuffer
283+ -> m OutputBuffer
282284serialize_output_ops d start_ptr in_fattr diffs ops = do
283285 (_, end_ptr, _, _) <- foldlM serialize_output_ops'
284286 ( 0, start_ptr, in_fattr, diffs )
@@ -293,13 +295,13 @@ serialize_output_ops d start_ptr in_fattr diffs ops = do
293295 serialize_output_ops' (_y, _out_ptr, _fattr, [] ) _span_ops
294296 = error "shouldn't be possible"
295297
296−serialize_span_ops :: DisplayTerminal d
298+serialize_span_ops :: ( MonadIO m, DisplayTerminal d )
297299 => d
298300 -> Word
299301 -> OutputBuffer
300302 -> FixedAttr
301303 -> SpanOps
302− -> IO (OutputBuffer, FixedAttr)
304+ -> m (OutputBuffer, FixedAttr)
303305serialize_span_ops d y out_ptr in_fattr span_ops = do
304306 -- The first operation is to set the cursor to the start of the row
305307 out_ptr' <- serialize_move_cursor d 0 y out_ptr
@@ -308,12 +310,12 @@ serialize_span_ops d y out_ptr in_fattr span_ops = do
308310 (out_ptr', in_fattr)
309311 span_ops
310312
311−serialize_span_op :: DisplayTerminal d
313+serialize_span_op :: ( MonadIO m, DisplayTerminal d )
312314 => d
313315 -> SpanOp
314316 -> OutputBuffer
315317 -> FixedAttr
316− -> IO (OutputBuffer, FixedAttr)
318+ -> m (OutputBuffer, FixedAttr)
317319serialize_span_op d (AttributeChange attr) out_ptr fattr = do
318320 let attr' = limit_attr_for_display d attr
319321 fattr' = fix_display_attr fattr attr'
@@ -324,16 +326,18 @@ serialize_span_op _d (TextSpan _ _ str) out_ptr fattr = do
324326 out_ptr' <- serialize_utf8_text str out_ptr
325327 return (out_ptr', fattr)
326328
327−marshall_to_terminal :: Terminal t => t -> Word -> (Ptr Word8 -> IO (Ptr Word8)) -> IO ()
329+marshall_to_terminal :: ( MonadIO m, Terminal t )
330+ => t -> Word -> (Ptr Word8 -> m (Ptr Word8)) -> m ()
328331marshall_to_terminal t c f = do
329− start_ptr <- mallocBytes (fromEnum c)
332+ start_ptr <- liftIO $ mallocBytes (fromEnum c)
330333 --
331334 -- todo: capture exceptions?
332335 end_ptr <- f start_ptr
333336 case end_ptr `minusPtr` start_ptr of
334337 count | count < 0 -> fail "End pointer before start pointer."
338+ | toEnum count > c -> fail $ "End pointer past end of buffer by " ++ show (toEnum count - c)
335339 | otherwise -> output_byte_buffer t start_ptr (toEnum count)
336− free start_ptr
340+ liftIO $ free start_ptr
337341 return ()
338342
339343data CursorOutputMap = CursorOutputMap