@@ -18,6 +18,7 @@ import Graphics.Vty.DisplayRegion
18import Graphics.Vty.DisplayAttributes
18import Graphics.Vty.DisplayAttributes
20import Control.Monad ( liftM )
20import Control.Monad ( liftM )
21+import Control.Monad.Trans
22import Data.Array
23import Data.Array
23import qualified Data.ByteString.Internal as BSCore
24import qualified Data.ByteString.Internal as BSCore
@@ -34,7 +35,7 @@ data TerminalHandle where
34terminal_state :: TerminalHandle -> TerminalState
35terminal_state :: TerminalHandle -> TerminalState
35terminal_state (TerminalHandle _ s) = s
36terminal_state (TerminalHandle _ s) = s
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
38new_terminal_handle t = liftM (TerminalHandle t) initial_terminal_state
39new_terminal_handle t = liftM (TerminalHandle t) initial_terminal_state
40data TerminalState = TerminalState
41data TerminalState = TerminalState
@@ -42,14 +43,14 @@ data TerminalState = TerminalState
42 current_attr :: Maybe FixedAttr
43 current_attr :: Maybe FixedAttr
45−initial_terminal_state :: IO TerminalState
46+initial_terminal_state :: MonadIO m => m TerminalState
46initial_terminal_state = return $ TerminalState Nothing
47initial_terminal_state = return $ TerminalState Nothing
48class Terminal t where
49class Terminal t where
49 -- | Text identifier for the terminal. Used for debugging.
50 -- | Text identifier for the terminal. Used for debugging.
50 terminal_ID :: t -> String
51 terminal_ID :: t -> String
52− release_terminal :: t -> IO ()
53+ release_terminal :: MonadIO m => t -> m ()
53 -- | Clear the display and initialize the terminal to some initial display state.
54 -- | Clear the display and initialize the terminal to some initial display state.
55 -- The expectation of a program is that the display starts in some initial state.
56 -- The expectation of a program is that the display starts in some initial state.
@@ -61,25 +62,26 @@ class Terminal t where
61 -- access to a display such that:
62 -- access to a display such that:
62 -- - The previous state cannot be determined
63 -- - The previous state cannot be determined
63 -- - When exclusive access to a display is release the display returns to the previous state.
64 -- - 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 ()
66 -- | Return the display to the state before reserve_display
67 -- | Return the display to the state before reserve_display
67 -- If no previous state then set the display state to the initial state.
68 -- 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 ()
70 -- | Returns the current display bounds.
71 -- | Returns the current display bounds.
71− display_bounds :: t -> IO DisplayRegion
72+ display_bounds :: MonadIO m => t -> m DisplayRegion
73 -- Internal method used to provide the DisplayTerminal instance to the DisplayHandle
74 -- Internal method used to provide the DisplayTerminal instance to the DisplayHandle
74 -- constructor.
75 -- constructor.
75− display_terminal_instance :: t
76+ display_terminal_instance :: MonadIO m
76 -> DisplayRegion
78 -> DisplayRegion
77 -> (forall d. DisplayTerminal d => d -> DisplayHandle)
79 -> (forall d. DisplayTerminal d => d -> DisplayHandle)
78− -> IO DisplayHandle
80+ -> m DisplayHandle
80 -- | Output the byte buffer of the specified size to the terminal device. The size is equal to
82 -- | Output the byte buffer of the specified size to the terminal device. The size is equal to
81 -- end_ptr - start_ptr
83 -- end_ptr - start_ptr
82− output_byte_buffer :: t -> OutputBuffer -> Word -> IO ()
84+ output_byte_buffer :: MonadIO m => t -> OutputBuffer -> Word -> m ()
84instance Terminal TerminalHandle where
86instance Terminal TerminalHandle where
85 terminal_ID (TerminalHandle t _) = terminal_ID t
87 terminal_ID (TerminalHandle t _) = terminal_ID t
@@ -96,7 +98,7 @@ data DisplayHandle where
96-- | Acquire display access to the given region of the display.
98-- | Acquire display access to the given region of the display.
97-- Currently all regions have the upper left corner of (0,0) and the lower right corner at
99-- Currently all regions have the upper left corner of (0,0) and the lower right corner at
98-- (max display_width provided_width, max display_height provided_height)
100-- (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
100display_context t b = do
102display_context t b = do
101 s <- initial_display_state
103 s <- initial_display_state
102 let c d = DisplayHandle d t s
104 let c d = DisplayHandle d t s
@@ -106,8 +108,8 @@ data DisplayState = DisplayState
106 { previous_output_ref :: IORef (Maybe SpanOpSequence)
108 { previous_output_ref :: IORef (Maybe SpanOpSequence)
109−initial_display_state :: IO DisplayState
111+initial_display_state :: MonadIO m => m DisplayState
110−initial_display_state = liftM DisplayState $ newIORef Nothing
112+initial_display_state = liftM DisplayState $ liftIO $ newIORef Nothing
112class DisplayTerminal d where
114class DisplayTerminal d where
113 -- | Provide the bounds of the display context.
115 -- | Provide the bounds of the display context.
@@ -119,13 +121,13 @@ class DisplayTerminal d where
119 -- | sets the output position to the specified row and column. Where the number of bytes
121 -- | sets the output position to the specified row and column. Where the number of bytes
120 -- required for the control codes can be specified seperate from the actual byte sequence.
122 -- required for the control codes can be specified seperate from the actual byte sequence.
121 move_cursor_required_bytes :: d -> Word -> Word -> Word
123 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
124 show_cursor_required_bytes :: d -> Word
126 show_cursor_required_bytes :: d -> Word
125− serialize_show_cursor :: d -> OutputBuffer -> IO OutputBuffer
127+ serialize_show_cursor :: MonadIO m => d -> OutputBuffer -> m OutputBuffer
127 hide_cursor_required_bytes :: d -> Word
129 hide_cursor_required_bytes :: d -> Word
128− serialize_hide_cursor :: d -> OutputBuffer -> IO OutputBuffer
130+ serialize_hide_cursor :: MonadIO m => d -> OutputBuffer -> m OutputBuffer
130 -- | Assure the specified output attributes will be applied to all the following text until the
132 -- | Assure the specified output attributes will be applied to all the following text until the
131 -- next output attribute change. Where the number of bytes required for the control codes can
133 -- next output attribute change. Where the number of bytes required for the control codes can
@@ -139,11 +141,11 @@ class DisplayTerminal d where
139 -- In addition it may be possible to optimize the state changes based off the currently applied
141 -- In addition it may be possible to optimize the state changes based off the currently applied
140 -- display attributes.
142 -- display attributes.
141 attr_required_bytes :: d -> FixedAttr -> Attr -> DisplayAttrDiff -> Word
143 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
144 -- | Reset the display attributes to the default display attributes
146 -- | Reset the display attributes to the default display attributes
145 default_attr_required_bytes :: d -> Word
147 default_attr_required_bytes :: d -> Word
146− serialize_default_attr :: d -> OutputBuffer -> IO OutputBuffer
148+ serialize_default_attr :: MonadIO m => d -> OutputBuffer -> m OutputBuffer
149instance DisplayTerminal DisplayHandle where
151instance DisplayTerminal DisplayHandle where
@@ -167,10 +169,10 @@ utf8_text_required_bytes str =
167 in toEnum src_bytes_length
169 in toEnum src_bytes_length
169-- | All terminals serialize UTF8 text to the terminal device exactly as serialized in memory.
171-- | 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
171serialize_utf8_text str dest_ptr =
173serialize_utf8_text str dest_ptr =
172 let (src_fptr, src_ptr_offset, src_bytes_length) = BSCore.toForeignPtr (toRep str)
174 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
174 let src_ptr' = src_ptr `plusPtr` src_ptr_offset
176 let src_ptr' = src_ptr `plusPtr` src_ptr_offset
175 BSCore.memcpy dest_ptr src_ptr' (toEnum src_bytes_length)
177 BSCore.memcpy dest_ptr src_ptr' (toEnum src_bytes_length)
176 return (dest_ptr `plusPtr` src_bytes_length)
178 return (dest_ptr `plusPtr` src_bytes_length)
@@ -191,7 +193,7 @@ serialize_utf8_text str dest_ptr =
192-- todo: specify possible IO exceptions.
194-- todo: specify possible IO exceptions.
193-- abstract from IO monad to a MonadIO instance.
195-- abstract from IO monad to a MonadIO instance.
194−output_picture :: DisplayHandle -> Picture -> IO ()
196+output_picture :: MonadIO m => DisplayHandle -> Picture -> m ()
195output_picture (DisplayHandle d t s) pic = do
197output_picture (DisplayHandle d t s) pic = do
196 let !r = context_region d
198 let !r = context_region d
197 let !ops = spans_for_pic pic r
199 let !ops = spans_for_pic pic r
@@ -199,7 +201,7 @@ output_picture (DisplayHandle d t s) pic = do
199 -- Diff the previous output against the requested output. Differences are currently on a per-row
201 -- Diff the previous output against the requested output. Differences are currently on a per-row
200 -- basis.
202 -- basis.
201 diffs :: [Bool]
203 diffs :: [Bool]
202− <- readIORef (previous_output_ref s)
204+ <- liftIO ( readIORef (previous_output_ref s) )
203 >>= \mprevious_ops -> case mprevious_ops of
205 >>= \mprevious_ops -> case mprevious_ops of
205 -> return $ replicate ( fromEnum $ region_height $ effected_region ops )
207 -> return $ replicate ( fromEnum $ region_height $ effected_region ops )
@@ -221,7 +223,7 @@ output_picture (DisplayHandle d t s) pic = do
221 + move_cursor_required_bytes d x y
223 + move_cursor_required_bytes d x y
223 -- ... then serialize
225 -- ... then serialize
224− allocaBytes (fromEnum total) $ \start_ptr -> do
226+ liftIO $ allocaBytes (fromEnum total) $ \start_ptr -> do
225 ptr <- serialize_hide_cursor d start_ptr
227 ptr <- serialize_hide_cursor d start_ptr
226 ptr' <- serialize_default_attr d ptr
228 ptr' <- serialize_default_attr d ptr
227 ptr'' <- serialize_output_ops d ptr' initial_attr diffs ops
229 ptr'' <- serialize_output_ops d ptr' initial_attr diffs ops
@@ -237,7 +239,7 @@ output_picture (DisplayHandle d t s) pic = do
237 | toEnum count > total -> fail $ "End pointer past end of buffer by " ++ show (toEnum count - total)
239 | toEnum count > total -> fail $ "End pointer past end of buffer by " ++ show (toEnum count - total)
238 | otherwise -> output_byte_buffer t start_ptr (toEnum count)
240 | otherwise -> output_byte_buffer t start_ptr (toEnum count)
239 -- Cache the output spans.
241 -- Cache the output spans.
240− writeIORef (previous_output_ref s) (Just ops)
242+ liftIO $ writeIORef (previous_output_ref s) (Just ops)
241 return ()
243 return ()
243required_bytes :: DisplayTerminal d => d -> FixedAttr -> [Bool] -> SpanOpSequence -> Word
245required_bytes :: DisplayTerminal d => d -> FixedAttr -> [Bool] -> SpanOpSequence -> Word
@@ -272,13 +274,13 @@ span_op_required_bytes d fattr (AttributeChange attr) =
272 in (c, fattr')
274 in (c, fattr')
273span_op_required_bytes _d fattr (TextSpan _ _ str) = (utf8_text_required_bytes str, fattr)
275span_op_required_bytes _d fattr (TextSpan _ _ str) = (utf8_text_required_bytes str, fattr)
275−serialize_output_ops :: DisplayTerminal d
277+serialize_output_ops :: ( MonadIO m, DisplayTerminal d )
277 -> OutputBuffer
279 -> OutputBuffer
278 -> FixedAttr
280 -> FixedAttr
279 -> [Bool]
281 -> [Bool]
280 -> SpanOpSequence
282 -> SpanOpSequence
281− -> IO OutputBuffer
283+ -> m OutputBuffer
282serialize_output_ops d start_ptr in_fattr diffs ops = do
284serialize_output_ops d start_ptr in_fattr diffs ops = do
283 (_, end_ptr, _, _) <- foldlM serialize_output_ops'
285 (_, end_ptr, _, _) <- foldlM serialize_output_ops'
284 ( 0, start_ptr, in_fattr, diffs )
286 ( 0, start_ptr, in_fattr, diffs )
@@ -293,13 +295,13 @@ serialize_output_ops d start_ptr in_fattr diffs ops = do
293 serialize_output_ops' (_y, _out_ptr, _fattr, [] ) _span_ops
295 serialize_output_ops' (_y, _out_ptr, _fattr, [] ) _span_ops
294 = error "shouldn't be possible"
296 = error "shouldn't be possible"
296−serialize_span_ops :: DisplayTerminal d
298+serialize_span_ops :: ( MonadIO m, DisplayTerminal d )
299 -> OutputBuffer
301 -> OutputBuffer
300 -> FixedAttr
302 -> FixedAttr
301 -> SpanOps
303 -> SpanOps
302− -> IO (OutputBuffer, FixedAttr)
304+ -> m (OutputBuffer, FixedAttr)
303serialize_span_ops d y out_ptr in_fattr span_ops = do
305serialize_span_ops d y out_ptr in_fattr span_ops = do
304 -- The first operation is to set the cursor to the start of the row
306 -- The first operation is to set the cursor to the start of the row
305 out_ptr' <- serialize_move_cursor d 0 y out_ptr
307 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
308 (out_ptr', in_fattr)
310 (out_ptr', in_fattr)
311−serialize_span_op :: DisplayTerminal d
313+serialize_span_op :: ( MonadIO m, DisplayTerminal d )
313 -> SpanOp
315 -> SpanOp
314 -> OutputBuffer
316 -> OutputBuffer
315 -> FixedAttr
317 -> FixedAttr
316− -> IO (OutputBuffer, FixedAttr)
318+ -> m (OutputBuffer, FixedAttr)
317serialize_span_op d (AttributeChange attr) out_ptr fattr = do
319serialize_span_op d (AttributeChange attr) out_ptr fattr = do
318 let attr' = limit_attr_for_display d attr
320 let attr' = limit_attr_for_display d attr
319 fattr' = fix_display_attr fattr attr'
321 fattr' = fix_display_attr fattr attr'
@@ -324,16 +326,18 @@ serialize_span_op _d (TextSpan _ _ str) out_ptr fattr = do
324 out_ptr' <- serialize_utf8_text str out_ptr
326 out_ptr' <- serialize_utf8_text str out_ptr
325 return (out_ptr', fattr)
327 return (out_ptr', fattr)
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 ()
328marshall_to_terminal t c f = do
331marshall_to_terminal t c f = do
329− start_ptr <- mallocBytes (fromEnum c)
332+ start_ptr <- liftIO $ mallocBytes (fromEnum c)
331 -- todo: capture exceptions?
334 -- todo: capture exceptions?
332 end_ptr <- f start_ptr
335 end_ptr <- f start_ptr
333 case end_ptr `minusPtr` start_ptr of
336 case end_ptr `minusPtr` start_ptr of
334 count | count < 0 -> fail "End pointer before start pointer."
337 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)
335 | otherwise -> output_byte_buffer t start_ptr (toEnum count)
339 | otherwise -> output_byte_buffer t start_ptr (toEnum count)
336− free start_ptr
340+ liftIO $ free start_ptr
337 return ()
341 return ()
339data CursorOutputMap = CursorOutputMap
343data CursorOutputMap = CursorOutputMap