@@ -78,7 +78,7 @@ send_cap_to_terminal t cap cap_params = do
7878 - should be used instead of the generic "sgr" string capability.
7979 -}
8080reserve_terminal :: ( Applicative m, MonadIO m ) => String -> Handle -> m Terminal
81−reserve_terminal in_ID out_handle = liftIO $ mfix $ \self -> do
81+reserve_terminal in_ID out_handle = liftIO $ do
8282 ti <- Terminfo.setupTerm in_ID
8383 -- assumes set foreground always implies set background exists.
8484 -- if set foreground is not set then all color changing style attributes are filtered.
@@ -112,42 +112,44 @@ reserve_terminal in_ID out_handle = liftIO $ mfix $ \self -> do
112112 <*> require_cap ti "clear"
113113 <*> require_cap ti "el"
114114 <*> current_display_attr_caps ti
115− let send_cap s = send_cap_to_terminal self (s terminfo_caps)
116− maybe_send_cap s = when (isJust $ s terminfo_caps) . send_cap (fromJust . s)
117115 new_assumed_state_ref <- newIORef initial_assumed_state
118− return $ Terminal
119− { terminal_ID = in_ID
120− , release_terminal = liftIO $ do
121− send_cap set_default_attr []
122− maybe_send_cap cnorm []
123− hClose out_handle
124− , reserve_display = liftIO $ do
125− -- If there is no support for smcup: Clear the screen and then move the mouse to the
126− -- home position to approximate the behavior.
127− maybe_send_cap smcup []
128− hFlush out_handle
129− send_cap clear_screen []
130− , release_display = liftIO $ do
131− maybe_send_cap rmcup []
132− maybe_send_cap cnorm []
133− , display_bounds = do
134− raw_size <- liftIO $ get_window_size
135− case raw_size of
136− (w, h) | w < 0 || h < 0 -> fail $ "getwinsize returned < 0 : " ++ show raw_size
137− | otherwise -> return $ DisplayRegion (toEnum w) (toEnum h)
138− , output_byte_buffer = \out_ptr out_byte_count -> do
139− hPutBuf out_handle out_ptr (fromEnum out_byte_count)
140− hFlush out_handle
141− , context_color_count
142− = case supports_no_colors terminfo_caps of
143− False -> case Terminfo.getCapability ti (Terminfo.tiGetNum "colors" ) of
144− Nothing -> 8
145− Just v -> toEnum v
146− True -> 1
147− , supports_cursor_visibility = isJust $ civis terminfo_caps
148− , assumed_state_ref = new_assumed_state_ref
149− , mk_display_context = mk_terminfo_display_context terminfo_caps
150− }
116+ let t = Terminal
117+ { terminal_ID = in_ID
118+ , release_terminal = liftIO $ do
119+ send_cap set_default_attr []
120+ maybe_send_cap cnorm []
121+ hClose out_handle
122+ , reserve_display = liftIO $ do
123+ -- If there is no support for smcup: Clear the screen and then move the mouse to the
124+ -- home position to approximate the behavior.
125+ maybe_send_cap smcup []
126+ hFlush out_handle
127+ send_cap clear_screen []
128+ , release_display = liftIO $ do
129+ maybe_send_cap rmcup []
130+ maybe_send_cap cnorm []
131+ , display_bounds = do
132+ raw_size <- liftIO $ get_window_size
133+ case raw_size of
134+ (w, h) | w < 0 || h < 0 -> fail $ "getwinsize returned < 0 : " ++ show raw_size
135+ | otherwise -> return $ DisplayRegion (toEnum w) (toEnum h)
136+ , output_byte_buffer = \out_ptr out_byte_count -> do
137+ hPutBuf out_handle out_ptr (fromEnum out_byte_count)
138+ hFlush out_handle
139+ , context_color_count
140+ = case supports_no_colors terminfo_caps of
141+ False -> case Terminfo.getCapability ti (Terminfo.tiGetNum "colors" ) of
142+ Nothing -> 8
143+ Just v -> toEnum v
144+ True -> 1
145+ , supports_cursor_visibility = isJust $ civis terminfo_caps
146+ , assumed_state_ref = new_assumed_state_ref
147+ -- would be better to use fix, but I'm having issues avoiding <<loop>>
148+ , display_context = liftIO . terminfo_display_context terminfo_caps t
149+ }
150+ send_cap s = send_cap_to_terminal t (s terminfo_caps)
151+ maybe_send_cap s = when (isJust $ s terminfo_caps) . send_cap (fromJust . s)
152+ return t
151153
152154require_cap :: (Applicative m, MonadIO m) => Terminfo.Terminal -> String -> m CapExpression
153155require_cap ti cap_name
@@ -189,35 +191,39 @@ get_window_size = do
189191 (a,b) <- (`divMod` 65536) `fmap` c_get_window_size
190192 return (fromIntegral b, fromIntegral a)
191193
192−mk_terminfo_display_context :: TerminfoCaps -> DisplayContext -> IO DisplayContext
193−mk_terminfo_display_context terminfo_caps self = do
194− return $ self
195− { move_cursor_required_bytes = \x y -> cap_expression_required_bytes (cup terminfo_caps)
196− [toEnum y, toEnum x]
197− , serialize_move_cursor = \x y out_ptr -> serialize_cap_expression (cup terminfo_caps)
198− [toEnum y, toEnum x]
199− out_ptr
200− , show_cursor_required_bytes = case cnorm terminfo_caps of
201− Nothing -> error "this terminal does not support show cursor"
202− Just c -> cap_expression_required_bytes c []
203− , serialize_show_cursor = \out_ptr -> do
204− case cnorm terminfo_caps of
205− Nothing -> fail "this terminal does not support show cursor"
206− Just c -> serialize_cap_expression c [] out_ptr
207− , hide_cursor_required_bytes = case civis terminfo_caps of
208− Nothing -> error "this terminal does not support hide cursor"
209− Just c -> cap_expression_required_bytes c []
210− , serialize_hide_cursor = \out_ptr -> do
211− case civis terminfo_caps of
212− Nothing -> fail "this terminal does not support hide cursor"
213− Just c -> serialize_cap_expression c [] out_ptr
214− , attr_required_bytes = \_prev_attr _req_attr _diffs -> assumed_attr_required_bytes
215− , serialize_set_attr = terminfo_serialize_set_attr self terminfo_caps
216− , default_attr_required_bytes = cap_expression_required_bytes (set_default_attr terminfo_caps) []
217− , serialize_default_attr = serialize_cap_expression (set_default_attr terminfo_caps) []
218− , row_end_required_bytes = cap_expression_required_bytes (clear_eol terminfo_caps) []
219− , serialize_row_end = serialize_cap_expression (clear_eol terminfo_caps) []
220− }
194+terminfo_display_context :: TerminfoCaps -> Terminal -> DisplayRegion -> IO DisplayContext
195+terminfo_display_context terminfo_caps t r = do
196+ let dc = DisplayContext
197+ { context_region = r
198+ , context_device = t
199+ , move_cursor_required_bytes = \x y -> cap_expression_required_bytes (cup terminfo_caps)
200+ [toEnum y, toEnum x]
201+ , serialize_move_cursor = \x y out_ptr -> serialize_cap_expression (cup terminfo_caps)
202+ [toEnum y, toEnum x]
203+ out_ptr
204+ , show_cursor_required_bytes = case cnorm terminfo_caps of
205+ Nothing -> error "this terminal does not support show cursor"
206+ Just c -> cap_expression_required_bytes c []
207+ , serialize_show_cursor = \out_ptr -> do
208+ case cnorm terminfo_caps of
209+ Nothing -> fail "this terminal does not support show cursor"
210+ Just c -> serialize_cap_expression c [] out_ptr
211+ , hide_cursor_required_bytes = case civis terminfo_caps of
212+ Nothing -> error "this terminal does not support hide cursor"
213+ Just c -> cap_expression_required_bytes c []
214+ , serialize_hide_cursor = \out_ptr -> do
215+ case civis terminfo_caps of
216+ Nothing -> fail "this terminal does not support hide cursor"
217+ Just c -> serialize_cap_expression c [] out_ptr
218+ , attr_required_bytes = \_prev_attr _req_attr _diffs -> assumed_attr_required_bytes
219+ , serialize_set_attr = terminfo_serialize_set_attr dc terminfo_caps
220+ , default_attr_required_bytes = cap_expression_required_bytes (set_default_attr terminfo_caps) []
221+ , serialize_default_attr = serialize_cap_expression (set_default_attr terminfo_caps) []
222+ , row_end_required_bytes = cap_expression_required_bytes (clear_eol terminfo_caps) []
223+ , serialize_row_end = serialize_cap_expression (clear_eol terminfo_caps) []
224+ , inline_hack = return ()
225+ }
226+ return dc
221227
222228-- | Instead of evaluating all the rules related to setting display attributes twice (once in
223229-- required bytes and again in serialize) or some memoization scheme just return a size