@@ -1,4 +1,5 @@
1-- Copyright Corey O'Connor
1-- Copyright Corey O'Connor
2+-- General philosophy is: MonadIO is for equations exposed to clients.
2{-# LANGUAGE BangPatterns #-}
3{-# LANGUAGE BangPatterns #-}
3{-# LANGUAGE RankNTypes #-}
4{-# LANGUAGE RankNTypes #-}
4{-# LANGUAGE ScopedTypeVariables #-}
5{-# LANGUAGE ScopedTypeVariables #-}
@@ -18,41 +19,17 @@ import Graphics.Vty.DisplayRegion
19import Graphics.Vty.DisplayAttributes
20import Graphics.Vty.DisplayAttributes
21−import Control.Monad ( liftM )
22+import Control.Monad.Fix
22import Control.Monad.Trans
23import Control.Monad.Trans
24import qualified Data.ByteString.Internal as BS
25import qualified Data.ByteString.Internal as BS
25import Data.IORef
26import Data.IORef
26import qualified Data.Vector as Vector
27import qualified Data.Vector as Vector
28−import System.IO
29+data Terminal = Terminal
30−-- | An handle to a terminal that hides the implementation.
31−data TerminalHandle where
32− TerminalHandle :: Terminal t => t -> IORef TerminalState -> TerminalHandle
34−state_ref :: TerminalHandle -> IORef TerminalState
35−state_ref (TerminalHandle _ s_ref) = s_ref
37−new_terminal_handle :: forall m t. ( MonadIO m, Terminal t ) => t -> m TerminalHandle
38−new_terminal_handle t = do
39− s_ref <- liftIO $ newIORef initial_terminal_state
40− return $ TerminalHandle t s_ref
42−-- | The current terminal state. This may not exactly be known.
43−data TerminalState = TerminalState
44− { known_fattr :: Maybe FixedAttr
47−-- | Initially we know nothing about a terminal's state.
48−initial_terminal_state :: TerminalState
49−initial_terminal_state = TerminalState Nothing
51−class Terminal t where
52− -- | Text identifier for the terminal. Used for debugging.
30+ { -- | Text identifier for the terminal. Used for debugging.
53− terminal_ID :: t -> String
31+ terminal_ID :: String
54− -- |
32+ , release_device :: MonadIO m => m ()
55− release_terminal :: MonadIO m => t -> m ()
56 -- | Clear the display and initialize the terminal to some initial display state.
33 -- | Clear the display and initialize the terminal to some initial display state.
58 -- The expectation of a program is that the display starts in some initial state.
35 -- The expectation of a program is that the display starts in some initial state.
@@ -63,77 +40,67 @@ class Terminal t where
63 -- The abstract operation I think all these behaviors are instances of is reserving exclusive
40 -- The abstract operation I think all these behaviors are instances of is reserving exclusive
64 -- access to a display such that:
41 -- access to a display such that:
65 -- - The previous state cannot be determined
42 -- - The previous state cannot be determined
66− -- - When exclusive access to a display is release the display returns to the previous state.
43+ -- - When exclusive access to a display is released the display returns to the previous state.
67− reserve_display :: MonadIO m => t -> m ()
44+ , reserve_display :: MonadIO m => m ()
69 -- | Return the display to the state before reserve_display
45 -- | Return the display to the state before reserve_display
70 -- If no previous state then set the display state to the initial state.
46 -- If no previous state then set the display state to the initial state.
71− release_display :: MonadIO m => t -> m ()
47+ , release_display :: MonadIO m => m ()
73 -- | Returns the current display bounds.
48 -- | Returns the current display bounds.
74− display_bounds :: MonadIO m => t -> m DisplayRegion
49+ , display_bounds :: MonadIO m => m DisplayRegion
76− -- Internal method used to provide the DisplayTerminal instance to the DisplayHandle
78− display_terminal_instance :: MonadIO m
81− -> (forall d. DisplayTerminal d => d -> DisplayHandle)
84 -- | Output the byte buffer of the specified size to the terminal device. The size is equal to
50 -- | Output the byte buffer of the specified size to the terminal device. The size is equal to
85 -- end_ptr - start_ptr
51 -- end_ptr - start_ptr
86− output_byte_buffer :: t -> OutputBuffer -> Int -> IO ()
52+ , output_byte_buffer :: OutputBuffer -> Int -> IO ()
87−
53+ -- | Maximum number of colors supported by the context.
88− -- | Handle of output device
54+ , context_color_count :: Int
89− output_handle :: t -> IO Handle
55+ , assumed_state_ref :: IORef AssumedState
56+ , mk_display_context :: DisplayContext -> IO DisplayContext
91−instance Terminal TerminalHandle where
59+data AssumedState = AssumedState
92− terminal_ID (TerminalHandle t _) = terminal_ID t
60+ { prev_fattr :: Maybe FixedAttr
93− release_terminal (TerminalHandle t _) = release_terminal t
61+ , prev_output_ops :: Maybe DisplayOps
94− reserve_display (TerminalHandle t _) = reserve_display t
62+ }
95− release_display (TerminalHandle t _) = release_display t
96− display_bounds (TerminalHandle t _) = display_bounds t
97− display_terminal_instance (TerminalHandle t _) = display_terminal_instance t
98− output_byte_buffer (TerminalHandle t _) = output_byte_buffer t
99− output_handle (TerminalHandle t _) = output_handle t
101−data DisplayHandle where
64+initial_assumed_state :: AssumedState
102− DisplayHandle :: forall d . DisplayTerminal d => d -> TerminalHandle -> DisplayState -> DisplayHandle
65+initial_assumed_state = AssumedState Nothing Nothing
104-- | Acquire display access to the given region of the display.
67-- | Acquire display access to the given region of the display.
105-- Currently all regions have the upper left corner of (0,0) and the lower right corner at
68-- Currently all regions have the upper left corner of (0,0) and the lower right corner at
106-- (max display_width provided_width, max display_height provided_height)
69-- (max display_width provided_width, max display_height provided_height)
107−display_context :: MonadIO m => TerminalHandle -> DisplayRegion -> m DisplayHandle
70+display_context :: MonadIO m
108−display_context t b = do
74+display_context t r = liftIO $ do
109− s <- initial_display_state
75+ let def_context self = DisplayContext
110− display_terminal_instance t b (\ d -> DisplayHandle d t s)
76+ { context_region = r
111−
77+ , context_device = t
112−data DisplayState = DisplayState
78+ , move_cursor_required_bytes = move_cursor_required_bytes self
113− { previous_output_ref :: IORef (Maybe DisplayOps)
79+ , serialize_move_cursor = serialize_move_cursor self
114− }
80+ , show_cursor_required_bytes = show_cursor_required_bytes self
115−
81+ , serialize_show_cursor = serialize_show_cursor self
116−initial_display_state :: MonadIO m => m DisplayState
82+ , hide_cursor_required_bytes = hide_cursor_required_bytes self
117−initial_display_state = liftM DisplayState $ liftIO $ newIORef Nothing
83+ , serialize_hide_cursor = serialize_hide_cursor self
118−
84+ , attr_required_bytes = attr_required_bytes self
119−class DisplayTerminal d where
85+ , serialize_set_attr = serialize_set_attr self
86+ , default_attr_required_bytes = default_attr_required_bytes self
87+ , serialize_default_attr = serialize_default_attr self
88+ , inline_hack = return ()
90+ mfix (mk_display_context t . def_context)
92+data DisplayContext = DisplayContext
120− -- | Provide the bounds of the display context.
93+ { -- | Provide the bounds of the display context.
121− context_region :: d -> DisplayRegion
94+ context_region :: DisplayRegion
122−
95+ , context_device :: Terminal
123− -- | Maximum number of colors supported by the context.
124− context_color_count :: d -> Int
126 -- | sets the output position to the specified row and column. Where the number of bytes
96 -- | sets the output position to the specified row and column. Where the number of bytes
127 -- required for the control codes can be specified seperate from the actual byte sequence.
97 -- required for the control codes can be specified seperate from the actual byte sequence.
128− move_cursor_required_bytes :: d -> Int -> Int -> Int
98+ , move_cursor_required_bytes :: Int -> Int -> Int
129− serialize_move_cursor :: MonadIO m => d -> Int -> Int -> OutputBuffer -> m OutputBuffer
99+ , serialize_move_cursor :: Int -> Int -> OutputBuffer -> IO OutputBuffer
131− show_cursor_required_bytes :: d -> Int
100+ , show_cursor_required_bytes :: Int
132− serialize_show_cursor :: MonadIO m => d -> OutputBuffer -> m OutputBuffer
101+ , serialize_show_cursor :: OutputBuffer -> IO OutputBuffer
134− hide_cursor_required_bytes :: d -> Int
102+ , hide_cursor_required_bytes :: Int
135− serialize_hide_cursor :: MonadIO m => d -> OutputBuffer -> m OutputBuffer
103+ , serialize_hide_cursor :: OutputBuffer -> IO OutputBuffer
137 -- | Assure the specified output attributes will be applied to all the following text until the
104 -- | Assure the specified output attributes will be applied to all the following text until the
138 -- next output attribute change. Where the number of bytes required for the control codes can
105 -- next output attribute change. Where the number of bytes required for the control codes can
139 -- be specified seperate from the actual byte sequence. The required number of bytes must be
106 -- be specified seperate from the actual byte sequence. The required number of bytes must be
@@ -145,33 +112,15 @@ class DisplayTerminal d where
145 -- attributes. In order to support this the currently applied display attributes are required.
112 -- attributes. In order to support this the currently applied display attributes are required.
146 -- In addition it may be possible to optimize the state changes based off the currently applied
113 -- In addition it may be possible to optimize the state changes based off the currently applied
147 -- display attributes.
114 -- display attributes.
148− attr_required_bytes :: d -> FixedAttr -> Attr -> DisplayAttrDiff -> Int
115+ , attr_required_bytes :: FixedAttr -> Attr -> DisplayAttrDiff -> Int
149− serialize_set_attr :: MonadIO m => d -> FixedAttr -> Attr -> DisplayAttrDiff -> OutputBuffer -> m OutputBuffer
116+ , serialize_set_attr :: FixedAttr -> Attr -> DisplayAttrDiff -> OutputBuffer -> IO OutputBuffer
151 -- | Reset the display attributes to the default display attributes
117 -- | Reset the display attributes to the default display attributes
152− default_attr_required_bytes :: d -> Int
118+ , default_attr_required_bytes :: Int
153− serialize_default_attr :: MonadIO m => d -> OutputBuffer -> m OutputBuffer
119+ , serialize_default_attr :: OutputBuffer -> IO OutputBuffer
155 -- | See Graphics.Vty.Terminal.XTermColor.inline_hack
120 -- | See Graphics.Vty.Terminal.XTermColor.inline_hack
156− inline_hack :: MonadIO m => d -> m ()
121+ , inline_hack :: IO ()
157− inline_hack _d = return ()
122+ }
160−instance DisplayTerminal DisplayHandle where
161− context_region (DisplayHandle d _ _) = context_region d
162− context_color_count (DisplayHandle d _ _) = context_color_count d
163− move_cursor_required_bytes (DisplayHandle d _ _) = move_cursor_required_bytes d
164− serialize_move_cursor (DisplayHandle d _ _) = serialize_move_cursor d
165− show_cursor_required_bytes (DisplayHandle d _ _) = show_cursor_required_bytes d
166− serialize_show_cursor (DisplayHandle d _ _) = serialize_show_cursor d
167− hide_cursor_required_bytes (DisplayHandle d _ _) = hide_cursor_required_bytes d
168− serialize_hide_cursor (DisplayHandle d _ _) = serialize_hide_cursor d
169− attr_required_bytes (DisplayHandle d _ _) = attr_required_bytes d
170− serialize_set_attr (DisplayHandle d _ _) = serialize_set_attr d
171− default_attr_required_bytes (DisplayHandle d _ _) = default_attr_required_bytes d
172− serialize_default_attr (DisplayHandle d _ _) = serialize_default_attr d
173− inline_hack (DisplayHandle d _ _) = inline_hack d
175-- | All terminals serialize UTF8 text to the terminal device exactly as serialized in memory.
124-- | All terminals serialize UTF8 text to the terminal device exactly as serialized in memory.
176utf8_text_required_bytes :: BS.ByteString -> Int
125utf8_text_required_bytes :: BS.ByteString -> Int
177utf8_text_required_bytes str =
126utf8_text_required_bytes str =
@@ -179,15 +128,14 @@ utf8_text_required_bytes str =
179 in src_bytes_length
128 in src_bytes_length
181-- | All terminals serialize UTF8 text to the terminal device exactly as serialized in memory.
130-- | All terminals serialize UTF8 text to the terminal device exactly as serialized in memory.
182−serialize_utf8_text :: MonadIO m => BS.ByteString -> OutputBuffer -> m OutputBuffer
131+serialize_utf8_text :: BS.ByteString -> OutputBuffer -> IO OutputBuffer
183serialize_utf8_text str dest_ptr =
132serialize_utf8_text str dest_ptr =
184 let (src_fptr, src_ptr_offset, src_bytes_length) = BS.toForeignPtr str
133 let (src_fptr, src_ptr_offset, src_bytes_length) = BS.toForeignPtr str
185− in liftIO $ withForeignPtr src_fptr $ \src_ptr -> do
134+ in withForeignPtr src_fptr $ \src_ptr -> do
186 let src_ptr' = src_ptr `plusPtr` src_ptr_offset
135 let src_ptr' = src_ptr `plusPtr` src_ptr_offset
187 BS.memcpy dest_ptr src_ptr' (toEnum src_bytes_length)
136 BS.memcpy dest_ptr src_ptr' (toEnum src_bytes_length)
188 return (dest_ptr `plusPtr` src_bytes_length)
137 return (dest_ptr `plusPtr` src_bytes_length)
191-- | Displays the given `Picture`.
139-- | Displays the given `Picture`.
193-- 0. The image is cropped to the display size.
141-- 0. The image is cropped to the display size.
@@ -199,159 +147,142 @@ serialize_utf8_text str dest_ptr =
199-- 3. Serialized to the display.
147-- 3. Serialized to the display.
201-- 4. The cursor is then shown and positioned or kept hidden.
149-- 4. The cursor is then shown and positioned or kept hidden.
204-- todo: specify possible IO exceptions.
151-- todo: specify possible IO exceptions.
205-- abstract from IO monad to a MonadIO instance.
152-- abstract from IO monad to a MonadIO instance.
206−output_picture :: MonadIO m => DisplayHandle -> Picture -> m ()
153+output_picture :: MonadIO m => DisplayContext -> Picture -> m ()
207−output_picture (DisplayHandle d t s) pic = do
154+output_picture dc pic = liftIO $ do
155+ as <- readIORef (assumed_state_ref $ context_device dc)
208− let !r = context_region d
156+ let !r = context_region dc
209− let !ops = spans_for_pic pic r
157+ !ops = spans_for_pic pic r
210− let !initial_attr = FixedAttr default_style_mask Nothing Nothing
158+ !initial_attr = FixedAttr default_style_mask Nothing Nothing
211− -- Diff the previous output against the requested output. Differences are currently on a per-row
159+ -- Diff the previous output against the requested output. Differences are currently on a per-row
212− -- basis.
160+ -- basis.
161+ -- \todo handle resizes that crop the dominate directions better.
213− diffs :: [Bool]
162+ diffs :: [Bool] = case prev_output_ops as of
214− <- liftIO ( readIORef (previous_output_ref s) )
215− >>= \mprevious_ops -> case mprevious_ops of
217− -> return $ replicate ( fromEnum $ region_height $ effected_region ops )
163+ Nothing -> replicate (fromEnum $ region_height $ effected_region ops) True
220− -> if effected_region previous_ops /= effected_region ops
164+ Just previous_ops -> if effected_region previous_ops /= effected_region ops
221− then return $ replicate ( fromEnum $ region_height $ effected_region ops )
165+ then replicate (fromEnum $ region_height $ effected_region ops) True
223− else return $ zipWith (/=) ( Vector.toList $ display_ops previous_ops )
166+ else zipWith (/=) (Vector.toList $ display_ops previous_ops)
224− ( Vector.toList $ display_ops ops )
167+ (Vector.toList $ display_ops ops)
226− -- determine the number of bytes required to completely serialize the output ops.
168+ -- determine the number of bytes required to completely serialize the output ops.
227− let total = hide_cursor_required_bytes d
169+ total = hide_cursor_required_bytes dc
228− + default_attr_required_bytes d
170+ + default_attr_required_bytes dc
229− + required_bytes d initial_attr diffs ops
171+ + required_bytes dc initial_attr diffs ops
230 + case pic_cursor pic of
172 + case pic_cursor pic of
231 NoCursor -> 0
173 NoCursor -> 0
232 Cursor x y -> let m = cursor_output_map ops $ pic_cursor pic
174 Cursor x y -> let m = cursor_output_map ops $ pic_cursor pic
233 ( ox, oy ) = char_to_output_pos m ( x, y )
175 ( ox, oy ) = char_to_output_pos m ( x, y )
234− in show_cursor_required_bytes d
235− + move_cursor_required_bytes d ox oy
176+ in show_cursor_required_bytes dc + move_cursor_required_bytes dc ox oy
237 -- ... then serialize
177 -- ... then serialize
238− liftIO $ allocaBytes (fromEnum total) $ \start_ptr -> do
178+ allocaBytes (fromEnum total) $ \start_ptr -> do
239− ptr <- serialize_hide_cursor d start_ptr
179+ ptr <- serialize_hide_cursor dc start_ptr
240− ptr' <- serialize_default_attr d ptr
180+ ptr' <- serialize_default_attr dc ptr
241− ptr'' <- serialize_output_ops d ptr' initial_attr diffs ops
181+ ptr'' <- serialize_output_ops dc ptr' initial_attr diffs ops
242 end_ptr <- case pic_cursor pic of
182 end_ptr <- case pic_cursor pic of
243 NoCursor -> return ptr''
183 NoCursor -> return ptr''
244 Cursor x y -> do
184 Cursor x y -> do
245 let m = cursor_output_map ops $ pic_cursor pic
185 let m = cursor_output_map ops $ pic_cursor pic
246 (ox, oy) = char_to_output_pos m (x,y)
186 (ox, oy) = char_to_output_pos m (x,y)
247− serialize_show_cursor d ptr'' >>= serialize_move_cursor d ox oy
187+ serialize_show_cursor dc ptr'' >>= serialize_move_cursor dc ox oy
248 -- todo: How to handle exceptions?
188 -- todo: How to handle exceptions?
249 case end_ptr `minusPtr` start_ptr of
189 case end_ptr `minusPtr` start_ptr of
250 count | count < 0 -> fail "End pointer before start of buffer."
190 count | count < 0 -> fail "End pointer before start of buffer."
251 | toEnum count > total -> fail $ "End pointer past end of buffer by " ++ show (toEnum count - total)
191 | toEnum count > total -> fail $ "End pointer past end of buffer by " ++ show (toEnum count - total)
252− | otherwise -> output_byte_buffer t start_ptr (toEnum count)
192+ | otherwise -> output_byte_buffer (context_device dc) start_ptr (toEnum count)
253 -- Cache the output spans.
193 -- Cache the output spans.
254− liftIO $ writeIORef (previous_output_ref s) (Just ops)
194+ let as' = as { prev_output_ops = Just ops }
255− return ()
195+ writeIORef (assumed_state_ref $ context_device dc) as'
257−required_bytes :: DisplayTerminal d => d -> FixedAttr -> [Bool] -> DisplayOps -> Int
197+required_bytes :: DisplayContext -> FixedAttr -> [Bool] -> DisplayOps -> Int
258−required_bytes d in_fattr diffs ops =
198+required_bytes dc in_fattr diffs ops =
259 let (_, n, _, _) = Vector.foldl' required_bytes' (0, 0, in_fattr, diffs) ( display_ops ops )
199 let (_, n, _, _) = Vector.foldl' required_bytes' (0, 0, in_fattr, diffs) ( display_ops ops )
262 required_bytes' (y, current_sum, fattr, True : diffs') span_ops
202 required_bytes' (y, current_sum, fattr, True : diffs') span_ops
263− = let (s, fattr') = span_ops_required_bytes d y fattr span_ops
203+ = let (s, fattr') = span_ops_required_bytes dc y fattr span_ops
264 in ( y + 1, s + current_sum, fattr', diffs' )
204 in ( y + 1, s + current_sum, fattr', diffs' )
265 required_bytes' (y, current_sum, fattr, False : diffs') _span_ops
205 required_bytes' (y, current_sum, fattr, False : diffs') _span_ops
266 = ( y + 1, current_sum, fattr, diffs' )
206 = ( y + 1, current_sum, fattr, diffs' )
267 required_bytes' (_y, _current_sum, _fattr, [] ) _span_ops
207 required_bytes' (_y, _current_sum, _fattr, [] ) _span_ops
268 = error "shouldn't be possible"
208 = error "shouldn't be possible"
270−span_ops_required_bytes :: DisplayTerminal d => d -> Int -> FixedAttr -> SpanOps -> (Int, FixedAttr)
210+span_ops_required_bytes :: DisplayContext -> Int -> FixedAttr -> SpanOps -> (Int, FixedAttr)
271−span_ops_required_bytes d y in_fattr span_ops =
211+span_ops_required_bytes dc y in_fattr span_ops =
272 -- The first operation is to set the cursor to the start of the row
212 -- The first operation is to set the cursor to the start of the row
273− let header_required_bytes = move_cursor_required_bytes d 0 y
213+ let header_required_bytes = move_cursor_required_bytes dc 0 y
274 -- then the span ops are serialized in the order specified
214 -- then the span ops are serialized in the order specified
275− in Vector.foldl' ( \(current_sum, fattr) op -> let (c, fattr') = span_op_required_bytes d fattr op
215+ in Vector.foldl' ( \(current_sum, fattr) op -> let (c, fattr') = span_op_required_bytes dc fattr op
276 in (c + current_sum, fattr')
216 in (c + current_sum, fattr')
278 (header_required_bytes, in_fattr)
218 (header_required_bytes, in_fattr)
281−span_op_required_bytes :: DisplayTerminal d => d -> FixedAttr -> SpanOp -> (Int, FixedAttr)
221+span_op_required_bytes :: DisplayContext -> FixedAttr -> SpanOp -> (Int, FixedAttr)
282−span_op_required_bytes d fattr (AttributeChange attr) =
222+span_op_required_bytes dc fattr (AttributeChange attr) =
283− let attr' = limit_attr_for_display d attr
223+ let attr' = limit_attr_for_display (context_device dc) attr
284 diffs = display_attr_diffs fattr fattr'
224 diffs = display_attr_diffs fattr fattr'
285− c = attr_required_bytes d fattr attr' diffs
225+ c = attr_required_bytes dc fattr attr' diffs
286 fattr' = fix_display_attr fattr attr'
226 fattr' = fix_display_attr fattr attr'
287 in (c, fattr')
227 in (c, fattr')
288−span_op_required_bytes _d fattr (TextSpan _ _ str) = (utf8_text_required_bytes str, fattr)
228+span_op_required_bytes _dc fattr (TextSpan _ _ str) = (utf8_text_required_bytes str, fattr)
290−serialize_output_ops :: ( MonadIO m, DisplayTerminal d )
230+serialize_output_ops :: DisplayContext
292 -> OutputBuffer
231 -> OutputBuffer
293 -> FixedAttr
232 -> FixedAttr
294 -> [Bool]
233 -> [Bool]
295 -> DisplayOps
234 -> DisplayOps
296− -> m OutputBuffer
235+ -> IO OutputBuffer
297−serialize_output_ops d start_ptr in_fattr diffs ops = do
236+serialize_output_ops dc start_ptr in_fattr diffs ops = do
298 (_, end_ptr, _, _) <- Vector.foldM' serialize_output_ops'
237 (_, end_ptr, _, _) <- Vector.foldM' serialize_output_ops'
299 ( 0, start_ptr, in_fattr, diffs )
238 ( 0, start_ptr, in_fattr, diffs )
300 ( display_ops ops )
239 ( display_ops ops )
301 return end_ptr
240 return end_ptr
303 serialize_output_ops' ( y, out_ptr, fattr, True : diffs' ) span_ops
242 serialize_output_ops' ( y, out_ptr, fattr, True : diffs' ) span_ops
304− = serialize_span_ops d y out_ptr fattr span_ops
243+ = serialize_span_ops dc y out_ptr fattr span_ops
305 >>= return . ( \(out_ptr', fattr') -> ( y + 1, out_ptr', fattr', diffs' ) )
244 >>= return . ( \(out_ptr', fattr') -> ( y + 1, out_ptr', fattr', diffs' ) )
306 serialize_output_ops' ( y, out_ptr, fattr, False : diffs' ) _span_ops
245 serialize_output_ops' ( y, out_ptr, fattr, False : diffs' ) _span_ops
307 = return ( y + 1, out_ptr, fattr, diffs' )
246 = return ( y + 1, out_ptr, fattr, diffs' )
308 serialize_output_ops' (_y, _out_ptr, _fattr, [] ) _span_ops
247 serialize_output_ops' (_y, _out_ptr, _fattr, [] ) _span_ops
309 = error "shouldn't be possible"
248 = error "shouldn't be possible"
311−serialize_span_ops :: ( MonadIO m, DisplayTerminal d )
250+serialize_span_ops :: DisplayContext
314 -> OutputBuffer
252 -> OutputBuffer
315 -> FixedAttr
253 -> FixedAttr
316 -> SpanOps
254 -> SpanOps
317− -> m (OutputBuffer, FixedAttr)
255+ -> IO (OutputBuffer, FixedAttr)
318−serialize_span_ops d y out_ptr in_fattr span_ops = do
256+serialize_span_ops dc y out_ptr in_fattr span_ops = do
319 -- The first operation is to set the cursor to the start of the row
257 -- The first operation is to set the cursor to the start of the row
320− out_ptr' <- serialize_move_cursor d 0 y out_ptr
258+ out_ptr' <- serialize_move_cursor dc 0 y out_ptr
321 -- then the span ops are serialized in the order specified
259 -- then the span ops are serialized in the order specified
322− Vector.foldM ( \(out_ptr'', fattr) op -> serialize_span_op d op out_ptr'' fattr )
260+ Vector.foldM ( \(out_ptr'', fattr) op -> serialize_span_op dc op out_ptr'' fattr )
323 (out_ptr', in_fattr)
261 (out_ptr', in_fattr)
326−serialize_span_op :: ( MonadIO m, DisplayTerminal d )
264+serialize_span_op :: DisplayContext
328 -> SpanOp
265 -> SpanOp
329 -> OutputBuffer
266 -> OutputBuffer
330 -> FixedAttr
267 -> FixedAttr
331− -> m (OutputBuffer, FixedAttr)
268+ -> IO (OutputBuffer, FixedAttr)
332−serialize_span_op d (AttributeChange attr) out_ptr fattr = do
269+serialize_span_op dc (AttributeChange attr) out_ptr fattr = do
333− let attr' = limit_attr_for_display d attr
270+ let attr' = limit_attr_for_display (context_device dc) attr
334 fattr' = fix_display_attr fattr attr'
271 fattr' = fix_display_attr fattr attr'
335 diffs = display_attr_diffs fattr fattr'
272 diffs = display_attr_diffs fattr fattr'
336− out_ptr' <- serialize_set_attr d fattr attr' diffs out_ptr
273+ out_ptr' <- serialize_set_attr dc fattr attr' diffs out_ptr
337 return (out_ptr', fattr')
274 return (out_ptr', fattr')
338−serialize_span_op _d (TextSpan _ _ str) out_ptr fattr = do
275+serialize_span_op _dc (TextSpan _ _ str) out_ptr fattr = do
339 out_ptr' <- serialize_utf8_text str out_ptr
276 out_ptr' <- serialize_utf8_text str out_ptr
340 return (out_ptr', fattr)
277 return (out_ptr', fattr)
342−marshall_to_terminal :: ( Terminal t )
343− => t -> Int -> (Ptr Word8 -> IO (Ptr Word8)) -> IO ()
279+send_to_terminal :: Terminal -> Int -> (Ptr Word8 -> IO (Ptr Word8)) -> IO ()
344−marshall_to_terminal t c f = do
280+send_to_terminal t c f = allocaBytes (fromEnum c) $ \start_ptr -> do
345− start_ptr <- mallocBytes (fromEnum c)
347− -- todo: capture exceptions?
348 end_ptr <- f start_ptr
281 end_ptr <- f start_ptr
349 case end_ptr `minusPtr` start_ptr of
282 case end_ptr `minusPtr` start_ptr of
350 count | count < 0 -> fail "End pointer before start pointer."
283 count | count < 0 -> fail "End pointer before start pointer."
351 | toEnum count > c -> fail $ "End pointer past end of buffer by " ++ show (toEnum count - c)
284 | toEnum count > c -> fail $ "End pointer past end of buffer by " ++ show (toEnum count - c)
352 | otherwise -> output_byte_buffer t start_ptr (toEnum count)
285 | otherwise -> output_byte_buffer t start_ptr (toEnum count)
356-- | The cursor position is given in X,Y character offsets. Due to multi-column characters this
287-- | The cursor position is given in X,Y character offsets. Due to multi-column characters this
357-- needs to be translated to column, row positions.
288-- needs to be translated to column, row positions.
@@ -391,8 +322,8 @@ cursor_column_offset span_ops cx cy =
392-- | Not all terminals support all display attributes. This filters a display attribute to what the
323-- | Not all terminals support all display attributes. This filters a display attribute to what the
393-- given terminal can display.
324-- given terminal can display.
394−limit_attr_for_display :: DisplayTerminal d => d -> Attr -> Attr
325+limit_attr_for_display :: Terminal -> Attr -> Attr
395−limit_attr_for_display d attr
326+limit_attr_for_display t attr
396 = attr { attr_fore_color = clamp_color $ attr_fore_color attr
327 = attr { attr_fore_color = clamp_color $ attr_fore_color attr
397 , attr_back_color = clamp_color $ attr_back_color attr
328 , attr_back_color = clamp_color $ attr_back_color attr
@@ -401,16 +332,16 @@ limit_attr_for_display d attr
401 clamp_color KeepCurrent = KeepCurrent
332 clamp_color KeepCurrent = KeepCurrent
402 clamp_color (SetTo c) = clamp_color' c
333 clamp_color (SetTo c) = clamp_color' c
403 clamp_color' (ISOColor v)
334 clamp_color' (ISOColor v)
404− | context_color_count d < 8 = Default
335+ | context_color_count t < 8 = Default
405− | context_color_count d < 16 && v >= 8 = SetTo $ ISOColor (v - 8)
336+ | context_color_count t < 16 && v >= 8 = SetTo $ ISOColor (v - 8)
406 | otherwise = SetTo $ ISOColor v
337 | otherwise = SetTo $ ISOColor v
407 clamp_color' (Color240 v)
338 clamp_color' (Color240 v)
408 -- TODO: Choose closes ISO color?
339 -- TODO: Choose closes ISO color?
409− | context_color_count d < 8 = Default
340+ | context_color_count t < 8 = Default
410− | context_color_count d < 16 = Default
341+ | context_color_count t < 16 = Default
411− | context_color_count d == 240 = SetTo $ Color240 v
342+ | context_color_count t == 240 = SetTo $ Color240 v
412 | otherwise
343 | otherwise
413 = let p :: Double = fromIntegral v / 240.0
344 = let p :: Double = fromIntegral v / 240.0
414− v' = floor $ p * (fromIntegral $ context_color_count d)
345+ v' = floor $ p * (fromIntegral $ context_color_count t)
415 in SetTo $ Color240 v'
346 in SetTo $ Color240 v'