@@ -13,6 +13,7 @@ module Graphics.Vty.Output.TerminfoBased ( reserve_terminal )
14import Graphics.Vty.Prelude
14import Graphics.Vty.Prelude
16+import qualified Data.ByteString as BS
16import Data.Terminfo.Parse
17import Data.Terminfo.Parse
17import Data.Terminfo.Eval
18import Data.Terminfo.Eval
@@ -20,11 +21,15 @@ import Graphics.Vty.Attributes
20import Graphics.Vty.DisplayAttributes
21import Graphics.Vty.DisplayAttributes
21import Graphics.Vty.Output.Interface
22import Graphics.Vty.Output.Interface
24+import Blaze.ByteString.Builder (Write, writeToByteString)
23import Control.Monad.Trans
26import Control.Monad.Trans
25−import Data.Bits ( (.&.) )
28+import Data.Bits ((.&.))
29+import Data.Foldable (foldMap)
26import Data.IORef
30import Data.IORef
27−import Data.Maybe ( isJust, isNothing, fromJust )
31+import Data.Maybe (isJust, isNothing, fromJust)
29import Foreign.C.Types ( CLong(..) )
34import Foreign.C.Types ( CLong(..) )
@@ -61,8 +66,7 @@ data DisplayAttrCaps = DisplayAttrCaps
62send_cap_to_terminal :: Output -> CapExpression -> [CapParam] -> IO ()
67send_cap_to_terminal :: Output -> CapExpression -> [CapParam] -> IO ()
63send_cap_to_terminal t cap cap_params = do
68send_cap_to_terminal t cap cap_params = do
64− send_to_terminal t (cap_expression_required_bytes cap cap_params)
69+ output_byte_buffer t $ writeToByteString $ write_cap_expr cap cap_params
65− (serialize_cap_expression cap cap_params)
67{- | Uses terminfo for all control codes. While this should provide the most compatible terminal
71{- | Uses terminfo for all control codes. While this should provide the most compatible terminal
68 - terminfo does not support some features that would increase efficiency and improve compatibility:
72 - terminfo does not support some features that would increase efficiency and improve compatibility:
@@ -130,8 +134,8 @@ reserve_terminal in_ID out_handle = liftIO $ do
130 case raw_size of
134 case raw_size of
131 (w, h) | w < 0 || h < 0 -> fail $ "getwinsize returned < 0 : " ++ show raw_size
135 (w, h) | w < 0 || h < 0 -> fail $ "getwinsize returned < 0 : " ++ show raw_size
132 | otherwise -> return (w,h)
136 | otherwise -> return (w,h)
133− , output_byte_buffer = \out_ptr out_byte_count -> do
137+ , output_byte_buffer = \out_bytes -> do
134− hPutBuf out_handle out_ptr (fromEnum out_byte_count)
138+ BS.hPut out_handle out_bytes
135 hFlush out_handle
139 hFlush out_handle
136 , context_color_count
140 , context_color_count
137 = case supports_no_colors terminfo_caps of
141 = case supports_no_colors terminfo_caps of
@@ -163,8 +167,7 @@ probe_cap ti cap_name
164parse_cap :: (Applicative m, MonadIO m) => String -> m CapExpression
168parse_cap :: (Applicative m, MonadIO m) => String -> m CapExpression
165parse_cap cap_str = do
169parse_cap cap_str = do
166− parse_result <- parse_cap_expression cap_str
170+ case parse_cap_expression cap_str of
167− case parse_result of
168 Left e -> fail $ show e
171 Left e -> fail $ show e
169 Right cap -> return cap
172 Right cap -> return cap
@@ -194,45 +197,20 @@ terminfo_display_context t_actual terminfo_caps r =
194 let dc = DisplayContext
197 let dc = DisplayContext
195 { context_device = t_actual
198 { context_device = t_actual
196 , context_region = r
199 , context_region = r
197− , move_cursor_required_bytes = \x y -> cap_expression_required_bytes (cup terminfo_caps)
200+ , write_move_cursor = \x y -> write_cap_expr (cup terminfo_caps) [toEnum y, toEnum x]
198− [toEnum y, toEnum x]
199− , serialize_move_cursor = \x y out_ptr -> serialize_cap_expression (cup terminfo_caps)
200− [toEnum y, toEnum x]
202− , show_cursor_required_bytes = case cnorm terminfo_caps of
201+ , write_show_cursor = case cnorm terminfo_caps of
203 Nothing -> error "this terminal does not support show cursor"
202 Nothing -> error "this terminal does not support show cursor"
204− Just c -> cap_expression_required_bytes c []
203+ Just c -> write_cap_expr c []
205− , serialize_show_cursor = \out_ptr -> do
206− case cnorm terminfo_caps of
207− Nothing -> fail "this terminal does not support show cursor"
208− Just c -> serialize_cap_expression c [] out_ptr
209− , hide_cursor_required_bytes = case civis terminfo_caps of
204+ , write_hide_cursor = case civis terminfo_caps of
210 Nothing -> error "this terminal does not support hide cursor"
205 Nothing -> error "this terminal does not support hide cursor"
211− Just c -> cap_expression_required_bytes c []
206+ Just c -> write_cap_expr c []
212− , serialize_hide_cursor = \out_ptr -> do
207+ , write_set_attr = terminfo_write_set_attr dc terminfo_caps
213− case civis terminfo_caps of
208+ , write_default_attr = write_cap_expr (set_default_attr terminfo_caps) []
214− Nothing -> fail "this terminal does not support hide cursor"
209+ , write_row_end = write_cap_expr (clear_eol terminfo_caps) []
215− Just c -> serialize_cap_expression c [] out_ptr
216− , attr_required_bytes = \_prev_attr _req_attr _diffs -> assumed_attr_required_bytes
217− , serialize_set_attr = terminfo_serialize_set_attr dc terminfo_caps
218− , default_attr_required_bytes = cap_expression_required_bytes (set_default_attr terminfo_caps) []
219− , serialize_default_attr = serialize_cap_expression (set_default_attr terminfo_caps) []
220− , row_end_required_bytes = cap_expression_required_bytes (clear_eol terminfo_caps) []
221− , serialize_row_end = serialize_cap_expression (clear_eol terminfo_caps) []
222 , inline_hack = return ()
210 , inline_hack = return ()
224 in return dc
212 in return dc
226−-- | Instead of evaluating all the rules related to setting display attributes twice (once in
227−-- required bytes and again in serialize) or some memoization scheme just return a size
228−-- requirement as big the longest possible control string.
230−-- Which is assumed to the be less than 512 for now.
232−-- \todo Not verified as safe and wastes memory.
233−assumed_attr_required_bytes :: Int
234−assumed_attr_required_bytes = 512
236-- | Portably setting the display attributes is a giant pain in the ass.
214-- | Portably setting the display attributes is a giant pain in the ass.
238-- If the terminal supports the sgr capability (which sets the on/off state of each style
216-- If the terminal supports the sgr capability (which sets the on/off state of each style
@@ -260,32 +238,29 @@ assumed_attr_required_bytes = 512
261-- \todo This assumes that fewer state changes, followed by fewer bytes, is what to optimize. I
239-- \todo This assumes that fewer state changes, followed by fewer bytes, is what to optimize. I
262-- haven't measured this or even examined terminal implementations. *shrug*
240-- haven't measured this or even examined terminal implementations. *shrug*
263−terminfo_serialize_set_attr :: DisplayContext
265− -> FixedAttr -> Attr -> DisplayAttrDiff -> OutputBuffer -> IO OutputBuffer
241+terminfo_write_set_attr :: DisplayContext -> TerminfoCaps -> FixedAttr -> Attr -> DisplayAttrDiff -> Write
266−terminfo_serialize_set_attr dc terminfo_caps prev_attr req_attr diffs out_ptr = do
242+terminfo_write_set_attr dc terminfo_caps prev_attr req_attr diffs = do
267 case (fore_color_diff diffs == ColorToDefault) || (back_color_diff diffs == ColorToDefault) of
243 case (fore_color_diff diffs == ColorToDefault) || (back_color_diff diffs == ColorToDefault) of
268 -- The only way to reset either color, portably, to the default is to use either the set
244 -- The only way to reset either color, portably, to the default is to use either the set
269 -- state capability or the set default capability.
245 -- state capability or the set default capability.
270 True -> do
246 True -> do
271− case req_display_cap_seq_for ( display_attr_caps terminfo_caps )
247+ case req_display_cap_seq_for (display_attr_caps terminfo_caps)
272− ( fixed_style attr )
248+ (fixed_style attr )
273− ( style_to_apply_seq $ fixed_style attr )
249+ (style_to_apply_seq $ fixed_style attr) of
276− -- only way to reset a color to the defaults
250+ -- only way to reset a color to the defaults
277− -> serialize_default_attr dc out_ptr
251+ EnterExitSeq caps -> write_default_attr dc
278− >>= (\out_ptr' -> liftIO $ foldM (\ptr cap -> serialize_cap_expression cap [] ptr) out_ptr' caps)
252+ `mappend`
253+ foldMap (\cap -> write_cap_expr cap []) caps
279− >>= set_colors
255+ set_colors
281− -- implicitly resets the colors to the defaults
256+ -- implicitly resets the colors to the defaults
282− -> liftIO $ serialize_cap_expression ( fromJust $ set_attr_states
257+ SetState state -> write_cap_expr (fromJust $ set_attr_states
283− $ display_attr_caps
258+ $ display_attr_caps
284− $ terminfo_caps
259+ $ terminfo_caps
286− ( sgr_args_for_state state )
261+ (sgr_args_for_state state)
287− out_ptr
262+ `mappend`
288− >>= set_colors
263+ set_colors
289 -- Otherwise the display colors are not changing or changing between two non-default
264 -- Otherwise the display colors are not changing or changing between two non-default
290 -- points.
265 -- points.
291 False -> do
266 False -> do
@@ -293,50 +268,43 @@ terminfo_serialize_set_attr dc terminfo_caps prev_attr req_attr diffs out_ptr =
293 -- colors to be reset because the required capability was not available.
268 -- colors to be reset because the required capability was not available.
294 case req_display_cap_seq_for (display_attr_caps terminfo_caps)
269 case req_display_cap_seq_for (display_attr_caps terminfo_caps)
295 (fixed_style attr)
270 (fixed_style attr)
296− (style_diffs diffs)
271+ (style_diffs diffs) of
298− -- Really, if terminals were re-implemented with modern concepts instead of
272+ -- Really, if terminals were re-implemented with modern concepts instead of bowing
299− -- bowing down to 40 yr old dumb terminal requirements this would be the
273+ -- down to 40 yr old dumb terminal requirements this would be the only case ever
300− -- only case ever reached!
301− -- Changes the style and color states according to the differences with the
274+ -- reached! Changes the style and color states according to the differences with
302− -- currently applied states.
275+ -- the currently applied states.
303− EnterExitSeq caps
276+ EnterExitSeq caps -> foldMap (\cap -> write_cap_expr cap []) caps
304− -> foldM (\ptr cap -> serialize_cap_expression cap [] ptr) out_ptr caps
277+ `mappend`
305− >>= apply_color_diff set_fore_color (fore_color_diff diffs)
278+ write_color_diff set_fore_color (fore_color_diff diffs)
306− >>= apply_color_diff set_back_color (back_color_diff diffs)
280+ write_color_diff set_back_color (back_color_diff diffs)
308− -- implicitly resets the colors to the defaults
281+ -- implicitly resets the colors to the defaults
309− -> serialize_cap_expression (fromJust $ set_attr_states
282+ SetState state -> write_cap_expr (fromJust $ set_attr_states
310− $ display_attr_caps terminfo_caps
283+ $ display_attr_caps terminfo_caps
312− (sgr_args_for_state state)
285+ (sgr_args_for_state state)
314− >>= set_colors
286+ `mappend` set_colors
316 color_map = case use_alt_color_map terminfo_caps of
288 color_map = case use_alt_color_map terminfo_caps of
317 False -> ansi_color_index
289 False -> ansi_color_index
318 True -> alt_color_index
290 True -> alt_color_index
319 attr = fix_display_attr prev_attr req_attr
291 attr = fix_display_attr prev_attr req_attr
320− set_colors ptr = do
292+ set_colors =
321− ptr' <- case fixed_fore_color attr of
293+ (case fixed_fore_color attr of
322− Just c -> serialize_cap_expression (set_fore_color terminfo_caps)
294+ Just c -> write_cap_expr (set_fore_color terminfo_caps)
323− [ toEnum $ color_map c ]
295+ [toEnum $ color_map c]
325− Nothing -> return ptr
296+ Nothing -> mempty)
326− ptr'' <- case fixed_back_color attr of
298+ (case fixed_back_color attr of
327− Just c -> serialize_cap_expression (set_back_color terminfo_caps)
299+ Just c -> write_cap_expr (set_back_color terminfo_caps)
328− [ toEnum $ color_map c ]
300+ [toEnum $ color_map c]
330− Nothing -> return ptr'
301+ Nothing -> mempty)
332− apply_color_diff _f NoColorChange ptr
302+ write_color_diff _f NoColorChange
333− = return ptr
303+ = mempty
334− apply_color_diff _f ColorToDefault _ptr
304+ write_color_diff _f ColorToDefault
335− = fail "ColorToDefault is not a possible case for apply_color_diffs"
305+ = error "ColorToDefault is not a possible case for apply_color_diffs"
336− apply_color_diff f ( SetColor c ) ptr
306+ write_color_diff f (SetColor c)
337− = serialize_cap_expression (f terminfo_caps)
338− [ toEnum $ color_map c ]
307+ = write_cap_expr (f terminfo_caps) [toEnum $ color_map c]
341-- | The color table used by a terminal is a 16 color set followed by a 240 color set that might not
309-- | The color table used by a terminal is a 16 color set followed by a 240 color set that might not
342-- be supported by the terminal.
310-- be supported by the terminal.